Make the parser support as many identifiers on the LHS in for in loops to improve error messages

This commit is contained in:
gingerBill
2021-03-24 12:11:00 +00:00
parent 295c1550a8
commit 0e3ecc350a
5 changed files with 45 additions and 53 deletions
+18 -9
View File
@@ -1666,7 +1666,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
Ast *expr = unparen_expr(rs->expr); Ast *expr = unparen_expr(rs->expr);
isize max_val_count = 2;
if (is_ast_range(expr)) { if (is_ast_range(expr)) {
ast_node(ie, BinaryExpr, expr); ast_node(ie, BinaryExpr, expr);
Operand x = {}; Operand x = {};
@@ -1739,9 +1739,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
break; break;
case Type_Tuple: case Type_Tuple:
if (false) { {
check_not_tuple(ctx, &operand);
} else {
isize count = t->Tuple.variables.count; isize count = t->Tuple.variables.count;
if (count < 1 || count > 3) { if (count < 1 || count > 3) {
check_not_tuple(ctx, &operand); 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 > 1) val0 = t->Tuple.variables[0]->type;
if (count > 2) val1 = t->Tuple.variables[1]->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); gbString s = type_to_string(t);
error(operand.expr, "Expected a 3-value tuple on the rhs, got (%s)", s); error(operand.expr, "Expected a 3-value tuple on the rhs, got (%s)", s);
gb_string_free(s); gb_string_free(s);
break; break;
} }
if (rs->val0 != nullptr && count < 2) { if (rs->vals.count > 0 && rs->vals[0] != nullptr && count < 2) {
gbString s = type_to_string(t); gbString s = type_to_string(t);
error(operand.expr, "Expected at least a 2-values tuple on the rhs, got (%s)", s); error(operand.expr, "Expected at least a 2-values tuple on the rhs, got (%s)", s);
gb_string_free(s); gb_string_free(s);
@@ -1776,6 +1774,11 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
} }
break; 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); 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)) { 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)); defer (gb_string_free(v));
error_line("\tSuggestion: place parentheses around the expression\n"); error_line("\tSuggestion: place parentheses around the expression\n");
error_line("\t for (%s in %s) {\n", v, s); 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. 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}; 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++) { for (isize i = 0; i < 2; i++) {
if (lhs[i] == nullptr) { if (lhs[i] == nullptr) {
+10 -10
View File
@@ -10735,18 +10735,18 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) {
Type *val0_type = nullptr; Type *val0_type = nullptr;
Type *val1_type = nullptr; Type *val1_type = nullptr;
if (rs->val0 != nullptr && !is_blank_ident(rs->val0)) { if (rs->vals.count > 0 && rs->vals[0] != nullptr && !is_blank_ident(rs->vals[0])) {
val0_type = type_of_expr(rs->val0); val0_type = type_of_expr(rs->vals[0]);
} }
if (rs->val1 != nullptr && !is_blank_ident(rs->val1)) { if (rs->vals.count > 1 && rs->vals[1] != nullptr && !is_blank_ident(rs->vals[1])) {
val1_type = type_of_expr(rs->val1); val1_type = type_of_expr(rs->vals[1]);
} }
if (val0_type != nullptr) { 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) { 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; irValue *val = nullptr;
@@ -10851,11 +10851,11 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) {
if (is_map) { if (is_map) {
if (val0_type) ir_store_range_stmt_val(proc, rs->val0, key); if (val0_type) ir_store_range_stmt_val(proc, rs->vals[0], key);
if (val1_type) ir_store_range_stmt_val(proc, rs->val1, val); if (val1_type) ir_store_range_stmt_val(proc, rs->vals[1], val);
} else { } else {
if (val0_type) ir_store_range_stmt_val(proc, rs->val0, val); if (val0_type) ir_store_range_stmt_val(proc, rs->vals[0], val);
if (val1_type) ir_store_range_stmt_val(proc, rs->val1, key); if (val1_type) ir_store_range_stmt_val(proc, rs->vals[1], key);
} }
ir_push_target_list(proc, rs->label, done, loop, nullptr); ir_push_target_list(proc, rs->label, done, loop, nullptr);
+10 -10
View File
@@ -3889,19 +3889,19 @@ void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *scope) {
Type *val0_type = nullptr; Type *val0_type = nullptr;
Type *val1_type = nullptr; Type *val1_type = nullptr;
if (rs->val0 != nullptr && !is_blank_ident(rs->val0)) { if (rs->vals.count > 0 && rs->vals[0] != nullptr && !is_blank_ident(rs->vals[0])) {
val0_type = type_of_expr(rs->val0); val0_type = type_of_expr(rs->vals[0]);
} }
if (rs->val1 != nullptr && !is_blank_ident(rs->val1)) { if (rs->vals.count > 1 && rs->vals[1] != nullptr && !is_blank_ident(rs->vals[1])) {
val1_type = type_of_expr(rs->val1); val1_type = type_of_expr(rs->vals[1]);
} }
if (val0_type != nullptr) { 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); lb_add_local(p, e->type, e, true);
} }
if (val1_type != nullptr) { 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); 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 (is_map) {
if (val0_type) lb_store_range_stmt_val(p, rs->val0, key); if (val0_type) lb_store_range_stmt_val(p, rs->vals[0], key);
if (val1_type) lb_store_range_stmt_val(p, rs->val1, val); if (val1_type) lb_store_range_stmt_val(p, rs->vals[1], val);
} else { } else {
if (val0_type) lb_store_range_stmt_val(p, rs->val0, val); if (val0_type) lb_store_range_stmt_val(p, rs->vals[0], val);
if (val1_type) lb_store_range_stmt_val(p, rs->val1, key); if (val1_type) lb_store_range_stmt_val(p, rs->vals[1], key);
} }
lb_push_target_list(p, rs->label, done, loop, nullptr); lb_push_target_list(p, rs->label, done, loop, nullptr);
+6 -22
View File
@@ -315,8 +315,7 @@ Ast *clone_ast(Ast *node) {
break; break;
case Ast_RangeStmt: case Ast_RangeStmt:
n->RangeStmt.label = clone_ast(n->RangeStmt.label); n->RangeStmt.label = clone_ast(n->RangeStmt.label);
n->RangeStmt.val0 = clone_ast(n->RangeStmt.val0); n->RangeStmt.vals = clone_ast_array(n->RangeStmt.vals);
n->RangeStmt.val1 = clone_ast(n->RangeStmt.val1);
n->RangeStmt.expr = clone_ast(n->RangeStmt.expr); n->RangeStmt.expr = clone_ast(n->RangeStmt.expr);
n->RangeStmt.body = clone_ast(n->RangeStmt.body); n->RangeStmt.body = clone_ast(n->RangeStmt.body);
break; break;
@@ -842,11 +841,10 @@ Ast *ast_for_stmt(AstFile *f, Token token, Ast *init, Ast *cond, Ast *post, Ast
return result; 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<Ast *> vals, Token in_token, Ast *expr, Ast *body) {
Ast *result = alloc_ast_node(f, Ast_RangeStmt); Ast *result = alloc_ast_node(f, Ast_RangeStmt);
result->RangeStmt.token = token; result->RangeStmt.token = token;
result->RangeStmt.val0 = val0; result->RangeStmt.vals = vals;
result->RangeStmt.val1 = val1;
result->RangeStmt.in_token = in_token; result->RangeStmt.in_token = in_token;
result->RangeStmt.expr = expr; result->RangeStmt.expr = expr;
result->RangeStmt.body = body; result->RangeStmt.body = body;
@@ -3914,7 +3912,7 @@ Ast *parse_for_stmt(AstFile *f) {
} else { } else {
body = parse_block_stmt(f, false); 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) { if (f->curr_token.kind != Token_Semicolon) {
@@ -3954,26 +3952,12 @@ Ast *parse_for_stmt(AstFile *f) {
if (is_range) { if (is_range) {
GB_ASSERT(cond->kind == Ast_AssignStmt); GB_ASSERT(cond->kind == Ast_AssignStmt);
Token in_token = cond->AssignStmt.op; Token in_token = cond->AssignStmt.op;
Ast *value = nullptr; Slice<Ast *> vals = cond->AssignStmt.lhs;
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);
}
Ast *rhs = nullptr; Ast *rhs = nullptr;
if (cond->AssignStmt.rhs.count > 0) { if (cond->AssignStmt.rhs.count > 0) {
rhs = cond->AssignStmt.rhs[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")); cond = convert_stmt_to_expr(f, cond, str_lit("boolean expression"));
+1 -2
View File
@@ -407,8 +407,7 @@ AST_KIND(_ComplexStmtBegin, "", bool) \
AST_KIND(RangeStmt, "range statement", struct { \ AST_KIND(RangeStmt, "range statement", struct { \
Token token; \ Token token; \
Ast *label; \ Ast *label; \
Ast *val0; \ Slice<Ast *> vals; \
Ast *val1; \
Token in_token; \ Token in_token; \
Ast *expr; \ Ast *expr; \
Ast *body; \ Ast *body; \