aboutsummaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-07-24 21:28:33 +0200
committerEugen Wissner <belka@caraus.de>2026-07-25 02:22:34 +0200
commit1e0f89df48ba10cdde80bd623b84e20fb48b977d (patch)
tree58f550342ff7ef42e506131b5c04a35ffdeb4a00 /boot
parent6301c1f2f669b84a429e836888629873721e7219 (diff)
downloadelna-1e0f89df48ba10cdde80bd623b84e20fb48b977d.tar.gz
Accept any constant types in case labels
Diffstat (limited to 'boot')
-rw-r--r--boot/evaluator.cc24
-rw-r--r--boot/name_analysis.cc21
-rw-r--r--boot/type_check.cc28
3 files changed, 44 insertions, 29 deletions
diff --git a/boot/evaluator.cc b/boot/evaluator.cc
index 4b37668..40a6533 100644
--- a/boot/evaluator.cc
+++ b/boot/evaluator.cc
@@ -61,25 +61,32 @@ namespace elna::boot
}
else if (auto *record_constructor = subject.is_record_constructor())
{
+ ordered_map<constant_value> aggregate;
+
for (const field_initializer& field_initializer : record_constructor->field_initializers)
{
- if (!evaluate(field_initializer.value()))
+ auto value = evaluate(field_initializer.value());
+ if (!value)
{
return std::nullopt;
}
+ aggregate.insert(field_initializer.name(), std::move(*value));
}
- return constant_value{ compound_constant{} };
+ return constant_value{ constant_aggregate<ordered_map>{ std::move(aggregate) } };
}
else if (auto *array_constructor = subject.is_array_constructor())
{
+ std::vector<constant_value> elements;
for (expression *element : array_constructor->elements)
{
- if (!evaluate(*element))
+ auto value = evaluate(*element);
+ if (!value)
{
return std::nullopt;
}
+ elements.push_back(std::move(*value));
}
- return constant_value{ compound_constant{} };
+ return constant_value{ constant_aggregate<std::vector>{ std::move(elements) } };
}
return std::nullopt;
}
@@ -171,7 +178,7 @@ namespace elna::boot
}
if (subject.operation() == unary_operator::logical_negation)
{
- return std::visit([](auto value) -> std::optional<constant_value> {
+ return std::visit([](const auto& value) -> std::optional<constant_value> {
using T = std::decay_t<decltype(value)>;
if constexpr (std::is_same_v<T, bool>)
@@ -183,7 +190,7 @@ namespace elna::boot
}
if (subject.operation() == unary_operator::bitwise_negation)
{
- return std::visit([](auto value) -> std::optional<constant_value> {
+ return std::visit([](const auto& value) -> std::optional<constant_value> {
using T = std::decay_t<decltype(value)>;
if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>)
@@ -240,10 +247,11 @@ namespace elna::boot
}
template<typename T>
- static std::optional<constant_value> evaluate_operation(binary_operator operation, T lhs, T rhs)
+ static std::optional<constant_value> evaluate_operation(binary_operator operation, const T& lhs, const T& rhs)
{
if constexpr (std::is_same_v<T, std::nullptr_t>
- || std::is_same_v<T, compound_constant>)
+ || std::is_same_v<T, constant_aggregate<ordered_map>>
+ || std::is_same_v<T, constant_aggregate<std::vector>>)
{
switch (operation)
{
diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc
index 1e224da..07f6d31 100644
--- a/boot/name_analysis.cc
+++ b/boot/name_analysis.cc
@@ -303,7 +303,7 @@ namespace elna::boot
* Collects field names from a record type recursively, base first.
*/
static void collect_field_names(const type& composite_type,
- std::map<std::string, field_origin>& names)
+ ordered_map<field_origin>& names)
{
auto record = resolve_underlying_type(composite_type).get<record_type>();
if (record == nullptr)
@@ -316,24 +316,25 @@ namespace elna::boot
}
for (auto& field : record->fields)
{
- names.insert({ field.first, field_origin{ .declaration = std::nullopt, .base_type = composite_type } });
+ names.insert(field.first, field_origin{ .declaration = std::nullopt, .base_type = composite_type });
}
}
- std::vector<type_field> name_analysis_visitor::build_composite_type(
+ ordered_map<type> name_analysis_visitor::build_composite_type(
const std::vector<field_declaration>& fields,
- std::map<std::string, field_origin>& field_names,
+ ordered_map<field_origin>& field_names,
const type& aggregate)
{
- std::vector<type_field> result;
+ ordered_map<type> result;
for (const auto& field : fields)
{
field.second->accept(this);
for (const auto& field_name : field.first)
{
- auto existing = field_names.find(field_name.name());
- if (existing != field_names.end())
+ auto [existing, inserted] = field_names.insert(field_name.name(),
+ field_origin{ .declaration = field.second->position(), .base_type = type() });
+ if (!inserted)
{
std::optional<std::string> base_name;
@@ -351,9 +352,7 @@ namespace elna::boot
}
else
{
- field_names.insert({ field_name.name(),
- field_origin{ .declaration = field.second->position(), .base_type = type() } });
- result.emplace_back(field_name.name(), this->current_type);
+ result.insert(field_name.name(), this->current_type);
}
}
}
@@ -394,7 +393,7 @@ namespace elna::boot
result_type = std::make_shared<record_type>();
}
- std::map<std::string, field_origin> field_names;
+ ordered_map<field_origin> field_names;
collect_field_names(result_type->base, field_names);
result_type->fields = build_composite_type(expression->fields, field_names, type(result_type));
diff --git a/boot/type_check.cc b/boot/type_check.cc
index 9bab537..c88a7d1 100644
--- a/boot/type_check.cc
+++ b/boot/type_check.cc
@@ -199,6 +199,18 @@ namespace elna::boot
return false;
}
+ bool type_analysis_visitor::is_equality_compatible(const type& left, const type& right)
+ {
+ auto resolved_left = resolve_underlying_type(left);
+ auto resolved_right = resolve_underlying_type(right);
+
+ return resolved_left == resolved_right
+ || (is_primitive_type(resolved_left, "Pointer") && is_any_pointer_type(resolved_right))
+ || (is_any_pointer_type(resolved_left) && is_primitive_type(resolved_right, "Pointer"))
+ || (resolved_left.get<slice_type>() && resolved_right.get<slice_type>())
+ || (resolved_left.get<record_type>() && resolved_right.get<record_type>());
+ }
+
bool type_analysis_visitor::check_unresolved_symbol(const std::shared_ptr<alias_type>& alias,
std::vector<std::string>& alias_path)
{
@@ -462,8 +474,7 @@ namespace elna::boot
auto variable_symbol = this->bag.lookup(variable_identifier.name())->is_variable();
if (!is_assignable_from(variable_symbol->symbol, declaration->initializer->type_decoration))
{
- add_error<type_mismatch_error>(
- declaration->initializer->position(),
+ add_error<type_mismatch_error>(declaration->initializer->position(),
variable_symbol->symbol, declaration->initializer->type_decoration);
}
}
@@ -478,10 +489,11 @@ namespace elna::boot
{
for (const expression *case_label : case_block.labels)
{
- if (!is_assignable_from(condition_type, case_label->type_decoration))
+ if (!is_equality_compatible(condition_type, case_label->type_decoration))
{
- add_error<type_mismatch_error>(
- case_label->position(), condition_type, case_label->type_decoration);
+ add_error<binary_operation_error>(
+ case_label->position(), condition_type,
+ case_label->type_decoration, binary_operator::equals);
}
}
}
@@ -836,11 +848,7 @@ namespace elna::boot
break;
case equals:
case not_equals:
- valid = lhs_resolved == rhs_resolved
- || (is_primitive_type(lhs_resolved, "Pointer") && is_any_pointer_type(rhs_resolved))
- || (is_any_pointer_type(lhs_resolved) && is_primitive_type(rhs_resolved, "Pointer"))
- || (lhs_resolved.get<slice_type>() && rhs_resolved.get<slice_type>())
- || (lhs_resolved.get<record_type>() && rhs_resolved.get<record_type>());
+ valid = is_equality_compatible(lhs_resolved, rhs_resolved);
break;
case shift_left:
case shift_right: