aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compile.c10
-rw-r--r--docs/README.md5
-rw-r--r--docs/optionals.md11
-rw-r--r--environment.c8
-rw-r--r--examples/game/game.tm4
-rw-r--r--examples/ini.tm8
-rw-r--r--examples/tomodeps.tm2
-rw-r--r--test/optionals.tm3
-rw-r--r--typecheck.c1
9 files changed, 37 insertions, 15 deletions
diff --git a/compile.c b/compile.c
index de5531cc..3aeebfd6 100644
--- a/compile.c
+++ b/compile.c
@@ -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);
}
diff --git a/docs/README.md b/docs/README.md
index 642293ce..13401f32 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -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.
diff --git a/docs/optionals.md b/docs/optionals.md
index 1414ca6a..54fe5f5c 100644
--- a/docs/optionals.md
+++ b/docs/optionals.md
@@ -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!
```
diff --git a/environment.c b/environment.c
index 6810f37a..10aa0b58 100644
--- a/environment.c
+++ b/environment.c
@@ -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)}},
diff --git a/examples/game/game.tm b/examples/game/game.tm
index c7020f55..8c5124d0 100644
--- a/examples/game/game.tm
+++ b/examples/game/game.tm
@@ -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)
diff --git a/examples/ini.tm b/examples/ini.tm
index 50668793..afd71a30 100644
--- a/examples/ini.tm
+++ b/examples/ini.tm
@@ -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))
diff --git a/examples/tomodeps.tm b/examples/tomodeps.tm
index 209f14e0..a427c5f9 100644
--- a/examples/tomodeps.tm
+++ b/examples/tomodeps.tm
@@ -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
")
diff --git a/test/optionals.tm b/test/optionals.tm
index ced42274..05008e20 100644
--- a/test/optionals.tm
+++ b/test/optionals.tm
@@ -89,6 +89,9 @@ func main():
>> (5?):or_fail()
= 5 : Int
+ >> (5?):or_exit()
+ = 5 : Int
+
>> (!Int):or_else(-1)
= -1 : Int
diff --git a/typecheck.c b/typecheck.c
index 933f1f90..5d74a3cd 100644
--- a/typecheck.c
+++ b/typecheck.c
@@ -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: {