aboutsummaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
authorMel <mel@rnrd.eu>2025-06-01 00:47:39 +0200
committerMel <mel@rnrd.eu>2025-06-01 00:47:39 +0200
commitcea333644191567bcfdd1e24e4606aafbf34e3cb (patch)
tree42d50d37059a7f23cd659823fb3fba7695c83615 /boot
parentef66c99536a631ff2bd1dab4a825ce16d2efa530 (diff)
downloadcatskill-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.c51
-rw-r--r--boot/tree.c55
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;