about summary refs log tree commit diff
path: root/boot/parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'boot/parse.c')
-rw-r--r--boot/parse.c130
1 files changed, 79 insertions, 51 deletions
diff --git a/boot/parse.c b/boot/parse.c
index 54461fa..3da213a 100644
--- a/boot/parse.c
+++ b/boot/parse.c
@@ -275,6 +275,41 @@ parser_function_header_node(struct Parser* p, struct Parser_Error* error)
     return header;
 }
 
+struct Bare_Declaration_Node
+parser_bare_declaration_node(struct Parser* p, struct Parser_Error* error)
+{
+    struct String_Array names = string_array_new();
+
+    struct Span span = { 0 };
+    struct Cursor location = parser_peek(p).location;
+    for (;;) {
+        struct Token name_token =
+            CHECK_RETURN(parser_need(p, TOKEN_NAME, error), struct Bare_Declaration_Node);
+
+        span = span_is_empty(span) ? name_token.span : span_merge(span, name_token.span);
+        string_array_add(&names, name_token.value.name);
+
+        struct Token next = parser_peek(p);
+        if (token_can_begin_type(&next)) break;
+        if (next.kind == TOKEN_COMMA) parser_next(p);
+    }
+
+    // for now, type is always required.
+    struct Type_Node* type = CHECK_RETURN(parser_node_type(p, error), struct Bare_Declaration_Node);
+    CHECK_RETURN(parser_need(p, TOKEN_ASSIGN, error), struct Bare_Declaration_Node);
+    struct Expression* initializer =
+        CHECK_RETURN(parser_expression(p, error), struct Bare_Declaration_Node);
+
+    return (struct Bare_Declaration_Node){
+        .names = names,
+        .initializer = initializer,
+        .type = type,
+
+        .span = span,
+        .location = location,
+    };
+}
+
 struct Type_Node*
 parser_node_type_name(struct Parser* p, struct Parser_Error* error)
 {
@@ -787,37 +822,16 @@ parser_statement_declaration(struct Parser* p, struct Parser_Error* error)
         statement_declaration_kind_from_token(&declaration_token);
     check(declaration_kind, "expected valid declaration token");
 
-    struct String_Array names = string_array_new();
+    struct Bare_Declaration_Node inner = CHECK(parser_bare_declaration_node(p, error));
 
-    struct Span span = { 0 };
-    struct Cursor location = parser_peek(p).location;
-    for (;;) {
-        struct Token name_token = parser_need(p, TOKEN_NAME, error);
-        if (!parser_error_is_none(error)) return nil;
-
-        span = span_is_empty(span) ? name_token.span : span_merge(span, name_token.span);
-        string_array_add(&names, name_token.value.name);
-
-        struct Token next = parser_peek(p);
-        if (next.kind == TOKEN_NAME) break;
-        if (next.kind == TOKEN_COMMA) parser_next(p);
-    }
-
-    // for now, type is always required.
-    struct Type_Node* type = CHECK(parser_node_type(p, error));
-    CHECK(parser_need(p, TOKEN_ASSIGN, error));
-    struct Expression* initializer = CHECK(parser_expression(p, error));
-
-    span = span_merge(span, initializer->span);
+    struct Span span = span_merge(declaration_token.span, inner.span);
     union Statement_Value value = {
         .declaration = {
             .kind = declaration_kind,
-            .names = names,
-            .type = type,
-            .initializer = initializer,
+            .inner = inner,
         },
     };
-    return statement_new(STATEMENT_DECLARATION, value, span, location);
+    return statement_new(STATEMENT_DECLARATION, value, span, declaration_token.location);
 }
 
 struct Statement*
@@ -870,44 +884,35 @@ parser_statement_conditional(struct Parser* p, struct Parser_Error* error)
 }
 
 struct Statement*
-parser_statement_loop(struct Parser* p, struct Parser_Error* error)
+parser_statement_for(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 var name String = collection {}`, as iteration over container
-    // * `for check() {}`, as a simple while-style loop
-    // * `for var i u8 = 0, i < 10, i++ {}`, as a c-style semi-semi loop
-    // * `for {}`, as an infinite loop
+    // * `for name String = collection {}`, as iteration over container
+    // * `for i u8 = 0, i < 10, i++ {}`, as a c-style semi-semi loop
 
-    struct Statement* declaration = nil;
-    struct Expression *condition = nil, *iteration = nil;
+    // a declaration without a signifier like `var` or `let`.
+    struct Bare_Declaration_Node declaration = CHECK(parser_bare_declaration_node(p, error));
+    enum Statement_Loop_Style style = STATEMENT_LOOP_STYLE_FOR_EACH;
 
-    // c-style or iterator-style
-    struct Token next = parser_peek(p);
-    // TODO: i do not like the `for var` combination, it is too verbose.
-    // it would be beneficial to bring back `while`, so that declarations without `var`
-    // are no longer ambiguous.
-    if (token_can_begin_declaration(&next)) {
-        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));
+    // c-style semi-semi loop.
+    struct Expression *condition = nil, *iteration = nil;
+    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));
 
-            iteration = CHECK(parser_expression(p, error));
-        }
+        style = STATEMENT_LOOP_STYLE_C;
     }
 
-    // while-style
-    if (!token_is(&next, 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 = {
+            .style = style,
             .declaration = declaration,
             .condition = condition,
             .iteration = iteration,
@@ -918,6 +923,27 @@ parser_statement_loop(struct Parser* p, struct Parser_Error* error)
 }
 
 struct Statement*
+parser_statement_while(struct Parser* p, struct Parser_Error* error)
+{
+    struct Token while_token = CHECK(parser_need(p, TOKEN_WORD_WHILE, error));
+
+    enum Statement_Loop_Style style = STATEMENT_LOOP_STYLE_ENDLESS;
+    struct Expression* condition = nil;
+    if (!parser_probe(p, TOKEN_CURLY_OPEN)) {
+        condition = CHECK(parser_expression(p, error));
+        style = STATEMENT_LOOP_STYLE_WHILE;
+    }
+
+    struct Block_Node body = CHECK(parser_block_node(p, error));
+
+    struct Span span = span_merge(while_token.span, body.span);
+    union Statement_Value value = {
+        .loop = { .style = style, .condition = condition, .body = body }
+    };
+    return statement_new(STATEMENT_LOOP, value, span, while_token.location);
+}
+
+struct Statement*
 parser_statement_block(struct Parser* p, struct Parser_Error* error)
 {
     struct Block_Node block = CHECK(parser_block_node(p, error));
@@ -1011,7 +1037,9 @@ parser_statement(struct Parser* p, struct Parser_Error* error)
     case TOKEN_WORD_IF:
         return parser_statement_conditional(p, error);
     case TOKEN_WORD_FOR:
-        return parser_statement_loop(p, error);
+        return parser_statement_for(p, error);
+    case TOKEN_WORD_WHILE:
+        return parser_statement_while(p, error);
     case TOKEN_CURLY_OPEN:
         return parser_statement_block(p, error);
     case TOKEN_WORD_RETURN: