diff options
Diffstat (limited to 'boot/name_analysis.cc')
| -rw-r--r-- | boot/name_analysis.cc | 135 |
1 files changed, 100 insertions, 35 deletions
diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc index a2cacb2..907f318 100644 --- a/boot/name_analysis.cc +++ b/boot/name_analysis.cc @@ -17,7 +17,6 @@ along with GCC; see the file COPYING3. If not see #include "elna/boot/name_analysis.h" -#include <algorithm> #include <utility> namespace elna::boot @@ -81,6 +80,84 @@ namespace elna::boot 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)) + { + } + + std::string field_not_found_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) + { + 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; + } + 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)) + { + } + + std::string duplicate_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"; + + if (auto alias = aggregate.get<alias_type>()) + { + message += " '" + alias->name + "'"; + } + message += " already has a " + kind + " named '" + member_name + "'"; + + if (base_name.has_value()) + { + message += " (defined in base type '" + *base_name + "')"; + } + return message; + } + + std::optional<std::pair<std::string, source_position>> duplicate_member_error::note() const + { + if (original.has_value() && original->start().available()) + { + return std::make_pair("previously declared here", *original); + } + return std::nullopt; + } + + unsupported_trait_type_error::unsupported_trait_type_error(const identifier& trait, + type actual) + : error(trait.position()), actual(std::move(actual)), trait_name(trait.name()) + { + } + + std::string unsupported_trait_type_error::what() const + { + return "Type '" + actual.to_string() + + "' does not support trait '#" + trait_name + "'"; + } + // Members of a constant aggregate are constant themselves. static type qualify_member_type(const type& element, const type& aggregate) { @@ -133,6 +210,20 @@ namespace elna::boot return result_type; } + std::optional<type> name_analysis_visitor::lookup_pointer_like_field( + const std::string& field_name, const type& element_type) + { + if (field_name == "length") + { + return lookup_primitive_type("Word"); + } + if (field_name == "ptr") + { + return type(std::make_shared<pointer_type>(element_type)); + } + return std::nullopt; + } + type name_analysis_visitor::lookup_primitive_type(const std::string& name) { return this->bag.lookup(name)->is_type()->symbol; @@ -156,26 +247,18 @@ namespace elna::boot return lookup_field(record->base, field_name); } } - else if (auto slice = resolved_type.get<slice_type>()) + else if (auto array = resolved_type.get<array_type>()) { - if (field_name == "length") - { - return lookup_primitive_type("Word"); - } - else if (field_name == "ptr") + if (auto field = lookup_pointer_like_field(field_name, array->base)) { - return type(std::make_shared<pointer_type>(slice->base)); + return field.value(); } } - else if (auto primitive = resolved_type.get<primitive_type>(); primitive != nullptr && primitive->identifier == "String") + else if (auto slice = resolved_type.get<slice_type>()) { - if (field_name == "length") + if (auto field = lookup_pointer_like_field(field_name, slice->base)) { - return lookup_primitive_type("Word"); - } - else if (field_name == "ptr") - { - return type(std::make_shared<pointer_type>(lookup_primitive_type("Char"))); + return field.value(); } } return type(); @@ -303,17 +386,6 @@ namespace elna::boot } else { - type actual; - - if (auto var = base_symbol->is_variable()) - { - actual = var->symbol; - } - else if (auto proc = base_symbol->is_procedure()) - { - actual = type(std::make_shared<procedure_type>(proc->symbol)); - } - add_error<base_type_error>(actual, expression->position()); this->current_type = type(); return; } @@ -513,10 +585,6 @@ for (const auto& member : expression->members) { call->type_decoration = procedure->return_type.proper_type; } - else if (call->callable().is_named() != nullptr) - { - call->type_decoration = this->current_type; - } for (expression *const argument : call->arguments) { argument->accept(this); @@ -653,10 +721,6 @@ for (const auto& member : expression->members) { expression->type_decoration = slice->base; } - else if (resolved_base == lookup_primitive_type("String")) - { - expression->type_decoration = lookup_primitive_type("Char"); - } // Elements of a constant array are constant themselves since a static // array is a holistic type. if (!expression->type_decoration.empty()) @@ -765,7 +829,8 @@ for (const auto& member : expression->members) void name_analysis_visitor::visit(literal<std::string> *literal) { - literal->type_decoration = lookup_primitive_type("String"); + literal->type_decoration = type(std::make_shared<slice_type>( + type(std::make_shared<constant_type>(lookup_primitive_type("Char"))))); } declaration_visitor::declaration_visitor() |
