From ef66c99536a631ff2bd1dab4a825ce16d2efa530 Mon Sep 17 00:00:00 2001 From: Mel Date: Sat, 31 May 2025 23:56:35 +0200 Subject: Parse blocks of statements as node Signed-off-by: Mel --- boot/parse.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 61 insertions(+), 18 deletions(-) (limited to 'boot/parse.c') diff --git a/boot/parse.c b/boot/parse.c index 5d3b26c..5bfa006 100644 --- a/boot/parse.c +++ b/boot/parse.c @@ -9,6 +9,10 @@ parse; \ if (!parser_error_is_none(error)) return nil; +#define CHECK_RETURN(parse, ret) \ + parse; \ + if (!parser_error_is_none(error)) return (ret){ 0 }; + struct Parser_Error { enum Parser_Error_Kind @@ -162,8 +166,52 @@ parser_probe(struct Parser* p, enum Token_Kind kind) return token_is(&token, kind); } +struct Statement* parser_statement(struct Parser* p, struct Parser_Error* error); struct Expression* parser_expression(struct Parser* p, struct Parser_Error* error); +void +parser_end_statement(struct Parser* p, struct Parser_Error* error) +{ + struct Token token = parser_peek(p); + if (!token_ends_statement(&token)) { + *error = parser_error(PARSER_ERROR_EXPECTED_STATEMENT_END); + return; + } + parser_next(p); +} + +struct Block_Node +parser_block_node(struct Parser* p, struct Parser_Error* error) +{ + struct Token start_token = + CHECK_RETURN(parser_need(p, TOKEN_CURLY_OPEN, error), struct Block_Node); + + struct Statement* head = nil; + struct Statement* current = nil; + + while (!parser_probe(p, TOKEN_CURLY_CLOSE)) { + struct Statement* statement = CHECK_RETURN(parser_statement(p, error), struct Block_Node); + CHECK_RETURN(parser_end_statement(p, error), struct Block_Node); + + if (!head) { + head = statement; + } else { + current->next = statement; + } + current = statement; + } + + struct Token end_token = + CHECK_RETURN(parser_need(p, TOKEN_CURLY_CLOSE, error), struct Block_Node); + struct Span span = span_merge(start_token.span, end_token.span); + + return (struct Block_Node){ + .statements = head, + .span = span, + .location = start_token.location, + }; +} + struct Type_Node parser_node_type(struct Parser* p, struct Parser_Error* error) { @@ -482,17 +530,6 @@ parser_statement_declaration(struct Parser* p, struct Parser_Error* error) return statement_new(STATEMENT_DECLARATION, value, span, location); } -void -parser_end_statement(struct Parser* p, struct Parser_Error* error) -{ - struct Token token = parser_peek(p); - if (!token_ends_statement(&token)) { - *error = parser_error(PARSER_ERROR_EXPECTED_STATEMENT_END); - return; - } - parser_next(p); -} - struct Statement* parser_statement(struct Parser* p, struct Parser_Error* error) { @@ -504,7 +541,7 @@ parser_statement(struct Parser* p, struct Parser_Error* error) token = parser_peek(p); } - if (token.kind == TOKEN_NAME) { + if (token_is(&token, TOKEN_NAME)) { // NOTE: these can be a variable declaration: // x uint = 123 // me, them Obj = create() @@ -516,6 +553,14 @@ parser_statement(struct Parser* p, struct Parser_Error* error) return parser_statement_declaration(p, error); } + if (token_is(&token, TOKEN_CURLY_OPEN)) { + // a block statement. + struct Block_Node block = CHECK(parser_block_node(p, error)); + return statement_new( + STATEMENT_BLOCK, (union Statement_Value){ .block = { block } }, block.span, + block.location); + } + struct Expression* expression = CHECK(parser_expression(p, error)); // expand by one byte to include the statement terminator. @@ -533,11 +578,8 @@ parser_do_your_thing(struct Parser* p, struct Parser_Error* error) struct Statement* current = nil; while (!p->lexer->eof) { - 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 }; + struct Statement* next = CHECK_RETURN(parser_statement(p, error), struct Tree); + CHECK_RETURN(parser_end_statement(p, error), struct Tree); if (current) { current->next = next; @@ -551,4 +593,5 @@ parser_do_your_thing(struct Parser* p, struct Parser_Error* error) return (struct Tree){ head }; } -#undef CHECK \ No newline at end of file +#undef CHECK +#undef CHECK_RETURN \ No newline at end of file -- cgit 1.4.1