aboutsummaryrefslogtreecommitdiff
path: root/src/checker/stmt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/checker/stmt.cpp')
-rw-r--r--src/checker/stmt.cpp151
1 files changed, 78 insertions, 73 deletions
diff --git a/src/checker/stmt.cpp b/src/checker/stmt.cpp
index 75c6ad11d..636ccdb34 100644
--- a/src/checker/stmt.cpp
+++ b/src/checker/stmt.cpp
@@ -9,17 +9,17 @@ enum StmtFlag : u32 {
void check_stmt(Checker *c, AstNode *node, u32 flags);
-void check_stmt_list(Checker *c, AstNode *list, isize list_count, u32 flags) {
+void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
b32 ft_ok = (flags & Stmt_FallthroughAllowed) != 0;
u32 f = flags & (~Stmt_FallthroughAllowed);
- isize i = 0;
- for (AstNode *n = list; n != NULL; n = n->next, i++) {
+ gb_for_array(i, stmts) {
+ AstNode *n = stmts[i];
if (n->kind == AstNode_EmptyStmt) {
continue;
}
u32 new_flags = f;
- if (ft_ok && i+1 == list_count) {
+ if (ft_ok && i+1 == gb_array_count(stmts)) {
new_flags |= Stmt_FallthroughAllowed;
}
check_stmt(c, n, new_flags);
@@ -29,24 +29,22 @@ void check_stmt_list(Checker *c, AstNode *list, isize list_count, u32 flags) {
b32 check_is_terminating(AstNode *node);
b32 check_has_break(AstNode *stmt, b32 implicit);
-b32 check_is_terminating_list(AstNode *list) {
- // Get to end of list
- for (; list != NULL; list = list->next) {
- if (list->next == NULL)
- break;
- }
+b32 check_is_terminating_list(AstNodeArray stmts) {
// Iterate backwards
- for (AstNode *n = list; n != NULL; n = n->prev) {
- if (n->kind != AstNode_EmptyStmt)
- return check_is_terminating(n);
+ for (isize n = gb_array_count(stmts)-1; n >= 0; n--) {
+ AstNode *stmt = stmts[n];
+ if (stmt->kind != AstNode_EmptyStmt) {
+ return check_is_terminating(stmt);
+ }
}
return false;
}
-b32 check_has_break_list(AstNode *list, b32 implicit) {
- for (AstNode *stmt = list; stmt != NULL; stmt = stmt->next) {
+b32 check_has_break_list(AstNodeArray stmts, b32 implicit) {
+ gb_for_array(i, stmts) {
+ AstNode *stmt = stmts[i];
if (check_has_break(stmt, implicit)) {
return true;
}
@@ -63,7 +61,7 @@ b32 check_has_break(AstNode *stmt, b32 implicit) {
}
break;
case AstNode_BlockStmt:
- return check_has_break_list(stmt->BlockStmt.list, implicit);
+ return check_has_break_list(stmt->BlockStmt.stmts, implicit);
case AstNode_IfStmt:
if (check_has_break(stmt->IfStmt.body, implicit) ||
@@ -91,7 +89,7 @@ b32 check_is_terminating(AstNode *node) {
case_end;
case_ast_node(bs, BlockStmt, node);
- return check_is_terminating_list(bs->list);
+ return check_is_terminating_list(bs->stmts);
case_end;
case_ast_node(es, ExprStmt, node);
@@ -115,7 +113,8 @@ b32 check_is_terminating(AstNode *node) {
case_ast_node(ms, MatchStmt, node);
b32 has_default = false;
- for (AstNode *clause = ms->body->BlockStmt.list; clause != NULL; clause = clause->next) {
+ gb_for_array(i, ms->body->BlockStmt.stmts) {
+ AstNode *clause = ms->body->BlockStmt.stmts[i];
ast_node(cc, CaseClause, clause);
if (cc->list == NULL) {
has_default = true;
@@ -130,7 +129,8 @@ b32 check_is_terminating(AstNode *node) {
case_ast_node(ms, TypeMatchStmt, node);
b32 has_default = false;
- for (AstNode *clause = ms->body->BlockStmt.list; clause != NULL; clause = clause->next) {
+ gb_for_array(i, ms->body->BlockStmt.stmts) {
+ AstNode *clause = ms->body->BlockStmt.stmts[i];
ast_node(cc, CaseClause, clause);
if (cc->list == NULL) {
has_default = true;
@@ -259,8 +259,8 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
return e->type;
}
-void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNode *init_list, isize init_count, String context_name) {
- if ((lhs == NULL || lhs_count == 0) && init_count == 0)
+void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArray inits, String context_name) {
+ if ((lhs == NULL || lhs_count == 0) && gb_array_count(inits) == 0)
return;
// TODO(bill): Do not use heap allocation here if I can help it
@@ -268,7 +268,8 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNode *in
gb_array_init(operands, gb_heap_allocator());
defer (gb_array_free(operands));
- for (AstNode *rhs = init_list; rhs != NULL; rhs = rhs->next) {
+ gb_for_array(i, inits) {
+ AstNode *rhs = inits[i];
Operand o = {};
check_multi_expr(c, &o, rhs);
if (o.type->kind != Type_Tuple) {
@@ -422,7 +423,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
push_procedure(c, type);
ast_node(bs, BlockStmt, body);
// TODO(bill): Check declarations first (except mutable variable declarations)
- check_stmt_list(c, bs->list, bs->list_count, 0);
+ check_stmt_list(c, bs->stmts, 0);
if (type->Proc.result_count > 0) {
if (!check_is_terminating(body)) {
error(&c->error_collector, bs->close, "Missing return statement at the end of the procedure");
@@ -548,7 +549,10 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
entities[i]->type = e->type;
}
- check_init_variables(c, entities, entity_count, init_expr, 1, make_string("variable declaration"));
+ AstNodeArray inits;
+ gb_array_init(inits, c->allocator);
+ gb_array_append(inits, init_expr);
+ check_init_variables(c, entities, entity_count, inits, make_string("variable declaration"));
}
@@ -587,7 +591,7 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, Cyc
void check_var_decl_node(Checker *c, AstNode *node) {
ast_node(vd, VarDecl, node);
- isize entity_count = vd->name_count;
+ isize entity_count = gb_array_count(vd->names);
isize entity_index = 0;
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
switch (vd->kind) {
@@ -595,7 +599,8 @@ void check_var_decl_node(Checker *c, AstNode *node) {
Entity **new_entities = gb_alloc_array(c->allocator, Entity *, entity_count);
isize new_entity_count = 0;
- for (AstNode *name = vd->name_list; name != NULL; name = name->next) {
+ gb_for_array(i, vd->names) {
+ AstNode *name = vd->names[i];
Entity *entity = NULL;
Token token = name->Ident;
if (name->kind == AstNode_Ident) {
@@ -648,23 +653,22 @@ void check_var_decl_node(Checker *c, AstNode *node) {
e->type = init_type;
}
- check_init_variables(c, entities, entity_count, vd->value_list, vd->value_count, make_string("variable declaration"));
+ check_init_variables(c, entities, entity_count, vd->values, make_string("variable declaration"));
- AstNode *name = vd->name_list;
- for (isize i = 0; i < new_entity_count; i++, name = name->next) {
- add_entity(c, c->context.scope, name, new_entities[i]);
+ gb_for_array(i, vd->names) {
+ add_entity(c, c->context.scope, vd->names[i], new_entities[i]);
}
} break;
case Declaration_Immutable: {
- for (AstNode *name = vd->name_list, *value = vd->value_list;
- name != NULL && value != NULL;
- name = name->next, value = value->next) {
+ gb_for_array(i, vd->values) {
+ AstNode *name = vd->names[i];
+ AstNode *value = vd->values[i];
+
GB_ASSERT(name->kind == AstNode_Ident);
ExactValue v = {ExactValue_Invalid};
- ast_node(i, Ident, name);
- String str = i->string;
+ String str = name->Ident.string;
Entity *found = current_scope_lookup_entity(c->context.scope, str);
if (found == NULL) {
Entity *e = make_entity_constant(c->allocator, c->context.scope, name->Ident, NULL, v);
@@ -675,8 +679,8 @@ void check_var_decl_node(Checker *c, AstNode *node) {
}
}
- isize lhs_count = vd->name_count;
- isize rhs_count = vd->value_count;
+ isize lhs_count = gb_array_count(vd->names);
+ isize rhs_count = gb_array_count(vd->values);
// TODO(bill): Better error messages or is this good enough?
if (rhs_count == 0 && vd->type == NULL) {
@@ -685,9 +689,8 @@ void check_var_decl_node(Checker *c, AstNode *node) {
error(&c->error_collector, ast_node_token(node), "Extra initial expression");
}
- AstNode *name = vd->name_list;
- for (isize i = 0; i < entity_count; i++, name = name->next) {
- add_entity(c, c->context.scope, name, entities[i]);
+ gb_for_array(i, vd->names) {
+ add_entity(c, c->context.scope, vd->names[i], entities[i]);
}
} break;
@@ -769,7 +772,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
switch (as->op.kind) {
case Token_Eq: {
// a, b, c = 1, 2, 3; // Multisided
- if (as->lhs_count == 0) {
+ if (gb_array_count(as->lhs) == 0) {
error(&c->error_collector, as->op, "Missing lhs in assignment statement");
return;
}
@@ -779,7 +782,8 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
gb_array_init(operands, gb_heap_allocator());
defer (gb_array_free(operands));
- for (AstNode *rhs = as->rhs_list; rhs != NULL; rhs = rhs->next) {
+ gb_for_array(i, as->rhs) {
+ AstNode *rhs = as->rhs[i];
Operand o = {};
check_multi_expr(c, &o, rhs);
if (o.type->kind != Type_Tuple) {
@@ -793,25 +797,23 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
}
}
- isize lhs_count = as->lhs_count;
+ isize lhs_count = gb_array_count(as->lhs);
isize rhs_count = gb_array_count(operands);
isize operand_index = 0;
- for (AstNode *lhs = as->lhs_list;
- lhs != NULL;
- lhs = lhs->next, operand_index++) {
- check_assignment_variable(c, &operands[operand_index], lhs);
-
+ gb_for_array(i, as->lhs) {
+ AstNode *lhs = as->lhs[i];
+ check_assignment_variable(c, &operands[i], lhs);
}
if (lhs_count != rhs_count) {
- error(&c->error_collector, ast_node_token(as->lhs_list), "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
+ error(&c->error_collector, ast_node_token(as->lhs[0]), "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
}
} break;
default: {
// a += 1; // Single-sided
Token op = as->op;
- if (as->lhs_count != 1 || as->rhs_count != 1) {
+ if (gb_array_count(as->lhs) != 1 || gb_array_count(as->rhs) != 1) {
error(&c->error_collector, op, "Assignment operation `%.*s` requires single-valued expressions", LIT(op.string));
return;
}
@@ -825,21 +827,21 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
ast_node(be, BinaryExpr, &binary_expr);
be->op = op;
// NOTE(bill): Only use the first one will be used
- be->left = as->lhs_list;
- be->right = as->rhs_list;
+ be->left = as->lhs[0];
+ be->right = as->rhs[0];
check_binary_expr(c, &operand, &binary_expr);
if (operand.mode == Addressing_Invalid)
return;
// NOTE(bill): Only use the first one will be used
- check_assignment_variable(c, &operand, as->lhs_list);
+ check_assignment_variable(c, &operand, as->lhs[0]);
} break;
}
case_end;
case_ast_node(bs, BlockStmt, node);
check_open_scope(c, node);
- check_stmt_list(c, bs->list, bs->list_count, mod_flags);
+ check_stmt_list(c, bs->stmts, mod_flags);
check_close_scope(c);
case_end;
@@ -887,15 +889,15 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
isize result_count = 0;
if (proc_type->Proc.results)
result_count = proc_type->Proc.results->Tuple.variable_count;
- if (result_count != rs->result_count) {
+ if (result_count != gb_array_count(rs->results)) {
error(&c->error_collector, rs->token, "Expected %td return %s, got %td",
result_count,
(result_count != 1 ? "values" : "value"),
- rs->result_count);
+ gb_array_count(rs->results));
} else if (result_count > 0) {
auto *tuple = &proc_type->Proc.results->Tuple;
check_init_variables(c, tuple->variables, tuple->variable_count,
- rs->result_list, rs->result_count, make_string("return statement"));
+ rs->results, make_string("return statement"));
}
case_end;
@@ -947,11 +949,12 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
// NOTE(bill): Check for multiple defaults
AstNode *first_default = NULL;
ast_node(bs, BlockStmt, ms->body);
- for (AstNode *stmt = bs->list; stmt != NULL; stmt = stmt->next) {
+ gb_for_array(i, bs->stmts) {
+ AstNode *stmt = bs->stmts[i];
AstNode *default_stmt = NULL;
if (stmt->kind == AstNode_CaseClause) {
ast_node(c, CaseClause, stmt);
- if (c->list_count == 0) {
+ if (gb_array_count(c->list) == 0) {
default_stmt = stmt;
}
} else {
@@ -979,8 +982,8 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
Map<TypeAndToken> seen = {}; // Multimap
map_init(&seen, gb_heap_allocator());
defer (map_destroy(&seen));
- isize i = 0;
- for (AstNode *stmt = bs->list; stmt != NULL; stmt = stmt->next) {
+ gb_for_array(i, bs->stmts) {
+ AstNode *stmt = bs->stmts[i];
if (stmt->kind != AstNode_CaseClause) {
// NOTE(bill): error handled by above multiple default checker
continue;
@@ -988,7 +991,8 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
ast_node(cc, CaseClause, stmt);
- for (AstNode *expr = cc->list; expr != NULL; expr = expr->next) {
+ gb_for_array(j, cc->list) {
+ AstNode *expr = cc->list[j];
Operand y = {};
Operand z = {};
Token eq = {Token_CmpEq};
@@ -1051,12 +1055,11 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
check_open_scope(c, stmt);
u32 ft_flags = mod_flags;
- if (i+1 < bs->list_count) {
+ if (i+1 < gb_array_count(bs->stmts)) {
ft_flags |= Stmt_FallthroughAllowed;
}
- check_stmt_list(c, cc->stmts, cc->stmt_count, ft_flags);
+ check_stmt_list(c, cc->stmts, ft_flags);
check_close_scope(c);
- i++;
}
case_end;
@@ -1083,11 +1086,12 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
// NOTE(bill): Check for multiple defaults
AstNode *first_default = NULL;
ast_node(bs, BlockStmt, ms->body);
- for (AstNode *stmt = bs->list; stmt != NULL; stmt = stmt->next) {
+ gb_for_array(i, bs->stmts) {
+ AstNode *stmt = bs->stmts[i];
AstNode *default_stmt = NULL;
if (stmt->kind == AstNode_CaseClause) {
ast_node(c, CaseClause, stmt);
- if (c->list_count == 0) {
+ if (gb_array_count(c->list) == 0) {
default_stmt = stmt;
}
} else {
@@ -1116,15 +1120,15 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
defer (map_destroy(&seen));
-
- for (AstNode *stmt = bs->list; stmt != NULL; stmt = stmt->next) {
+ gb_for_array(i, bs->stmts) {
+ AstNode *stmt = bs->stmts[i];
if (stmt->kind != AstNode_CaseClause) {
// NOTE(bill): error handled by above multiple default checker
continue;
}
ast_node(cc, CaseClause, stmt);
- AstNode *type_expr = cc->list;
+ AstNode *type_expr = cc->list[0];
Type *tag_type = NULL;
if (type_expr != NULL) { // Otherwise it's a default expression
Operand y = {};
@@ -1171,7 +1175,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, ms->var->Ident, tag_ptr_type);
add_entity(c, c->context.scope, ms->var, tag_var);
}
- check_stmt_list(c, cc->stmts, cc->stmt_count, mod_flags);
+ check_stmt_list(c, cc->stmts, mod_flags);
check_close_scope(c);
}
case_end;
@@ -1311,12 +1315,13 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
case_end;
case_ast_node(vd, VarDecl, us->node);
- if (vd->name_count > 1 && vd->type != NULL) {
+ if (gb_array_count(vd->names) > 1 && vd->type != NULL) {
error(&c->error_collector, us->token, "`using` can only be applied to one variable of the same type");
}
check_var_decl_node(c, us->node);
- for (AstNode *item = vd->name_list; item != NULL; item = item->next) {
+ gb_for_array(name_index, vd->names) {
+ AstNode *item = vd->names[name_index];
ast_node(i, Ident, item);
String name = i->string;
Entity *e = scope_lookup_entity(c, c->context.scope, name);