multivalued procedure calls allows in for in to allow a pseudo-iterator; @thread_local for variables in procedure

This commit is contained in:
gingerBill
2019-11-02 16:36:46 +00:00
parent dbdbbcd60f
commit e3d3a81617
4 changed files with 158 additions and 29 deletions

View File

@@ -1233,6 +1233,44 @@ ranged_fields_for_array_compound_literals :: proc() {
}
}
range_statements_with_multiple_return_values :: proc() {
// IMPORTANT NOTE(bill, 2019-11-02): This feature is subject to be changed/removed
fmt.println("\n#range statements with multiple return values");
My_Iterator :: struct {
index: int,
data: []i32,
};
make_my_iterator :: proc(data: []i32) -> My_Iterator {
return My_Iterator{data = data};
}
my_iterator :: proc(it: ^My_Iterator) -> (val: i32, idx: int, cond: bool) {
if cond = it.index < len(it.data); cond {
val = it.data[it.index];
idx = it.index;
it.index += 1;
}
return;
}
data := make([]i32, 6);
for _, i in data {
data[i] = i32(i*i);
}
{
it := make_my_iterator(data);
for val in my_iterator(&it) {
fmt.println(val);
}
}
{
it := make_my_iterator(data);
for val, idx in my_iterator(&it) {
fmt.println(val, idx);
}
}
}
main :: proc() {
when true {
extra_general_stuff();
@@ -1256,6 +1294,7 @@ main :: proc() {
inline_for_statement();
where_clauses();
ranged_fields_for_array_compound_literals();
range_statements_with_multiple_return_values();
}
}

View File

@@ -1487,7 +1487,8 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
val1 = t_int;
} else {
Operand operand = {Addressing_Invalid};
check_expr_or_type(ctx, &operand, rs->expr);
check_expr_base(ctx, &operand, expr, nullptr);
error_operand_no_value(&operand);
if (operand.mode == Addressing_Type) {
if (!is_type_enum(operand.type)) {
@@ -1532,6 +1533,45 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
val0 = t->Map.key;
val1 = t->Map.value;
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);
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");
break;
}
Type *cond_type = t->Tuple.variables[count-1]->type;
if (!is_type_boolean(cond_type)) {
gbString s = type_to_string(cond_type);
error(operand.expr, "The final type of %td-valued tuple must be a boolean, got %s", count, s);
gb_string_free(s);
break;
}
if (count > 1) val0 = t->Tuple.variables[0]->type;
if (count > 2) val1 = t->Tuple.variables[1]->type;
if (rs->val1 != 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) {
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);
break;
}
}
break;
}
}
@@ -1849,6 +1889,19 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
e->flags |= EntityFlag_Static;
}
}
if (ac.thread_local_model != "") {
String name = e->token.string;
if (name == "_") {
error(e->token, "The 'thread_local' attribute is not allowed to be applied to '_'");
} else {
e->flags |= EntityFlag_Static;
}
e->Variable.thread_local_model = ac.thread_local_model;
}
if (ac.is_static && ac.thread_local_model != "") {
error(e->token, "The 'static' attribute is not needed if 'thread_local' is applied");
}
}
check_arity_match(ctx, vd);

View File

@@ -2217,6 +2217,33 @@ DECL_ATTRIBUTE_PROC(var_decl_attribute) {
}
ac->is_static = true;
return true;
} else if (name == "thread_local") {
if (ac->init_expr_list_count > 0) {
error(elem, "A thread local variable declaration cannot have initialization values");
} else if (c->foreign_context.curr_library) {
error(elem, "A foreign block variable cannot be thread local");
} else if (ac->is_export) {
error(elem, "An exported variable cannot be thread local");
} else if (ev.kind == ExactValue_Invalid) {
ac->thread_local_model = str_lit("default");
} else if (ev.kind == ExactValue_String) {
String model = ev.value_string;
if (model == "default" ||
model == "localdynamic" ||
model == "initialexec" ||
model == "localexec") {
ac->thread_local_model = model;
} else {
error(elem, "Invalid thread local model '%.*s'. Valid models:", LIT(model));
error_line("\tdefault\n");
error_line("\tlocaldynamic\n");
error_line("\tinitialexec\n");
error_line("\tlocalexec\n");
}
} else {
error(elem, "Expected either no value or a string for '%.*s'", LIT(name));
}
return true;
}
if (c->curr_proc_decl != nullptr) {
@@ -2257,33 +2284,6 @@ DECL_ATTRIBUTE_PROC(var_decl_attribute) {
error(elem, "Expected a string value for '%.*s'", LIT(name));
}
return true;
} else if (name == "thread_local") {
if (ac->init_expr_list_count > 0) {
error(elem, "A thread local variable declaration cannot have initialization values");
} else if (c->foreign_context.curr_library) {
error(elem, "A foreign block variable cannot be thread local");
} else if (ac->is_export) {
error(elem, "An exported variable cannot be thread local");
} else if (ev.kind == ExactValue_Invalid) {
ac->thread_local_model = str_lit("default");
} else if (ev.kind == ExactValue_String) {
String model = ev.value_string;
if (model == "default" ||
model == "localdynamic" ||
model == "initialexec" ||
model == "localexec") {
ac->thread_local_model = model;
} else {
error(elem, "Invalid thread local model '%.*s'. Valid models:", LIT(model));
error_line("\tdefault\n");
error_line("\tlocaldynamic\n");
error_line("\tinitialexec\n");
error_line("\tlocalexec\n");
}
} else {
error(elem, "Expected either no value or a string for '%.*s'", LIT(name));
}
return true;
}
return false;
}

View File

@@ -8741,6 +8741,35 @@ void ir_build_range_enum(irProcedure *proc, Type *enum_type, Type *val_type, irV
if (done_) *done_ = done;
}
void ir_build_range_tuple(irProcedure *proc, Ast *expr, Type *val0_type, Type *val1_type,
irValue **val0_, irValue **val1_, irBlock **loop_, irBlock **done_) {
irBlock *loop = ir_new_block(proc, nullptr, "for.tuple.loop");
ir_emit_jump(proc, loop);
ir_start_block(proc, loop);
irBlock *body = ir_new_block(proc, nullptr, "for.tuple.body");
irBlock *done = ir_new_block(proc, nullptr, "for.tuple.done");
irValue *tuple_value = ir_build_expr(proc, expr);
Type *tuple = ir_type(tuple_value);
GB_ASSERT(tuple->kind == Type_Tuple);
i32 tuple_count = cast(i32)tuple->Tuple.variables.count;
i32 cond_index = tuple_count-1;
irValue *cond = ir_emit_struct_ev(proc, tuple_value, cond_index);
ir_emit_if(proc, cond, body, done);
ir_start_block(proc, body);
irValue *val0 = nullptr;
if (val0_) *val0_ = ir_emit_struct_ev(proc, tuple_value, 0);
if (val1_) *val1_ = ir_emit_struct_ev(proc, tuple_value, 1);
if (loop_) *loop_ = loop;
if (done_) *done_ = done;
}
void ir_store_type_case_implicit(irProcedure *proc, Ast *clause, irValue *value) {
Entity *e = implicit_entity_of_node(clause);
GB_ASSERT(e != nullptr);
@@ -8818,7 +8847,12 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) {
irValue *g = ir_value_global(e, value);
g->Global.name = mangled_name;
g->Global.is_internal = true;
g->Global.is_private = true;
if (e->Variable.thread_local_model != "") {
g->Global.thread_local_model = e->Variable.thread_local_model;
} else {
g->Global.is_internal = true;
}
ir_module_add_value(proc->module, e, g);
map_set(&proc->module->members, key, g);
}
@@ -9252,6 +9286,9 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) {
ir_build_range_string(proc, string, val0_type, &val, &key, &loop, &done);
break;
}
case Type_Tuple:
ir_build_range_tuple(proc, rs->expr, val0_type, val1_type, &val, &key, &loop, &done);
break;
default:
GB_PANIC("Cannot range over %s", type_to_string(expr_type));
break;