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);
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) {
+10 -10
View File
@@ -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);
+10 -10
View File
@@ -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);
+6 -22
View File
@@ -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<Ast *> 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<Ast *> 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"));
+1 -2
View File
@@ -407,8 +407,7 @@ AST_KIND(_ComplexStmtBegin, "", bool) \
AST_KIND(RangeStmt, "range statement", struct { \
Token token; \
Ast *label; \
Ast *val0; \
Ast *val1; \
Slice<Ast *> vals; \
Token in_token; \
Ast *expr; \
Ast *body; \