Detect alias cycles

This commit is contained in:
2025-06-21 22:32:34 +02:00
parent 67a8d2c057
commit a187e5e62a
10 changed files with 84 additions and 66 deletions

View File

@ -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))
{
}

View File

@ -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"
{

View File

@ -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);
}
}
}