aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMustafa Quraish <[email protected]>2022-02-03 06:22:24 -0500
committerMustafa Quraish <[email protected]>2022-02-03 06:26:17 -0500
commit19c27785a9d1e66ea72f36d4e2a6dad3d492c57f (patch)
tree1bb956b37e6ccd7fa681273e4c43fc53173ba773
parentMake `make test` exit early if any of the tests fail (diff)
downloadcup-19c27785a9d1e66ea72f36d4e2a6dad3d492c57f.tar.xz
cup-19c27785a9d1e66ea72f36d4e2a6dad3d492c57f.zip
Add an implicit block around a `for` loop, allow statement init
Now we can have variable declarations as part of the initialization of the for loop, and it can only be accessed within the loop.
-rw-r--r--src/parser.c39
1 files changed, 27 insertions, 12 deletions
diff --git a/src/parser.c b/src/parser.c
index f412c79..e3076f2 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -346,7 +346,7 @@ Node *parse_identifier(Lexer *lexer)
Node *parse_factor(Lexer *lexer)
{
// TODO: We need to properly handle type conversions / operations with different types
- // where we need to cast one of the operands / etc. Perhaps have a separate
+ // where we need to cast one of the operands / etc. Perhaps have a separate
// type-checking / adding casts/conversions pass?
Token token = Lexer_peek(lexer);
Node *expr = NULL;
@@ -409,7 +409,7 @@ Node *parse_factor(Lexer *lexer)
offset->binary.left = expr;
offset->binary.right = index;
offset = handle_binary_expr_types(offset, &token);
-
+
expr = Node_new(OP_DEREF);
expr->unary_expr = offset;
expr = handle_unary_expr_types(expr, &token);
@@ -470,7 +470,7 @@ Node *parse_conditional_exp(Lexer *lexer)
if (!type_equals(then_expr->expr_type, else_expr->expr_type))
die_location(token.loc, "Type mismatch in conditional expression cases");
-
+
conditional->expr_type = then_expr->expr_type;
expr = conditional;
expr->expr_type = then_expr->expr_type;
@@ -547,26 +547,41 @@ Node *parse_statement(Lexer *lexer)
node->loop.body = parse_statement(lexer);
} else if (token.type == TOKEN_FOR) {
Lexer_next(lexer);
- node = Node_new(AST_FOR);
+
+
+ Node *loop = Node_new(AST_FOR);
assert_token(Lexer_next(lexer), TOKEN_OPEN_PAREN);
+ // NOTE: We're going to put the for loop in it's own block
+ // so that any declarations in the init of the loop
+ // can only be referenced within the loop.
+ node = Node_new(AST_BLOCK);
+ Node_add_child(node, loop);
+ block_stack_push(node);
+
// All of the expressions in the for loop are optional
- // TODO: Allow this to be a declaration, need to inject
- // the variable into the symbol table for the block
- if (Lexer_peek(lexer).type != TOKEN_SEMICOLON)
- node->loop.init = parse_expression(lexer);
- assert_token(Lexer_next(lexer), TOKEN_SEMICOLON);
+ token = Lexer_peek(lexer);
+ // FIXME: Maybe `parse_var_declaration` shouldn't consume the semicolon?
+ if (token.type == TOKEN_LET) {
+ loop->loop.init = parse_var_declaration(lexer);
+ } else {
+ if (token.type != TOKEN_SEMICOLON)
+ loop->loop.init = parse_expression(lexer);
+ assert_token(Lexer_next(lexer), TOKEN_SEMICOLON);
+ }
if (Lexer_peek(lexer).type != TOKEN_SEMICOLON)
- node->loop.cond = parse_expression(lexer);
+ loop->loop.cond = parse_expression(lexer);
assert_token(Lexer_next(lexer), TOKEN_SEMICOLON);
if (Lexer_peek(lexer).type != TOKEN_CLOSE_PAREN)
- node->loop.step = parse_expression(lexer);
+ loop->loop.step = parse_expression(lexer);
assert_token(Lexer_next(lexer), TOKEN_CLOSE_PAREN);
- node->loop.body = parse_statement(lexer);
+ loop->loop.body = parse_statement(lexer);
+ block_stack_pop();
+
} else if (token.type == TOKEN_OPEN_BRACE) {
node = parse_block(lexer);
} else if (token.type == TOKEN_DEFER) {