aboutsummaryrefslogtreecommitdiff
path: root/boot/evaluator.cc
diff options
context:
space:
mode:
Diffstat (limited to 'boot/evaluator.cc')
-rw-r--r--boot/evaluator.cc54
1 files changed, 35 insertions, 19 deletions
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<T, enumeration_value>)
+ {
+ 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<std::size_t>(value)).cast_to(true, size);
+ }
+
std::optional<type_properties> 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::size_t>(
- 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<std::size_t>(enumeration_position)),
+ this->target.word_properties.front().size) };
}
}
}
@@ -897,21 +918,21 @@ namespace elna::boot
}
std::optional<constant_value> 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<constant_value> position = cast_to_integer(source_expression, false, target_size);
+ std::optional<constant_value> 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<integer_literal>(&position.value());
+ const auto *converted = std::get_if<integer_literal>(&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<constant_value> 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<enumeration_type>())
{
- return constant_value{
- integer_literal::from<std::size_t>(
- 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<enumeration_type>())
{
- return constant_value{
- integer_literal::from<std::size_t>(
- 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")