about summary refs log tree commit diff
path: root/boot/lower.c
diff options
context:
space:
mode:
authorMel <mel@rnrd.eu>2026-05-19 21:07:59 +0200
committerMel <mel@rnrd.eu>2026-05-19 21:07:59 +0200
commit0e4ce87b90b28cdf044a6a1dd8ce1690813faf92 (patch)
tree6d59fb35bd2599fe8b9294966a229c694eefe0f5 /boot/lower.c
parent556aafa5eb681f5500169268d3cdea82a298c2af (diff)
downloadcatskill-0e4ce87b90b28cdf044a6a1dd8ce1690813faf92.tar.zst
catskill-0e4ce87b90b28cdf044a6a1dd8ce1690813faf92.zip
Simplify statement synthesis boilerplate
Signed-off-by: Mel <mel@rnrd.eu>
Diffstat (limited to 'boot/lower.c')
-rw-r--r--boot/lower.c172
1 files changed, 54 insertions, 118 deletions
diff --git a/boot/lower.c b/boot/lower.c
index fb2d29a..b2b2349 100644
--- a/boot/lower.c
+++ b/boot/lower.c
@@ -995,10 +995,9 @@ lower_statement(struct Lower_Context* ctx, struct Tree_Statement* tree_stmt)
             struct Tree_Expression* rhs_tree = inner->value.binary_operator.right_operand;
 
             if (op == BINARY_ASSIGN) {
-                union Statement_Value v = { 0 };
-                v.assign.lhs = lower_expression(ctx, lhs_tree);
-                v.assign.rhs = lower_expression(ctx, rhs_tree);
-                return statement_new(STATEMENT_ASSIGN, v, tree_stmt->span);
+                struct Expression* lhs = lower_expression(ctx, lhs_tree);
+                struct Expression* rhs = lower_expression(ctx, rhs_tree);
+                return ir_make_assign(lhs, rhs, tree_stmt->span);
             }
             if (op > BINARY_ASSIGN) {
                 // compound assigns always synthesize into a basic assignment
@@ -1019,18 +1018,10 @@ lower_statement(struct Lower_Context* ctx, struct Tree_Statement* tree_stmt)
                     return nil;
                 }
 
-                union Expression_Value bin_v = { 0 };
-                bin_v.binary_operator.operation = simple_op;
-                bin_v.binary_operator.left_operand = lower_expression(ctx, lhs_tree);
-                bin_v.binary_operator.right_operand = lower_expression(ctx, rhs_tree);
-                struct Expression* binary =
-                    expression_new(EXPRESSION_BINARY_OPERATION, bin_v, inner->span);
-
-                union Statement_Value v = { 0 };
-                v.assign.lhs = lower_expression(ctx, lhs_tree);
-                v.assign.rhs = binary;
-
-                return statement_new(STATEMENT_ASSIGN, v, tree_stmt->span);
+                struct Expression* binary = ir_make_binary(
+                    simple_op, lower_expression(ctx, lhs_tree), lower_expression(ctx, rhs_tree),
+                    inner->span);
+                return ir_make_assign(lower_expression(ctx, lhs_tree), binary, tree_stmt->span);
             }
         }
         if (inner && inner->kind == TREE_EXPRESSION_INCREMENT_DECREMENT) {
@@ -1048,28 +1039,13 @@ lower_statement(struct Lower_Context* ctx, struct Tree_Statement* tree_stmt)
             enum Binary_Operation simple_op =
                 incdec->operation == INCREMENT_DECREMENT_INCREMENT ? BINARY_PLUS : BINARY_MINUS;
 
-            union Expression_Value one_v = { 0 };
-            one_v.integer_literal.value = 1;
-            struct Expression* one = expression_new(EXPRESSION_INTEGER_LITERAL, one_v, inner->span);
-
-            union Expression_Value bin_v = { 0 };
-            bin_v.binary_operator.operation = simple_op;
-            bin_v.binary_operator.left_operand = lower_expression(ctx, subject);
-            bin_v.binary_operator.right_operand = one;
+            struct Expression* one = ir_make_integer(1, inner->span);
             struct Expression* binary =
-                expression_new(EXPRESSION_BINARY_OPERATION, bin_v, inner->span);
-
-            union Statement_Value v = { 0 };
-            v.assign.lhs = lower_expression(ctx, subject);
-            v.assign.rhs = binary;
-
-            return statement_new(STATEMENT_ASSIGN, v, tree_stmt->span);
+                ir_make_binary(simple_op, lower_expression(ctx, subject), one, inner->span);
+            return ir_make_assign(lower_expression(ctx, subject), binary, tree_stmt->span);
         }
 
-        union Statement_Value v = { 0 };
-        v.expression.inner = lower_expression(ctx, inner);
-
-        return statement_new(STATEMENT_EXPRESSION, v, tree_stmt->span);
+        return ir_make_expression_statement(lower_expression(ctx, inner), tree_stmt->span);
     }
     case TREE_STATEMENT_BLOCK: {
         union Statement_Value v = { 0 };
@@ -1100,20 +1076,16 @@ lower_statement(struct Lower_Context* ctx, struct Tree_Statement* tree_stmt)
 
         switch (loop->style) {
         case TREE_STATEMENT_LOOP_STYLE_WHILE: {
-            union Statement_Value v = { 0 };
-            v.loop.condition = lower_expression(ctx, loop->condition);
-            v.loop.body = lower_block(ctx, &loop->body);
-            return statement_new(STATEMENT_LOOP, v, tree_stmt->span);
+            struct Expression* cond = lower_expression(ctx, loop->condition);
+            struct Block* body = lower_block(ctx, &loop->body);
+            return ir_make_loop(cond, body, tree_stmt->span);
         }
         case TREE_STATEMENT_LOOP_STYLE_ENDLESS: {
             // synthesize a `true` literal so the ir always has a real
             // condition to emit.
-            union Expression_Value tv = { 0 };
-            tv.bool_literal.value = true;
-            union Statement_Value v = { 0 };
-            v.loop.condition = expression_new(EXPRESSION_BOOLEAN_LITERAL, tv, tree_stmt->span);
-            v.loop.body = lower_block(ctx, &loop->body);
-            return statement_new(STATEMENT_LOOP, v, tree_stmt->span);
+            struct Expression* cond = ir_make_bool(true, tree_stmt->span);
+            struct Block* body = lower_block(ctx, &loop->body);
+            return ir_make_loop(cond, body, tree_stmt->span);
         }
         case TREE_STATEMENT_LOOP_STYLE_C:
         case TREE_STATEMENT_LOOP_STYLE_FOR_EACH: {
@@ -1126,8 +1098,6 @@ lower_statement(struct Lower_Context* ctx, struct Tree_Statement* tree_stmt)
             struct Tree_Expression* init = nil;
             struct Tree_Expression* cond_tree = loop->condition;
             struct Tree_Expression* iter_tree = loop->iteration;
-            struct Tree_Expression* synth_cond = nil;
-            struct Statement* synth_iter = nil;
 
             if (loop->style == TREE_STATEMENT_LOOP_STYLE_FOR_EACH) {
                 if (!decl->initializer
@@ -1139,7 +1109,6 @@ lower_statement(struct Lower_Context* ctx, struct Tree_Statement* tree_stmt)
                     return nil;
                 }
                 init = decl->initializer->value.binary_operator.left_operand;
-
                 // condition and iteration step are synthesized below
             } else {
                 init = decl->initializer;
@@ -1170,76 +1139,47 @@ lower_statement(struct Lower_Context* ctx, struct Tree_Statement* tree_stmt)
             struct Type_Ref iter_type = lower_intern_type_ref(ctx, decl->type);
             lower_declare_local(ctx, name, iter_type);
 
-            // build the iteration variable
-            union Statement_Value decl_v = { 0 };
-            decl_v.declaration.name = name;
-            decl_v.declaration.type = iter_type;
-            decl_v.declaration.initializer = init ? lower_expression(ctx, init) : nil;
-            struct Statement* decl_stmt = statement_new(STATEMENT_DECLARATION, decl_v, decl->span);
+            // build the iteration variable declaration
+            struct Statement* decl_stmt = ir_make_declaration(
+                name, iter_type, init ? lower_expression(ctx, init) : nil, decl->span);
 
-            // for range for-each
-            // we synthesize the right condition and step.
+            // condition and iteration step: for c-style we lower the source
+            // ones, for for-each over a range we synthesize `i < hi` and
+            // `i = i + 1`.
+            struct Expression* cond_expr = nil;
+            struct Statement* iter_stmt = nil;
             if (loop->style == TREE_STATEMENT_LOOP_STYLE_FOR_EACH) {
                 struct Tree_Expression* hi = decl->initializer->value.binary_operator.right_operand;
-                struct Expression* lhs = ir_make_name(name, tree_stmt->span);
-                struct Expression* rhs = lower_expression(ctx, hi);
-                synth_cond = nil; // unused; we go straight to the ir form
-                (void)synth_cond;
-
-                struct Expression* cond_expr =
-                    ir_make_binary(BINARY_LESS_THAN, lhs, rhs, tree_stmt->span);
-
-                // step: x = x + 1
-                struct Expression* iter_lhs = ir_make_name(name, tree_stmt->span);
-                struct Expression* iter_rhs_left = ir_make_name(name, tree_stmt->span);
-                struct Expression* one = ir_make_integer(1, tree_stmt->span);
-                struct Expression* iter_rhs =
-                    ir_make_binary(BINARY_PLUS, iter_rhs_left, one, tree_stmt->span);
-                union Statement_Value iter_v = { 0 };
-                iter_v.assign.lhs = iter_lhs;
-                iter_v.assign.rhs = iter_rhs;
-                synth_iter = statement_new(STATEMENT_ASSIGN, iter_v, tree_stmt->span);
-
-                // rest of the construction continues below
-                struct Block* body = lower_block(ctx, &loop->body);
-                if (synth_iter) array_push(&body->statements, &synth_iter);
-
-                union Statement_Value while_v = { 0 };
-                while_v.loop.condition = cond_expr;
-                while_v.loop.body = body;
-                struct Statement* while_stmt =
-                    statement_new(STATEMENT_LOOP, while_v, tree_stmt->span);
-
-                struct Block* outer = block_new();
-                outer->statements = array_new(struct Statement*, 4);
-                array_push(&outer->statements, &decl_stmt);
-                array_push(&outer->statements, &while_stmt);
-
-                lower_pop_scope(ctx, SCOPE_TYPE_BLOCK);
-
-                union Statement_Value v = { 0 };
-                v.block.inner = outer;
-
-                return statement_new(STATEMENT_BLOCK, v, tree_stmt->span);
+                // condition: i < hi
+                cond_expr = ir_make_binary(
+                    BINARY_LESS_THAN, ir_make_name(name, tree_stmt->span),
+                    lower_expression(ctx, hi), tree_stmt->span);
+                // step: i = i + 1
+                iter_stmt = ir_make_assign(
+                    ir_make_name(name, tree_stmt->span),
+                    ir_make_binary(
+                        BINARY_PLUS, ir_make_name(name, tree_stmt->span),
+                        ir_make_integer(1, tree_stmt->span), tree_stmt->span),
+                    tree_stmt->span);
+            } else {
+                cond_expr = cond_tree ? lower_expression(ctx, cond_tree) : nil;
+                if (iter_tree) {
+                    struct Tree_Statement iter_node = {
+                        .kind = TREE_STATEMENT_EXPRESSION,
+                        .value = { .expression = { .inner = iter_tree } },
+                        .span = iter_tree->span,
+                    };
+                    iter_stmt = lower_statement(ctx, &iter_node);
+                }
             }
 
-            // c-style
-            // no synthesis needed!
+            // assemble the body, appending the iteration step at the end so
+            // both for-styles share the same `{ decl; while { body; iter; } }`
+            // shape.
             struct Block* body = lower_block(ctx, &loop->body);
-            if (iter_tree) {
-                struct Tree_Statement iter_node = {
-                    .kind = TREE_STATEMENT_EXPRESSION,
-                    .value = { .expression = { .inner = iter_tree } },
-                    .span = iter_tree->span,
-                };
-                struct Statement* iter_stmt = lower_statement(ctx, &iter_node);
-                if (iter_stmt) array_push(&body->statements, &iter_stmt);
-            }
+            if (iter_stmt) array_push(&body->statements, &iter_stmt);
 
-            union Statement_Value while_v = { 0 };
-            while_v.loop.condition = cond_tree ? lower_expression(ctx, cond_tree) : nil;
-            while_v.loop.body = body;
-            struct Statement* while_stmt = statement_new(STATEMENT_LOOP, while_v, tree_stmt->span);
+            struct Statement* while_stmt = ir_make_loop(cond_expr, body, tree_stmt->span);
 
             struct Block* outer = block_new();
             outer->statements = array_new(struct Statement*, 4);
@@ -1247,11 +1187,7 @@ lower_statement(struct Lower_Context* ctx, struct Tree_Statement* tree_stmt)
             array_push(&outer->statements, &while_stmt);
 
             lower_pop_scope(ctx, SCOPE_TYPE_BLOCK);
-
-            union Statement_Value v = { 0 };
-            v.block.inner = outer;
-
-            return statement_new(STATEMENT_BLOCK, v, tree_stmt->span);
+            return ir_make_block_statement(outer, tree_stmt->span);
         }
         default:
             lower_emit_error_c(ctx->unit, tree_stmt->span, "unknown loop style");
@@ -1259,9 +1195,9 @@ lower_statement(struct Lower_Context* ctx, struct Tree_Statement* tree_stmt)
         }
     }
     case TREE_STATEMENT_BREAK:
-        return statement_new(STATEMENT_BREAK, (union Statement_Value){ 0 }, tree_stmt->span);
+        return ir_make_break(tree_stmt->span);
     case TREE_STATEMENT_CONTINUE:
-        return statement_new(STATEMENT_CONTINUE, (union Statement_Value){ 0 }, tree_stmt->span);
+        return ir_make_continue(tree_stmt->span);
     default:
         lower_emit_error_c(ctx->unit, tree_stmt->span, "unimplemented: this statement kind");
         return nil;