Detect alias cycles
This commit is contained in:
@ -17,6 +17,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
|
||||
#include "elna/boot/semantic.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
|
||||
namespace elna::boot
|
||||
@ -44,7 +45,7 @@ namespace elna::boot
|
||||
}
|
||||
|
||||
field_duplication_error::field_duplication_error(const std::string& field_name,
|
||||
const char *path, const struct position)
|
||||
const char *path, const struct position position)
|
||||
: error(path, position), field_name(field_name)
|
||||
{
|
||||
}
|
||||
@ -55,14 +56,22 @@ namespace elna::boot
|
||||
}
|
||||
|
||||
cyclic_declaration_error::cyclic_declaration_error(const std::vector<std::string>& cycle,
|
||||
const char *path, const struct position)
|
||||
const char *path, const struct position position)
|
||||
: error(path, position), cycle(cycle)
|
||||
{
|
||||
}
|
||||
|
||||
std::string cyclic_declaration_error::what() const
|
||||
{
|
||||
return "Type declaration forms a cycle";
|
||||
auto segment = std::cbegin(this->cycle);
|
||||
std::string message = "Type declaration forms a cycle: " + *segment;
|
||||
|
||||
++segment;
|
||||
for (; segment != std::cend(this->cycle); ++segment)
|
||||
{
|
||||
message += " -> " + *segment;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
name_analysis_visitor::name_analysis_visitor(const char *path, std::shared_ptr<symbol_table> symbols,
|
||||
@ -348,6 +357,22 @@ 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)
|
||||
@ -356,8 +381,17 @@ namespace elna::boot
|
||||
}
|
||||
for (auto& unresolved : this->unresolved)
|
||||
{
|
||||
auto info = std::make_shared<type_info>(type_info(type(unresolved.second)));
|
||||
this->symbols->enter(std::move(unresolved.first), info);
|
||||
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->symbols->enter(std::move(unresolved.first), info);
|
||||
}
|
||||
else
|
||||
{
|
||||
add_error<cyclic_declaration_error>(path, this->input_file, position{ 0, 0 });
|
||||
}
|
||||
}
|
||||
for (variable_declaration *const variable : unit->variables)
|
||||
{
|
||||
@ -539,6 +573,10 @@ namespace elna::boot
|
||||
|
||||
void declaration_visitor::visit(unit *unit)
|
||||
{
|
||||
for (import_declaration *const _import : unit->imports)
|
||||
{
|
||||
_import->accept(this);
|
||||
}
|
||||
for (type_declaration *const type : unit->types)
|
||||
{
|
||||
const std::string& type_identifier = type->identifier.identifier;
|
||||
@ -547,10 +585,6 @@ namespace elna::boot
|
||||
{
|
||||
add_error<already_declared_error>(type->identifier.identifier, this->input_file, type->position());
|
||||
}
|
||||
else
|
||||
{
|
||||
type->accept(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user