diff options
| -rw-r--r-- | boot/parse.c | 40 | ||||
| -rw-r--r-- | boot/tree.c | 52 |
2 files changed, 85 insertions, 7 deletions
diff --git a/boot/parse.c b/boot/parse.c index ed00f94..3870e6c 100644 --- a/boot/parse.c +++ b/boot/parse.c @@ -225,6 +225,7 @@ parser_node_type(struct Parser* p, struct Parser_Error* error) // for now, we only support a single type name. // in the future, we might want to support more complex types. return (struct Type_Node){ + .type = TYPE_NAME, .name = type_name, .span = token.span, .location = token.location, @@ -287,6 +288,42 @@ parser_expression_primary_group(struct Parser* p, struct Parser_Error* error) } struct Expression* +parser_expression_function(struct Parser* p, struct Parser_Error* error) +{ + struct Token fun_token = CHECK(parser_need(p, TOKEN_WORD_FUN, error)); + CHECK(parser_need(p, TOKEN_ROUND_OPEN, error)); + + struct Expression_Function fun = { 0 }; + while (!parser_probe(p, TOKEN_ROUND_CLOSE)) { + struct Token name_token = CHECK(parser_need(p, TOKEN_NAME, error)); + struct String name = name_token.value.name; + + struct Type_Node type = { 0 }; + + struct Token next = parser_peek(p); + if (!token_is(&next, TOKEN_ROUND_CLOSE) && !token_is(&next, TOKEN_COMMA)) + type = CHECK(parser_node_type(p, error)); + + if (parser_probe(p, TOKEN_COMMA)) parser_next(p); + + check(fun.parameter_count < EXPRESSION_FUNCTION_MAX_PARAMS, "too many function parameters"); + fun.parameters[fun.parameter_count++] = (struct Expression_Function_Parameter){ + .name = name, + .type = type, + }; + } + parser_next(p); + + if (!parser_probe(p, TOKEN_CURLY_OPEN)) fun.return_type = CHECK(parser_node_type(p, error)); + + fun.body = CHECK(parser_block_node(p, error)); + + return expression_new( + EXPRESSION_FUNCTION, (union Expression_Value){ .function = fun }, + span_merge(fun_token.span, fun.body.span), fun_token.location); +} + +struct Expression* parser_expression_primary(struct Parser* p, struct Parser_Error* error) { struct Token token = parser_peek(p); @@ -304,6 +341,8 @@ parser_expression_primary(struct Parser* p, struct Parser_Error* error) return parser_expression_primary_boolean(p, error); case TOKEN_ROUND_OPEN: return parser_expression_primary_group(p, error); + case TOKEN_WORD_FUN: + return parser_expression_function(p, error); default: *error = parser_error(PARSER_ERROR_EXPECTED_PRIMARY_EXPRESSION); return nil; @@ -522,7 +561,6 @@ parser_statement_declaration(struct Parser* p, struct Parser_Error* error) union Statement_Value value = { .declaration = { .names = names, - .has_type = true, .type = type, .initializer = initializer, }, diff --git a/boot/tree.c b/boot/tree.c index dcda4da..64eb23b 100644 --- a/boot/tree.c +++ b/boot/tree.c @@ -335,10 +335,20 @@ struct Block_Node struct Cursor location; }; +void block_node_print(const struct Block_Node* block); + +enum Type_Type +{ + TYPE_NONE, + TYPE_NAME, +}; + // a type node represents a type in the syntax tree. // currently, we only support types that are simple names. +// or null types. struct Type_Node { + enum Type_Type type; // note: we could also just include the token here i think? struct String name; struct Span span; @@ -362,6 +372,8 @@ enum Expression_Kind EXPRESSION_CALL, EXPRESSION_SUBSCRIPT, EXPRESSION_MEMBER, + + EXPRESSION_FUNCTION, }; struct Expression_Integer_Literal @@ -425,6 +437,21 @@ struct Expression_Member struct String name; }; +#define EXPRESSION_FUNCTION_MAX_PARAMS 32 + +struct Expression_Function +{ + struct Expression_Function_Parameter + { + struct String name; + struct Type_Node type; + } parameters[EXPRESSION_FUNCTION_MAX_PARAMS]; + uint parameter_count; + + struct Type_Node return_type; + struct Block_Node body; +}; + union Expression_Value { struct Expression_Integer_Literal integer_literal; @@ -438,6 +465,7 @@ union Expression_Value struct Expression_Call call; struct Expression_Subscript subscript; struct Expression_Member member; + struct Expression_Function function; }; struct Expression @@ -535,6 +563,20 @@ expression_print(const struct Expression* expression) expression_print(expression->value.member.subject); printf(")"); break; + case EXPRESSION_FUNCTION: { + const struct Expression_Function* fun = &expression->value.function; + printf("(function"); + for (uint i = 0; i < fun->parameter_count; ++i) { + const struct Expression_Function_Parameter* param = &fun->parameters[i]; + printf(" (param %s)", param->name.data); + if (param->type.type != TYPE_NONE) { printf(" (type %s)", param->type.name.data); } + } + if (fun->return_type.type != TYPE_NONE) printf(" (returns %s)", fun->return_type.name.data); + printf(" "); + block_node_print(&fun->body); + printf(")"); + break; + } default: failure("unexpected expression kind passed to `expression_print`"); break; @@ -559,11 +601,9 @@ struct Statement_Value_Expression struct Statement_Value_Declaration { - struct String_Array names; // the names of the variables being declared. - struct Expression* initializer; // the expression to initialize the variable with. - - bool has_type; // whether the declaration has a type. - struct Type_Node type; // the type of the variable, if any. + struct String_Array names; + struct Expression* initializer; + struct Type_Node type; }; struct Statement_Value_Block @@ -657,7 +697,7 @@ statement_print(const struct Statement* statement) { printf("%s ", name.data); } - if (statement->value.declaration.has_type) { + if (statement->value.declaration.type.type != TYPE_NONE) { printf("(type %s) ", statement->value.declaration.type.name.data); } if (statement->value.declaration.initializer) { |
