about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--boot/lex.c11
-rw-r--r--boot/parse.c41
-rw-r--r--boot/tree.c27
3 files changed, 54 insertions, 25 deletions
diff --git a/boot/lex.c b/boot/lex.c
index 52760e9..f09e5e3 100644
--- a/boot/lex.c
+++ b/boot/lex.c
@@ -97,6 +97,7 @@ enum Token_Kind
     TOKEN_WORD_SWITCH,
     TOKEN_WORD_RETURN,
     TOKEN_WORD_VAR,
+    TOKEN_WORD_LET,
     TOKEN_WORD_TYPE,
     TOKEN_WORD_VARIANT,
     TOKEN_WORD_CLASS,
@@ -200,6 +201,8 @@ token_kind_to_string(enum Token_Kind kind)
         return "WORD_RETURN";
     case TOKEN_WORD_VAR:
         return "WORD_VAR";
+    case TOKEN_WORD_LET:
+        return "WORD_LET";
     case TOKEN_WORD_TYPE:
         return "WORD_TYPE";
     case TOKEN_WORD_VARIANT:
@@ -407,6 +410,12 @@ token_can_begin_type(const struct Token* t)
 }
 
 bool
+token_can_begin_declaration(const struct Token* t)
+{
+    return token_is(t, TOKEN_WORD_VAR) || token_is(t, TOKEN_WORD_LET);
+}
+
+bool
 ascii_in_range(ascii c, ascii from, ascii to)
 {
     return c >= from && c <= to;
@@ -793,6 +802,8 @@ lexer_word_from_name(struct Lexer* l, struct String word_or_name)
         return TOKEN_WORD_RETURN;
     case 1662845996: // "var"
         return TOKEN_WORD_VAR;
+    case 860722406:
+        return TOKEN_WORD_LET;
     case 91700392: // "type"
         return TOKEN_WORD_TYPE;
     case 3267162257: // "variant"
diff --git a/boot/parse.c b/boot/parse.c
index a0dd12c..6129950 100644
--- a/boot/parse.c
+++ b/boot/parse.c
@@ -193,26 +193,6 @@ parser_end_statement(struct Parser* p, struct Parser_Error* error)
     parser_next(p);
 }
 
-// checks if the next 2 tokens could begin a variable declaration.
-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!"
-
-    // NOTE: maybe move this into `lex.c`?
-    // or change the API a bit, this isn't really a parser method.
-    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_can_begin_type(&second);
-    return first_matches && second_matches;
-}
-
 struct Block_Node
 parser_block_node(struct Parser* p, struct Parser_Error* error)
 {
@@ -795,6 +775,12 @@ parser_expression(struct Parser* p, struct Parser_Error* error)
 struct Statement*
 parser_statement_declaration(struct Parser* p, struct Parser_Error* error)
 {
+    struct Token declaration_token = parser_next(p);
+
+    enum Statement_Declaration_Kind declaration_kind =
+        statement_declaration_kind_from_token(&declaration_token);
+    check(declaration_kind, "expected valid declaration token");
+
     struct String_Array names = string_array_new();
 
     struct Span span = { 0 };
@@ -819,6 +805,7 @@ parser_statement_declaration(struct Parser* p, struct Parser_Error* error)
     span = span_merge(span, initializer->span);
     union Statement_Value value = {
         .declaration = {
+            .kind = declaration_kind,
             .names = names,
             .type = type,
             .initializer = initializer,
@@ -882,16 +869,20 @@ 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 var name String = 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 var i u8 = 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)) {
+    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
@@ -905,7 +896,7 @@ parser_statement_loop(struct Parser* p, struct Parser_Error* error)
     }
 
     // while-style
-    if (!parser_probe(p, TOKEN_CURLY_OPEN)) condition = CHECK(parser_expression(p, error));
+    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);
@@ -1007,7 +998,7 @@ parser_statement(struct Parser* p, struct Parser_Error* error)
         token = parser_peek(p);
     }
 
-    if (parser_could_be_variable_declaration(p)) return parser_statement_declaration(p, error);
+    if (token_can_begin_declaration(&token)) return parser_statement_declaration(p, error);
 
     switch (token.kind) {
     case TOKEN_WORD_IF:
diff --git a/boot/tree.c b/boot/tree.c
index 449f4e6..dff0858 100644
--- a/boot/tree.c
+++ b/boot/tree.c
@@ -912,8 +912,30 @@ struct Statement_Value_Expression
     struct Expression* inner;
 };
 
+enum Statement_Declaration_Kind
+{
+    STATEMENT_DECLARATION_NONE,
+    STATEMENT_DECLARATION_VARIABLE,
+    STATEMENT_DECLARATION_CONSTANT,
+};
+
+enum Statement_Declaration_Kind
+statement_declaration_kind_from_token(const struct Token* token)
+{
+    switch (token->kind) {
+    case TOKEN_WORD_VAR:
+        return STATEMENT_DECLARATION_VARIABLE;
+    case TOKEN_WORD_LET:
+        return STATEMENT_DECLARATION_CONSTANT;
+
+    default:
+        return STATEMENT_DECLARATION_NONE;
+    }
+}
+
 struct Statement_Value_Declaration
 {
+    enum Statement_Declaration_Kind kind;
     struct String_Array names;
     struct Expression* initializer;
     struct Type_Node* type;
@@ -1042,6 +1064,11 @@ statement_print(const struct Statement* statement)
     }
     case STATEMENT_DECLARATION: {
         printf("(declaration ");
+        if (statement->value.declaration.kind == STATEMENT_DECLARATION_VARIABLE)
+            printf("variable ");
+        else if (statement->value.declaration.kind == STATEMENT_DECLARATION_CONSTANT)
+            printf("constant ");
+
         STRING_ARRAY_FOR_EACH(i, name, statement->value.declaration.names)
         {
             printf("%s ", name.data);