aboutsummaryrefslogtreecommitdiff
path: root/boot/name_analysis.cc
diff options
context:
space:
mode:
Diffstat (limited to 'boot/name_analysis.cc')
-rw-r--r--boot/name_analysis.cc135
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()