diff options
| author | Mel <mel@rnrd.eu> | 2025-07-05 22:48:09 +0200 |
|---|---|---|
| committer | Mel <mel@rnrd.eu> | 2025-07-05 22:48:09 +0200 |
| commit | 620d82a5e314a82784e02b4af387a67d53242149 (patch) | |
| tree | e91774653130cb34d19901aeaa7cdd6be97f3e93 /boot/parse.c | |
| parent | b71f85a7c3ee9e36b6eab9f113436fa990f6e561 (diff) | |
| download | catskill-620d82a5e314a82784e02b4af387a67d53242149.tar.zst catskill-620d82a5e314a82784e02b4af387a67d53242149.zip | |
Correctly recurse over self-containing non-homogenous postfix-type expressions
Signed-off-by: Mel <mel@rnrd.eu>
Diffstat (limited to 'boot/parse.c')
| -rw-r--r-- | boot/parse.c | 208 |
1 files changed, 106 insertions, 102 deletions
diff --git a/boot/parse.c b/boot/parse.c index c08d247..5d839a8 100644 --- a/boot/parse.c +++ b/boot/parse.c @@ -806,158 +806,162 @@ parser_expression_primary(struct Parser* p, struct Parser_Error* error) } struct Expression* -parser_expression_member(struct Parser* p, struct Parser_Error* error) +parser_expression_postfix_member( + struct Parser* p, struct Expression* subject, struct Parser_Error* error) { - struct Expression* left = CHECK(parser_expression_primary(p, error)); - - // NOTE: see `parser_expression_postfix_call_or_construct`. - while (parser_probe(p, TOKEN_DOT)) { - parser_next(p); - struct Token name_token = CHECK(parser_need(p, TOKEN_NAME, error)); - struct String name = name_token.value.name; + CHECK(parser_need(p, TOKEN_DOT, error)); - struct Span span = span_merge(left->span, name_token.span); - union Expression_Value value = { .member = { left, name } }; - left = expression_new(EXPRESSION_MEMBER, value, span, name_token.location); - } + struct Token name_token = CHECK(parser_need(p, TOKEN_NAME, error)); + struct String name = name_token.value.name; - return left; + struct Span span = span_merge(subject->span, name_token.span); + union Expression_Value value = { .member = { subject, name } }; + return expression_new(EXPRESSION_MEMBER, value, span, name_token.location); } struct Expression* parser_expression_postfix_call_or_construct( struct Parser* p, struct Expression* subject, struct Parser_Error* error) { - // NOTE: because of the way the parser works, we have to parse all subsequent - // call/construct expressions in the same loop. - // this is the case with an expression like `meow_function()(123)`, - // where the hypothetical `meow_function` returns a function pointer. - // calls and constructs look identical in the parser. // * call: `meow_function(123, "hello")` // * construct: `Meow(num = 123, str = "hello")` - while (parser_probe(p, TOKEN_ROUND_OPEN)) { - parser_next(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(parser_need(p, TOKEN_ROUND_OPEN, error)); - // 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(parser_expression(p, error)); - if (!arguments_head) - arguments_head = argument; - else - arguments_current->next = argument; - arguments_current = argument; + 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; + } - // 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 Expression* argument = CHECK(parser_expression(p, error)); + if (!arguments_head) + arguments_head = argument; + else + arguments_current->next = argument; + arguments_current = argument; - if (parser_probe(p, TOKEN_COMMA)) parser_next(p); - } + // 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 Token token = CHECK(parser_need(p, TOKEN_ROUND_CLOSE, error)); - struct Span span = span_merge(subject->span, token.span); - union Expression_Value value = { - .call_or_construct = { subject, arguments_head, argument_names } - }; - subject = expression_new(EXPRESSION_CALL_OR_CONSTRUCT, value, span, token.location); + if (parser_probe(p, TOKEN_COMMA)) parser_next(p); } - return subject; + struct Token token = CHECK(parser_need(p, TOKEN_ROUND_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); } struct Expression* parser_expression_postfix_subscript( struct Parser* p, struct Expression* subject, struct Parser_Error* error) { - // NOTE: see `parser_expression_postfix_call_or_construct`. - while (parser_probe(p, TOKEN_SQUARE_OPEN)) { - parser_next(p); + CHECK(parser_need(p, TOKEN_SQUARE_OPEN, error)); - struct Expression* index = CHECK(parser_expression(p, error)); - struct Token token = CHECK(parser_need(p, TOKEN_SQUARE_CLOSE, error)); + struct Expression* index = CHECK(parser_expression(p, error)); + struct Token token = CHECK(parser_need(p, TOKEN_SQUARE_CLOSE, error)); - struct Span span = span_merge(subject->span, span_merge(index->span, token.span)); - union Expression_Value value = { .subscript = { subject, index } }; - subject = expression_new(EXPRESSION_SUBSCRIPT, value, span, token.location); - } - return subject; + struct Span span = span_merge(subject->span, span_merge(index->span, token.span)); + union Expression_Value value = { .subscript = { subject, index } }; + return expression_new(EXPRESSION_SUBSCRIPT, value, span, token.location); +} + +struct Expression* +parser_expression_postfix_increment_decrement( + struct Parser* p, struct Expression* subject, struct Parser_Error* error) +{ + struct Token token = parser_peek(p); + enum Increment_Decrement_Operation operation = increment_decrement_operation_from_token(&token); + + struct Expression_Increment_Decrement inc_dec = { + .prefix = false, + .subject = subject, + .operation = operation, + }; + + struct Span span = span_merge(subject->span, token.span); + union Expression_Value value = { .increment_decrement = inc_dec }; + return expression_new(EXPRESSION_INCREMENT_DECREMENT, value, span, token.location); } struct Expression* parser_expression_postfix_try( struct Parser* p, struct Expression* subject, struct Parser_Error* error) { - while (parser_probe(p, TOKEN_QUESTION)) { - struct Token question_token = parser_next(p); + struct Token question_token = parser_next(p); - struct Span span = span_merge(subject->span, question_token.span); - union Expression_Value value = { .try = { subject } }; - subject = expression_new(EXPRESSION_TRY, value, span, subject->location); - } - return subject; + struct Span span = span_merge(subject->span, question_token.span); + union Expression_Value value = { .try = { subject } }; + return expression_new(EXPRESSION_TRY, value, span, subject->location); } struct Expression* parser_expression_postfix_must( struct Parser* p, struct Expression* subject, struct Parser_Error* error) { - while (parser_probe(p, TOKEN_BANG)) { - struct Token bang_token = parser_next(p); + struct Token bang_token = CHECK(parser_need(p, TOKEN_BANG, error)); - struct Span span = span_merge(subject->span, bang_token.span); - union Expression_Value value = { .try = { subject } }; - subject = expression_new(EXPRESSION_MUST, value, span, subject->location); - } - return subject; + struct Span span = span_merge(subject->span, bang_token.span); + union Expression_Value value = { .try = { subject } }; + return expression_new(EXPRESSION_MUST, value, span, subject->location); } struct Expression* parser_expression_postfix(struct Parser* p, struct Parser_Error* error) { - struct Expression* expression = CHECK(parser_expression_member(p, error)); + struct Expression* expression = CHECK(parser_expression_primary(p, error)); - struct Token token = parser_peek(p); - switch (token.kind) { - case TOKEN_ROUND_OPEN: - return parser_expression_postfix_call_or_construct(p, expression, error); - case TOKEN_SQUARE_OPEN: - return parser_expression_postfix_subscript(p, expression, error); + // NOTE: we have to parse all subsequent postfix expressions non-recursively. + for (;;) { + struct Token token = parser_peek(p); + switch (token.kind) { + case TOKEN_ROUND_OPEN: + expression = parser_expression_postfix_call_or_construct(p, expression, error); + continue; + case TOKEN_SQUARE_OPEN: + expression = parser_expression_postfix_subscript(p, expression, error); + continue; + case TOKEN_DOT: + expression = parser_expression_postfix_member(p, expression, error); + continue; + case TOKEN_QUESTION: + expression = parser_expression_postfix_try(p, expression, error); + continue; + case TOKEN_BANG: + expression = parser_expression_postfix_must(p, expression, error); + continue; + default:; + } - case TOKEN_QUESTION: - return parser_expression_postfix_try(p, expression, error); - case TOKEN_BANG: - return parser_expression_postfix_must(p, expression, error); - default:; - } + enum Increment_Decrement_Operation inc_dec_op = + increment_decrement_operation_from_token(&token); + if (inc_dec_op) { + parser_next(p); + struct Expression_Increment_Decrement inc_dec = { + .prefix = false, + .subject = expression, + .operation = inc_dec_op, + }; - enum Increment_Decrement_Operation inc_dec_op = - increment_decrement_operation_from_token(&token); - if (inc_dec_op) { - parser_next(p); - struct Expression_Increment_Decrement inc_dec = { - .prefix = false, - .subject = expression, - .operation = inc_dec_op, - }; + struct Span span = span_merge(expression->span, token.span); + union Expression_Value value = { .increment_decrement = inc_dec }; + expression = + expression_new(EXPRESSION_INCREMENT_DECREMENT, value, span, token.location); + continue; + } - struct Span span = span_merge(expression->span, token.span); - union Expression_Value value = { .increment_decrement = inc_dec }; - return expression_new(EXPRESSION_INCREMENT_DECREMENT, value, span, token.location); + return expression; } - - return expression; } struct Expression* |
