aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-09-27 11:23:17 +0200
committerEugen Wissner <belka@caraus.de>2026-09-27 11:23:17 +0200
commitc57a24b9fe37e233e7ec0e2e65405738d9c09c6e (patch)
tree99b5f4dc22d27d8159c3ba76f2cf3a455ed37fb6
parentd048b633dd02014f8bff1b512ce4d5ae2b8b7903 (diff)
downloadelna-c57a24b9fe37e233e7ec0e2e65405738d9c09c6e.tar.gz
Reuse container visiting logic
-rw-r--r--boot/ast.cc93
-rw-r--r--boot/materialization.cc20
-rw-r--r--boot/name_analysis.cc55
-rw-r--r--boot/type_check.cc25
-rw-r--r--boot/validation.cc27
-rw-r--r--gcc/gcc/elna-generic.cc15
-rw-r--r--include/elna/boot/ast.h33
-rw-r--r--include/elna/boot/materialization.h4
-rw-r--r--include/elna/boot/name_analysis.h6
-rw-r--r--include/elna/boot/type_check.h4
-rw-r--r--include/elna/boot/validation.h3
11 files changed, 112 insertions, 173 deletions
diff --git a/boot/ast.cc b/boot/ast.cc
index cd2ac55..87d6313 100644
--- a/boot/ast.cc
+++ b/boot/ast.cc
@@ -243,7 +243,11 @@ namespace elna::boot
}
if (declaration->body.has_value())
{
- traverse_body(this, declaration->body.value());
+ traverse_block(this, declaration->body.value());
+ if (declaration->body.value().return_expression != nullptr)
+ {
+ declaration->body.value().return_expression->accept(this);
+ }
}
}
@@ -253,66 +257,54 @@ namespace elna::boot
statement->rvalue().accept(this);
}
- void walking_visitor::traverse_block(block& body)
- {
- for (variable_declaration *const variable : body.variables)
- {
- variable->accept(this);
- }
- for (statement *const body_statement : body.statements)
- {
- body_statement->accept(this);
- }
- }
-
void walking_visitor::visit(if_statement *statement)
{
statement->branch().prerequisite().accept(this);
- traverse_block(statement->branch().body);
+ traverse_block(this, statement->branch().body);
for (conditional_statements& branch : statement->branches)
{
branch.prerequisite().accept(this);
- traverse_block(branch.body);
+ traverse_block(this, branch.body);
}
if (statement->alternative != nullptr)
{
- traverse_block(*statement->alternative);
+ traverse_block(this, *statement->alternative);
}
}
void walking_visitor::visit(while_statement *statement)
{
statement->branch().prerequisite().accept(this);
- traverse_block(statement->branch().body);
+ traverse_block(this, statement->branch().body);
for (conditional_statements& branch : statement->branches)
{
branch.prerequisite().accept(this);
- traverse_block(branch.body);
+ traverse_block(this, branch.body);
}
}
void walking_visitor::visit(repeat_statement *statement)
{
statement->condition().accept(this);
- traverse_block(statement->body);
+ traverse_block(this, statement->body);
}
void walking_visitor::visit(for_statement *statement)
{
statement->range().accept(this);
- traverse_block(statement->body);
+ traverse_block(this, statement->body);
}
void walking_visitor::visit(defer_statement *statement)
{
- traverse_block(statement->body);
+ traverse_block(this, statement->body);
}
void walking_visitor::visit(block_statement *statement)
{
- traverse_block(statement->body);
+ traverse_block(this, statement->body);
}
void walking_visitor::visit(break_statement *)
@@ -326,50 +318,30 @@ namespace elna::boot
void walking_visitor::visit(case_statement *statement)
{
statement->condition().accept(this);
- for (switch_case& case_block : statement->cases)
+ for (const switch_case& case_block : statement->cases)
{
- for (expression *case_label : case_block.labels)
- {
- case_label->accept(this);
- }
- traverse_block(case_block.body);
+ visit_all(this, case_block.labels);
+ traverse_block(this, case_block.body);
}
if (statement->alternative != nullptr)
{
- traverse_block(*statement->alternative);
+ traverse_block(this, *statement->alternative);
}
}
void walking_visitor::visit(procedure_call *call)
{
call->callable().accept(this);
- for (expression *argument : call->arguments)
- {
- argument->accept(this);
- }
+ visit_all(this, call->arguments);
}
void walking_visitor::visit(unit *unit)
{
- for (import_declaration *_import : unit->imports)
- {
- _import->accept(this);
- }
- for (declaration *const unit_declaration : unit->declarations)
- {
- unit_declaration->accept(this);
- }
+ visit_all(this, unit->imports);
+ visit_all(this, unit->declarations);
if (unit->entry_point.has_value())
{
- visit_entry_point(unit);
- }
- }
-
- void walking_visitor::visit_entry_point(unit *unit)
- {
- for (statement *body_statement : unit->entry_point.value())
- {
- body_statement->accept(this);
+ visit_all(this, unit->entry_point.value());
}
}
@@ -452,10 +424,7 @@ namespace elna::boot
void walking_visitor::visit(array_constructor_expression *expression)
{
- for (auto *element : expression->elements)
- {
- element->accept(this);
- }
+ visit_all(this, expression->elements);
}
void walking_visitor::visit(slicing_expression *expression)
@@ -1115,20 +1084,10 @@ namespace elna::boot
delete this->return_expression;
}
- void traverse_body(parser_visitor *visitor, const procedure_body& body)
+ void traverse_block(parser_visitor *visitor, const block& body)
{
- for (variable_declaration *variable : body.variables)
- {
- variable->accept(visitor);
- }
- for (statement *body_statement : body.statements)
- {
- body_statement->accept(visitor);
- }
- if (body.return_expression != nullptr)
- {
- body.return_expression->accept(visitor);
- }
+ visit_all(visitor, body.variables);
+ visit_all(visitor, body.statements);
}
unit::unit(const source_position position,
diff --git a/boot/materialization.cc b/boot/materialization.cc
index 0ca81aa..6eea0d1 100644
--- a/boot/materialization.cc
+++ b/boot/materialization.cc
@@ -48,6 +48,19 @@ namespace elna::boot
{
}
+ void materialization_visitor::visit(unit *unit)
+ {
+ visit_all(this, unit->imports);
+ visit_all(this, unit->declarations);
+
+ this->in_global_scope = false;
+ if (unit->entry_point.has_value())
+ {
+ visit_all(this, unit->entry_point.value());
+ }
+ this->in_global_scope = true;
+ }
+
void materialization_visitor::visit(procedure_declaration *declaration)
{
this->in_global_scope = false;
@@ -144,11 +157,4 @@ namespace elna::boot
materialization_error::kind::real_overflow);
}
}
-
- void materialization_visitor::visit_entry_point(unit *unit)
- {
- this->in_global_scope = false;
- walking_visitor::visit_entry_point(unit);
- this->in_global_scope = true;
- }
}
diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc
index 2ee3da1..20f08ee 100644
--- a/boot/name_analysis.cc
+++ b/boot/name_analysis.cc
@@ -284,10 +284,7 @@ namespace elna::boot
void forward_declaration_visitor::visit(unit *unit)
{
- for (auto *const unit_declaration: unit->declarations)
- {
- unit_declaration->accept(this);
- }
+ visit_all(this, unit->declarations);
}
void forward_declaration_visitor::visit(type_declaration *declaration)
@@ -733,22 +730,10 @@ namespace elna::boot
statement->rvalue().accept(this);
}
- void resolving_visitor::traverse_block(block& body)
- {
- for (variable_declaration *const variable : body.variables)
- {
- variable->accept(this);
- }
- for (statement *const body_statement : body.statements)
- {
- body_statement->accept(this);
- }
- }
-
void resolving_visitor::visit_block(block& body)
{
body.symbols = this->bag.enter();
- traverse_block(body);
+ traverse_block(this, body);
this->bag.leave();
}
@@ -813,7 +798,7 @@ namespace elna::boot
add_error<symbol_declaration_error>(statement->name.position(),
label_name, original_definition);
}
- traverse_block(statement->body);
+ traverse_block(this, statement->body);
this->bag.leave();
}
@@ -852,10 +837,7 @@ namespace elna::boot
statement->condition().accept(this);
for (switch_case& case_block : statement->cases)
{
- for (expression *case_label : case_block.labels)
- {
- case_label->accept(this);
- }
+ visit_all(this, case_block.labels);
visit_block(case_block.body);
}
if (statement->alternative != nullptr)
@@ -871,10 +853,7 @@ namespace elna::boot
{
call->type_decoration = procedure->return_type.proper_type;
}
- for (expression *const argument : call->arguments)
- {
- argument->accept(this);
- }
+ visit_all(this, call->arguments);
this->current_type = type();
}
@@ -918,11 +897,9 @@ namespace elna::boot
void resolving_visitor::visit(array_constructor_expression *expression)
{
- for (auto *const element : expression->elements)
- {
- element->accept(this);
- }
+ visit_all(this, expression->elements);
const type element_type = expression->elements.front()->type_decoration;
+
expression->type_decoration = type(std::make_shared<array_type>(element_type,
expression->elements.size()));
this->current_type = type();
@@ -1347,10 +1324,7 @@ namespace elna::boot
void declaration_visitor::visit(unit *unit)
{
- for (declaration *const unit_declaration : unit->declarations)
- {
- unit_declaration->accept(this);
- }
+ visit_all(this, unit->declarations);
if (unit->entry_point.has_value())
{
const type word8_primitive = lookup_primitive_type("Word8");
@@ -1540,10 +1514,7 @@ namespace elna::boot
const std::shared_ptr<procedure_info> info = this->bag.lookup("")->is_procedure();
this->bag.enter(info->scope);
- for (statement *body_statement : unit->entry_point.value())
- {
- body_statement->accept(this);
- }
+ visit_all(this, unit->entry_point.value());
this->bag.leave();
}
}
@@ -1590,7 +1561,11 @@ namespace elna::boot
declaration->body->symbols = info->scope;
this->bag.enter(info->scope);
- traverse_body(this, declaration->body.value());
+ traverse_block(this, declaration->body.value());
+ if (declaration->body.value().return_expression != nullptr)
+ {
+ declaration->body.value().return_expression->accept(this);
+ }
this->bag.leave();
}
}
@@ -1612,7 +1587,7 @@ namespace elna::boot
register_variable(statement->counter->name(), lookup_primitive_type("Word"),
statement->counter->position());
}
- traverse_block(statement->body);
+ traverse_block(this, statement->body);
this->bag.leave();
}
}
diff --git a/boot/type_check.cc b/boot/type_check.cc
index 71fd8ab..15a01dc 100644
--- a/boot/type_check.cc
+++ b/boot/type_check.cc
@@ -800,13 +800,19 @@ namespace elna::boot
}
}
- void type_analysis_visitor::visit_entry_point(unit *unit)
+ void type_analysis_visitor::visit(unit *unit)
{
- this->current_procedure = this->bag.lookup("")->is_procedure();
- this->bag.enter(this->current_procedure->scope);
- walking_visitor::visit_entry_point(unit);
- this->bag.leave();
- this->current_procedure.reset();
+ visit_all(this, unit->imports);
+ visit_all(this, unit->declarations);
+
+ if (unit->entry_point.has_value())
+ {
+ this->current_procedure = this->bag.lookup("")->is_procedure();
+ this->bag.enter(this->current_procedure->scope);
+ visit_all(this, unit->entry_point.value());
+ this->bag.leave();
+ this->current_procedure.reset();
+ }
}
void type_analysis_visitor::visit(variable_declaration *declaration)
@@ -885,7 +891,7 @@ namespace elna::boot
void type_analysis_visitor::traverse_block(block& body)
{
this->bag.enter(body.symbols);
- walking_visitor::traverse_block(body);
+ boot::traverse_block(this, body);
this->bag.leave();
}
@@ -1409,10 +1415,7 @@ namespace elna::boot
{
// Inference reads the argument types, so they are decorated
// before the parameter types they will be checked against exist.
- for (expression *const argument : call->arguments)
- {
- argument->accept(this);
- }
+ visit_all(this, call->arguments);
inferred = procedure;
callable_type = infer_call(*call, *reference, *procedure);
diff --git a/boot/validation.cc b/boot/validation.cc
index 0c9259e..4539633 100644
--- a/boot/validation.cc
+++ b/boot/validation.cc
@@ -41,34 +41,27 @@ namespace elna::boot
{
}
- void validation_visitor::visit_statements(const std::vector<statement *>& statements)
+ void validation_visitor::visit_statements(const std::vector<statement *>& statements,
+ const std::shared_ptr<symbol_table>& scope)
{
- for (statement *const body_statement : statements)
- {
- body_statement->accept(this);
- }
+ this->bag.enter(scope);
+ visit_all(this, statements);
+ this->bag.leave();
}
void validation_visitor::visit_block(const block& body)
{
- this->bag.enter(body.symbols);
- visit_statements(body.statements);
- this->bag.leave();
+ visit_statements(body.statements, body.symbols);
}
void validation_visitor::visit(unit *unit)
{
- for (declaration *unit_declaration : unit->declarations)
- {
- unit_declaration->accept(this);
- }
+ visit_all(this, unit->declarations);
if (unit->entry_point.has_value())
{
const std::shared_ptr<procedure_info> entry_point = this->bag.lookup("")->is_procedure();
- this->bag.enter(entry_point->scope);
- visit_statements(unit->entry_point.value());
- this->bag.leave();
+ visit_statements(unit->entry_point.value(), entry_point->scope);
}
}
@@ -87,9 +80,7 @@ namespace elna::boot
const std::shared_ptr<procedure_info> procedure =
this->bag.lookup(declaration->identifier.name())->is_procedure();
- this->bag.enter(procedure->scope);
- visit_statements(declaration->body.value().statements);
- this->bag.leave();
+ visit_statements(declaration->body.value().statements, procedure->scope);
}
}
diff --git a/gcc/gcc/elna-generic.cc b/gcc/gcc/elna-generic.cc
index 464124a..fcc4c64 100644
--- a/gcc/gcc/elna-generic.cc
+++ b/gcc/gcc/elna-generic.cc
@@ -342,10 +342,7 @@ namespace elna::gcc
void generic_visitor::visit(boot::unit *unit)
{
- for (boot::declaration *const unit_declaration : unit->declarations)
- {
- unit_declaration->accept(this);
- }
+ visit_all(this, unit->declarations);
if (unit->entry_point.has_value())
{
const std::shared_ptr<boot::procedure_info> entry_point = this->bag.lookup("")->is_procedure();
@@ -491,10 +488,7 @@ namespace elna::gcc
{
this->symbols->enter(IDENTIFIER_POINTER(DECL_NAME(argument_chain)), argument_chain);
}
- for (boot::variable_declaration *const variable : declaration->body.value().variables)
- {
- variable->accept(this);
- }
+ visit_all(this, declaration->body.value().variables);
visit_statements(declaration->body.value().statements);
if (declaration->body.value().return_expression != nullptr)
@@ -1165,10 +1159,7 @@ namespace elna::gcc
void generic_visitor::visit_block(boot::block& body)
{
this->bag.enter(body.symbols);
- for (boot::variable_declaration *const variable : body.variables)
- {
- variable->accept(this);
- }
+ visit_all(this, body.variables);
visit_statements(body.statements);
this->bag.leave();
}
diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h
index 6a3b9c9..82dde80 100644
--- a/include/elna/boot/ast.h
+++ b/include/elna/boot/ast.h
@@ -21,6 +21,8 @@ along with GCC; see the file COPYING3. If not see
#include <string>
#include <vector>
#include <optional>
+#include <concepts>
+#include <ranges>
#include "elna/boot/symbol.h"
#include "elna/boot/result.h"
@@ -321,12 +323,6 @@ namespace elna::boot
void visit(literal<std::uint32_t> *) override;
void visit(literal<std::nullptr_t> *) override;
void visit(literal<std::string> *) override;
-
- protected:
- /// Passes needing the entry point's scope override this.
- virtual void visit_entry_point(unit *unit);
- /// Passes needing the scope of a block override this.
- virtual void traverse_block(block& body);
};
/**
@@ -700,7 +696,30 @@ namespace elna::boot
procedure_body& operator=(procedure_body&& that) noexcept;
};
- void traverse_body(parser_visitor *visitor, const procedure_body& body);
+ /**
+ * Vistis all nodes in a container.
+ *
+ * \tparam R Container or range type.
+ * \param visitor Visitor.
+ * \param nodes Visited container.
+ */
+ template<std::ranges::input_range R>
+ requires std::derived_from<std::remove_pointer_t<std::ranges::range_value_t<R>>, node>
+ void visit_all(parser_visitor *visitor, R&& nodes)
+ {
+ for (auto *const node : nodes)
+ {
+ node->accept(visitor);
+ }
+ }
+
+ /**
+ * Visits the declarations and the statements of a block.
+ *
+ * \param visitor Visitor.
+ * \param nodes Visited block.
+ */
+ void traverse_block(parser_visitor *visitor, const block& body);
/**
* Procedure definition.
diff --git a/include/elna/boot/materialization.h b/include/elna/boot/materialization.h
index 63d6155..b239836 100644
--- a/include/elna/boot/materialization.h
+++ b/include/elna/boot/materialization.h
@@ -49,6 +49,7 @@ namespace elna::boot
public:
explicit materialization_visitor(const target_info& target);
+ void visit(unit *unit) override;
void visit(procedure_declaration *declaration) override;
void visit(variable_declaration *declaration) override;
@@ -56,8 +57,5 @@ namespace elna::boot
void visit(literal<integer_literal> *literal) override;
void visit(literal<float_literal> *literal) override;
-
- protected:
- void visit_entry_point(unit *unit) override;
};
}
diff --git a/include/elna/boot/name_analysis.h b/include/elna/boot/name_analysis.h
index 004aeae..c726a4f 100644
--- a/include/elna/boot/name_analysis.h
+++ b/include/elna/boot/name_analysis.h
@@ -298,11 +298,7 @@ namespace elna::boot
std::optional<type> lookup_pointer_like_field(const std::string& field_name,
const type& element_type);
type lookup_field(const type& composite_type, const std::string& field_name);
- /*
- * Visits the declarations and the statements of a block in the scope
- * the caller has opened for it.
- */
- void traverse_block(block& body);
+
/*
* Opens the scope of a block, remembers it on the block for the later
* passes and visits the block in it.
diff --git a/include/elna/boot/type_check.h b/include/elna/boot/type_check.h
index 620af74..5e4f792 100644
--- a/include/elna/boot/type_check.h
+++ b/include/elna/boot/type_check.h
@@ -305,12 +305,12 @@ namespace elna::boot
type promote_variadic_argument(const expression& argument);
protected:
- void visit_entry_point(unit *unit) override;
- void traverse_block(block& body) override;
+ void traverse_block(block& body);
public:
explicit type_analysis_visitor(symbol_bag bag, const target_info& target);
+ void visit(unit *unit) override;
void visit(procedure_declaration *declaration) override;
void visit(assign_statement *statement) override;
void visit(variable_declaration *declaration) override;
diff --git a/include/elna/boot/validation.h b/include/elna/boot/validation.h
index d3a22d1..2af68e0 100644
--- a/include/elna/boot/validation.h
+++ b/include/elna/boot/validation.h
@@ -48,7 +48,8 @@ namespace elna::boot
symbol_bag& bag;
evaluator constant_evaluator;
- void visit_statements(const std::vector<statement *>& statements);
+ void visit_statements(const std::vector<statement *>& statements,
+ const std::shared_ptr<symbol_table>& scope);
/// Visits the statements of a block in its own scope.
void visit_block(const block& body);