diff options
Diffstat (limited to 'boot/parse.c')
| -rw-r--r-- | boot/parse.c | 115 |
1 files changed, 80 insertions, 35 deletions
diff --git a/boot/parse.c b/boot/parse.c index 6363379..4403024 100644 --- a/boot/parse.c +++ b/boot/parse.c @@ -30,6 +30,7 @@ enum Parser_Error_Kind PARSER_ERROR_EXPECTED_STATEMENT_END, PARSER_ERROR_EXPECTED_PRIMARY_EXPRESSION, PARSER_ERROR_EXPECTED_TYPE, + PARSER_ERROR_EXPECTED_ARGUMENTS, PARSER_ERROR_EXPECTED_PRAGMA, PARSER_ERROR_EXPECTED_PRAGMA_ARGUMENT }; @@ -50,6 +51,8 @@ parser_error_kind_to_string(enum Parser_Error_Kind error_kind) return "expected primary expression"; case PARSER_ERROR_EXPECTED_TYPE: return "expected type"; + case PARSER_ERROR_EXPECTED_ARGUMENTS: + return "expected arguments"; case PARSER_ERROR_EXPECTED_PRAGMA: return "expected pragma"; case PARSER_ERROR_EXPECTED_PRAGMA_ARGUMENT: @@ -467,6 +470,45 @@ parser_function_header_node(struct Parser* p, struct Parser_Error* error) return header; } +struct Argument_Group_Node +parser_argument_group_node(struct Parser* p, struct Parser_Error* error) +{ + struct String_Array argument_names = string_array_new(); + struct Expression *arguments_head = nil, *arguments_current = nil; + for (;;) { + // check if we have a named argument. + struct String name = string_empty(); + struct Token name_token = parser_peek(p), next = parser_peek_further(p); + if (token_is(&name_token, TOKEN_NAME) && token_is(&next, TOKEN_ASSIGN)) { + parser_next(p); + parser_next(p); + name = name_token.value.name; + } + + struct Expression* argument = + CHECK_RETURN(parser_expression(p, error), struct Argument_Group_Node); + if (!arguments_head) + arguments_head = argument; + else + arguments_current->next = argument; + arguments_current = argument; + + // if we have a named argument, we need to add it to the names array, + // otherwise we just add an empty string. + string_array_add(&argument_names, name); + + if (parser_probe(p, TOKEN_COMMA)) { + parser_next(p); + } else { + break; + } + } + + return (struct Argument_Group_Node){ + .arguments = arguments_head, .argument_names = argument_names + }; +} + struct Bare_Declaration_Node parser_bare_declaration_node(struct Parser* p, struct Parser_Error* error) { @@ -990,46 +1032,46 @@ parser_expression_postfix_member( } struct Expression* -parser_expression_postfix_call_or_construct( +parser_expression_postfix_call( struct Parser* p, struct Expression* subject, struct Parser_Error* error) { - // calls and constructs look identical in the parser. - // * call: `meow_function(123, "hello")` - // * construct: `Meow(num = 123, str = "hello")` CHECK(parser_need(p, TOKEN_ROUND_OPEN, error)); + parser_unglue(p); - struct String_Array argument_names = string_array_new(); - struct Expression *arguments_head = nil, *arguments_current = nil; - while (!parser_probe(p, TOKEN_ROUND_CLOSE)) { - // check if we have a named argument. - struct String name = string_empty(); - struct Token name_token = parser_peek(p), next = parser_peek_further(p); - if (token_is(&name_token, TOKEN_NAME) && token_is(&next, TOKEN_ASSIGN)) { - parser_next(p); - parser_next(p); - name = name_token.value.name; - } + struct Argument_Group_Node argument_group = parser_argument_group_node(p, error); + if (!parser_error_is_none(error)) { + parser_error_wrap(error, PARSER_ERROR_EXPECTED_ARGUMENTS); + return nil; + } - struct Expression* argument = CHECK(parser_expression(p, error)); - if (!arguments_head) - arguments_head = argument; - else - arguments_current->next = argument; - arguments_current = argument; + parser_unglue(p); + struct Token close_token = CHECK(parser_need(p, TOKEN_ROUND_CLOSE, error)); - // if we have a named argument, we need to add it to the names array, - // otherwise we just add an empty string. - string_array_add(&argument_names, name); + struct Span span = span_merge(subject->span, close_token.span); + union Expression_Value value = { .call = { subject, argument_group } }; + return expression_new(EXPRESSION_CALL, value, span, close_token.location); +} - if (parser_probe(p, TOKEN_COMMA)) parser_next(p); +struct Expression* +parser_expression_postfix_construct( + struct Parser* p, struct Expression* subject, struct Parser_Error* error) +{ + CHECK(parser_need(p, TOKEN_CURLY_OPEN, error)); + parser_unglue(p); + + struct Argument_Group_Node argument_group = parser_argument_group_node(p, error); + if (!parser_error_is_none(error)) { + parser_error_wrap(error, PARSER_ERROR_EXPECTED_ARGUMENTS); + return nil; } - struct Token token = CHECK(parser_need(p, TOKEN_ROUND_CLOSE, error)); + parser_unglue(p); + struct Token token = CHECK(parser_need(p, TOKEN_CURLY_CLOSE, error)); + struct Span span = span_merge(subject->span, token.span); - union Expression_Value value = { - .call_or_construct = { subject, arguments_head, argument_names } - }; - return expression_new(EXPRESSION_CALL_OR_CONSTRUCT, value, span, token.location); + // TODO: convert the `subject` expression to a type node? somehow? + union Expression_Value value = { .construct = { subject, argument_group } }; + return expression_new(EXPRESSION_CONSTRUCT, value, span, token.location); } struct Expression* @@ -1096,19 +1138,22 @@ parser_expression_postfix(struct Parser* p, struct Parser_Error* error) struct Token token = parser_peek(p); switch (token.kind) { case TOKEN_ROUND_OPEN: - expression = parser_expression_postfix_call_or_construct(p, expression, error); + expression = CHECK(parser_expression_postfix_call(p, expression, error)); + continue; + case TOKEN_CURLY_OPEN: + expression = CHECK(parser_expression_postfix_construct(p, expression, error)); continue; case TOKEN_SQUARE_OPEN: - expression = parser_expression_postfix_subscript(p, expression, error); + expression = CHECK(parser_expression_postfix_subscript(p, expression, error)); continue; case TOKEN_DOT: - expression = parser_expression_postfix_member(p, expression, error); + expression = CHECK(parser_expression_postfix_member(p, expression, error)); continue; case TOKEN_QUESTION: - expression = parser_expression_postfix_try(p, expression, error); + expression = CHECK(parser_expression_postfix_try(p, expression, error)); continue; case TOKEN_BANG: - expression = parser_expression_postfix_must(p, expression, error); + expression = CHECK(parser_expression_postfix_must(p, expression, error)); continue; default:; } |
