From 12e304fd56f054ba7296ab538eecd4280a67832a Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Wed, 7 Oct 2026 17:33:40 +0200 Subject: Allow assigning contants to enumeration members --- boot/evaluator.cc | 54 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 19 deletions(-) (limited to 'boot/evaluator.cc') diff --git a/boot/evaluator.cc b/boot/evaluator.cc index 67fc42a..18633ba 100644 --- a/boot/evaluator.cc +++ b/boot/evaluator.cc @@ -48,6 +48,10 @@ namespace elna::boot return "Array dimensions for type '" + payload.array_type.to_string() + "' should be constant"; } + else if constexpr (std::is_same_v) + { + return "Enumeration member value must be an integer constant expression"; + } }, this->payload); } @@ -63,6 +67,21 @@ namespace elna::boot } } + /** + * Builds the constant for an enumeration value. + * + * Goes through the bit pattern because \c integer_literal::from imports + * the magnitude of a negative value, not its two's complement. + * + * \param value Member value. + * \param size Size of the enumeration type in bytes. + * \return Signed constant of the given size. + */ + static integer_literal enumeration_constant(const std::ptrdiff_t value, const std::size_t size) + { + return integer_literal::from(static_cast(value)).cast_to(true, size); + } + std::optional get_type_properties(const type& subject, const target_info& target) { const type resolved = resolve_underlying_type(subject); @@ -330,10 +349,12 @@ namespace elna::boot { return std::nullopt; } - const std::size_t enumeration_position = static_cast( - std::distance(enumeration->members.begin(), member_iterator)); + const std::ptrdiff_t enumeration_position = + std::distance(enumeration->members.begin(), member_iterator); - return constant_value{ integer_literal::from(enumeration_position + 1U) }; + return constant_value{ enumeration_constant( + enumeration->values.at(static_cast(enumeration_position)), + this->target.word_properties.front().size) }; } } } @@ -897,21 +918,21 @@ namespace elna::boot } std::optional evaluator::cast_to_enumeration(const constant_value& source_expression, - const std::size_t member_count, const std::size_t target_size) + const enumeration_type& enumeration, const std::size_t target_size) { - std::optional position = cast_to_integer(source_expression, false, target_size); + std::optional value = cast_to_integer(source_expression, true, target_size); - if (!position.has_value()) + if (!value.has_value()) { return std::nullopt; } - const auto *converted = std::get_if(&position.value()); + const auto *converted = std::get_if(&value.value()); - if (converted == nullptr || *converted < std::size_t{ 1 } || *converted > member_count) + if (converted == nullptr || *converted < enumeration.minimum() || *converted > enumeration.maximum()) { return std::nullopt; } - return position; + return value; } std::optional evaluator::cast_to_pointer(const constant_value& source_expression) @@ -952,7 +973,7 @@ namespace elna::boot { return std::nullopt; } - return cast_to_enumeration(value.value(), enumeration->members.size(), properties->size); + return cast_to_enumeration(value.value(), *enumeration, properties->size); } if (is_integral_type(target_type)) { @@ -1055,10 +1076,8 @@ namespace elna::boot } if (const auto enumeration = resolved.get()) { - return constant_value{ - integer_literal::from( - this->target.word_properties.front().size, 1U).value() - }; + return constant_value{ enumeration_constant(enumeration->minimum(), + this->target.word_properties.front().size) }; } } else if (subject.name.name() == "max") @@ -1104,11 +1123,8 @@ namespace elna::boot } if (const auto enumeration = resolved.get()) { - return constant_value{ - integer_literal::from( - this->target.word_properties.front().size, - enumeration->members.size()).value() - }; + return constant_value{ enumeration_constant(enumeration->maximum(), + this->target.word_properties.front().size) }; } } else if (subject.name.name() == "offset") -- cgit v1.2.3