aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMel <mel@rnrd.eu>2026-05-04 21:34:42 +0200
committerMel <mel@rnrd.eu>2026-05-04 21:34:42 +0200
commit81c9e336eb88bc2d010a7cd776bb14789977fb4a (patch)
tree6cc7bddb22bbb5446e4331ae9ddedfc260c2c40d
parent59cf0e45d701bd7ec0bbdbf10f69ec7cec66051a (diff)
downloadcatskill-81c9e336eb88bc2d010a7cd776bb14789977fb4a.tar.zst
catskill-81c9e336eb88bc2d010a7cd776bb14789977fb4a.zip
Lower source compound assigns and inc/dec statements
Signed-off-by: Mel <mel@rnrd.eu>
-rw-r--r--boot/lower.c75
-rw-r--r--boot/tree.c38
2 files changed, 102 insertions, 11 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 };
diff --git a/boot/tree.c b/boot/tree.c
index 07b96a3..e0bb4ec 100644
--- a/boot/tree.c
+++ b/boot/tree.c
@@ -361,6 +361,41 @@ binary_operation_to_string(enum Binary_Operation operation)
}
}
+// turn a compound-assign operator into a simple binary operator.
+// returns none if the operator is not a compound.
+enum Binary_Operation
+binary_operation_strip_assign(enum Binary_Operation operation)
+{
+ switch (operation) {
+ case BINARY_ASSIGN_PLUS:
+ return BINARY_PLUS;
+ case BINARY_ASSIGN_MINUS:
+ return BINARY_MINUS;
+ case BINARY_ASSIGN_MULTIPLY:
+ return BINARY_MULTIPLY;
+ case BINARY_ASSIGN_DIVIDE:
+ return BINARY_DIVIDE;
+ case BINARY_ASSIGN_MODULO:
+ return BINARY_MODULO;
+ case BINARY_ASSIGN_AND:
+ return BINARY_AND;
+ case BINARY_ASSIGN_OR:
+ return BINARY_OR;
+ case BINARY_ASSIGN_BITWISE_AND:
+ return BINARY_BITWISE_AND;
+ case BINARY_ASSIGN_BITWISE_OR:
+ return BINARY_BITWISE_OR;
+ case BINARY_ASSIGN_BITWISE_XOR:
+ return BINARY_BITWISE_XOR;
+ case BINARY_ASSIGN_BITWISE_LEFT_SHIFT:
+ return BINARY_BITWISE_LEFT_SHIFT;
+ case BINARY_ASSIGN_BITWISE_RIGHT_SHIFT:
+ return BINARY_BITWISE_RIGHT_SHIFT;
+ default:
+ return BINARY_NONE;
+ }
+}
+
enum Increment_Decrement_Operation
{
INCREMENT_DECREMENT_NONE,
@@ -1009,7 +1044,8 @@ REGION(struct Tree_Statement, tree_statement)
struct Tree_Statement*
tree_statement_new(
- enum Tree_Statement_Kind kind, union Tree_Statement_Value value, struct Span span, struct Cursor location)
+ enum Tree_Statement_Kind kind, union Tree_Statement_Value value, struct Span span,
+ struct Cursor location)
{
check(region_tree_statement_cursor < REGION_SIZE, "out of statement memory");
struct Tree_Statement* statement = &region_tree_statement[region_tree_statement_cursor++];