aboutsummaryrefslogtreecommitdiff
path: root/boot/name_analysis.cc
diff options
context:
space:
mode:
Diffstat (limited to 'boot/name_analysis.cc')
-rw-r--r--boot/name_analysis.cc73
1 files changed, 67 insertions, 6 deletions
diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc
index 8820684..9ba030c 100644
--- a/boot/name_analysis.cc
+++ b/boot/name_analysis.cc
@@ -48,8 +48,14 @@ namespace elna::boot
return "Trait '#" + this->name + "' not declared";
case undeclared_symbol:
return "Symbol '" + this->name + "' not declared";
+ case undeclared_label:
+ return "Label '" + this->name + "' not declared";
case not_a_type:
return "'" + this->name + "' is not a type";
+ case not_a_label:
+ return "'" + this->name + "' is not a label";
+ case break_leaves_defer:
+ return "'break' cannot leave a defer statement";
default:
__builtin_unreachable();
}
@@ -781,9 +787,64 @@ namespace elna::boot
void resolving_visitor::visit(defer_statement *statement)
{
- for (auto *block_statement : statement->statements)
+ ++this->defer_depth;
+ for (auto *body_statement : statement->statements)
{
- block_statement->accept(this);
+ body_statement->accept(this);
+ }
+ --this->defer_depth;
+ }
+
+ void resolving_visitor::visit(block_statement *statement)
+ {
+ const std::string& label_name = statement->name.name();
+
+ this->bag.enter();
+
+ auto label_symbol = std::make_shared<label_info>(this->defer_depth);
+ label_symbol->position.emplace(statement->name.position());
+ label_symbol->file = this->module_file;
+
+ if (!this->bag.enter(label_name, label_symbol))
+ {
+ auto original = this->bag.lookup(label_name);
+ symbol_declaration_error::redefinition original_definition{
+ .original = original->position,
+ .file = this->redefinition_file(original)
+ };
+ add_error<symbol_declaration_error>(statement->name.position(),
+ label_name, original_definition);
+ }
+ for (auto *body_statement : statement->statements)
+ {
+ body_statement->accept(this);
+ }
+ this->bag.leave();
+ }
+
+ void resolving_visitor::visit(break_statement *statement)
+ {
+ const std::string& label_name = statement->label.name();
+ const source_position position = statement->label.position();
+ const std::shared_ptr<info> symbol = this->bag.lookup(label_name);
+
+ if (symbol == nullptr)
+ {
+ add_error<symbol_declaration_error>(position, label_name,
+ symbol_declaration_error::kind::undeclared_label);
+ return;
+ }
+ auto label_symbol = symbol->is_label();
+
+ if (label_symbol == nullptr)
+ {
+ add_error<symbol_declaration_error>(position, label_name,
+ symbol_declaration_error::kind::not_a_label);
+ }
+ else if (label_symbol->defer_depth != this->defer_depth)
+ {
+ add_error<symbol_declaration_error>(position, label_name,
+ symbol_declaration_error::kind::break_leaves_defer);
}
}
@@ -800,16 +861,16 @@ namespace elna::boot
{
case_label->accept(this);
}
- for (auto *block_statement : case_block.statements)
+ for (auto *body_statement : case_block.statements)
{
- block_statement->accept(this);
+ body_statement->accept(this);
}
}
if (statement->alternative != nullptr)
{
- for (auto *block_statement : *statement->alternative)
+ for (auto *body_statement : *statement->alternative)
{
- block_statement->accept(this);
+ body_statement->accept(this);
}
}
}