Detect alias cycles
This commit is contained in:
@ -914,8 +914,8 @@ namespace elna::boot
|
||||
}
|
||||
|
||||
while_statement::while_statement(const struct position position, conditional_statements *body,
|
||||
std::vector<conditional_statements *>&& branches, std::vector<statement *> *alternative)
|
||||
: node(position), m_body(body), branches(std::move(branches)), alternative(alternative)
|
||||
std::vector<conditional_statements *>&& branches)
|
||||
: node(position), m_body(body), branches(std::move(branches))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -410,10 +410,10 @@ designator_expression:
|
||||
statement:
|
||||
designator_expression ":=" expression
|
||||
{ $$ = new boot::assign_statement(boot::make_position(@1), $1, $3); }
|
||||
| "while" expression "do" optional_statements elsif_do_statements else_statements "end"
|
||||
| "while" expression "do" optional_statements elsif_do_statements "end"
|
||||
{
|
||||
boot::conditional_statements *body = new boot::conditional_statements($2, std::move($4));
|
||||
$$ = new boot::while_statement(boot::make_position(@1), body, std::move($5), $6);
|
||||
$$ = new boot::while_statement(boot::make_position(@1), body, std::move($5));
|
||||
}
|
||||
| "if" expression "then" optional_statements elsif_then_statements else_statements "end"
|
||||
{
|
||||
|
@ -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