aboutsummaryrefslogtreecommitdiff
path: root/boot/name_analysis.cc
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-07-23 01:01:03 +0200
committerEugen Wissner <belka@caraus.de>2026-07-23 01:01:03 +0200
commit275fa4bff6d153019b6914fed7127a7d919ca177 (patch)
tree37f8ef0d49c304fe0fde47ce7d4b3ea32ffce707 /boot/name_analysis.cc
parentbd9fe800349dc139cc5841980bcae96e0d18e2db (diff)
downloadelna-275fa4bff6d153019b6914fed7127a7d919ca177.tar.gz
Implement for loop
Diffstat (limited to 'boot/name_analysis.cc')
-rw-r--r--boot/name_analysis.cc259
1 files changed, 143 insertions, 116 deletions
diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc
index 907f318..f932a5d 100644
--- a/boot/name_analysis.cc
+++ b/boot/name_analysis.cc
@@ -21,127 +21,120 @@ along with GCC; see the file COPYING3. If not see
namespace elna::boot
{
- declaration_error::declaration_error(const kind error_kind,
- const boot::identifier& identifier)
- : error(identifier.position()), identifier(identifier.name()), error_kind(error_kind)
+ symbol_error::symbol_error(const source_position position, payload_type payload)
+ : error(position), payload(std::move(payload))
{
}
- std::string declaration_error::what() const
+ std::string symbol_error::what() const
{
- switch (this->error_kind)
- {
- case kind::undeclared:
- return "Type '" + identifier + "' not declared";
- case kind::local_export:
- return "Local symbol '" + this->identifier + "' cannot be exported";
- default:
- __builtin_unreachable();
- }
- }
-
- redefinition_error::redefinition_error(const boot::identifier& identifier,
- std::optional<source_position> original)
- : error(identifier.position()), identifier(identifier.name()), original(original)
- {
- }
-
- std::string redefinition_error::what() const
- {
- return "Symbol '" + identifier + "' has been already defined";
+ return std::visit([](const auto& pay) -> std::string {
+ using T = std::decay_t<decltype(pay)>;
+ if constexpr (std::is_same_v<T, undeclared>)
+ {
+ return "Type '" + pay.name + "' not declared";
+ }
+ else if constexpr (std::is_same_v<T, local_export>)
+ {
+ return "Local symbol '" + pay.name + "' cannot be exported";
+ }
+ else if constexpr (std::is_same_v<T, redefinition>)
+ {
+ return "Symbol '" + pay.name + "' has been already defined";
+ }
+ }, payload);
}
- std::optional<std::pair<std::string, source_position>> redefinition_error::note() const
+ std::optional<std::pair<std::string, source_position>> symbol_error::note() const
{
- if (original.has_value() && original->start().available())
+ if (const auto *redef = std::get_if<redefinition>(&payload))
{
- return std::make_pair("previously declared here", *original);
+ if (redef->original.has_value() && redef->original->start().available())
+ {
+ return std::make_pair("previously declared here", *redef->original);
+ }
}
return std::nullopt;
}
- const_array_error::const_array_error(const source_position position)
- : error(position)
- {
- }
-
- std::string const_array_error::what() const
- {
- return "const must be written before the array size, not after";
- }
-
- double_const_error::double_const_error(const source_position position)
- : error(position)
- {
- }
-
- std::string double_const_error::what() const
- {
- return "Duplicate 'const' qualifier is not allowed";
- }
-
- field_not_found_error::field_not_found_error(const identifier& field_name,
- type composite_type)
- : error(field_name.position()), field_name(field_name.name()), composite_type(std::move(composite_type))
+ const_qualifier_error::const_qualifier_error(const source_position position, kind error_kind)
+ : error(position), error_kind(error_kind)
{
}
- std::string field_not_found_error::what() const
+ std::string const_qualifier_error::what() const
{
- type const resolved = resolve_underlying_type(composite_type);
- bool const is_enum = resolved.get<enumeration_type>() != nullptr;
- bool const is_record = resolved.get<record_type>() != nullptr;
-
- if (is_enum || is_record)
+ switch (error_kind)
{
- std::string message = is_enum ? "Enumeration" : "Record";
-
- if (auto alias = composite_type.get<alias_type>())
- {
- message += " '" + alias->name + "'";
- }
- message += " does not have a ";
- message += is_enum ? "member" : "field";
- message += " named '" + field_name + "'";
- return message;
+ case kind::array_position:
+ return "const must be written before the array size, not after";
+ case kind::duplicate:
+ return "Duplicate 'const' qualifier is not allowed";
+ default:
+ __builtin_unreachable();
}
- return "Type '" + composite_type.to_string()
- + "' does not have a field named '" + field_name + "'";
}
- duplicate_member_error::duplicate_member_error(const boot::identifier& member_name,
- type aggregate, std::optional<source_position> original,
- std::optional<std::string> base_name)
- : error(member_name.position()), member_name(member_name.name()), aggregate(std::move(aggregate)),
- original(original), base_name(std::move(base_name))
+ member_error::member_error(const source_position position, payload_type payload)
+ : error(position), payload(std::move(payload))
{
}
- std::string duplicate_member_error::what() const
+ std::string member_error::what() const
{
- type const resolved = resolve_underlying_type(aggregate);
- bool const is_enum = resolved.get<enumeration_type>() != nullptr;
- std::string const kind = is_enum ? "member" : "field";
- std::string message = is_enum ? "Enumeration" : "Record";
+ return std::visit([](const auto& pay) -> std::string {
+ using T = std::decay_t<decltype(pay)>;
+ if constexpr (std::is_same_v<T, not_found>)
+ {
+ const type resolved = resolve_underlying_type(pay.composite);
+ const bool is_enum = resolved.get<enumeration_type>() != nullptr;
+ const bool is_record = resolved.get<record_type>() != nullptr;
- if (auto alias = aggregate.get<alias_type>())
- {
- message += " '" + alias->name + "'";
- }
- message += " already has a " + kind + " named '" + member_name + "'";
+ if (is_enum || is_record)
+ {
+ std::string message = is_enum ? "Enumeration" : "Record";
+ if (auto alias = pay.composite.template get<alias_type>())
+ {
+ message += " '" + alias->name + "'";
+ }
+ message += " does not have a ";
+ message += is_enum ? "member" : "field";
+ message += " named '" + pay.name + "'";
+ return message;
+ }
+ return "Type '" + pay.composite.to_string()
+ + "' does not have a field named '" + pay.name + "'";
+ }
+ else if constexpr (std::is_same_v<T, duplicate>)
+ {
+ const type resolved = resolve_underlying_type(pay.aggregate);
+ const bool is_enum = resolved.get<enumeration_type>() != nullptr;
+ const std::string kind = is_enum ? "member" : "field";
+ std::string message = is_enum ? "Enumeration" : "Record";
- if (base_name.has_value())
- {
- message += " (defined in base type '" + *base_name + "')";
- }
- return message;
+ if (auto alias = pay.aggregate.template get<alias_type>())
+ {
+ message += " '" + alias->name + "'";
+ }
+ message += " already has a " + kind + " named '" + pay.name + "'";
+
+ if (pay.base.has_value())
+ {
+ message += " (defined in base type '" + *pay.base + "')";
+ }
+ return message;
+ }
+ }, payload);
}
- std::optional<std::pair<std::string, source_position>> duplicate_member_error::note() const
+ std::optional<std::pair<std::string, source_position>> member_error::note() const
{
- if (original.has_value() && original->start().available())
+ if (const auto *dup = std::get_if<duplicate>(&payload))
{
- return std::make_pair("previously declared here", *original);
+ if (dup->original.has_value() && dup->original->start().available())
+ {
+ return std::make_pair("previously declared here", *dup->original);
+ }
}
return std::nullopt;
}
@@ -231,7 +224,7 @@ namespace elna::boot
type name_analysis_visitor::lookup_field(const type& composite_type, const std::string& field_name)
{
- type const resolved_type = resolve_underlying_type(composite_type);
+ const type resolved_type = resolve_underlying_type(composite_type);
if (auto record = resolved_type.get<record_type>())
{
@@ -287,7 +280,8 @@ namespace elna::boot
if (this->current_type.get<constant_type>() != nullptr)
{
- add_error<double_const_error>(expression->position());
+ add_error<const_qualifier_error>(expression->position(),
+ const_qualifier_error::kind::duplicate);
}
this->current_type = type(std::make_shared<constant_type>(this->current_type));
}
@@ -298,7 +292,8 @@ namespace elna::boot
if (this->current_type.get<constant_type>() != nullptr)
{
- add_error<const_array_error>(expression->position());
+ add_error<const_qualifier_error>(expression->position(),
+ const_qualifier_error::kind::array_position);
}
this->current_type = type(std::make_shared<array_type>(this->current_type, expression->size));
}
@@ -355,8 +350,9 @@ namespace elna::boot
base_name = alias->name;
}
}
- add_error<duplicate_member_error>(field_name, aggregate,
- existing->second.declaration, base_name);
+ add_error<member_error>(field_name.position(),
+ member_error::duplicate{.name = field_name.name(), .aggregate = aggregate,
+ .original = existing->second.declaration, .base = base_name});
}
else
{
@@ -392,8 +388,8 @@ namespace elna::boot
}
else
{
- add_error<declaration_error>(declaration_error::kind::undeclared,
- expression->base.value());
+ add_error<symbol_error>(expression->base.value().position(),
+ symbol_error::undeclared{.name = expression->base.value().name()});
this->current_type = type();
return;
}
@@ -421,8 +417,8 @@ namespace elna::boot
}
else
{
- add_error<declaration_error>(declaration_error::kind::undeclared,
- expression->type_name);
+ add_error<symbol_error>(expression->type_name.position(),
+ symbol_error::undeclared{.name = expression->type_name.name()});
}
for (const field_initializer& initializer : expression->field_initializers)
{
@@ -430,8 +426,8 @@ namespace elna::boot
if (!expression->type_decoration.empty()
&& lookup_field(expression->type_decoration, initializer.name()).empty())
{
- add_error<declaration_error>(declaration_error::kind::undeclared,
- initializer.id());
+ add_error<symbol_error>(initializer.id().position(),
+ symbol_error::undeclared{.name = initializer.id().name()});
}
}
}
@@ -485,14 +481,16 @@ for (const auto& member : expression->members)
std::shared_ptr<enumeration_type> const result_type = std::make_shared<enumeration_type>(
member_names);
std::map<std::string, source_position> seen;
- type const aggregate(result_type);
+ const type aggregate(result_type);
for (const auto& member : expression->members)
{
auto existing = seen.find(member.name());
if (existing != seen.end())
{
- add_error<duplicate_member_error>(member, aggregate, existing->second);
+ add_error<member_error>(member.position(),
+ member_error::duplicate{.name = member.name(), .aggregate = aggregate,
+ .original = existing->second, .base = std::nullopt});
}
else
{
@@ -511,8 +509,8 @@ for (const auto& member : expression->members)
if (!this->bag.enter(name, variable_symbol))
{
auto original = this->bag.lookup(name);
- add_error<redefinition_error>(boot::identifier(name, position),
- original->position);
+ add_error<symbol_error>(position,
+ symbol_error::redefinition{.name = name, .original = original->position});
}
return variable_symbol;
}
@@ -642,7 +640,7 @@ for (const auto& member : expression->members)
if (!trait->type_decoration.empty())
{
- type const resolved = resolve_underlying_type(trait->type_decoration);
+ const type resolved = resolve_underlying_type(trait->type_decoration);
if (resolved.get<enumeration_type>() == nullptr
&& !is_primitive_type(resolved, "Float")
@@ -656,8 +654,8 @@ for (const auto& member : expression->members)
}
else
{
- add_error<declaration_error>(declaration_error::kind::undeclared,
- trait->name);
+ add_error<symbol_error>(trait->name.position(),
+ symbol_error::undeclared{.name = trait->name.name()});
}
}
@@ -742,7 +740,9 @@ for (const auto& member : expression->members)
}
if (expression->type_decoration.empty())
{
- add_error<field_not_found_error>(expression->field(), expression->base().type_decoration);
+ add_error<member_error>(expression->field().position(),
+ member_error::not_found{.name = expression->field().name(),
+ .composite = expression->base().type_decoration});
}
else
{
@@ -761,6 +761,27 @@ for (const auto& member : expression->members)
}
}
+ void name_analysis_visitor::visit(for_statement *statement)
+ {
+ statement->initial_value().accept(this);
+ const type control_variable_type = type(std::make_shared<constant_type>(this->current_type));
+ auto initial_value_info = std::make_shared<variable_info>(control_variable_type, false);
+
+ statement->final_value().accept(this);
+ if (statement->step != nullptr)
+ {
+ statement->step->accept(this);
+ }
+ statement->symbols = this->bag.enter();
+
+ this->bag.enter(statement->control_variable.name(), initial_value_info);
+ for (auto *body_statement : statement->body)
+ {
+ body_statement->accept(this);
+ }
+ this->bag.leave();
+ }
+
void name_analysis_visitor::visit(cast_expression *expression)
{
walking_visitor::visit(expression);
@@ -792,29 +813,33 @@ for (const auto& member : expression->members)
}
else
{
- add_error<declaration_error>(declaration_error::kind::undeclared,
- boot::identifier(expression->name, expression->position()));
+ add_error<symbol_error>(expression->position(),
+ symbol_error::undeclared{.name = expression->name});
}
}
void name_analysis_visitor::visit(literal<std::int32_t> *literal)
{
literal->type_decoration = lookup_primitive_type("Int");
+ this->current_type = literal->type_decoration;
}
void name_analysis_visitor::visit(literal<std::uint32_t> *literal)
{
literal->type_decoration = lookup_primitive_type("Word");
+ this->current_type = literal->type_decoration;
}
void name_analysis_visitor::visit(literal<double> *literal)
{
literal->type_decoration = lookup_primitive_type("Float");
+ this->current_type = literal->type_decoration;
}
void name_analysis_visitor::visit(literal<bool> *literal)
{
literal->type_decoration = lookup_primitive_type("Bool");
+ this->current_type = literal->type_decoration;
}
void name_analysis_visitor::visit(literal<unsigned char> *literal)
@@ -831,6 +856,7 @@ for (const auto& member : expression->members)
{
literal->type_decoration = type(std::make_shared<slice_type>(
type(std::make_shared<constant_type>(lookup_primitive_type("Char")))));
+ this->current_type = literal->type_decoration;
}
declaration_visitor::declaration_visitor()
@@ -864,8 +890,9 @@ for (const auto& member : expression->members)
if (!this->unresolved.insert({ type_identifier, std::make_shared<alias_type>(type_identifier) }).second)
{
- add_error<redefinition_error>(declaration->identifier.id(),
- declaration->position());
+ add_error<symbol_error>(declaration->identifier.id().position(),
+ symbol_error::redefinition{.name = declaration->identifier.id().name(),
+ .original = declaration->position()});
}
}
@@ -887,8 +914,8 @@ for (const auto& member : expression->members)
{
if (variable_identifier.exported())
{
- add_error<declaration_error>(declaration_error::kind::local_export,
- variable_identifier.id());
+ add_error<symbol_error>(variable_identifier.id().position(),
+ symbol_error::local_export{.name = variable_identifier.id().name()});
}
}
}