diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index c539da99b..3b5593516 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1666,7 +1666,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { Ast *expr = unparen_expr(rs->expr); - + isize max_val_count = 2; if (is_ast_range(expr)) { ast_node(ie, BinaryExpr, expr); Operand x = {}; @@ -1739,9 +1739,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { break; case Type_Tuple: - if (false) { - check_not_tuple(ctx, &operand); - } else { + { isize count = t->Tuple.variables.count; if (count < 1 || count > 3) { check_not_tuple(ctx, &operand); @@ -1759,14 +1757,14 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { if (count > 1) val0 = t->Tuple.variables[0]->type; if (count > 2) val1 = t->Tuple.variables[1]->type; - if (rs->val1 != nullptr && count < 3) { + if (rs->vals.count > 1 && rs->vals[1] != nullptr && count < 3) { gbString s = type_to_string(t); error(operand.expr, "Expected a 3-value tuple on the rhs, got (%s)", s); gb_string_free(s); break; } - if (rs->val0 != nullptr && count < 2) { + if (rs->vals.count > 0 && rs->vals[0] != nullptr && count < 2) { gbString s = type_to_string(t); error(operand.expr, "Expected at least a 2-values tuple on the rhs, got (%s)", s); gb_string_free(s); @@ -1776,6 +1774,11 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { } break; + case Type_Struct: + if (t->Struct.soa_kind != StructSoa_None) { + error(operand.expr, "#soa structures do not yet support for in loop iteration"); + } + break; } } @@ -1787,9 +1790,9 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { error(operand.expr, "Cannot iterate over '%s' of type '%s'", s, t); - if (rs->val0 != nullptr && rs->val1 == nullptr) { + if (rs->vals.count == 1) { if (is_type_map(operand.type) || is_type_bit_set(operand.type)) { - gbString v = expr_to_string(rs->val0); + gbString v = expr_to_string(rs->vals[0]); defer (gb_string_free(v)); error_line("\tSuggestion: place parentheses around the expression\n"); error_line("\t for (%s in %s) {\n", v, s); @@ -1800,8 +1803,14 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { skip_expr_range_stmt:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird. - Ast * lhs[2] = {rs->val0, rs->val1}; + if (rs->vals.count > max_val_count) { + error(rs->vals[max_val_count], "Expected a maximum of %td identifier%s, got %td", max_val_count, max_val_count == 1 ? "" : "s", rs->vals.count); + } + + Ast * lhs[2] = {}; Type *rhs[2] = {val0, val1}; + if (rs->vals.count > 1) { lhs[1] = rs->vals[1]; } + if (rs->vals.count > 0) { lhs[0] = rs->vals[0]; } for (isize i = 0; i < 2; i++) { if (lhs[i] == nullptr) { diff --git a/src/ir.cpp b/src/ir.cpp index d17951f9f..ee463296a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10735,18 +10735,18 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) { Type *val0_type = nullptr; Type *val1_type = nullptr; - if (rs->val0 != nullptr && !is_blank_ident(rs->val0)) { - val0_type = type_of_expr(rs->val0); + if (rs->vals.count > 0 && rs->vals[0] != nullptr && !is_blank_ident(rs->vals[0])) { + val0_type = type_of_expr(rs->vals[0]); } - if (rs->val1 != nullptr && !is_blank_ident(rs->val1)) { - val1_type = type_of_expr(rs->val1); + if (rs->vals.count > 1 && rs->vals[1] != nullptr && !is_blank_ident(rs->vals[1])) { + val1_type = type_of_expr(rs->vals[1]); } if (val0_type != nullptr) { - ir_add_local_for_identifier(proc, rs->val0, true); + ir_add_local_for_identifier(proc, rs->vals[0], true); } if (val1_type != nullptr) { - ir_add_local_for_identifier(proc, rs->val1, true); + ir_add_local_for_identifier(proc, rs->vals[1], true); } irValue *val = nullptr; @@ -10851,11 +10851,11 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) { if (is_map) { - if (val0_type) ir_store_range_stmt_val(proc, rs->val0, key); - if (val1_type) ir_store_range_stmt_val(proc, rs->val1, val); + if (val0_type) ir_store_range_stmt_val(proc, rs->vals[0], key); + if (val1_type) ir_store_range_stmt_val(proc, rs->vals[1], val); } else { - if (val0_type) ir_store_range_stmt_val(proc, rs->val0, val); - if (val1_type) ir_store_range_stmt_val(proc, rs->val1, key); + if (val0_type) ir_store_range_stmt_val(proc, rs->vals[0], val); + if (val1_type) ir_store_range_stmt_val(proc, rs->vals[1], key); } ir_push_target_list(proc, rs->label, done, loop, nullptr); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index a350e5883..d09c55b79 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -3889,19 +3889,19 @@ void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *scope) { Type *val0_type = nullptr; Type *val1_type = nullptr; - if (rs->val0 != nullptr && !is_blank_ident(rs->val0)) { - val0_type = type_of_expr(rs->val0); + if (rs->vals.count > 0 && rs->vals[0] != nullptr && !is_blank_ident(rs->vals[0])) { + val0_type = type_of_expr(rs->vals[0]); } - if (rs->val1 != nullptr && !is_blank_ident(rs->val1)) { - val1_type = type_of_expr(rs->val1); + if (rs->vals.count > 1 && rs->vals[1] != nullptr && !is_blank_ident(rs->vals[1])) { + val1_type = type_of_expr(rs->vals[1]); } if (val0_type != nullptr) { - Entity *e = entity_of_node(rs->val0); + Entity *e = entity_of_node(rs->vals[0]); lb_add_local(p, e->type, e, true); } if (val1_type != nullptr) { - Entity *e = entity_of_node(rs->val1); + Entity *e = entity_of_node(rs->vals[1]); lb_add_local(p, e->type, e, true); } @@ -4002,11 +4002,11 @@ void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *scope) { if (is_map) { - if (val0_type) lb_store_range_stmt_val(p, rs->val0, key); - if (val1_type) lb_store_range_stmt_val(p, rs->val1, val); + if (val0_type) lb_store_range_stmt_val(p, rs->vals[0], key); + if (val1_type) lb_store_range_stmt_val(p, rs->vals[1], val); } else { - if (val0_type) lb_store_range_stmt_val(p, rs->val0, val); - if (val1_type) lb_store_range_stmt_val(p, rs->val1, key); + if (val0_type) lb_store_range_stmt_val(p, rs->vals[0], val); + if (val1_type) lb_store_range_stmt_val(p, rs->vals[1], key); } lb_push_target_list(p, rs->label, done, loop, nullptr); diff --git a/src/parser.cpp b/src/parser.cpp index 07521c8e0..8f1741054 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -315,8 +315,7 @@ Ast *clone_ast(Ast *node) { break; case Ast_RangeStmt: n->RangeStmt.label = clone_ast(n->RangeStmt.label); - n->RangeStmt.val0 = clone_ast(n->RangeStmt.val0); - n->RangeStmt.val1 = clone_ast(n->RangeStmt.val1); + n->RangeStmt.vals = clone_ast_array(n->RangeStmt.vals); n->RangeStmt.expr = clone_ast(n->RangeStmt.expr); n->RangeStmt.body = clone_ast(n->RangeStmt.body); break; @@ -842,11 +841,10 @@ Ast *ast_for_stmt(AstFile *f, Token token, Ast *init, Ast *cond, Ast *post, Ast return result; } -Ast *ast_range_stmt(AstFile *f, Token token, Ast *val0, Ast *val1, Token in_token, Ast *expr, Ast *body) { +Ast *ast_range_stmt(AstFile *f, Token token, Slice vals, Token in_token, Ast *expr, Ast *body) { Ast *result = alloc_ast_node(f, Ast_RangeStmt); result->RangeStmt.token = token; - result->RangeStmt.val0 = val0; - result->RangeStmt.val1 = val1; + result->RangeStmt.vals = vals; result->RangeStmt.in_token = in_token; result->RangeStmt.expr = expr; result->RangeStmt.body = body; @@ -3914,7 +3912,7 @@ Ast *parse_for_stmt(AstFile *f) { } else { body = parse_block_stmt(f, false); } - return ast_range_stmt(f, token, nullptr, nullptr, in_token, rhs, body); + return ast_range_stmt(f, token, {}, in_token, rhs, body); } if (f->curr_token.kind != Token_Semicolon) { @@ -3954,26 +3952,12 @@ Ast *parse_for_stmt(AstFile *f) { if (is_range) { GB_ASSERT(cond->kind == Ast_AssignStmt); Token in_token = cond->AssignStmt.op; - Ast *value = nullptr; - Ast *index = nullptr; - switch (cond->AssignStmt.lhs.count) { - case 1: - value = cond->AssignStmt.lhs[0]; - break; - case 2: - value = cond->AssignStmt.lhs[0]; - index = cond->AssignStmt.lhs[1]; - break; - default: - syntax_error(cond, "Expected either 1 or 2 identifiers"); - return ast_bad_stmt(f, token, f->curr_token); - } - + Slice vals = cond->AssignStmt.lhs; Ast *rhs = nullptr; if (cond->AssignStmt.rhs.count > 0) { rhs = cond->AssignStmt.rhs[0]; } - return ast_range_stmt(f, token, value, index, in_token, rhs, body); + return ast_range_stmt(f, token, vals, in_token, rhs, body); } cond = convert_stmt_to_expr(f, cond, str_lit("boolean expression")); diff --git a/src/parser.hpp b/src/parser.hpp index eab230816..03a37739e 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -407,8 +407,7 @@ AST_KIND(_ComplexStmtBegin, "", bool) \ AST_KIND(RangeStmt, "range statement", struct { \ Token token; \ Ast *label; \ - Ast *val0; \ - Ast *val1; \ + Slice vals; \ Token in_token; \ Ast *expr; \ Ast *body; \