Add optional:or_exit(...)

This commit is contained in:
Bruce Hill 2024-09-15 16:42:42 -04:00
parent fb37b0ee42
commit 835eb7e896
9 changed files with 37 additions and 15 deletions

View File

@ -2817,6 +2817,16 @@ CORD compile(env_t *env, ast_t *ast)
(long)(call->self->end - call->self->file->text),
compile_arguments(env, ast, arg_spec, call->args)),
optional_into_nonnull(self_value_t, "opt"), "; })");
} else if (streq(call->name, "or_exit")) {
CORD self = compile_to_pointer_depth(env, call->self, 0, false);
arg_t *arg_spec = new(arg_t, .name="message", .type=Type(OptionalType, .type=TEXT_TYPE),
.default_val=FakeAST(Null, .type=new(type_ast_t, .tag=VarTypeAST, .__data.VarTypeAST.name="Text")),
.next=new(arg_t, .name="code", .type=Type(IntType, .bits=TYPE_IBITS32),
.default_val=FakeAST(Int, .bits=IBITS32, .str="1")));
return CORD_all("({ ", compile_declaration(self_value_t, "opt"), " = ", self, "; ",
"if (", check_null(self_value_t, "opt"), ")\n",
"tomo_exit(", compile_arguments(env, ast, arg_spec, call->args), ");\n",
optional_into_nonnull(self_value_t, "opt"), "; })");
}
code_err(ast, "There is no '%s' method for optional %T values", call->name, nonnull);
}

View File

@ -76,14 +76,15 @@ Exits the program with a given status and optionally prints a message.
**Usage:**
```markdown
ask(message:Text = "", status:Int32 = 0[32]) -> Void
ask(message:Text? = !Text, status:Int32 = 1[32]) -> Void
```
**Parameters:**
- `message`: If nonempty, this message will be printed (with a newline) before
exiting.
- `status`: The status code that the program with exit with.
- `status`: The status code that the program with exit with (default: 1, which
is a failure status).
**Returns:**
This function never returns.

View File

@ -30,7 +30,7 @@ having to use a more generalized form of `enum` which may have different naming
conventions and which would generate a lot of unnecessary code.
In addition to using conditionals to check for null values, you can also use
`:or_else(fallback)` or `:or_fail()`:
`:or_else(fallback)` or `:or_fail()` or `:or_exit()`:
```tomo
maybe_x := 5?
@ -42,6 +42,13 @@ maybe_x := 5?
maybe_x = !Int
>> maybe_x:or_else(-1)
= -1 : Int
>> maybe_x:or_fail()
>> maybe_x:or_fail("No value!")
# Failure!
maybe_x = !Int
>> maybe_x:or_exit()
= -1 : Int
>> maybe_x:or_exit("No value!")
# Exit!
```

View File

@ -42,9 +42,11 @@ env_t *new_compilation_unit(CORD *libname)
.default_val=FakeAST(Bool, true)))),
.ret=TEXT_TYPE)}},
{"exit", {.code="tomo_exit",
.type=Type(FunctionType, .args=new(arg_t, .name="message", .type=Type(TextType), .default_val=FakeAST(TextLiteral),
.next=new(arg_t, .name="code", .type=Type(IntType, .bits=TYPE_IBITS32),
.default_val=FakeAST(Int, .bits=IBITS32, .str="0"))), .ret=Type(AbortType))}},
.type=Type(FunctionType, .args=new(
arg_t, .name="message", .type=Type(OptionalType, .type=Type(TextType)),
.default_val=FakeAST(Null, .type=new(type_ast_t, .tag=VarTypeAST, .__data.VarTypeAST.name="Text")),
.next=new(arg_t, .name="code", .type=Type(IntType, .bits=TYPE_IBITS32),
.default_val=FakeAST(Int, .bits=IBITS32, .str="1"))), .ret=Type(AbortType))}},
{"fail", {.code="fail", .type=Type(FunctionType, .args=new(arg_t, .name="message", .type=Type(CStringType)), .ret=Type(AbortType))}},
{"sleep", {.code="sleep_num", .type=Type(FunctionType, .args=new(arg_t, .name="seconds", .type=Type(NumType, .bits=TYPE_NBITS64)), .ret=Type(VoidType))}},
{"USE_COLOR", {.code="USE_COLOR", .type=Type(BoolType)}},

View File

@ -9,9 +9,7 @@ func main(map=(./map.txt)):
extern InitWindow:func(w:Int32, h:Int32, title:CString)->Void
InitWindow(1600, 900, "raylib [core] example - 2d camera")
map_contents := if contents := map:read():
contents
else: exit(code=1, "Could not find the game map: $map")
map_contents := map:read():or_exit("Could not find the game map: $map")
World.CURRENT:load_map(map_contents)

View File

@ -32,13 +32,13 @@ func parse_ini(path:Path)->{Text:{Text:Text}}:
func main(path:Path, key:Text):
keys := key:split($Pattern"/")
if keys.length > 2:
exit(1, message="
exit("
Too many arguments!
$_USAGE
")
if not path:is_file() or path:is_pipe():
exit(code=1, "Could not read file: $(path.text_content)")
exit("Could not read file: $(path.text_content)")
data := parse_ini(path)
if keys.length < 1 or keys[1] == '*':
@ -47,7 +47,7 @@ func main(path:Path, key:Text):
section := keys[1]:lower()
if not data:has(section):
exit(1, message="Invalid section name: $section; valid names: $(", ":join([k:quoted() for k in data.keys]))")
exit("Invalid section name: $section; valid names: $(", ":join([k:quoted() for k in data.keys]))")
section_data := data:get(section)
if keys.length < 2 or keys[2] == '*':
@ -56,6 +56,6 @@ func main(path:Path, key:Text):
section_key := keys[2]:lower()
if not section_data:has(section_key):
exit(1, message="Invalid key: $section_key; valid keys: $(", ":join(section_data.keys))")
exit("Invalid key: $section_key; valid keys: $(", ":join(section_data.keys))")
say(section_data:get(section_key))

View File

@ -103,7 +103,7 @@ func draw_tree(dep:Dependency, dependencies:{Dependency:{Dependency}}):
func main(files:[Text]):
if files.length == 0:
exit(1, message="
exit("
Please provide at least one file!
$_USAGE
")

View File

@ -89,6 +89,9 @@ func main():
>> (5?):or_fail()
= 5 : Int
>> (5?):or_exit()
= 5 : Int
>> (!Int):or_else(-1)
= -1 : Int

View File

@ -845,6 +845,7 @@ type_t *get_type(env_t *env, ast_t *ast)
type_t *nonnull = Match(self_value_t, OptionalType)->type;
if (streq(call->name, "or_else")) return nonnull;
else if (streq(call->name, "or_fail")) return nonnull;
else if (streq(call->name, "or_exit")) return nonnull;
code_err(ast, "There is no '%s' method for optional %T values", call->name, nonnull);
}
default: {