Remove type visiting in generic visitor

This commit is contained in:
2025-08-06 12:55:37 +02:00
parent b18effbdd8
commit 5d1804fbc2
10 changed files with 374 additions and 232 deletions

View File

@@ -19,6 +19,191 @@ along with GCC; see the file COPYING3. If not see
namespace elna::boot
{
void empty_visitor::not_implemented()
{
__builtin_unreachable();
}
void empty_visitor::visit(named_type_expression *)
{
not_implemented();
}
void empty_visitor::visit(array_type_expression *)
{
not_implemented();
}
void empty_visitor::visit(pointer_type_expression *)
{
not_implemented();
}
void empty_visitor::visit(program *)
{
not_implemented();
}
void empty_visitor::visit(type_declaration *)
{
not_implemented();
}
void empty_visitor::visit(record_type_expression *)
{
not_implemented();
}
void empty_visitor::visit(union_type_expression *)
{
not_implemented();
}
void empty_visitor::visit(procedure_type_expression *)
{
not_implemented();
}
void empty_visitor::visit(enumeration_type_expression *)
{
not_implemented();
}
void empty_visitor::visit(variable_declaration *)
{
not_implemented();
}
void empty_visitor::visit(constant_declaration *)
{
not_implemented();
}
void empty_visitor::visit(procedure_declaration *)
{
not_implemented();
}
void empty_visitor::visit(assign_statement *)
{
not_implemented();
}
void empty_visitor::visit(if_statement *)
{
not_implemented();
}
void empty_visitor::visit(import_declaration *)
{
not_implemented();
}
void empty_visitor::visit(while_statement *)
{
not_implemented();
}
void empty_visitor::visit(return_statement *)
{
not_implemented();
}
void empty_visitor::visit(defer_statement *)
{
not_implemented();
}
void empty_visitor::visit(case_statement *)
{
not_implemented();
}
void empty_visitor::visit(procedure_call *)
{
not_implemented();
}
void empty_visitor::visit(unit *)
{
not_implemented();
}
void empty_visitor::visit(cast_expression *)
{
not_implemented();
}
void empty_visitor::visit(traits_expression *)
{
not_implemented();
}
void empty_visitor::visit(binary_expression *)
{
not_implemented();
}
void empty_visitor::visit(unary_expression *)
{
not_implemented();
}
void empty_visitor::visit(variable_expression *)
{
not_implemented();
}
void empty_visitor::visit(array_access_expression *)
{
not_implemented();
}
void empty_visitor::visit(field_access_expression *)
{
not_implemented();
}
void empty_visitor::visit(dereference_expression *)
{
not_implemented();
}
void empty_visitor::visit(literal<std::int32_t> *)
{
not_implemented();
}
void empty_visitor::visit(literal<std::uint32_t> *)
{
not_implemented();
}
void empty_visitor::visit(literal<double> *)
{
not_implemented();
}
void empty_visitor::visit(literal<bool> *)
{
not_implemented();
}
void empty_visitor::visit(literal<unsigned char> *)
{
not_implemented();
}
void empty_visitor::visit(literal<std::nullptr_t> *)
{
not_implemented();
}
void empty_visitor::visit(literal<std::string> *)
{
not_implemented();
}
node::node(const struct position position)
: source_position(position)
{

View File

@@ -32,7 +32,7 @@ namespace elna::boot
{
}
dependency read_sources(std::istream& entry_point, const char *entry_path)
dependency read_source(std::istream& entry_point, const char *entry_path)
{
driver parse_driver{ entry_path };
lexer tokenizer(entry_point);
@@ -60,6 +60,25 @@ namespace elna::boot
return outcome;
}
error_list analyze_semantics(const char *path, std::unique_ptr<unit>& tree, symbol_bag bag)
{
name_analysis_visitor name_analyser(path, bag);
tree->accept(&name_analyser);
if (name_analyser.has_errors())
{
return std::move(name_analyser.errors());
}
type_analysis_visitor type_analyzer(path);
tree->accept(&type_analyzer);
if (type_analyzer.has_errors())
{
return std::move(type_analyzer.errors());
}
return error_list{};
}
std::filesystem::path build_path(const std::vector<std::string>& segments)
{
std::filesystem::path result;

View File

@@ -32,7 +32,6 @@ namespace elna::boot
return "Type '" + identifier + "' not declared";
}
already_declared_error::already_declared_error(const std::string& identifier,
const char *path, const struct position position)
: error(path, position), identifier(identifier)
@@ -74,6 +73,83 @@ namespace elna::boot
return message;
}
return_error::return_error(const std::string& identifier, const char *path, const struct position position)
: error(path, position), identifier(identifier)
{
}
std::string return_error::what() const
{
return "Procedure '" + identifier + "' is expected to return, but does not have a return statement";
}
type_analysis_visitor::type_analysis_visitor(const char *path)
: error_container(path)
{
}
void type_analysis_visitor::visit(program *program)
{
visit(static_cast<unit *>(program));
}
void type_analysis_visitor::visit(procedure_declaration *definition)
{
if (definition->body.has_value() && definition->heading().return_type.proper_type != nullptr)
{
for (statement *const statement : definition->body.value().body())
{
statement->accept(this);
}
if (!this->returns)
{
add_error<return_error>(definition->identifier.identifier, this->input_file, definition->position());
}
}
}
void type_analysis_visitor::visit(assign_statement *)
{
}
void type_analysis_visitor::visit(if_statement *)
{
}
void type_analysis_visitor::visit(import_declaration *)
{
}
void type_analysis_visitor::visit(while_statement *)
{
}
void type_analysis_visitor::visit(return_statement *)
{
this->returns = true;
}
void type_analysis_visitor::visit(defer_statement *)
{
}
void type_analysis_visitor::visit(case_statement *)
{
}
void type_analysis_visitor::visit(procedure_call *)
{
}
void type_analysis_visitor::visit(unit *unit)
{
for (procedure_declaration *const procedure : unit->procedures)
{
this->returns = false;
procedure->accept(this);
}
}
name_analysis_visitor::name_analysis_visitor(const char *path, symbol_bag bag)
: error_container(path), bag(bag)
{
@@ -484,87 +560,15 @@ namespace elna::boot
{
}
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 (import_declaration *const _import : unit->imports)
@@ -581,64 +585,4 @@ namespace elna::boot
}
}
}
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 *)
{
}
void declaration_visitor::visit(field_access_expression *)
{
}
void declaration_visitor::visit(dereference_expression *)
{
}
void declaration_visitor::visit(literal<std::int32_t> *)
{
}
void declaration_visitor::visit(literal<std::uint32_t> *)
{
}
void declaration_visitor::visit(literal<double> *)
{
}
void declaration_visitor::visit(literal<bool> *)
{
}
void declaration_visitor::visit(literal<unsigned char> *)
{
}
void declaration_visitor::visit(literal<std::nullptr_t> *)
{
}
void declaration_visitor::visit(literal<std::string> *)
{
}
}

View File

@@ -77,7 +77,7 @@ namespace elna::gcc
if (!VOID_TYPE_P(TREE_VALUE(current_parameter)))
{
error_at(call_location, "too few arguments, expected %i, got %lu",
error_at(call_location, "Too few arguments, expected %i, got %lu",
list_length(TYPE_ARG_TYPES(symbol_type)) - 1, arguments.size());
this->current_expression = error_mark_node;
}
@@ -1179,46 +1179,6 @@ namespace elna::gcc
this->current_expression = NULL_TREE;
}
void generic_visitor::visit(boot::named_type_expression *type)
{
this->current_expression = TREE_TYPE(this->symbols->lookup(type->name));
}
void generic_visitor::visit(boot::array_type_expression *)
{
gcc_unreachable();
}
void generic_visitor::visit(boot::pointer_type_expression *type)
{
type->base().accept(this);
if (this->current_expression != NULL_TREE && this->current_expression != error_mark_node)
{
this->current_expression = build_global_pointer_type(this->current_expression);
}
}
void generic_visitor::visit(boot::record_type_expression *)
{
gcc_unreachable();
}
void generic_visitor::visit(boot::union_type_expression *)
{
gcc_unreachable();
}
void generic_visitor::visit(boot::procedure_type_expression *)
{
gcc_unreachable();
}
void generic_visitor::visit(boot::enumeration_type_expression *)
{
gcc_unreachable();
}
void generic_visitor::visit(boot::defer_statement *statement)
{
enter_scope();

View File

@@ -74,7 +74,7 @@ static elna::boot::dependency elna_parse_file(dependency_state& state, const cha
fatal_error(UNKNOWN_LOCATION, "Cannot open filename %s: %m", filename);
}
linemap_add(line_table, LC_ENTER, 0, filename, 1);
elna::boot::dependency outcome = elna::boot::read_sources(entry_point, filename);
elna::boot::dependency outcome = elna::boot::read_source(entry_point, filename);
if (outcome.has_errors())
{
@@ -92,12 +92,11 @@ static elna::boot::dependency elna_parse_file(dependency_state& state, const cha
}
outcome_bag.add_import(state.cache.find(sub_path)->second);
}
elna::boot::name_analysis_visitor name_analysis_visitor(filename, outcome_bag);
outcome.tree->accept(&name_analysis_visitor);
elna::boot::error_list semantic_errors = analyze_semantics(filename, outcome.tree, outcome_bag);
if (name_analysis_visitor.has_errors())
if (!semantic_errors.empty())
{
elna::gcc::report_errors(name_analysis_visitor.errors());
elna::gcc::report_errors(semantic_errors);
}
state.cache.insert({ filename, outcome_bag });
elna::gcc::rewrite_symbol_table(module_table, state.custom);

View File

@@ -131,6 +131,53 @@ namespace elna::boot
virtual void visit(literal<std::string> *) = 0;
};
/**
* Abstract visitor that doesn't visit any nodes by default.
*/
class empty_visitor : public parser_visitor
{
[[noreturn]] void not_implemented();
public:
[[noreturn]] virtual void visit(named_type_expression *) override;
[[noreturn]] virtual void visit(array_type_expression *) override;
[[noreturn]] virtual void visit(pointer_type_expression *) override;
[[noreturn]] virtual void visit(program *) override;
[[noreturn]] virtual void visit(type_declaration *) override;
[[noreturn]] virtual void visit(record_type_expression *) override;
[[noreturn]] virtual void visit(union_type_expression *) override;
[[noreturn]] virtual void visit(procedure_type_expression *) override;
[[noreturn]] virtual void visit(enumeration_type_expression *) override;
[[noreturn]] virtual void visit(variable_declaration *) override;
[[noreturn]] virtual void visit(constant_declaration *) override;
[[noreturn]] virtual void visit(procedure_declaration *) override;
[[noreturn]] virtual void visit(assign_statement *) override;
[[noreturn]] virtual void visit(if_statement *) override;
[[noreturn]] virtual void visit(import_declaration *) override;
[[noreturn]] virtual void visit(while_statement *) override;
[[noreturn]] virtual void visit(return_statement *) override;
[[noreturn]] virtual void visit(defer_statement *) override;
[[noreturn]] virtual void visit(case_statement *) override;
[[noreturn]] virtual void visit(procedure_call *) override;
[[noreturn]] virtual void visit(unit *) override;
[[noreturn]] virtual void visit(cast_expression *) override;
[[noreturn]] virtual void visit(traits_expression *) override;
[[noreturn]] virtual void visit(binary_expression *) override;
[[noreturn]] virtual void visit(unary_expression *) override;
[[noreturn]] virtual void visit(variable_expression *) override;
[[noreturn]] virtual void visit(array_access_expression *) override;
[[noreturn]] virtual void visit(field_access_expression *) override;
[[noreturn]] virtual void visit(dereference_expression *) override;
[[noreturn]] virtual void visit(literal<std::int32_t> *) override;
[[noreturn]] virtual void visit(literal<std::uint32_t> *) override;
[[noreturn]] virtual void visit(literal<double> *) override;
[[noreturn]] virtual void visit(literal<bool> *) override;
[[noreturn]] virtual void visit(literal<unsigned char> *) override;
[[noreturn]] virtual void visit(literal<std::nullptr_t> *) override;
[[noreturn]] virtual void visit(literal<std::string> *) override;
};
/**
* AST node.
*/

View File

@@ -35,15 +35,16 @@ namespace elna::boot
explicit dependency(const char *path);
};
dependency read_sources(std::istream& entry_point, const char *entry_path);
dependency read_source(std::istream& entry_point, const char *entry_path);
std::filesystem::path build_path(const std::vector<std::string>& segments);
error_list analyze_semantics(const char *path, std::unique_ptr<unit>& tree, symbol_bag bag);
template<typename T>
struct dependency_state
{
const std::shared_ptr<symbol_table> globals;
T custom;
std::unordered_map<std::filesystem::path, elna::boot::symbol_bag> cache;
std::unordered_map<std::filesystem::path, symbol_bag> cache;
explicit dependency_state(T custom)
: globals(elna::boot::builtin_symbol_table()), custom(custom)

View File

@@ -69,6 +69,40 @@ namespace elna::boot
std::string what() const override;
};
class return_error : public error
{
const std::string identifier;
public:
return_error(const std::string& identifier, const char *path, const struct position position);
std::string what() const override;
};
/**
* Checks types.
*/
class type_analysis_visitor final : public empty_visitor, public error_container
{
bool returns;
public:
explicit type_analysis_visitor(const char *path);
void visit(program *program) override;
void visit(procedure_declaration *definition) 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;
};
/**
* Performs name analysis.
*/
@@ -128,51 +162,17 @@ namespace elna::boot
};
/**
* Collects global declarations.
* Collects global declarations without resolving any symbols.
*/
class declaration_visitor final : public parser_visitor, public error_container
class declaration_visitor final : public empty_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;
};
}

View File

@@ -33,7 +33,7 @@ along with GCC; see the file COPYING3. If not see
namespace elna::gcc
{
class generic_visitor final : public boot::parser_visitor
class generic_visitor final : public boot::empty_visitor
{
tree current_expression{ NULL_TREE };
elna::boot::symbol_bag bag;
@@ -91,13 +91,6 @@ namespace elna::gcc
void visit(boot::if_statement *statement) override;
void visit(boot::import_declaration *) override;
void visit(boot::while_statement *statement) override;
void visit(boot::named_type_expression *type) override;
void visit(boot::array_type_expression *) override;
void visit(boot::pointer_type_expression *type) override;
void visit(boot::record_type_expression *) override;
void visit(boot::union_type_expression *) override;
void visit(boot::procedure_type_expression *) override;
void visit(boot::enumeration_type_expression *) override;
void visit(boot::return_statement *statement) override;
void visit(boot::defer_statement *statement) override;
void visit(boot::case_statement *statement) override;

View File

@@ -1074,12 +1074,6 @@ begin
return return_code
end;
proc f();
var x: Char;
begin
x := '\x4'
end;
begin
exit(process(count, parameters))
end.