aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2019-11-02 16:36:46 +0000
committergingerBill <bill@gingerbill.org>2019-11-02 16:36:46 +0000
commite3d3a81617dd78a9b193bbc07f2a29315774ff57 (patch)
treed285fd38b6daae5ac62a8adb10269d31b8f97135 /src
parentdbdbbcd60f1273e246d11696476ac4772f91c258 (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.cpp55
-rw-r--r--src/checker.cpp54
-rw-r--r--src/ir.cpp39
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;