diff options
| author | gingerBill <bill@gingerbill.org> | 2019-11-02 16:36:46 +0000 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2019-11-02 16:36:46 +0000 |
| commit | e3d3a81617dd78a9b193bbc07f2a29315774ff57 (patch) | |
| tree | d285fd38b6daae5ac62a8adb10269d31b8f97135 /src | |
| parent | dbdbbcd60f1273e246d11696476ac4772f91c258 (diff) | |
multivalued procedure calls allows in `for in` to allow a pseudo-iterator; `@thread_local` for variables in procedure
Diffstat (limited to 'src')
| -rw-r--r-- | src/check_stmt.cpp | 55 | ||||
| -rw-r--r-- | src/checker.cpp | 54 | ||||
| -rw-r--r-- | src/ir.cpp | 39 |
3 files changed, 119 insertions, 29 deletions
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 2bf82facd..63cb4da8b 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -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); diff --git a/src/checker.cpp b/src/checker.cpp index 8ba45a799..184f99ab9 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -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; } diff --git a/src/ir.cpp b/src/ir.cpp index d7db09180..bb3253b7d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -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; |