aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-08-24 20:55:29 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-08-24 20:55:29 -0400
commitf5b2281084d31700690916c6dd250e2da927e566 (patch)
tree067f566a72fab976feccdb92f5bc26c16736e3f3 /src
parentbb1af5c7b5e76ddd3e76ff75e62c0f0a65026ded (diff)
Clean up and fix issue with `if var := val` statements. Previous
implementation was kinda janky, but the new one is more robust and simple.
Diffstat (limited to 'src')
-rw-r--r--src/compile/conditionals.c39
-rw-r--r--src/compile/optionals.c21
-rw-r--r--src/stdlib/util.h11
3 files changed, 39 insertions, 32 deletions
diff --git a/src/compile/conditionals.c b/src/compile/conditionals.c
index 6071b6c4..23d2a177 100644
--- a/src/compile/conditionals.c
+++ b/src/compile/conditionals.c
@@ -36,19 +36,38 @@ Text_t compile_if_statement(env_t *env, ast_t *ast) {
DeclareMatch(if_, ast, If);
ast_t *condition = if_->condition;
if (condition->tag == Declare) {
- if (Match(condition, Declare)->value == NULL) code_err(condition, "This declaration must have a value");
+ DeclareMatch(decl, condition, Declare);
+ if (decl->value == NULL) code_err(condition, "This declaration must have a value");
+
env_t *truthy_scope = fresh_scope(env);
- Text_t code = Texts("IF_DECLARE(", compile_statement(truthy_scope, condition), ", ");
+ ast_t *var = decl->var;
+ type_t *var_type = get_type(truthy_scope, decl->value);
+
+ const char *name = Match(var, Var)->name;
bind_statement(truthy_scope, condition);
- ast_t *var = Match(condition, Declare)->var;
- code = Texts(code, compile_condition(truthy_scope, var), ", ");
- type_t *cond_t = get_type(truthy_scope, var);
- if (cond_t->tag == OptionalType) {
- set_binding(truthy_scope, Match(var, Var)->name, Match(cond_t, OptionalType)->type,
- optional_into_nonnone(cond_t, compile(truthy_scope, var)));
+
+ Text_t code = Texts("if (true) {\n", compile_statement(env, condition), //
+ "if (", compile_condition(truthy_scope, var), ")");
+
+ env_t *nonnull_scope = truthy_scope;
+ if (var_type->tag == OptionalType) {
+ nonnull_scope = fresh_scope(truthy_scope);
+ set_binding(nonnull_scope, name, Match(var_type, OptionalType)->type,
+ optional_into_nonnone(var_type, compile(truthy_scope, var)));
}
- code = Texts(code, compile_statement(truthy_scope, if_->body), ")");
- if (if_->else_body) code = Texts(code, "\nelse ", compile_statement(env, if_->else_body));
+
+ code = Texts(code, compile_block(nonnull_scope, if_->body));
+
+ if (if_->else_body) {
+ Text_t label = Texts("_falsey_", String((int64_t)(ast->start - ast->file->text)));
+ code = Texts(code, "else goto ", label,
+ ";\n"
+ "} else {\n",
+ label, ":;\n", compile_inline_block(env, if_->else_body), "}\n");
+ } else {
+ code = Texts(code, "}\n");
+ }
+
return code;
} else {
Text_t code = Texts("if (", compile_condition(env, condition), ")");
diff --git a/src/compile/optionals.c b/src/compile/optionals.c
index 1cd86c29..b3d94005 100644
--- a/src/compile/optionals.c
+++ b/src/compile/optionals.c
@@ -92,21 +92,20 @@ Text_t check_none(type_t *t, Text_t value) {
t = Match(t, OptionalType)->type;
// NOTE: these use statement expressions ({...;}) because some compilers
// complain about excessive parens around equality comparisons
- if (t->tag == PointerType || t->tag == FunctionType || t->tag == CStringType)
- return Texts("({", value, " == NULL;})");
- else if (t == PATH_TYPE) return Texts("({(", value, ").type.$tag == PATH_NONE;})");
- else if (t == PATH_TYPE_TYPE) return Texts("({(", value, ").$tag == PATH_NONE;})");
- else if (t->tag == BigIntType) return Texts("({(", value, ").small == 0;})");
- else if (t->tag == ClosureType) return Texts("({(", value, ").fn == NULL;})");
+ if (t->tag == PointerType || t->tag == FunctionType || t->tag == CStringType) return Texts("(", value, " == NULL)");
+ else if (t == PATH_TYPE) return Texts("((", value, ").type.$tag == PATH_NONE)");
+ else if (t == PATH_TYPE_TYPE) return Texts("((", value, ").$tag == PATH_NONE)");
+ else if (t->tag == BigIntType) return Texts("((", value, ").small == 0)");
+ else if (t->tag == ClosureType) return Texts("((", value, ").fn == NULL)");
else if (t->tag == NumType)
return Texts(Match(t, NumType)->bits == TYPE_NBITS64 ? "Num$isnan(" : "Num32$isnan(", value, ")");
- else if (t->tag == ListType) return Texts("({(", value, ").length < 0;})");
- else if (t->tag == TableType || t->tag == SetType) return Texts("({(", value, ").entries.length < 0;})");
- else if (t->tag == BoolType) return Texts("({(", value, ") == NONE_BOOL;})");
- else if (t->tag == TextType) return Texts("({(", value, ").length < 0;})");
+ else if (t->tag == ListType) return Texts("((", value, ").length < 0)");
+ else if (t->tag == TableType || t->tag == SetType) return Texts("((", value, ").entries.length < 0)");
+ else if (t->tag == BoolType) return Texts("((", value, ") == NONE_BOOL)");
+ else if (t->tag == TextType) return Texts("((", value, ").length < 0)");
else if (t->tag == IntType || t->tag == ByteType || t->tag == StructType) return Texts("(", value, ").is_none");
else if (t->tag == EnumType) {
- if (enum_has_fields(t)) return Texts("({(", value, ").$tag == 0;})");
+ if (enum_has_fields(t)) return Texts("((", value, ").$tag == 0)");
else return Texts("((", value, ") == 0)");
}
print_err("Optional check not implemented for: ", type_to_str(t));
diff --git a/src/stdlib/util.h b/src/stdlib/util.h
index a789c5f0..1530bd9e 100644
--- a/src/stdlib/util.h
+++ b/src/stdlib/util.h
@@ -21,17 +21,6 @@
&var; \
})
-#define IF_DECLARE(decl, expr, block) \
- if (({ \
- decl; \
- expr ? ({ \
- block; \
- 1; \
- }) \
- : 0; \
- })) { \
- }
-
#define WHEN(type, subj, var, body) \
{ \
type var = subj; \