aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compile.c2
-rw-r--r--parse.c10
-rw-r--r--test/enums.tm6
-rw-r--r--typecheck.c4
4 files changed, 19 insertions, 3 deletions
diff --git a/compile.c b/compile.c
index 9be60d77..f3a13309 100644
--- a/compile.c
+++ b/compile.c
@@ -623,7 +623,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
CORD body = compile_statement(scope, while_->body);
if (loop_ctx.skip_label)
body = CORD_all(body, "\n", loop_ctx.skip_label, ": continue;");
- CORD loop = CORD_all("while (", compile(scope, while_->condition), ") {\n\t", body, "\n}");
+ CORD loop = CORD_all("while (", while_->condition ? compile(scope, while_->condition) : "yes", ") {\n\t", body, "\n}");
if (loop_ctx.stop_label)
loop = CORD_all(loop, "\n", loop_ctx.stop_label, ":;");
return loop;
diff --git a/parse.c b/parse.c
index 28e91b27..75aff30b 100644
--- a/parse.c
+++ b/parse.c
@@ -983,10 +983,18 @@ PARSER(parse_while) {
// while condition [do] [<indent>] body
const char *start = pos;
if (!match_word(&pos, "while")) return NULL;
+
+ const char *tmp = pos;
+ // Shorthand form: `while when ...`
+ if (match_word(&tmp, "when")) {
+ ast_t *when = expect(ctx, start, &pos, parse_when, "I expected a 'when' block after this");
+ if (!when->__data.When.else_body) when->__data.When.else_body = NewAST(ctx->file, pos, pos, Stop);
+ return NewAST(ctx->file, start, pos, While, .body=when);
+ }
ast_t *condition = expect(ctx, start, &pos, parse_expr, "I don't see a viable condition for this 'while'");
expect_str(ctx, start, &pos, ":", "I expected a ':' here");
ast_t *body = expect(ctx, start, &pos, parse_opt_indented_block, "I expected a body for this 'while'");
- const char *tmp = pos;
+ tmp = pos;
whitespace(&tmp);
return NewAST(ctx->file, start, pos, While, .condition=condition, .body=body);
}
diff --git a/test/enums.tm b/test/enums.tm
index 9f700410..553fcf84 100644
--- a/test/enums.tm
+++ b/test/enums.tm
@@ -55,3 +55,9 @@ func main():
>> choose_text(Foo.Last("XX"))
= "else: Foo.Last(t=\"XX\")"
+ i := 1
+ cases := [Foo.One(1), Foo.One(2), Foo.Zero]
+ while when cases[i] is One(x):
+ >> x
+ i += 1
+
diff --git a/typecheck.c b/typecheck.c
index 217937ed..9964c9d9 100644
--- a/typecheck.c
+++ b/typecheck.c
@@ -948,7 +948,9 @@ type_t *get_type(env_t *env, ast_t *ast)
break;
}
}
- if (!any_unhandled)
+ // HACK: `while when ...` is handled by the parser adding an implicit
+ // `else: stop`, which has an empty source code span.
+ if (!any_unhandled && when->else_body->end > when->else_body->start)
code_err(when->else_body, "This 'else' block will never run because every tag is handled");
type_t *else_t = get_type(env, when->else_body);