aboutsummaryrefslogtreecommitdiff
path: root/boot/evaluator.cc
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-08-28 02:39:42 +0200
committerEugen Wissner <belka@caraus.de>2026-08-28 02:39:42 +0200
commit8e655a0786aec5e0215e09f2a9629c6f32e34793 (patch)
tree0788634cf66fed9c1a1d264b5b8c30da49380559 /boot/evaluator.cc
parent4d4537866690a1ef3d882f5e9a6e01d8220a3650 (diff)
downloadelna-8e655a0786aec5e0215e09f2a9629c6f32e34793.tar.gz
Reject declarations shadowing imports
Diffstat (limited to 'boot/evaluator.cc')
-rw-r--r--boot/evaluator.cc75
1 files changed, 50 insertions, 25 deletions
diff --git a/boot/evaluator.cc b/boot/evaluator.cc
index 1d10346..6a9fb3b 100644
--- a/boot/evaluator.cc
+++ b/boot/evaluator.cc
@@ -51,7 +51,7 @@ namespace elna::boot
}, this->payload);
}
- std::optional<std::pair<std::string, source_position>> non_constant_expression_error::note() const
+ std::optional<diagnostic_note> non_constant_expression_error::note() const
{
if (std::holds_alternative<initializer>(this->payload))
{
@@ -297,25 +297,37 @@ namespace elna::boot
std::optional<constant_value> evaluator::evaluate_field_access(field_access_expression& subject)
{
- auto type_to_check = subject.base().type_decoration;
- if (type_to_check.empty())
+ // Accessing a member of an enumeration. The base is the type name,
+ // so the enumeration is looked up in the symbol table instead of
+ // reading the type decoration set by name analysis.
+ if (auto *base_designator = subject.base().is_designator())
{
- type_to_check = subject.type_decoration;
- }
- auto resolved_base = resolve_underlying_type(type_to_check);
- if (auto enumeration = resolved_base.get<enumeration_type>())
- {
- auto enumeration_distance = std::distance(enumeration->members.begin(),
- std::ranges::find(enumeration->members, subject.field().name()));
- const std::size_t enumeration_position = static_cast<std::size_t>(enumeration_distance);
-
- if (enumeration_position >= enumeration->members.size())
+ if (auto *base_name = base_designator->is_named())
{
- return std::nullopt;
+ auto symbol = this->bag.lookup(base_name->name);
+
+ if (symbol != nullptr)
+ {
+ if (auto type_symbol = symbol->is_type())
+ {
+ if (auto enumeration = resolve_underlying_type(type_symbol->symbol).get<enumeration_type>())
+ {
+ auto member_iterator = std::ranges::find(enumeration->members, subject.field().name());
+
+ if (member_iterator == enumeration->members.end())
+ {
+ return std::nullopt;
+ }
+ const std::size_t enumeration_position = static_cast<std::size_t>(
+ std::distance(enumeration->members.begin(), member_iterator));
+
+ return constant_value{ integer_literal::from(enumeration_position + 1U) };
+ }
+ }
+ }
}
- return constant_value{ integer_literal::from(enumeration_position + 1U) };
}
- else if (auto base = evaluate(subject.base()))
+ if (auto base = evaluate(subject.base()))
{
if (auto *record = std::get_if<constant_aggregate<ordered_map>>(&base.value()))
{
@@ -732,19 +744,32 @@ namespace elna::boot
{
auto value = evaluate(subject.value());
- if (!value.has_value() || subject.type_decoration.empty())
+ if (!value.has_value())
{
return std::nullopt;
}
- const type resolved = resolve_underlying_type(subject.type_decoration);
-
- if (is_primitive_type(resolved, "Int"))
- {
- return cast_to_int(value.value());
- }
- else if (is_primitive_type(resolved, "Word"))
+ // The target type is looked up in the symbol table instead of reading
+ // the type decoration set by name analysis.
+ if (auto *target = subject.target().is_named())
{
- return cast_to_word(value.value());
+ auto symbol = this->bag.lookup(target->name);
+
+ if (symbol != nullptr)
+ {
+ if (auto type_symbol = symbol->is_type())
+ {
+ const type resolved = resolve_underlying_type(type_symbol->symbol);
+
+ if (is_primitive_type(resolved, "Int"))
+ {
+ return cast_to_int(value.value());
+ }
+ else if (is_primitive_type(resolved, "Word"))
+ {
+ return cast_to_word(value.value());
+ }
+ }
+ }
}
return constant_value{ value.value() };