diff options
Diffstat (limited to 'boot')
| -rw-r--r-- | boot/parse.c | 79 | ||||
| -rw-r--r-- | boot/tree.c | 27 |
2 files changed, 88 insertions, 18 deletions
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 diff --git a/boot/tree.c b/boot/tree.c index 1d88743..7dd6447 100644 --- a/boot/tree.c +++ b/boot/tree.c @@ -326,6 +326,15 @@ binary_operation_to_string(enum Binary_Operation operation) // nodes are parts of the syntax tree that are reused often // and in different places. +// a block of code, enclosed in curly braces. +// represents a sequence of statements that are executed in order. +struct Block_Node +{ + struct Statement* statements; + struct Span span; + struct Cursor location; +}; + // a type node represents a type in the syntax tree. // currently, we only support types that are simple names. struct Type_Node @@ -538,6 +547,8 @@ enum Statement_Kind STATEMENT_NONE, STATEMENT_EXPRESSION, STATEMENT_DECLARATION, + // NOTE: a block could be an expression in the future. + STATEMENT_BLOCK, }; struct Statement_Value_Expression @@ -554,10 +565,16 @@ struct Statement_Value_Declaration struct Type_Node type; // the type of the variable, if any. }; +struct Statement_Value_Block +{ + struct Block_Node inner; // the block of statements. +}; + union Statement_Value { struct Statement_Value_Expression expression; struct Statement_Value_Declaration declaration; + struct Statement_Value_Block block; }; struct Statement @@ -621,6 +638,16 @@ statement_print(const struct Statement* statement) printf(")"); break; } + case STATEMENT_BLOCK: + printf("(block \n"); + FOR_EACH(struct Statement*, sub_statement, statement->value.block.inner.statements) + { + printf("\t"); + statement_print(sub_statement); + printf("\n"); + } + printf(")"); + break; default: failure("unexpected statement kind passed to `statement_print`"); break; |
