Declare an additional name analysis visitor

This commit is contained in:
2025-06-20 22:33:37 +02:00
parent 6da2a70329
commit 67a8d2c057
4 changed files with 312 additions and 74 deletions

View File

@ -43,11 +43,6 @@ namespace elna::boot
return "Symbol '" + identifier + "' has been already declared";
}
declaration_visitor::declaration_visitor(const char *path, std::shared_ptr<symbol_table> symbols)
: error_container(path), symbols(symbols)
{
}
field_duplication_error::field_duplication_error(const std::string& field_name,
const char *path, const struct position)
: error(path, position), field_name(field_name)
@ -59,7 +54,24 @@ namespace elna::boot
return "Repeated field name '" + field_name + "'";
}
procedure_type declaration_visitor::build_procedure(procedure_type_expression& type_expression)
cyclic_declaration_error::cyclic_declaration_error(const std::vector<std::string>& cycle,
const char *path, const struct position)
: error(path, position), cycle(cycle)
{
}
std::string cyclic_declaration_error::what() const
{
return "Type declaration forms a cycle";
}
name_analysis_visitor::name_analysis_visitor(const char *path, std::shared_ptr<symbol_table> symbols,
std::unordered_map<std::string, std::shared_ptr<alias_type>>&& unresolved)
: error_container(path), symbols(symbols), unresolved(std::move(unresolved))
{
}
procedure_type name_analysis_visitor::build_procedure(procedure_type_expression& type_expression)
{
procedure_type::return_t result_return;
@ -86,7 +98,7 @@ namespace elna::boot
return result_type;
}
void declaration_visitor::visit(program *program)
void name_analysis_visitor::visit(program *program)
{
visit(static_cast<unit *>(program));
@ -96,7 +108,7 @@ namespace elna::boot
}
}
void declaration_visitor::visit(type_declaration *definition)
void name_analysis_visitor::visit(type_declaration *definition)
{
definition->body().accept(this);
auto unresolved_declaration = this->unresolved.at(definition->identifier.identifier);
@ -104,7 +116,7 @@ namespace elna::boot
unresolved_declaration->reference = this->current_type;
}
void declaration_visitor::visit(named_type_expression *type_expression)
void name_analysis_visitor::visit(named_type_expression *type_expression)
{
auto unresolved_alias = this->unresolved.find(type_expression->name);
@ -123,19 +135,19 @@ namespace elna::boot
}
}
void declaration_visitor::visit(pointer_type_expression *type_expression)
void name_analysis_visitor::visit(pointer_type_expression *type_expression)
{
type_expression->base().accept(this);
this->current_type = type(std::make_shared<pointer_type>(this->current_type));
}
void declaration_visitor::visit(array_type_expression *type_expression)
void name_analysis_visitor::visit(array_type_expression *type_expression)
{
type_expression->base().accept(this);
this->current_type = type(std::make_shared<array_type>(this->current_type, type_expression->size));
}
std::vector<type_field> declaration_visitor::build_composite_type(const std::vector<field_declaration>& fields)
std::vector<type_field> name_analysis_visitor::build_composite_type(const std::vector<field_declaration>& fields)
{
std::vector<type_field> result;
std::set<std::string> field_names;
@ -156,7 +168,7 @@ namespace elna::boot
return result;
}
void declaration_visitor::visit(record_type_expression *type_expression)
void name_analysis_visitor::visit(record_type_expression *type_expression)
{
auto result_type = std::make_shared<record_type>();
@ -165,7 +177,7 @@ namespace elna::boot
this->current_type = type(result_type);
}
void declaration_visitor::visit(union_type_expression *type_expression)
void name_analysis_visitor::visit(union_type_expression *type_expression)
{
auto result_type = std::make_shared<union_type>();
@ -174,7 +186,7 @@ namespace elna::boot
this->current_type = type(result_type);
}
void declaration_visitor::visit(procedure_type_expression *type_expression)
void name_analysis_visitor::visit(procedure_type_expression *type_expression)
{
std::shared_ptr<procedure_type> result_type =
std::make_shared<procedure_type>(std::move(build_procedure(*type_expression)));
@ -182,14 +194,14 @@ namespace elna::boot
this->current_type = type(result_type);
}
void declaration_visitor::visit(enumeration_type_expression *type_expression)
void name_analysis_visitor::visit(enumeration_type_expression *type_expression)
{
std::shared_ptr<enumeration_type> result_type = std::make_shared<enumeration_type>(type_expression->members);
this->current_type = type(result_type);
}
void declaration_visitor::visit(variable_declaration *declaration)
void name_analysis_visitor::visit(variable_declaration *declaration)
{
declaration->variable_type().accept(this);
@ -197,7 +209,7 @@ namespace elna::boot
std::make_shared<variable_info>(this->current_type));
}
void declaration_visitor::visit(constant_declaration *definition)
void name_analysis_visitor::visit(constant_declaration *definition)
{
definition->body().accept(this);
@ -205,7 +217,7 @@ namespace elna::boot
std::make_shared<constant_info>(this->current_literal));
}
void declaration_visitor::visit(procedure_declaration *definition)
void name_analysis_visitor::visit(procedure_declaration *definition)
{
std::shared_ptr<procedure_info> info;
@ -238,13 +250,13 @@ namespace elna::boot
this->symbols->enter(definition->identifier.identifier, info);
}
void declaration_visitor::visit(assign_statement *statement)
void name_analysis_visitor::visit(assign_statement *statement)
{
statement->lvalue().accept(this);
statement->rvalue().accept(this);
}
void declaration_visitor::visit(if_statement *statement)
void name_analysis_visitor::visit(if_statement *statement)
{
statement->body().prerequisite().accept(this);
for (struct statement *const statement : statement->body().statements)
@ -269,11 +281,11 @@ namespace elna::boot
}
}
void declaration_visitor::visit(import_declaration *)
void name_analysis_visitor::visit(import_declaration *)
{
}
void declaration_visitor::visit(while_statement *statement)
void name_analysis_visitor::visit(while_statement *statement)
{
statement->body().prerequisite().accept(this);
for (struct statement *const statement : statement->body().statements)
@ -291,12 +303,12 @@ namespace elna::boot
}
}
void declaration_visitor::visit(return_statement *statement)
void name_analysis_visitor::visit(return_statement *statement)
{
statement->return_expression().accept(this);
}
void declaration_visitor::visit(defer_statement *statement)
void name_analysis_visitor::visit(defer_statement *statement)
{
for (struct statement *const statement : statement->statements)
{
@ -304,7 +316,7 @@ namespace elna::boot
}
}
void declaration_visitor::visit(case_statement *statement)
void name_analysis_visitor::visit(case_statement *statement)
{
statement->condition().accept(this);
for (const switch_case& case_block : statement->cases)
@ -327,7 +339,7 @@ namespace elna::boot
}
}
void declaration_visitor::visit(procedure_call *call)
void name_analysis_visitor::visit(procedure_call *call)
{
call->callable().accept(this);
for (expression *const argument: call->arguments)
@ -336,18 +348,8 @@ namespace elna::boot
}
}
void declaration_visitor::visit(unit *unit)
void name_analysis_visitor::visit(unit *unit)
{
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
|| this->symbols->contains(type_identifier))
{
add_error<already_declared_error>(type->identifier.identifier, this->input_file, type->position());
}
}
for (type_declaration *const type : unit->types)
{
type->accept(this);
@ -367,7 +369,7 @@ namespace elna::boot
}
}
void declaration_visitor::visit(traits_expression *trait)
void name_analysis_visitor::visit(traits_expression *trait)
{
if (!trait->parameters.empty())
{
@ -376,76 +378,239 @@ namespace elna::boot
}
}
void declaration_visitor::visit(cast_expression *expression)
void name_analysis_visitor::visit(cast_expression *expression)
{
expression->value().accept(this);
expression->target().accept(this);
expression->expression_type = this->current_type;
}
void declaration_visitor::visit(binary_expression *expression)
void name_analysis_visitor::visit(binary_expression *expression)
{
expression->lhs().accept(this);
expression->rhs().accept(this);
}
void declaration_visitor::visit(unary_expression *expression)
void name_analysis_visitor::visit(unary_expression *expression)
{
expression->operand().accept(this);
}
void name_analysis_visitor::visit(variable_expression *)
{
}
void name_analysis_visitor::visit(array_access_expression *expression)
{
expression->base().accept(this);
expression->index().accept(this);
}
void name_analysis_visitor::visit(field_access_expression *expression)
{
expression->base().accept(this);
}
void name_analysis_visitor::visit(dereference_expression *expression)
{
expression->base().accept(this);
}
void name_analysis_visitor::visit(literal<std::int32_t> *literal)
{
this->current_literal = literal->value;
}
void name_analysis_visitor::visit(literal<std::uint32_t> *literal)
{
this->current_literal = literal->value;
}
void name_analysis_visitor::visit(literal<double> *literal)
{
this->current_literal = literal->value;
}
void name_analysis_visitor::visit(literal<bool> *literal)
{
this->current_literal = literal->value;
}
void name_analysis_visitor::visit(literal<unsigned char> *literal)
{
this->current_literal = literal->value;
}
void name_analysis_visitor::visit(literal<std::nullptr_t> *literal)
{
this->current_literal = literal->value;
}
void name_analysis_visitor::visit(literal<std::string> *literal)
{
this->current_literal = literal->value;
}
declaration_visitor::declaration_visitor(const char *path)
: error_container(path)
{
}
void declaration_visitor::visit(named_type_expression *)
{
}
void declaration_visitor::visit(array_type_expression *)
{
}
void declaration_visitor::visit(pointer_type_expression *)
{
}
void declaration_visitor::visit(program *program)
{
visit(static_cast<unit *>(program));
}
void declaration_visitor::visit(type_declaration *)
{
}
void declaration_visitor::visit(record_type_expression *)
{
}
void declaration_visitor::visit(union_type_expression *)
{
}
void declaration_visitor::visit(procedure_type_expression *)
{
}
void declaration_visitor::visit(enumeration_type_expression *)
{
}
void declaration_visitor::visit(variable_declaration *)
{
}
void declaration_visitor::visit(constant_declaration *)
{
}
void declaration_visitor::visit(procedure_declaration *)
{
}
void declaration_visitor::visit(assign_statement *)
{
}
void declaration_visitor::visit(if_statement *)
{
}
void declaration_visitor::visit(import_declaration *)
{
}
void declaration_visitor::visit(while_statement *)
{
}
void declaration_visitor::visit(return_statement *)
{
}
void declaration_visitor::visit(defer_statement *)
{
}
void declaration_visitor::visit(case_statement *)
{
}
void declaration_visitor::visit(procedure_call *)
{
}
void declaration_visitor::visit(unit *unit)
{
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());
}
else
{
type->accept(this);
}
}
}
void declaration_visitor::visit(cast_expression *)
{
}
void declaration_visitor::visit(traits_expression *)
{
}
void declaration_visitor::visit(binary_expression *)
{
}
void declaration_visitor::visit(unary_expression *)
{
}
void declaration_visitor::visit(variable_expression *)
{
}
void declaration_visitor::visit(array_access_expression *expression)
void declaration_visitor::visit(array_access_expression *)
{
expression->base().accept(this);
expression->index().accept(this);
}
void declaration_visitor::visit(field_access_expression *expression)
void declaration_visitor::visit(field_access_expression *)
{
expression->base().accept(this);
}
void declaration_visitor::visit(dereference_expression *expression)
void declaration_visitor::visit(dereference_expression *)
{
expression->base().accept(this);
}
void declaration_visitor::visit(literal<std::int32_t> *literal)
void declaration_visitor::visit(literal<std::int32_t> *)
{
this->current_literal = literal->value;
}
void declaration_visitor::visit(literal<std::uint32_t> *literal)
void declaration_visitor::visit(literal<std::uint32_t> *)
{
this->current_literal = literal->value;
}
void declaration_visitor::visit(literal<double> *literal)
void declaration_visitor::visit(literal<double> *)
{
this->current_literal = literal->value;
}
void declaration_visitor::visit(literal<bool> *literal)
void declaration_visitor::visit(literal<bool> *)
{
this->current_literal = literal->value;
}
void declaration_visitor::visit(literal<unsigned char> *literal)
void declaration_visitor::visit(literal<unsigned char> *)
{
this->current_literal = literal->value;
}
void declaration_visitor::visit(literal<std::nullptr_t> *literal)
void declaration_visitor::visit(literal<std::nullptr_t> *)
{
this->current_literal = literal->value;
}
void declaration_visitor::visit(literal<std::string> *literal)
void declaration_visitor::visit(literal<std::string> *)
{
this->current_literal = literal->value;
}
}

View File

@ -764,7 +764,7 @@ namespace elna::gcc
this->current_expression = NULL_TREE;
if (!result)
{
error_at(declaration_location, "variable '%s' already declared in this scope",
error_at(declaration_location, "Variable '%s' already declared in this scope",
declaration->identifier.identifier.c_str());
}
else if (lang_hooks.decls.global_bindings_p())

View File

@ -84,16 +84,26 @@ static void elna_parse_file(const char *filename)
{
for (const std::unique_ptr<elna::boot::program>& module_tree : outcome.modules)
{
elna::boot::declaration_visitor declaration_visitor(filename, info_table);
elna::boot::declaration_visitor declaration_visitor(filename);
declaration_visitor.visit(module_tree.get());
if (declaration_visitor.errors().empty())
{
elna::gcc::do_semantic_analysis(info_table, symbol_table);
elna::boot::name_analysis_visitor name_analysis_visitor(filename, info_table,
std::move(declaration_visitor.unresolved));
name_analysis_visitor.visit(module_tree.get());
elna::gcc::generic_visitor generic_visitor{ symbol_table, info_table };
generic_visitor.visit(module_tree.get());
if (name_analysis_visitor.errors().empty())
{
elna::gcc::do_semantic_analysis(info_table, symbol_table);
elna::gcc::generic_visitor generic_visitor{ symbol_table, info_table };
generic_visitor.visit(module_tree.get());
}
else
{
elna::gcc::report_errors(name_analysis_visitor.errors());
}
}
else
{

View File

@ -30,7 +30,7 @@ namespace elna::boot
{
class undeclared_error : public error
{
std::string identifier;
const std::string identifier;
public:
undeclared_error(const std::string& identifier, const char *path, const struct position position);
@ -40,7 +40,7 @@ namespace elna::boot
class already_declared_error : public error
{
std::string identifier;
const std::string identifier;
public:
already_declared_error(const std::string& identifier, const char *path, const struct position position);
@ -50,7 +50,7 @@ namespace elna::boot
class field_duplication_error : public error
{
std::string field_name;
const std::string field_name;
public:
field_duplication_error(const std::string& field_name, const char *path, const struct position);
@ -58,7 +58,20 @@ namespace elna::boot
std::string what() const override;
};
class declaration_visitor final : public parser_visitor, public error_container
class cyclic_declaration_error : public error
{
const std::vector<std::string> cycle;
public:
cyclic_declaration_error(const std::vector<std::string>& cycle, const char *path, const struct position);
std::string what() const override;
};
/**
* Performs name analysis.
*/
class name_analysis_visitor final : public parser_visitor, public error_container
{
type current_type;
constant_info::variant current_literal;
@ -70,7 +83,8 @@ namespace elna::boot
std::vector<type_field> build_composite_type(const std::vector<field_declaration>& fields);
public:
explicit declaration_visitor(const char *path, std::shared_ptr<symbol_table> symbols);
explicit name_analysis_visitor(const char *path, std::shared_ptr<symbol_table> symbols,
std::unordered_map<std::string, std::shared_ptr<alias_type>>&& unresolved);
void visit(named_type_expression *type_expression) override;
void visit(array_type_expression *type_expression) override;
@ -110,4 +124,53 @@ namespace elna::boot
void visit(literal<std::nullptr_t> *literal) override;
void visit(literal<std::string> *literal) override;
};
/**
* Collects global declarations.
*/
class declaration_visitor final : public parser_visitor, public error_container
{
public:
std::unordered_map<std::string, std::shared_ptr<alias_type>> unresolved;
explicit declaration_visitor(const char *path);
void visit(named_type_expression *) override;
void visit(array_type_expression *) override;
void visit(pointer_type_expression *) override;
void visit(program *program) override;
void visit(type_declaration *) override;
void visit(record_type_expression *) override;
void visit(union_type_expression *) override;
void visit(procedure_type_expression *) override;
void visit(enumeration_type_expression *) override;
void visit(variable_declaration *) override;
void visit(constant_declaration *) override;
void visit(procedure_declaration *) override;
void visit(assign_statement *) override;
void visit(if_statement *) override;
void visit(import_declaration *) override;
void visit(while_statement *) override;
void visit(return_statement *) override;
void visit(defer_statement *) override;
void visit(case_statement *) override;
void visit(procedure_call *) override;
void visit(unit *unit) override;
void visit(cast_expression *) override;
void visit(traits_expression *) override;
void visit(binary_expression *) override;
void visit(unary_expression *) override;
void visit(variable_expression *) override;
void visit(array_access_expression *) override;
void visit(field_access_expression *) override;
void visit(dereference_expression *) override;
void visit(literal<std::int32_t> *) override;
void visit(literal<std::uint32_t> *) override;
void visit(literal<double> *) override;
void visit(literal<bool> *) override;
void visit(literal<unsigned char> *) override;
void visit(literal<std::nullptr_t> *) override;
void visit(literal<std::string> *) override;
};
}