diff options
| author | Mel <mel@rnrd.eu> | 2025-06-01 00:47:39 +0200 |
|---|---|---|
| committer | Mel <mel@rnrd.eu> | 2025-06-01 00:47:39 +0200 |
| commit | cea333644191567bcfdd1e24e4606aafbf34e3cb (patch) | |
| tree | 42d50d37059a7f23cd659823fb3fba7695c83615 /boot | |
| parent | ef66c99536a631ff2bd1dab4a825ce16d2efa530 (diff) | |
| download | catskill-cea333644191567bcfdd1e24e4606aafbf34e3cb.tar.zst catskill-cea333644191567bcfdd1e24e4606aafbf34e3cb.zip | |
Parse if/else if/else statements
Signed-off-by: Mel <mel@rnrd.eu>
Diffstat (limited to 'boot')
| -rw-r--r-- | boot/parse.c | 51 | ||||
| -rw-r--r-- | boot/tree.c | 55 |
2 files changed, 100 insertions, 6 deletions
diff --git a/boot/parse.c b/boot/parse.c index 5bfa006..ed00f94 100644 --- a/boot/parse.c +++ b/boot/parse.c @@ -531,6 +531,55 @@ parser_statement_declaration(struct Parser* p, struct Parser_Error* error) } struct Statement* +parser_statement_conditional(struct Parser* p, struct Parser_Error* error) +{ + struct Statement_Value_Conditional conditional = { 0 }; + struct Token if_token = parser_need(p, TOKEN_WORD_IF, error); + + // primary if condition + block. + struct Expression* if_condition = CHECK(parser_expression(p, error)); + struct Block_Node then_block = CHECK(parser_block_node(p, error)); + conditional.conditions[conditional.condition_count++] = (struct Statement_Conditional_Branch){ + .when = if_condition, + .then = then_block, + }; + + struct Span span = span_merge(if_token.span, then_block.span); + while (parser_probe(p, TOKEN_WORD_ELSE)) { + check(conditional.condition_count < STATEMENT_VALUE_CONDITIONAL_MAX, + "too many conditional branches"); + parser_next(p); + + struct Statement_Conditional_Branch branch = { 0 }; + if (parser_probe(p, TOKEN_WORD_IF)) { + // else if condition + block. + parser_next(p); + struct Expression* else_condition = CHECK(parser_expression(p, error)); + struct Block_Node else_block = CHECK(parser_block_node(p, error)); + + branch = (struct Statement_Conditional_Branch){ + .when = else_condition, + .then = else_block, + }; + } else { + // else block. + struct Block_Node else_block = CHECK(parser_block_node(p, error)); + branch = (struct Statement_Conditional_Branch){ + .when = nil, + .then = else_block, + }; + } + + conditional.conditions[conditional.condition_count++] = branch; + span = span_merge(span, branch.then.span); + } + + return statement_new( + STATEMENT_CONDITIONAL, (union Statement_Value){ .conditional = conditional }, span, + if_token.location); +} + +struct Statement* parser_statement(struct Parser* p, struct Parser_Error* error) { struct Token token = parser_peek(p); @@ -553,6 +602,8 @@ parser_statement(struct Parser* p, struct Parser_Error* error) return parser_statement_declaration(p, error); } + if (token_is(&token, TOKEN_WORD_IF)) return parser_statement_conditional(p, error); + if (token_is(&token, TOKEN_CURLY_OPEN)) { // a block statement. struct Block_Node block = CHECK(parser_block_node(p, error)); diff --git a/boot/tree.c b/boot/tree.c index 7dd6447..dcda4da 100644 --- a/boot/tree.c +++ b/boot/tree.c @@ -549,6 +549,7 @@ enum Statement_Kind STATEMENT_DECLARATION, // NOTE: a block could be an expression in the future. STATEMENT_BLOCK, + STATEMENT_CONDITIONAL, }; struct Statement_Value_Expression @@ -570,11 +571,25 @@ struct Statement_Value_Block struct Block_Node inner; // the block of statements. }; +#define STATEMENT_VALUE_CONDITIONAL_MAX 8 + +struct Statement_Value_Conditional +{ + struct Statement_Conditional_Branch + { + // if nil, the condition is always true. + struct Expression* when; + struct Block_Node then; + } conditions[STATEMENT_VALUE_CONDITIONAL_MAX]; + uint condition_count; +}; + union Statement_Value { struct Statement_Value_Expression expression; struct Statement_Value_Declaration declaration; struct Statement_Value_Block block; + struct Statement_Value_Conditional conditional; }; struct Statement @@ -592,6 +607,21 @@ struct Statement REGION(struct Statement, statement) +void statement_print(const struct Statement* statement); + +void +block_node_print(const struct Block_Node* block) +{ + printf("(block \n"); + FOR_EACH(struct Statement*, statement, block->statements) + { + printf("\t"); + statement_print(statement); + printf("\n"); + } + printf(")"); +} + struct Statement* statement_new( enum Statement_Kind kind, union Statement_Value value, struct Span span, struct Cursor location) @@ -639,15 +669,28 @@ statement_print(const struct Statement* statement) 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"); + block_node_print(&statement->value.block.inner); + break; + case STATEMENT_CONDITIONAL: { + printf("(conditional"); + for (uint i = 0; i < statement->value.conditional.condition_count; ++i) { + const struct Statement_Conditional_Branch* branch = + &statement->value.conditional.conditions[i]; + + printf(" "); + if (branch->when) { + printf("(when "); + expression_print(branch->when); + printf(") "); + } else { + printf("(always) "); + } + + block_node_print(&branch->then); } printf(")"); break; + } default: failure("unexpected statement kind passed to `statement_print`"); break; |
