aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMel <mel@rnrd.eu>2025-06-03 01:20:50 +0200
committerMel <mel@rnrd.eu>2025-06-03 01:20:50 +0200
commita9b5fef2eb126500974a1cfe9ce4a8f7cc6e0490 (patch)
treec375798160976ce9dae1d4f386ee90260706e54e
parenta65c02b752722c873036a9246753f2e40c24305f (diff)
downloadcatskill-a9b5fef2eb126500974a1cfe9ce4a8f7cc6e0490.tar.zst
catskill-a9b5fef2eb126500974a1cfe9ce4a8f7cc6e0490.zip
Parse all 4 types of for-loops
Signed-off-by: Mel <mel@rnrd.eu>
-rw-r--r--boot/parse.c75
-rw-r--r--boot/tree.c37
2 files changed, 101 insertions, 11 deletions
diff --git a/boot/parse.c b/boot/parse.c
index 3870e6c..07b6e58 100644
--- a/boot/parse.c
+++ b/boot/parse.c
@@ -180,6 +180,23 @@ parser_end_statement(struct Parser* p, struct Parser_Error* error)
parser_next(p);
}
+bool
+parser_could_be_variable_declaration(struct Parser* p)
+{
+ // NOTE: these can be a variable declaration:
+ // x uint = 123
+ // me, them Obj = create()
+ // otherwise without a type, it is instead counted as an assignment:
+ // a = "hi!"
+
+ struct Token first = parser_peek(p);
+ struct Token second = parser_peek_further(p);
+
+ bool first_matches = token_is(&first, TOKEN_NAME);
+ bool second_matches = token_is(&second, TOKEN_COMMA) || token_is(&second, TOKEN_NAME);
+ return first_matches && second_matches;
+}
+
struct Block_Node
parser_block_node(struct Parser* p, struct Parser_Error* error)
{
@@ -618,6 +635,50 @@ parser_statement_conditional(struct Parser* p, struct Parser_Error* error)
}
struct Statement*
+parser_statement_loop(struct Parser* p, struct Parser_Error* error)
+{
+ struct Token for_token = CHECK(parser_need(p, TOKEN_WORD_FOR, error));
+
+ // these are the possible for loop variants:
+ // * `for String name = collection {}`, as iteration over container
+ // * `for check() {}`, as a simple while-style loop
+ // * `for u8 i = 0, i < 10, i++ {}`, as a c-style semi-semi loop
+ // * `for {}`, as an infinite loop
+
+ struct Statement* declaration = nil;
+ struct Expression *condition = nil, *iteration = nil;
+
+ // c-style or iterator-style
+ if (parser_could_be_variable_declaration(p)) {
+ declaration = CHECK(parser_statement_declaration(p, error));
+
+ // c-style
+ if (parser_probe(p, TOKEN_COMMA)) {
+ parser_next(p);
+ condition = CHECK(parser_expression(p, error));
+ CHECK(parser_need(p, TOKEN_COMMA, error));
+
+ iteration = CHECK(parser_expression(p, error));
+ }
+ }
+
+ // while-style
+ if (!parser_probe(p, TOKEN_CURLY_OPEN)) condition = CHECK(parser_expression(p, error));
+
+ struct Block_Node body = CHECK(parser_block_node(p, error));
+ struct Span span = span_merge(for_token.span, body.span);
+ union Statement_Value value = {
+ .loop = {
+ .declaration = declaration,
+ .condition = condition,
+ .iteration = iteration,
+ .body = body,
+ },
+ };
+ return statement_new(STATEMENT_LOOP, value, span, for_token.location);
+}
+
+struct Statement*
parser_statement(struct Parser* p, struct Parser_Error* error)
{
struct Token token = parser_peek(p);
@@ -628,20 +689,12 @@ parser_statement(struct Parser* p, struct Parser_Error* error)
token = parser_peek(p);
}
- if (token_is(&token, TOKEN_NAME)) {
- // NOTE: these can be a variable declaration:
- // x uint = 123
- // me, them Obj = create()
- // otherwise without a type, it is counted as an assignment:
- // a = "hi!"
-
- struct Token next_token = parser_peek_further(p);
- if (next_token.kind == TOKEN_COMMA || next_token.kind == TOKEN_NAME)
- return parser_statement_declaration(p, error);
- }
+ if (parser_could_be_variable_declaration(p)) return parser_statement_declaration(p, error);
if (token_is(&token, TOKEN_WORD_IF)) return parser_statement_conditional(p, error);
+ if (token_is(&token, TOKEN_WORD_FOR)) return parser_statement_loop(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 64eb23b..3ae90b8 100644
--- a/boot/tree.c
+++ b/boot/tree.c
@@ -592,6 +592,7 @@ enum Statement_Kind
// NOTE: a block could be an expression in the future.
STATEMENT_BLOCK,
STATEMENT_CONDITIONAL,
+ STATEMENT_LOOP,
};
struct Statement_Value_Expression
@@ -624,12 +625,25 @@ struct Statement_Value_Conditional
uint condition_count;
};
+struct Statement_Value_Loop
+{
+ // exists for iterator-style + c-style loops.
+ struct Statement* declaration;
+ // exists for all loop types, except for infinite loops.
+ struct Expression* condition;
+ // exists for c-style loops.
+ struct Expression* iteration;
+
+ struct Block_Node body;
+};
+
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_Value_Loop loop;
};
struct Statement
@@ -731,6 +745,29 @@ statement_print(const struct Statement* statement)
printf(")");
break;
}
+ case STATEMENT_LOOP: {
+ printf("(loop ");
+ if (statement->value.loop.declaration) {
+ printf("(declaration ");
+ statement_print(statement->value.loop.declaration);
+ printf(") ");
+ }
+
+ if (statement->value.loop.condition) {
+ printf("(condition ");
+ expression_print(statement->value.loop.condition);
+ printf(") ");
+ }
+
+ if (statement->value.loop.iteration) {
+ printf("(iteration ");
+ expression_print(statement->value.loop.iteration);
+ printf(") ");
+ }
+
+ block_node_print(&statement->value.loop.body);
+ break;
+ }
default:
failure("unexpected statement kind passed to `statement_print`");
break;