about summary refs log tree commit diff
path: root/boot/lower.c
diff options
context:
space:
mode:
Diffstat (limited to 'boot/lower.c')
-rw-r--r--boot/lower.c75
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 };