about summary refs log tree commit diff
path: root/boot
diff options
context:
space:
mode:
Diffstat (limited to 'boot')
-rw-r--r--boot/lower.c113
1 files changed, 112 insertions, 1 deletions
diff --git a/boot/lower.c b/boot/lower.c
index 3820408..03cdef5 100644
--- a/boot/lower.c
+++ b/boot/lower.c
@@ -673,33 +673,144 @@ struct Statement* lower_statement(struct Lower_Context* ctx, struct Tree_Stateme
 struct Expression*
 lower_expression(struct Lower_Context* ctx, struct Tree_Expression* tree_expr)
 {
-    // TODO: implement all the expressions
     switch (tree_expr->kind) {
     case TREE_EXPRESSION_INTEGER_LITERAL: {
         union Expression_Value v = { 0 };
         v.integer_literal.value = tree_expr->value.integer_literal.value;
+
         return expression_new(EXPRESSION_INTEGER_LITERAL, v, tree_expr->span);
     }
     case TREE_EXPRESSION_FLOAT_LITERAL: {
         union Expression_Value v = { 0 };
         v.float_literal.value = tree_expr->value.float_literal.value;
+
         return expression_new(EXPRESSION_FLOAT_LITERAL, v, tree_expr->span);
     }
     case TREE_EXPRESSION_STRING_LITERAL: {
         union Expression_Value v = { 0 };
         v.string_literal.value = tree_expr->value.string_literal.value;
+
         return expression_new(EXPRESSION_STRING_LITERAL, v, tree_expr->span);
     }
     case TREE_EXPRESSION_BOOLEAN_LITERAL: {
         union Expression_Value v = { 0 };
         v.bool_literal.value = tree_expr->value.bool_literal.value;
+
         return expression_new(EXPRESSION_BOOLEAN_LITERAL, v, tree_expr->span);
     }
     case TREE_EXPRESSION_NAME: {
         union Expression_Value v = { 0 };
         v.name.name = tree_expr->value.name.name;
+
         return expression_new(EXPRESSION_NAME, v, tree_expr->span);
     }
+    case TREE_EXPRESSION_GROUP:
+        // any groups are discarded in the lowered representation, their presence
+        // just yields different expression constructions.
+        // if required by precedence the final transpiler will handle them by itself.
+        return lower_expression(ctx, tree_expr->value.group.inner_expression);
+    case TREE_EXPRESSION_UNARY_OPERATION: {
+        union Expression_Value v = { 0 };
+        v.unary_operator.operation = tree_expr->value.unary_operator.operation;
+        v.unary_operator.operand = lower_expression(ctx, tree_expr->value.unary_operator.operand);
+
+        return expression_new(EXPRESSION_UNARY_OPERATION, v, tree_expr->span);
+    }
+    case TREE_EXPRESSION_BINARY_OPERATION: {
+        enum Binary_Operation op = tree_expr->value.binary_operator.operation;
+        // TODO: maybe we want to support assignment expressions? for now they're not supported.
+        if (op >= BINARY_ASSIGN) {
+            lower_emit_error_c(
+                ctx->unit, tree_expr->span, "assignment cannot appear as an expression");
+            return nil;
+        }
+        if (op == BINARY_RANGE) {
+            lower_emit_error_c(
+                ctx->unit, tree_expr->span,
+                "range expressions are only valid in loop initializers");
+            return nil;
+        }
+        union Expression_Value v = { 0 };
+        v.binary_operator.operation = op;
+        v.binary_operator.left_operand =
+            lower_expression(ctx, tree_expr->value.binary_operator.left_operand);
+        v.binary_operator.right_operand =
+            lower_expression(ctx, tree_expr->value.binary_operator.right_operand);
+
+        return expression_new(EXPRESSION_BINARY_OPERATION, v, tree_expr->span);
+    }
+    case TREE_EXPRESSION_CALL: {
+        struct Tree_Argument_Group* group = &tree_expr->value.call.argument_group;
+
+        // named arguments need lookup against the callee's parameter table to
+        // reorder; not in this commit. positional-only is fine for now.
+        FOR_EACH_ARRAY (struct String, name, &group->argument_names) {
+            if (name->length > 0) {
+                lower_emit_error_c(
+                    ctx->unit, tree_expr->span, "unimplemented: named call arguments");
+                return nil;
+            }
+        }
+
+        union Expression_Value v = { 0 };
+        v.call.subject = lower_expression(ctx, tree_expr->value.call.subject);
+        v.call.arguments = array_new(struct Expression*, 16);
+        FOR_EACH (struct Tree_Expression*, arg, group->arguments) {
+            struct Expression* lowered = lower_expression(ctx, arg);
+            array_push(&v.call.arguments, &lowered);
+        }
+
+        return expression_new(EXPRESSION_CALL, v, tree_expr->span);
+    }
+    case TREE_EXPRESSION_CONSTRUCT: {
+        struct Tree_Expression* subject = tree_expr->value.construct.subject;
+        if (!subject || subject->kind != TREE_EXPRESSION_NAME) {
+            lower_emit_error_c(
+                ctx->unit, tree_expr->span, "construction subject must be a type name");
+            return nil;
+        }
+        Type_Id type_id;
+        if (!lower_type_lookup_by_name(ctx->unit, subject->value.name.name, &type_id)) {
+            lower_emit_error(
+                ctx->unit, subject->span,
+                string_concatenate(
+                    ARG_ASCII, "undefined type '", ARG_STRING, subject->value.name.name, ARG_ASCII,
+                    "'", ARG_END));
+            return nil;
+        }
+
+        union Expression_Value v = { 0 };
+        v.construct.type_id = type_id;
+        v.construct.fields = array_new(struct Construct_Field, 16);
+
+        struct Tree_Argument_Group* group = &tree_expr->value.construct.argument_group;
+        uint i = 0;
+        FOR_EACH (struct Tree_Expression*, arg, group->arguments) {
+            struct String name = string_empty();
+            if (i < array_length(&group->argument_names))
+                name = *array_at(struct String, &group->argument_names, i);
+            struct Construct_Field field = {
+                .name = name,
+                .value = lower_expression(ctx, arg),
+            };
+            array_push(&v.construct.fields, &field);
+            ++i;
+        }
+
+        return expression_new(EXPRESSION_CONSTRUCT, v, tree_expr->span);
+    }
+    case TREE_EXPRESSION_TYPE:
+        // type-as-expression is only valid as the right-sided of a top-level binding.
+        lower_emit_error_c(
+            ctx->unit, tree_expr->span, "type expression not allowed inside a function body");
+        return nil;
+    case TREE_EXPRESSION_SUBSCRIPT:
+    case TREE_EXPRESSION_MEMBER:
+    case TREE_EXPRESSION_INCREMENT_DECREMENT:
+    case TREE_EXPRESSION_TRY:
+    case TREE_EXPRESSION_MUST:
+    case TREE_EXPRESSION_FUNCTION:
+        // TODO: implement these
     default:
         lower_emit_error_c(ctx->unit, tree_expr->span, "unimplemented: this expression kind");
         return nil;