diff options
| author | Mel <mel@rnrd.eu> | 2026-05-28 00:29:53 +0200 |
|---|---|---|
| committer | Mel <mel@rnrd.eu> | 2026-05-28 00:29:53 +0200 |
| commit | 7db79f43b431b94d525308699a87a3daeff31d92 (patch) | |
| tree | 7b6a6d10dc064c5ae54791dc1b65c8d42233b97a | |
| parent | ec2029cba68b1d25e1e1119d37318c1b0c581a83 (diff) | |
| download | catskill-7db79f43b431b94d525308699a87a3daeff31d92.tar.zst catskill-7db79f43b431b94d525308699a87a3daeff31d92.zip | |
Split endless and while loops into `loop` and `while`
Signed-off-by: Mel <mel@rnrd.eu>
| -rw-r--r-- | boot/lex.c | 7 | ||||
| -rw-r--r-- | boot/parse.c | 38 | ||||
| -rw-r--r-- | boot/tests/lower/endless_loop.cskt | 39 | ||||
| -rw-r--r-- | boot/tests/parse/loops.cskt | 9 | ||||
| -rw-r--r-- | boot/tree.c | 4 | ||||
| -rw-r--r-- | docs/grammar.md | 4 |
6 files changed, 86 insertions, 15 deletions
diff --git a/boot/lex.c b/boot/lex.c index 18f8690..e585e1a 100644 --- a/boot/lex.c +++ b/boot/lex.c @@ -31,6 +31,7 @@ enum Token_Kind TOKEN_WORD_ELSE, TOKEN_WORD_FOR, TOKEN_WORD_WHILE, + TOKEN_WORD_LOOP, TOKEN_WORD_BREAK, TOKEN_WORD_CONTINUE, TOKEN_WORD_DEFER, @@ -133,6 +134,8 @@ token_kind_to_string(enum Token_Kind kind) return "WORD_FOR"; case TOKEN_WORD_WHILE: return "WORD_WHILE"; + case TOKEN_WORD_LOOP: + return "WORD_LOOP"; case TOKEN_WORD_BREAK: return "WORD_BREAK"; case TOKEN_WORD_CONTINUE: @@ -766,8 +769,10 @@ lexer_word_from_name(struct Lexer* l, struct String word_or_name) return TOKEN_WORD_ELSE; case 2652874405: // "for" return TOKEN_WORD_FOR; - case 1327426133: // "loop" + case 1327426133: // "while" return TOKEN_WORD_WHILE; + case 1637870694: // "loop" + return TOKEN_WORD_LOOP; case 1007193266: // "break" return TOKEN_WORD_BREAK; case 1827824793: // "continue" diff --git a/boot/parse.c b/boot/parse.c index 1cf08fd..3ea4939 100644 --- a/boot/parse.c +++ b/boot/parse.c @@ -325,6 +325,7 @@ parser_panic(struct Parser* p) case TOKEN_WORD_IF: case TOKEN_WORD_FOR: case TOKEN_WORD_WHILE: + case TOKEN_WORD_LOOP: case TOKEN_WORD_RETURN: case TOKEN_WORD_TYPE: case TOKEN_WORD_CLASS: @@ -1424,26 +1425,41 @@ parser_statement_while(struct Parser* p, struct Parser_Error* error) { struct Token while_token = CHECK(parser_need(p, TOKEN_WORD_WHILE, error)); - enum Tree_Statement_Loop_Style style = TREE_STATEMENT_LOOP_STYLE_ENDLESS; - struct Tree_Expression* condition = nil; - if (!parser_probe(p, TOKEN_CURLY_OPEN)) { - CONTEXT_START(in_statement_clause); - condition = CHECK(parser_expression(p, error)); - CONTEXT_END(in_statement_clause); - - style = TREE_STATEMENT_LOOP_STYLE_WHILE; - } + CONTEXT_START(in_statement_clause); + struct Tree_Expression* condition = CHECK(parser_expression(p, error)); + CONTEXT_END(in_statement_clause); struct Tree_Block body = CHECK(parser_block_node(p, error)); struct Span span = span_merge(while_token.span, body.span); union Tree_Statement_Value value = { - .loop = { .style = style, .condition = condition, .body = body } + .loop = { + .style = TREE_STATEMENT_LOOP_STYLE_WHILE, + .condition = condition, + .body = body, + } }; return tree_statement_new(TREE_STATEMENT_LOOP, value, span, while_token.location); } struct Tree_Statement* +parser_statement_loop(struct Parser* p, struct Parser_Error* error) +{ + struct Token loop_token = CHECK(parser_need(p, TOKEN_WORD_LOOP, error)); + struct Tree_Block body = CHECK(parser_block_node(p, error)); + + struct Span span = span_merge(loop_token.span, body.span); + union Tree_Statement_Value value = { + .loop = { + .style = TREE_STATEMENT_LOOP_STYLE_ENDLESS, + .condition = nil, + .body = body, + } + }; + return tree_statement_new(TREE_STATEMENT_LOOP, value, span, loop_token.location); +} + +struct Tree_Statement* parser_statement_block(struct Parser* p, struct Parser_Error* error) { struct Tree_Block block = CHECK(parser_block_node(p, error)); @@ -1545,6 +1561,8 @@ parser_statement(struct Parser* p, struct Parser_Error* error) return parser_statement_for(p, error); case TOKEN_WORD_WHILE: return parser_statement_while(p, error); + case TOKEN_WORD_LOOP: + return parser_statement_loop(p, error); case TOKEN_CURLY_OPEN: return parser_statement_block(p, error); case TOKEN_WORD_RETURN: diff --git a/boot/tests/lower/endless_loop.cskt b/boot/tests/lower/endless_loop.cskt new file mode 100644 index 0000000..692597a --- /dev/null +++ b/boot/tests/lower/endless_loop.cskt @@ -0,0 +1,39 @@ +an endless `loop` block lowers to the single ir loop kind, with a +synthetic `true` condition. exiting the loop requires an explicit +`break` from inside the body. + +<<< + +main = fun () { + var count int = 0 + loop { + count++ + if count == 5 { + break + } + } +} + +>>> + +(unit + (types + (type 0 int primitive) + (type 1 uint primitive) + (type 2 bool primitive) + (type 3 string primitive) + (type 4 float primitive) + (type 5 byte primitive) + (type 6 ascii primitive) + (type 7 void primitive)) + (functions + (function 0 main main (returns (ref void)) (block + (declaration count (ref int) (initializer (expr 0))) + (loop (condition (expr true)) (block + (expression-stmt (expr (postfix-++ (expr (name count))))) + (conditional (when (expr (binary == (expr (name count)) (expr 5)))) (block + (break) + )) + )) + ))) + (emission_order 0 1 2 3 4 5 6 7)) diff --git a/boot/tests/parse/loops.cskt b/boot/tests/parse/loops.cskt index 45b1040..8e5feba 100644 --- a/boot/tests/parse/loops.cskt +++ b/boot/tests/parse/loops.cskt @@ -16,6 +16,11 @@ while y < 10 { y++ } +loop { + print(0) + break +} + >>> (loop for-each (declaration i (type name uint) (initializer (expr (binary .. (expr 0) (expr 10))))) (block @@ -28,4 +33,8 @@ while y < 10 { (loop while (condition (expr (binary < (expr (name y)) (expr 10)))) (block (expr (call (expr (name print)) (arg (expr (name y))))) (expr (increment/decrement ++ postfix (expr (name y)))) +)) +(loop endless (block + (expr (call (expr (name print)) (arg (expr 0)))) + (break) )) \ No newline at end of file diff --git a/boot/tree.c b/boot/tree.c index 8c00c53..4bac27e 100644 --- a/boot/tree.c +++ b/boot/tree.c @@ -981,8 +981,8 @@ enum Tree_Statement_Loop_Style TREE_STATEMENT_LOOP_STYLE_NONE, TREE_STATEMENT_LOOP_STYLE_C, // for i int = 0; i < 10; ++i {} TREE_STATEMENT_LOOP_STYLE_FOR_EACH, // for x Obj = list {} - TREE_STATEMENT_LOOP_STYLE_WHILE, // while true {} - TREE_STATEMENT_LOOP_STYLE_ENDLESS, // while {} + TREE_STATEMENT_LOOP_STYLE_WHILE, // while cond {} + TREE_STATEMENT_LOOP_STYLE_ENDLESS, // loop {} }; // stands for both `for` and `while` loops. diff --git a/docs/grammar.md b/docs/grammar.md index eee54e2..2fca56e 100644 --- a/docs/grammar.md +++ b/docs/grammar.md @@ -58,7 +58,7 @@ word_or_name = ident_char { ident_tail_char } ident_char = "A".."Z" | "a".."z" | "_" ident_tail_char = ident_char | "0".."9" -word = "fun" | "if" | "else" | "for" | "loop" +word = "fun" | "if" | "else" | "for" | "while" | "loop" | "break" | "continue" | "defer" | "switch" | "return" | "var" | "let" | "type" | "variant" | "class" @@ -120,7 +120,7 @@ statement_loop = statement_loop_for_each | statement_loop_endless statement_loop_for_each = "for" bare_declaration block statement_loop_c = "for" bare_declaration "," expression "," expression block -statement_loop_while = "loop" expression block +statement_loop_while = "while" expression block statement_loop_endless = "loop" block statement_block = block |
