diff options
Diffstat (limited to 'boot/parse.c')
| -rw-r--r-- | boot/parse.c | 81 |
1 files changed, 76 insertions, 5 deletions
diff --git a/boot/parse.c b/boot/parse.c index b009656..4fc6107 100644 --- a/boot/parse.c +++ b/boot/parse.c @@ -18,6 +18,7 @@ struct Parser_Error PARSER_ERROR_UNEXPECTED_EOF, PARSER_ERROR_EXPECTED_STATEMENT_END, PARSER_ERROR_EXPECTED_PRIMARY_EXPRESSION, + PARSER_ERROR_EXPECTED_TYPE, } kind; // TODO: add span to error }; @@ -54,6 +55,8 @@ parser_error_to_string(const struct Parser_Error* error) return "expected statement end"; case PARSER_ERROR_EXPECTED_PRIMARY_EXPRESSION: return "expected primary expression"; + case PARSER_ERROR_EXPECTED_TYPE: + return "expected type"; default: return "unknown error"; } @@ -161,6 +164,25 @@ parser_probe(struct Parser* p, enum Token_Kind kind) struct Expression* parser_expression(struct Parser* p, struct Parser_Error* error); +struct Type_Node +parser_node_type(struct Parser* p, struct Parser_Error* error) +{ + struct Token token = parser_need(p, TOKEN_NAME, error); + if (token_is_empty(&token)) { + *error = parser_error(PARSER_ERROR_EXPECTED_TYPE); + return (struct Type_Node){ 0 }; + } + struct String type_name = token.value.name; + + // for now, we only support a single type name. + // in the future, we might want to support more complex types. + return (struct Type_Node){ + .name = type_name, + .span = token.span, + .location = token.location, + }; +} + struct Expression* parser_expression_primary_name(struct Parser* p, struct Parser_Error* error) { @@ -424,6 +446,42 @@ parser_expression(struct Parser* p, struct Parser_Error* error) return parser_expression_binary_operation(p, error); } +struct Statement* +parser_statement_declaration(struct Parser* p, struct Parser_Error* error) +{ + struct String_Array names = string_array_new(); + + struct Span span = { 0 }; + struct Cursor location = parser_peek(p).location; + for (;;) { + struct Token name_token = parser_need(p, TOKEN_NAME, error); + if (!parser_error_is_none(error)) return nil; + + span = span_is_empty(span) ? name_token.span : span_merge(span, name_token.span); + string_array_add(&names, name_token.value.name); + + struct Token next = parser_peek(p); + if (next.kind == TOKEN_NAME) break; + if (next.kind == TOKEN_COMMA) parser_next(p); + } + + // for now, type is always required. + struct Type_Node type = CHECK(parser_node_type(p, error)); + CHECK(parser_need(p, TOKEN_ASSIGN, error)); + struct Expression* initializer = CHECK(parser_expression(p, error)); + + span = span_merge(span, initializer->span); + union Statement_Value value = { + .declaration = { + .names = names, + .has_type = true, + .type = type, + .initializer = initializer, + }, + }; + return statement_new(STATEMENT_DECLARATION, value, span, location); +} + void parser_end_statement(struct Parser* p, struct Parser_Error* error) { @@ -438,21 +496,31 @@ parser_end_statement(struct Parser* p, struct Parser_Error* error) struct Statement* parser_statement(struct Parser* p, struct Parser_Error* error) { - // skip empty statements. struct Token token = parser_peek(p); + + // skip empty statements. if (token_ends_statement(&token)) { parser_next(p); return nil; } - // TODO: no statements for now, just go straight to expressions. - struct Expression* expression = CHECK(parser_expression(p, error)); + if (token.kind == TOKEN_NAME) { + // NOTE: these can be a variable declaration: + // x uint = 123 + // me, them Obj = create() + // otherwise without a type, it is counted as an assignment: + // a = "hi!" + + struct Token next_token = parser_peek_further(p); + if (next_token.kind == TOKEN_COMMA || next_token.kind == TOKEN_NAME) + return parser_statement_declaration(p, error); + } - CHECK(parser_end_statement(p, error)); + struct Expression* expression = CHECK(parser_expression(p, error)); // expand by one byte to include the statement terminator. struct Span span = span_expand(expression->span, 1); - union Statement_Value value = { .expression = expression }; + union Statement_Value value = { .expression.inner = expression }; return statement_new(STATEMENT_EXPRESSION, value, span, expression->location); } @@ -468,6 +536,9 @@ parser_do_your_thing(struct Parser* p, struct Parser_Error* error) struct Statement* next = parser_statement(p, error); if (!parser_error_is_none(error)) return (struct Tree){ nil }; + parser_end_statement(p, error); + if (!parser_error_is_none(error)) return (struct Tree){ nil }; + if (current) { current->next = next; } else { |
