mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 23:58:50 +00:00
Generalize Odin call-based "iterators" to work with more than 2-values: for x, y, z, w in iterate(&it)
It has an artificial limitation of 100 values because if you need for than that, you're doing something wrong.
This commit is contained in:
+21
-14
@@ -1669,12 +1669,20 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
|
|||||||
case Type_Tuple:
|
case Type_Tuple:
|
||||||
{
|
{
|
||||||
isize count = t->Tuple.variables.count;
|
isize count = t->Tuple.variables.count;
|
||||||
if (count < 1 || count > 3) {
|
if (count < 1) {
|
||||||
ERROR_BLOCK();
|
ERROR_BLOCK();
|
||||||
check_not_tuple(ctx, &operand);
|
check_not_tuple(ctx, &operand);
|
||||||
error_line("\tMultiple return valued parameters in a range statement are limited to a maximum of 2 usable values with a trailing boolean for the conditional\n");
|
error_line("\tMultiple return valued parameters in a range statement are limited to a minimum of 1 usable values with a trailing boolean for the conditional, got %td\n", count);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
enum : isize {MAXIMUM_COUNT = 100};
|
||||||
|
if (count > MAXIMUM_COUNT) {
|
||||||
|
ERROR_BLOCK();
|
||||||
|
check_not_tuple(ctx, &operand);
|
||||||
|
error_line("\tMultiple return valued parameters in a range statement are limited to a maximum of %td usable values with a trailing boolean for the conditional, got %td\n", MAXIMUM_COUNT, count);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
Type *cond_type = t->Tuple.variables[count-1]->type;
|
Type *cond_type = t->Tuple.variables[count-1]->type;
|
||||||
if (!is_type_boolean(cond_type)) {
|
if (!is_type_boolean(cond_type)) {
|
||||||
gbString s = type_to_string(cond_type);
|
gbString s = type_to_string(cond_type);
|
||||||
@@ -1683,24 +1691,23 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
max_val_count = count;
|
||||||
|
|
||||||
for (Entity *e : t->Tuple.variables) {
|
for (Entity *e : t->Tuple.variables) {
|
||||||
array_add(&vals, e->type);
|
array_add(&vals, e->type);
|
||||||
}
|
}
|
||||||
|
|
||||||
is_possibly_addressable = false;
|
is_possibly_addressable = false;
|
||||||
|
|
||||||
if (rs->vals.count > 1 && rs->vals[1] != nullptr && count < 3) {
|
bool do_break = false;
|
||||||
gbString s = type_to_string(t);
|
for (isize i = rs->vals.count-1; i >= 0; i--) {
|
||||||
error(operand.expr, "Expected a 3-valued expression on the rhs, got (%s)", s);
|
if (rs->vals[i] != nullptr && count < i+2) {
|
||||||
gb_string_free(s);
|
gbString s = type_to_string(t);
|
||||||
break;
|
error(operand.expr, "Expected a %td-valued expression on the rhs, got (%s)", i+2, s);
|
||||||
}
|
gb_string_free(s);
|
||||||
|
do_break = true;
|
||||||
if (rs->vals.count > 0 && rs->vals[0] != nullptr && count < 2) {
|
break;
|
||||||
gbString s = type_to_string(t);
|
}
|
||||||
error(operand.expr, "Expected at least a 2-valued expression on the rhs, got (%s)", s);
|
|
||||||
gb_string_free(s);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_reverse) {
|
if (is_reverse) {
|
||||||
|
|||||||
@@ -802,8 +802,19 @@ gb_internal void lb_build_range_enum(lbProcedure *p, Type *enum_type, Type *val_
|
|||||||
if (done_) *done_ = done;
|
if (done_) *done_ = done;
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_internal void lb_build_range_tuple(lbProcedure *p, Ast *expr, Type *val0_type, Type *val1_type,
|
gb_internal void lb_build_range_tuple(lbProcedure *p, AstRangeStmt *rs, Scope *scope) {
|
||||||
lbValue *val0_, lbValue *val1_, lbBlock **loop_, lbBlock **done_) {
|
Ast *expr = unparen_expr(rs->expr);
|
||||||
|
|
||||||
|
Type *expr_type = type_of_expr(expr);
|
||||||
|
Type *et = base_type(type_deref(expr_type));
|
||||||
|
GB_ASSERT(et->kind == Type_Tuple);
|
||||||
|
|
||||||
|
i32 value_count = cast(i32)et->Tuple.variables.count;
|
||||||
|
|
||||||
|
lbValue *values = gb_alloc_array(permanent_allocator(), lbValue, value_count);
|
||||||
|
|
||||||
|
lb_open_scope(p, scope);
|
||||||
|
|
||||||
lbBlock *loop = lb_create_block(p, "for.tuple.loop");
|
lbBlock *loop = lb_create_block(p, "for.tuple.loop");
|
||||||
lb_emit_jump(p, loop);
|
lb_emit_jump(p, loop);
|
||||||
lb_start_block(p, loop);
|
lb_start_block(p, loop);
|
||||||
@@ -821,11 +832,26 @@ gb_internal void lb_build_range_tuple(lbProcedure *p, Ast *expr, Type *val0_type
|
|||||||
lb_emit_if(p, cond, body, done);
|
lb_emit_if(p, cond, body, done);
|
||||||
lb_start_block(p, body);
|
lb_start_block(p, body);
|
||||||
|
|
||||||
|
for (i32 i = 0; i < value_count; i++) {
|
||||||
|
values[i] = lb_emit_tuple_ev(p, tuple_value, i);
|
||||||
|
}
|
||||||
|
|
||||||
if (val0_) *val0_ = lb_emit_tuple_ev(p, tuple_value, 0);
|
GB_ASSERT(rs->vals.count <= value_count);
|
||||||
if (val1_) *val1_ = lb_emit_tuple_ev(p, tuple_value, 1);
|
for (isize i = 0; i < rs->vals.count; i++) {
|
||||||
if (loop_) *loop_ = loop;
|
Ast *val = rs->vals[i];
|
||||||
if (done_) *done_ = done;
|
if (val != nullptr) {
|
||||||
|
lb_store_range_stmt_val(p, val, values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lb_push_target_list(p, rs->label, done, loop, nullptr);
|
||||||
|
|
||||||
|
lb_build_stmt(p, rs->body);
|
||||||
|
|
||||||
|
lb_close_scope(p, lbDeferExit_Default, nullptr);
|
||||||
|
lb_pop_target_list(p);
|
||||||
|
lb_emit_jump(p, loop);
|
||||||
|
lb_start_block(p, done);
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs, Scope *scope) {
|
gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs, Scope *scope) {
|
||||||
@@ -968,6 +994,17 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypeAndValue tav = type_and_value_of_expr(expr);
|
||||||
|
if (tav.mode != Addressing_Type) {
|
||||||
|
Type *expr_type = type_of_expr(expr);
|
||||||
|
Type *et = base_type(type_deref(expr_type));
|
||||||
|
if (et->kind == Type_Tuple) {
|
||||||
|
lb_build_range_tuple(p, rs, scope);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
lb_open_scope(p, scope);
|
lb_open_scope(p, scope);
|
||||||
|
|
||||||
Ast *val0 = rs->vals.count > 0 ? lb_strip_and_prefix(rs->vals[0]) : nullptr;
|
Ast *val0 = rs->vals.count > 0 ? lb_strip_and_prefix(rs->vals[0]) : nullptr;
|
||||||
@@ -986,7 +1023,6 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
|
|||||||
lbBlock *loop = nullptr;
|
lbBlock *loop = nullptr;
|
||||||
lbBlock *done = nullptr;
|
lbBlock *done = nullptr;
|
||||||
bool is_map = false;
|
bool is_map = false;
|
||||||
TypeAndValue tav = type_and_value_of_expr(expr);
|
|
||||||
|
|
||||||
if (tav.mode == Addressing_Type) {
|
if (tav.mode == Addressing_Type) {
|
||||||
lb_build_range_enum(p, type_deref(tav.type), val0_type, &val, &key, &loop, &done);
|
lb_build_range_enum(p, type_deref(tav.type), val0_type, &val, &key, &loop, &done);
|
||||||
@@ -1062,8 +1098,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Type_Tuple:
|
case Type_Tuple:
|
||||||
lb_build_range_tuple(p, expr, val0_type, val1_type, &val, &key, &loop, &done);
|
GB_PANIC("Should be handled already");
|
||||||
break;
|
|
||||||
|
|
||||||
case Type_BitSet: {
|
case Type_BitSet: {
|
||||||
lbModule *m = p->module;
|
lbModule *m = p->module;
|
||||||
|
|||||||
Reference in New Issue
Block a user