diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2024-09-11 01:48:15 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2024-09-11 01:48:15 -0400 |
| commit | 989dc3f4428fd3185753336cb91baf48e0c85ad0 (patch) | |
| tree | 15eb26b7161f9953039f98625a42f7c68c688c86 | |
| parent | 23209a0aab983501701c62ac87c891309a7d3d58 (diff) | |
Support `if x := blah: ...`
| -rw-r--r-- | compile.c | 32 | ||||
| -rw-r--r-- | parse.c | 5 | ||||
| -rw-r--r-- | test/optionals.tm | 5 |
3 files changed, 30 insertions, 12 deletions
@@ -1196,21 +1196,30 @@ CORD compile_statement(env_t *env, ast_t *ast) } case If: { auto if_ = Match(ast, If); - type_t *cond_t = get_type(env, if_->condition); + ast_t *condition = if_->condition; + CORD code = CORD_EMPTY; + if (condition->tag == Declare) { + env = fresh_scope(env); + code = compile_statement(env, condition); + bind_statement(env, condition); + condition = Match(condition, Declare)->var; + } + + type_t *cond_t = get_type(env, condition); if (cond_t->tag == PointerType) { - code_err(if_->condition, "This pointer will always be non-null, so it should not be used in a conditional."); + code_err(condition, "This pointer will always be non-null, so it should not be used in a conditional."); } else if (cond_t->tag != BoolType && cond_t->tag != TextType && cond_t->tag != OptionalType) { - code_err(if_->condition, "Only boolean values, optional pointers, and text can be used in conditionals (this is a %T)", cond_t); + code_err(condition, "Only boolean values, optional pointers, and text can be used in conditionals (this is a %T)", cond_t); } env_t *truthy_scope = env; - CORD condition; + CORD condition_code; if (cond_t->tag == TextType) { - condition = CORD_all("(", compile(env, if_->condition), ").length"); + condition_code = CORD_all("(", compile(env, condition), ").length"); } else if (cond_t->tag == OptionalType) { - if (if_->condition->tag == Var) { + if (condition->tag == Var) { truthy_scope = fresh_scope(env); - const char *varname = Match(if_->condition, Var)->name; + const char *varname = Match(condition, Var)->name; binding_t *b = get_binding(env, varname); binding_t *nonnull_b = new(binding_t); *nonnull_b = *b; @@ -1218,14 +1227,17 @@ CORD compile_statement(env_t *env, ast_t *ast) nonnull_b->code = compile_optional_into_nonnull(env, b); set_binding(truthy_scope, varname, nonnull_b); } - condition = compile_optional_check(env, if_->condition); + condition_code = compile_optional_check(env, condition); } else { - condition = compile(env, if_->condition); + condition_code = compile(env, condition); } - CORD code = CORD_all("if (", condition, ")", compile_statement(truthy_scope, if_->body)); + code = CORD_all(code, "if (", condition_code, ")", compile_statement(truthy_scope, if_->body)); if (if_->else_body) code = CORD_all(code, "\nelse ", compile_statement(env, if_->else_body)); + + if (if_->condition->tag == Declare) + code = CORD_all("{\n", code, "}\n"); return code; } case Block: { @@ -1003,8 +1003,9 @@ PARSER(parse_if) { if (!match_word(&pos, "if")) return NULL; - ast_t *condition = expect(ctx, start, &pos, parse_expr, - "I expected to find a condition for this 'if'"); + ast_t *condition = optional(ctx, &pos, parse_declaration); + if (!condition) + condition = expect(ctx, start, &pos, parse_expr, "I expected to find a condition for this 'if'"); ast_t *body = expect(ctx, start, &pos, parse_block, "I expected a body for this 'if' statement"); diff --git a/test/optionals.tm b/test/optionals.tm index d8cbf741..8e24f66d 100644 --- a/test/optionals.tm +++ b/test/optionals.tm @@ -121,3 +121,8 @@ func main(): fail("Truthy: $nope") else: !! Falsey: $nope + + if yep := maybe_int(yes): + >> yep + = 123 : Int + else: fail("Unreachable") |
