diff options
| author | Eugen Wissner <belka@caraus.de> | 2026-07-24 21:28:33 +0200 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2026-07-25 02:22:34 +0200 |
| commit | 1e0f89df48ba10cdde80bd623b84e20fb48b977d (patch) | |
| tree | 58f550342ff7ef42e506131b5c04a35ffdeb4a00 /boot | |
| parent | 6301c1f2f669b84a429e836888629873721e7219 (diff) | |
| download | elna-1e0f89df48ba10cdde80bd623b84e20fb48b977d.tar.gz | |
Accept any constant types in case labels
Diffstat (limited to 'boot')
| -rw-r--r-- | boot/evaluator.cc | 24 | ||||
| -rw-r--r-- | boot/name_analysis.cc | 21 | ||||
| -rw-r--r-- | boot/type_check.cc | 28 |
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: |
