aboutsummaryrefslogtreecommitdiff
path: root/src/analyze.cpp
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2016-04-09 16:41:17 -0700
committerAndrew Kelley <superjoe30@gmail.com>2016-04-09 16:41:17 -0700
commit21eca6478f80f871f839b20044869cead55582a5 (patch)
treee638b655a8873ec255cc66493ed7cc6778a91c39 /src/analyze.cpp
parentfdf6a184615abab3314664b940ea18bc44de4546 (diff)
downloadzig-21eca6478f80f871f839b20044869cead55582a5.tar.gz
zig-21eca6478f80f871f839b20044869cead55582a5.zip
re-introduce goto
see #44
Diffstat (limited to 'src/analyze.cpp')
-rw-r--r--src/analyze.cpp71
1 files changed, 66 insertions, 5 deletions
diff --git a/src/analyze.cpp b/src/analyze.cpp
index d908c7fcbe..a5ba68da3d 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -1992,6 +1992,7 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
context->parent = parent;
context->decl_table.init(1);
context->var_table.init(1);
+ context->label_table.init(1);
if (parent) {
context->parent_loop_node = parent->parent_loop_node;
@@ -2037,6 +2038,18 @@ static VariableTableEntry *find_variable(CodeGen *g, BlockContext *orig_context,
return nullptr;
}
+static LabelTableEntry *find_label(CodeGen *g, BlockContext *orig_context, Buf *name) {
+ BlockContext *context = orig_context;
+ while (context && context->fn_entry) {
+ auto entry = context->label_table.maybe_get(name);
+ if (entry) {
+ return entry->value;
+ }
+ context = context->parent;
+ }
+ return nullptr;
+}
+
static TypeEnumField *get_enum_field(TypeTableEntry *enum_type, Buf *name) {
for (uint32_t i = 0; i < enum_type->data.enumeration.field_count; i += 1) {
TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
@@ -5326,8 +5339,19 @@ static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import,
for (int i = 0; i < node->data.block.statements.length; i += 1) {
AstNode *child = node->data.block.statements.at(i);
if (child->type == NodeTypeLabel) {
- add_node_error(g, child,
- buf_sprintf("label and goto not supported yet, see https://github.com/andrewrk/zig/issues/44"));
+ FnTableEntry *fn_table_entry = child_context->fn_entry;
+ assert(fn_table_entry);
+
+ LabelTableEntry *label = allocate<LabelTableEntry>(1);
+ label->decl_node = child;
+ label->entered_from_fallthrough = (return_type->id != TypeTableEntryIdUnreachable);
+
+ child->block_context = child_context;
+ child->data.label.label_entry = label;
+ fn_table_entry->all_labels.append(label);
+
+ child_context->label_table.put(&child->data.label.name, label);
+
return_type = g->builtin_types.entry_void;
continue;
}
@@ -5405,13 +5429,35 @@ static TypeTableEntry *analyze_asm_expr(CodeGen *g, ImportTableEntry *import, Bl
return return_type;
}
-static TypeTableEntry *analyze_goto(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+static TypeTableEntry *analyze_goto_pass1(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node)
{
- add_node_error(g, node, buf_sprintf("goto is broken, see https://github.com/andrewrk/zig/issues/44"));
+ assert(node->type == NodeTypeGoto);
+
+ FnTableEntry *fn_table_entry = context->fn_entry;
+ assert(fn_table_entry);
+
+ fn_table_entry->goto_list.append(node);
+
return g->builtin_types.entry_unreachable;
}
+static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *node) {
+ assert(node->type == NodeTypeGoto);
+ Buf *label_name = &node->data.goto_expr.name;
+ BlockContext *context = node->block_context;
+ assert(context);
+ LabelTableEntry *label = find_label(g, context, label_name);
+
+ if (!label) {
+ add_node_error(g, node, buf_sprintf("no label in scope named '%s'", buf_ptr(label_name)));
+ return;
+ }
+
+ label->used = true;
+ node->data.goto_expr.label_entry = label;
+}
+
static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEntry *import,
BlockContext *context, TypeTableEntry *expected_type, AstNode *node, bool pointer_only)
{
@@ -5433,7 +5479,7 @@ static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEn
return_type = g->builtin_types.entry_void;
break;
case NodeTypeGoto:
- analyze_goto(g, import, context, expected_type, node);
+ return_type = analyze_goto_pass1(g, import, context, expected_type, node);
break;
case NodeTypeBreak:
return_type = analyze_break_expr(g, import, context, expected_type, node);
@@ -5611,6 +5657,21 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
TypeTableEntry *block_return_type = analyze_expression(g, import, context, expected_type, node->data.fn_def.body);
node->data.fn_def.implicit_return_type = block_return_type;
+
+ for (int i = 0; i < fn_table_entry->goto_list.length; i += 1) {
+ AstNode *goto_node = fn_table_entry->goto_list.at(i);
+ assert(goto_node->type == NodeTypeGoto);
+ analyze_goto_pass2(g, import, goto_node);
+ }
+
+ for (int i = 0; i < fn_table_entry->all_labels.length; i += 1) {
+ LabelTableEntry *label = fn_table_entry->all_labels.at(i);
+ if (!label->used) {
+ add_node_error(g, label->decl_node,
+ buf_sprintf("label '%s' defined but not used",
+ buf_ptr(&label->decl_node->data.label.name)));
+ }
+ }
}
static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, BlockContext *block_context,