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