diff options
| author | Mel <mel@rnrd.eu> | 2026-05-04 21:34:42 +0200 |
|---|---|---|
| committer | Mel <mel@rnrd.eu> | 2026-05-04 21:34:42 +0200 |
| commit | 81c9e336eb88bc2d010a7cd776bb14789977fb4a (patch) | |
| tree | 6cc7bddb22bbb5446e4331ae9ddedfc260c2c40d /boot/lower.c | |
| parent | 59cf0e45d701bd7ec0bbdbf10f69ec7cec66051a (diff) | |
| download | catskill-81c9e336eb88bc2d010a7cd776bb14789977fb4a.tar.zst catskill-81c9e336eb88bc2d010a7cd776bb14789977fb4a.zip | |
Lower source compound assigns and inc/dec statements
Signed-off-by: Mel <mel@rnrd.eu>
Diffstat (limited to 'boot/lower.c')
| -rw-r--r-- | boot/lower.c | 75 |
1 files changed, 65 insertions, 10 deletions
diff --git a/boot/lower.c b/boot/lower.c index 9531483..9880d6e 100644 --- a/boot/lower.c +++ b/boot/lower.c @@ -963,26 +963,81 @@ lower_statement(struct Lower_Context* ctx, struct Tree_Statement* tree_stmt) case TREE_STATEMENT_EXPRESSION: { struct Tree_Expression* inner = tree_stmt->value.expression.inner; - // TODO: compound assignments! if (inner && inner->kind == TREE_EXPRESSION_BINARY_OPERATION) { enum Binary_Operation op = inner->value.binary_operator.operation; + struct Tree_Expression* lhs_tree = inner->value.binary_operator.left_operand; + 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, inner->value.binary_operator.left_operand); - v.assign.rhs = lower_expression(ctx, inner->value.binary_operator.right_operand); + 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); } if (op > BINARY_ASSIGN) { - lower_emit_error_c( - ctx->unit, tree_stmt->span, "unimplemented: compound assignment"); - return nil; + // compound assigns always synthesize into a basic assignment + // to a simple binary operation. + if (!lhs_tree || lhs_tree->kind != TREE_EXPRESSION_NAME) { + // TODO: implement non-trivial lhs assignments like function + // calls for example. not too common but sometimes necessary. + lower_emit_error_c( + ctx->unit, tree_stmt->span, + "unimplemented: compound assignment with non-trivial lvalue"); + return nil; + } + + enum Binary_Operation simple_op = binary_operation_strip_assign(op); + if (simple_op == BINARY_NONE) { + lower_emit_error_c( + ctx->unit, tree_stmt->span, "unknown compound assignment operator"); + 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); } } if (inner && inner->kind == TREE_EXPRESSION_INCREMENT_DECREMENT) { - lower_emit_error_c( - ctx->unit, tree_stmt->span, - "unimplemented: increment/decrement at statement position"); - return nil; + // synthesize into assignment and binary operation + struct Tree_Expression_Increment_Decrement* incdec = &inner->value.increment_decrement; + struct Tree_Expression* subject = incdec->subject; + if (!subject || subject->kind != TREE_EXPRESSION_NAME) { + // TODO: handle this too, like compound assignments + lower_emit_error_c( + ctx->unit, tree_stmt->span, + "unimplemented: increment/decrement on non-trivial lvalue"); + return nil; + } + + 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* 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); } union Statement_Value v = { 0 }; |
