Document symbol bag class and methods
This commit is contained in:
@@ -69,7 +69,7 @@ namespace elna::boot
|
||||
{
|
||||
return std::move(name_analyser.errors());
|
||||
}
|
||||
type_analysis_visitor type_analyzer(path);
|
||||
type_analysis_visitor type_analyzer(path, bag);
|
||||
tree->accept(&type_analyzer);
|
||||
|
||||
if (type_analyzer.has_errors())
|
||||
|
@@ -48,4 +48,20 @@ namespace elna::boot
|
||||
{
|
||||
return !m_errors.empty();
|
||||
}
|
||||
|
||||
bool identifier_definition::operator==(const identifier_definition& that) const
|
||||
{
|
||||
return *this == that.name;
|
||||
}
|
||||
|
||||
bool identifier_definition::operator==(const std::string& that) const
|
||||
{
|
||||
return this->name == that;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t std::hash<elna::boot::identifier_definition>::operator()(
|
||||
const elna::boot::identifier_definition& key) const
|
||||
{
|
||||
return std::hash<std::string>{}(key.name);
|
||||
}
|
||||
|
117
boot/semantic.cc
117
boot/semantic.cc
@@ -93,8 +93,8 @@ namespace elna::boot
|
||||
return "Only one variable can be initialized";
|
||||
}
|
||||
|
||||
type_analysis_visitor::type_analysis_visitor(const char *path)
|
||||
: error_container(path)
|
||||
type_analysis_visitor::type_analysis_visitor(const char *path, symbol_bag bag)
|
||||
: error_container(path), bag(bag)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace elna::boot
|
||||
}
|
||||
if (!this->returns)
|
||||
{
|
||||
add_error<return_error>(definition->identifier.identifier, this->input_file, definition->position());
|
||||
add_error<return_error>(definition->identifier.name, this->input_file, definition->position());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,10 +126,6 @@ namespace elna::boot
|
||||
{
|
||||
}
|
||||
|
||||
void type_analysis_visitor::visit(import_declaration *)
|
||||
{
|
||||
}
|
||||
|
||||
void type_analysis_visitor::visit(while_statement *)
|
||||
{
|
||||
}
|
||||
@@ -151,8 +147,28 @@ namespace elna::boot
|
||||
{
|
||||
}
|
||||
|
||||
bool type_analysis_visitor::check_unresolved_symbol(std::shared_ptr<alias_type> alias,
|
||||
std::vector<std::string>& alias_path)
|
||||
{
|
||||
if (std::find(std::cbegin(alias_path), std::cend(alias_path), alias->name) != std::cend(alias_path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
alias_path.push_back(alias->name);
|
||||
|
||||
if (auto another_alias = alias->reference.get<alias_type>())
|
||||
{
|
||||
return check_unresolved_symbol(another_alias, alias_path);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void type_analysis_visitor::visit(unit *unit)
|
||||
{
|
||||
for (type_declaration *const type : unit->types)
|
||||
{
|
||||
type->accept(this);
|
||||
}
|
||||
for (procedure_declaration *const procedure : unit->procedures)
|
||||
{
|
||||
this->returns = false;
|
||||
@@ -160,6 +176,17 @@ namespace elna::boot
|
||||
}
|
||||
}
|
||||
|
||||
void type_analysis_visitor::visit(type_declaration *definition)
|
||||
{
|
||||
std::vector<std::string> alias_path;
|
||||
auto unresolved_type = this->bag.lookup(definition->identifier.name)->is_type()->symbol.get<alias_type>();
|
||||
|
||||
if (!check_unresolved_symbol(unresolved_type, alias_path))
|
||||
{
|
||||
add_error<cyclic_declaration_error>(alias_path, this->input_file, definition->position());
|
||||
}
|
||||
}
|
||||
|
||||
name_analysis_visitor::name_analysis_visitor(const char *path, symbol_bag bag)
|
||||
: error_container(path), bag(bag)
|
||||
{
|
||||
@@ -205,18 +232,20 @@ namespace elna::boot
|
||||
void name_analysis_visitor::visit(type_declaration *definition)
|
||||
{
|
||||
definition->body().accept(this);
|
||||
auto unresolved_declaration = this->bag.unresolved.at(definition->identifier.identifier);
|
||||
auto resolved = this->bag.resolve(definition->identifier.name, this->current_type);
|
||||
auto info = std::make_shared<type_info>(type(resolved));
|
||||
|
||||
unresolved_declaration->reference = this->current_type;
|
||||
info->exported = definition->identifier.exported;
|
||||
this->bag.enter(definition->identifier.name, info);
|
||||
}
|
||||
|
||||
void name_analysis_visitor::visit(named_type_expression *type_expression)
|
||||
{
|
||||
auto unresolved_alias = this->bag.unresolved.find(type_expression->name);
|
||||
auto unresolved_alias = this->bag.declared(type_expression->name);
|
||||
|
||||
if (unresolved_alias != this->bag.unresolved.end())
|
||||
if (unresolved_alias != nullptr)
|
||||
{
|
||||
this->current_type = type(unresolved_alias->second);
|
||||
this->current_type = type(unresolved_alias);
|
||||
}
|
||||
else if (auto from_symbol_table = this->bag.lookup(type_expression->name))
|
||||
{
|
||||
@@ -301,15 +330,24 @@ namespace elna::boot
|
||||
|
||||
for (const auto& variable_identifier : declaration->identifiers)
|
||||
{
|
||||
this->bag.enter(variable_identifier.identifier, std::make_shared<variable_info>(this->current_type));
|
||||
auto variable_symbol = std::make_shared<variable_info>(this->current_type, declaration->is_extern);
|
||||
|
||||
variable_symbol->exported = variable_identifier.exported;
|
||||
if (!this->bag.enter(variable_identifier.name, variable_symbol))
|
||||
{
|
||||
add_error<already_declared_error>(variable_identifier.name, this->input_file,
|
||||
declaration->position());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void name_analysis_visitor::visit(constant_declaration *definition)
|
||||
{
|
||||
definition->body().accept(this);
|
||||
auto constant_symbol = std::make_shared<constant_info>(this->current_literal);
|
||||
|
||||
this->bag.enter(definition->identifier.identifier, std::make_shared<constant_info>(this->current_literal));
|
||||
constant_symbol->exported = definition->identifier.exported;
|
||||
this->bag.enter(definition->identifier.name, constant_symbol);
|
||||
}
|
||||
|
||||
void name_analysis_visitor::visit(procedure_declaration *definition)
|
||||
@@ -339,7 +377,8 @@ namespace elna::boot
|
||||
{
|
||||
info = std::make_shared<procedure_info>(heading, definition->parameter_names);
|
||||
}
|
||||
this->bag.enter(definition->identifier.identifier, info);
|
||||
info->exported = definition->identifier.exported;
|
||||
this->bag.enter(definition->identifier.name, info);
|
||||
}
|
||||
|
||||
void name_analysis_visitor::visit(assign_statement *statement)
|
||||
@@ -440,42 +479,12 @@ namespace elna::boot
|
||||
}
|
||||
}
|
||||
|
||||
bool name_analysis_visitor::check_unresolved_symbol(std::shared_ptr<alias_type> alias,
|
||||
std::vector<std::string>& path)
|
||||
{
|
||||
if (std::find(std::cbegin(path), std::cend(path), alias->name) != std::cend(path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
path.push_back(alias->name);
|
||||
|
||||
if (auto another_alias = alias->reference.get<alias_type>())
|
||||
{
|
||||
return check_unresolved_symbol(another_alias, path);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void name_analysis_visitor::visit(unit *unit)
|
||||
{
|
||||
for (type_declaration *const type : unit->types)
|
||||
{
|
||||
type->accept(this);
|
||||
}
|
||||
for (auto& unresolved : this->bag.unresolved)
|
||||
{
|
||||
std::vector<std::string> path;
|
||||
|
||||
if (check_unresolved_symbol(unresolved.second, path))
|
||||
{
|
||||
auto info = std::make_shared<type_info>(type_info(type(unresolved.second)));
|
||||
this->bag.enter(unresolved.first, info);
|
||||
}
|
||||
else
|
||||
{
|
||||
add_error<cyclic_declaration_error>(path, this->input_file, position{ 0, 0 });
|
||||
}
|
||||
}
|
||||
for (variable_declaration *const variable : unit->variables)
|
||||
{
|
||||
variable->accept(this);
|
||||
@@ -590,12 +599,7 @@ namespace elna::boot
|
||||
}
|
||||
for (type_declaration *const type : unit->types)
|
||||
{
|
||||
const std::string& type_identifier = type->identifier.identifier;
|
||||
|
||||
if (!this->unresolved.insert({ type_identifier, std::make_shared<alias_type>(type_identifier) }).second)
|
||||
{
|
||||
add_error<already_declared_error>(type->identifier.identifier, this->input_file, type->position());
|
||||
}
|
||||
type->accept(this);
|
||||
}
|
||||
for (variable_declaration *const variable : unit->variables)
|
||||
{
|
||||
@@ -607,6 +611,17 @@ namespace elna::boot
|
||||
}
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(type_declaration *definition)
|
||||
{
|
||||
const std::string& type_identifier = definition->identifier.name;
|
||||
|
||||
if (!this->unresolved.insert({ type_identifier, std::make_shared<alias_type>(type_identifier) }).second)
|
||||
{
|
||||
add_error<already_declared_error>(definition->identifier.name, this->input_file,
|
||||
definition->position());
|
||||
}
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(variable_declaration *declaration)
|
||||
{
|
||||
if (declaration->has_initializer() && declaration->identifiers.size() > 1)
|
||||
|
@@ -314,7 +314,7 @@ namespace elna::boot
|
||||
|
||||
procedure_info::procedure_info(const procedure_type symbol, const std::vector<std::string> names,
|
||||
std::shared_ptr<symbol_table> scope)
|
||||
: symbol(symbol), names(names), symbols(scope)
|
||||
: symbol(symbol), names(names), scope(scope)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -323,6 +323,11 @@ namespace elna::boot
|
||||
return std::static_pointer_cast<procedure_info>(shared_from_this());
|
||||
}
|
||||
|
||||
bool procedure_info::is_extern() const
|
||||
{
|
||||
return this->scope == nullptr;
|
||||
}
|
||||
|
||||
constant_info::constant_info(const variant& symbol)
|
||||
: symbol(symbol)
|
||||
{
|
||||
@@ -333,8 +338,8 @@ namespace elna::boot
|
||||
return std::static_pointer_cast<constant_info>(shared_from_this());
|
||||
}
|
||||
|
||||
variable_info::variable_info(const type symbol)
|
||||
: symbol(symbol)
|
||||
variable_info::variable_info(const type symbol, bool is_extern)
|
||||
: symbol(symbol), is_extern(is_extern)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -358,14 +363,10 @@ namespace elna::boot
|
||||
return result;
|
||||
}
|
||||
|
||||
symbol_bag::symbol_bag()
|
||||
{
|
||||
this->symbols = std::make_shared<symbol_table>();
|
||||
}
|
||||
|
||||
symbol_bag::symbol_bag(forward_table&& unresolved, std::shared_ptr<symbol_table> symbols)
|
||||
: symbols(symbols), unresolved(unresolved)
|
||||
symbol_bag::symbol_bag(forward_table&& unresolved, std::shared_ptr<symbol_table> global_table)
|
||||
: unresolved(unresolved)
|
||||
{
|
||||
this->symbols = std::make_shared<symbol_table>(global_table);
|
||||
}
|
||||
|
||||
std::shared_ptr<info> symbol_bag::lookup(const std::string& name)
|
||||
@@ -396,18 +397,31 @@ namespace elna::boot
|
||||
this->symbols = child;
|
||||
}
|
||||
|
||||
void symbol_bag::leave()
|
||||
std::shared_ptr<symbol_table> symbol_bag::leave()
|
||||
{
|
||||
this->symbols = this->symbols->scope();
|
||||
std::shared_ptr<symbol_table> result = this->symbols;
|
||||
|
||||
this->symbols = result->scope();
|
||||
return result;
|
||||
}
|
||||
|
||||
void symbol_bag::add_import(std::shared_ptr<symbol_table> table)
|
||||
std::shared_ptr<alias_type> symbol_bag::declared(const std::string& symbol_name)
|
||||
{
|
||||
this->imports.push_front(table);
|
||||
auto unresolved_alias = this->unresolved.find(symbol_name);
|
||||
|
||||
return unresolved_alias == this->unresolved.end() ? std::shared_ptr<alias_type>() : unresolved_alias->second;
|
||||
}
|
||||
|
||||
std::shared_ptr<alias_type> symbol_bag::resolve(const std::string& symbol_name, type& resolution)
|
||||
{
|
||||
auto unresolved_declaration = this->unresolved.at(symbol_name);
|
||||
|
||||
unresolved_declaration->reference = resolution;
|
||||
return unresolved_declaration;
|
||||
}
|
||||
|
||||
void symbol_bag::add_import(const symbol_bag& bag)
|
||||
{
|
||||
add_import(bag.symbols);
|
||||
this->imports.push_front(bag.symbols);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user