diff options
| author | Eugen Wissner <belka@caraus.de> | 2026-08-02 00:45:05 +0200 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2026-08-02 00:45:05 +0200 |
| commit | c07c43bf911f62ad6363c024b3f81ceb4f95b16c (patch) | |
| tree | d536b942ecede49741c090e61337947a26fbe030 /boot | |
| parent | e9cd3e5d0157f145dc0c3fea59f434fdd5ae55c6 (diff) | |
| download | elna-c07c43bf911f62ad6363c024b3f81ceb4f95b16c.tar.gz | |
Report field access errors
Diffstat (limited to 'boot')
| -rw-r--r-- | boot/evaluator.cc | 42 | ||||
| -rw-r--r-- | boot/name_analysis.cc | 115 |
2 files changed, 100 insertions, 57 deletions
diff --git a/boot/evaluator.cc b/boot/evaluator.cc index afa72db..097b6a5 100644 --- a/boot/evaluator.cc +++ b/boot/evaluator.cc @@ -283,32 +283,29 @@ namespace elna::boot auto resolved_base = resolve_underlying_type(type_to_check); if (auto enumeration = resolved_base.get<enumeration_type>()) { - auto member_iterator = std::ranges::find(enumeration->members, subject.field().name()); - if (member_iterator != enumeration->members.end()) - { - auto enumeration_position = std::distance(enumeration->members.begin(), member_iterator) + 1; - return constant_value{ - integer_literal::from(static_cast<std::size_t>(enumeration_position)) - }; - } - return std::nullopt; - } - auto base = evaluate(subject.base()); - if (!base.has_value()) - { - return std::nullopt; + auto enumeration_position = std::distance(enumeration->members.begin(), + std::ranges::find(enumeration->members, subject.field().name())); + + return constant_value{ + integer_literal::from(static_cast<std::size_t>(enumeration_position + 1)) + }; } - auto *record = std::get_if<constant_aggregate<ordered_map>>(&base.value()); - if (record == nullptr) + else if (auto base = evaluate(subject.base())) { - return std::nullopt; + if (auto *record = std::get_if<constant_aggregate<ordered_map>>(&base.value())) + { + return (**record)[subject.field().name()]; + } + else if (auto *string_value = std::get_if<std::string>(&base.value()); subject.field() == "length") + { + return constant_value{ integer_literal::from(string_value->size()) }; + } } - auto pos = (*record)->find(subject.field().name()); - if (pos == (*record)->end()) + else if (auto array = resolved_base.get<array_type>(); subject.field() == "length") { - return std::nullopt; + return constant_value{ integer_literal::from(array->size) }; } - return pos->second; + return std::nullopt; } std::optional<std::size_t> evaluator::evaluate_index(expression& subject) @@ -411,8 +408,9 @@ namespace elna::boot return operand; case negation: case reference: - return std::nullopt; + break; } + return std::nullopt; } template<typename T> diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc index 7ced7ea..e4f1920 100644 --- a/boot/name_analysis.cc +++ b/boot/name_analysis.cc @@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see #include <map> #include <utility> +#include <algorithm> namespace elna::boot { @@ -96,26 +97,35 @@ namespace elna::boot return std::visit([this](const auto& payload) -> std::string { using T = std::decay_t<decltype(payload)>; - if constexpr (std::is_same_v<T, not_found>) + if constexpr (std::is_same_v<T, kind>) { const type resolved = resolve_underlying_type(this->composite); const bool is_enum = resolved.get<enumeration_type>() != nullptr; const bool is_record = resolved.get<record_type>() != nullptr; - if (is_enum || is_record) + switch (payload) { - std::string message = is_enum ? "Enumeration" : "Record"; - if (auto alias = this->composite.get<alias_type>()) - { - message += " '" + alias->name + "'"; - } - message += " does not have a "; - message += is_enum ? "member" : "field"; - message += " named '" + this->name + "'"; - return message; + using enum kind; + case not_found: + if (is_enum || is_record) + { + std::string message = is_enum ? "Enumeration" : "Record"; + if (auto alias = this->composite.get<alias_type>()) + { + message += " '" + alias->name + "'"; + } + message += " does not have a "; + message += is_enum ? "member" : "field"; + message += " named '" + this->name + "'"; + return message; + } + return "Type '" + this->composite.to_string() + + "' does not have a field named '" + this->name + "'"; + case field_on_type: + return "Cannot access field '" + this->name + "' on type '" + + this->composite.to_string() + "'"; + break; } - return "Type '" + this->composite.to_string() - + "' does not have a field named '" + this->name + "'"; } else if constexpr (std::is_same_v<T, duplicate>) { @@ -417,9 +427,10 @@ namespace elna::boot && lookup_field(expression->type_decoration, initializer.name()).empty()) { add_error<member_error>(initializer.id().position(), initializer.id().name(), - expression->type_decoration, member_error::not_found{}); + expression->type_decoration, member_error::kind::not_found); } } + this->current_type = type(); } void name_analysis_visitor::visit(array_constructor_expression *expression) @@ -431,6 +442,7 @@ namespace elna::boot element->accept(this); } expression->type_decoration = type(std::make_shared<array_type>(element_type, expression->size)); + this->current_type = type(); } void name_analysis_visitor::visit(slicing_expression *expression) @@ -450,6 +462,7 @@ namespace elna::boot { expression->type_decoration = type(slice); } + this->current_type = type(); } void name_analysis_visitor::visit(procedure_type_expression *expression) @@ -576,6 +589,7 @@ namespace elna::boot { argument->accept(this); } + this->current_type = type(); } void name_analysis_visitor::visit(unit *unit) @@ -632,6 +646,7 @@ namespace elna::boot add_error<declaration_error>(trait->name.position(), trait->name.name(), declaration_error::kind::undeclared_trait); } + this->current_type = type(); } void name_analysis_visitor::visit(binary_expression *expression) @@ -640,7 +655,7 @@ namespace elna::boot switch (expression->operation()) { - using enum binary_operator; + using enum binary_operator; case equals: case not_equals: case less: @@ -664,6 +679,7 @@ namespace elna::boot expression->type_decoration = expression->lhs().type_decoration; break; } + this->current_type = type(); } void name_analysis_visitor::visit(unary_expression *expression) @@ -672,13 +688,14 @@ namespace elna::boot if (expression->operation() == unary_operator::reference) { - expression->type_decoration = this->current_type - = type(std::make_shared<pointer_type>(expression->operand().type_decoration)); + expression->type_decoration = type( + std::make_shared<pointer_type>(expression->operand().type_decoration)); } else { expression->type_decoration = expression->operand().type_decoration; } + this->current_type = type(); } void name_analysis_visitor::visit(array_access_expression *expression) @@ -695,28 +712,53 @@ namespace elna::boot expression->type_decoration = qualify_member_type(expression->type_decoration, expression->base().type_decoration); } + this->current_type = type(); } void name_analysis_visitor::visit(field_access_expression *expression) { walking_visitor::visit(expression); - expression->type_decoration = lookup_field(expression->base().type_decoration, expression->field().name()); - auto *is_designator = expression->base().is_designator(); - if (expression->type_decoration.empty() && is_designator != nullptr && is_designator->is_named() != nullptr) - { - expression->type_decoration = this->current_type; - } - if (expression->type_decoration.empty()) + // Handling field access on a type (only valid for enumerations). + if (!this->current_type.empty()) { - add_error<member_error>(expression->field().position(), - expression->field().name(), expression->base().type_decoration, - member_error::not_found{}); + auto resolved_base = resolve_underlying_type(this->current_type); + + if (auto enumeration_base = resolved_base.get<enumeration_type>()) + { + auto member_iterator = std::ranges::find(enumeration_base->members, expression->field().name()); + + if (member_iterator == enumeration_base->members.cend()) + { + add_error<member_error>(expression->field().position(), expression->field().name(), + this->current_type, member_error::kind::not_found); + } + else + { + expression->type_decoration = this->current_type; + } + } + else + { + add_error<member_error>(expression->field().position(), expression->field().name(), + this->current_type, member_error::kind::field_on_type); + } } - else + else // Handling field access on a value. { - expression->type_decoration = qualify_member_type(expression->type_decoration, - expression->base().type_decoration); + expression->type_decoration = lookup_field(expression->base().type_decoration, + expression->field().name()); + + if (expression->type_decoration.empty()) + { + add_error<member_error>(expression->field().position(), expression->field().name(), + expression->base().type_decoration, member_error::kind::not_found); + } + else + { + expression->type_decoration = qualify_member_type(expression->type_decoration, + expression->base().type_decoration); + } } } @@ -728,6 +770,7 @@ namespace elna::boot { expression->type_decoration = pointer->base; } + this->current_type = type(); } void name_analysis_visitor::visit(for_statement *statement) @@ -757,6 +800,7 @@ namespace elna::boot { walking_visitor::visit(expression); expression->type_decoration = this->current_type; + this->current_type = type(); } void name_analysis_visitor::visit(named_expression *expression) @@ -799,40 +843,41 @@ namespace elna::boot { literal->type_decoration = lookup_primitive_type("Word"); } - this->current_type = literal->type_decoration; + this->current_type = type(); } void name_analysis_visitor::visit(literal<double> *literal) { literal->type_decoration = lookup_primitive_type("Float"); - this->current_type = literal->type_decoration; + this->current_type = type(); } void name_analysis_visitor::visit(literal<bool> *literal) { literal->type_decoration = lookup_primitive_type("Bool"); - this->current_type = literal->type_decoration; + this->current_type = type(); } void name_analysis_visitor::visit(literal<unsigned char> *literal) { literal->type_decoration = lookup_primitive_type("Char"); + this->current_type = type(); } void name_analysis_visitor::visit(literal<std::nullptr_t> *literal) { literal->type_decoration = lookup_primitive_type("Pointer"); + this->current_type = type(); } void name_analysis_visitor::visit(literal<std::string> *literal) { 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; + this->current_type = type(); } declaration_visitor::declaration_visitor() - { } |
