From 5cc2947143f2a6ebd4ef1ae4d25ab956b87de808 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Tue, 21 Jul 2026 21:27:03 +0200 Subject: Redefine strings as slice of constant characters --- boot/name_analysis.cc | 135 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 100 insertions(+), 35 deletions(-) (limited to 'boot/name_analysis.cc') 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 #include 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() != nullptr; + bool const is_record = resolved.get() != nullptr; + + if (is_enum || is_record) + { + std::string message = is_enum ? "Enumeration" : "Record"; + + if (auto alias = composite_type.get()) + { + 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 original, + std::optional 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() != nullptr; + std::string const kind = is_enum ? "member" : "field"; + std::string message = is_enum ? "Enumeration" : "Record"; + + if (auto alias = aggregate.get()) + { + 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> 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 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(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()) + else if (auto array = resolved_type.get()) { - 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(slice->base)); + return field.value(); } } - else if (auto primitive = resolved_type.get(); primitive != nullptr && primitive->identifier == "String") + else if (auto slice = resolved_type.get()) { - 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(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(proc->symbol)); - } - add_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 *literal) { - literal->type_decoration = lookup_primitive_type("String"); + literal->type_decoration = type(std::make_shared( + type(std::make_shared(lookup_primitive_type("Char"))))); } declaration_visitor::declaration_visitor() -- cgit v1.2.3