diff options
| author | Mel <mel@rnrd.eu> | 2026-05-04 19:27:16 +0200 |
|---|---|---|
| committer | Mel <mel@rnrd.eu> | 2026-05-04 19:27:16 +0200 |
| commit | 69a285a524379d07292ac123092bf2a7b7cbf405 (patch) | |
| tree | 0dbc75d480aaa05c13045a89d92d37253796b6a9 /boot/lower.c | |
| parent | 06eff276ce3440df22674572a660e86fc21637d5 (diff) | |
| download | catskill-69a285a524379d07292ac123092bf2a7b7cbf405.tar.zst catskill-69a285a524379d07292ac123092bf2a7b7cbf405.zip | |
Lower source expressions into simple IR
Signed-off-by: Mel <mel@rnrd.eu>
Diffstat (limited to 'boot/lower.c')
| -rw-r--r-- | boot/lower.c | 113 |
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; |
