aboutsummaryrefslogtreecommitdiff
path: root/boot/evaluator.cc
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-08-01 09:30:39 +0200
committerEugen Wissner <belka@caraus.de>2026-08-01 09:34:21 +0200
commit8539c10542a4be1e1127daea60bf1b1e4c37e092 (patch)
treef04e3b0e97e4d201ee5ebdb0b2bd9079af4b1820 /boot/evaluator.cc
parent661c29a7835cf1755deaf21f91832f00e958a318 (diff)
downloadelna-8539c10542a4be1e1127daea60bf1b1e4c37e092.tar.gz
Fix compile-time negation and array access
Diffstat (limited to 'boot/evaluator.cc')
-rw-r--r--boot/evaluator.cc159
1 files changed, 62 insertions, 97 deletions
diff --git a/boot/evaluator.cc b/boot/evaluator.cc
index bff727d..14b8ea3 100644
--- a/boot/evaluator.cc
+++ b/boot/evaluator.cc
@@ -214,7 +214,7 @@ namespace elna::boot
if (is_primitive_type(decoration, "Int"))
{
- return constant_value{ static_cast<literal<std::int32_t>&>(subject).value };
+ return constant_value{ static_cast<literal<integer_literal>&>(subject).value };
}
if (is_primitive_type(decoration, "Word"))
{
@@ -260,38 +260,18 @@ namespace elna::boot
std::optional<constant_value> evaluator::evaluate_array_access(array_access_expression& subject)
{
auto base = evaluate(subject.base());
- auto index = evaluate(subject.index());
+ auto index = evaluate_index(subject.index());
+
if (!base.has_value() || !index.has_value())
{
return std::nullopt;
}
auto *array = std::get_if<constant_aggregate<std::vector>>(&base.value());
- if (array == nullptr)
- {
- return std::nullopt;
- }
- std::size_t position;
- if (auto *int_index = std::get_if<std::int32_t>(&index.value()))
- {
- if (*int_index < 0)
- {
- return std::nullopt;
- }
- position = static_cast<std::size_t>(*int_index);
- }
- else if (auto *word_index = std::get_if<integer_literal>(&index.value()))
- {
- position = word_index->to<std::uint32_t>();
- }
- else
- {
- return std::nullopt;
- }
- if (position >= (*array)->size())
+ if (array == nullptr || index.value() > (*array)->size())
{
return std::nullopt;
}
- return (*array)->at(position);
+ return (*array)->at(index.value() - 1);
}
std::optional<constant_value> evaluator::evaluate_field_access(field_access_expression& subject)
@@ -307,8 +287,9 @@ namespace elna::boot
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{
- static_cast<std::int32_t>(std::distance(enumeration->members.begin(), member_iterator) + 1)
+ integer_literal::from(static_cast<std::int32_t>(enumeration_position))
};
}
return std::nullopt;
@@ -331,31 +312,47 @@ namespace elna::boot
return pos->second;
}
- std::optional<constant_value> evaluator::evaluate_slicing(slicing_expression& subject)
+ std::optional<std::size_t> evaluator::evaluate_index(expression& subject)
{
- auto base = evaluate(subject.base());
- auto start = evaluate(subject.start());
- auto end = evaluate(subject.end());
- if (!base.has_value() || !start.has_value() || !end.has_value())
+ auto evaluated_index = evaluate(subject);
+ if (!evaluated_index.has_value())
{
return std::nullopt;
}
- auto *array = std::get_if<constant_aggregate<std::vector>>(&base.value());
- auto *start_idx = std::get_if<std::int32_t>(&start.value());
- auto *end_idx = std::get_if<std::int32_t>(&end.value());
- if (array == nullptr || start_idx == nullptr || end_idx == nullptr
- || *start_idx < 0 || *end_idx < 0)
+ auto index_literal = std::get<integer_literal>(evaluated_index.value());
+
+ if (index_literal.is_signed())
+ {
+ auto signed_index = index_literal.to_signed();
+
+ if (!signed_index.has_value() || signed_index.value() <= 0)
+ {
+ return std::nullopt;
+ }
+ return static_cast<std::size_t>(signed_index.value());
+ }
+ else
+ {
+ return index_literal.to_unsigned();
+ }
+ }
+
+ std::optional<constant_value> evaluator::evaluate_slicing(slicing_expression& subject)
+ {
+ auto base = evaluate(subject.base());
+ auto start_index = evaluate_index(subject.start());
+ auto end_index = evaluate_index(subject.end());
+ if (!base.has_value() || !start_index.has_value() || !end_index.has_value())
{
return std::nullopt;
}
- auto start_pos = static_cast<std::size_t>(*start_idx);
- auto end_pos = static_cast<std::size_t>(*end_idx);
- if (start_pos > end_pos || end_pos > (*array)->size())
+ auto *array = std::get_if<constant_aggregate<std::vector>>(&base.value());
+ if (array == nullptr || start_index > end_index || end_index > (*array)->size())
{
return std::nullopt;
}
- auto slice_begin = std::next((*array)->begin(), static_cast<std::ptrdiff_t>(start_pos));
- auto slice_end = std::next((*array)->begin(), static_cast<std::ptrdiff_t>(end_pos));
+ auto slice_begin = std::next((*array)->begin(), static_cast<std::ptrdiff_t>(start_index.value() - 1));
+ auto slice_end = std::next((*array)->begin(), static_cast<std::ptrdiff_t>(end_index.value()));
return constant_value{
constant_aggregate<std::vector>{ std::vector<constant_value>(slice_begin, slice_end) }
@@ -386,11 +383,13 @@ namespace elna::boot
return std::visit([](auto&& value) -> std::optional<constant_value> {
using T = std::decay_t<decltype(value)>;
- if constexpr (std::is_same_v<T, std::int32_t>)
+ if constexpr (std::is_same_v<T, integer_literal>)
{
- return value == std::numeric_limits<std::int32_t>::min()
- ? std::nullopt
- : std::make_optional<constant_value>(constant_value{ -value });
+ if (auto result = value.neg())
+ {
+ return constant_value{ result.value() };
+ }
+ return std::nullopt;
}
if constexpr (std::is_same_v<T, double>)
{
@@ -416,7 +415,7 @@ namespace elna::boot
return std::visit([](const auto& value) -> std::optional<constant_value> {
using T = std::decay_t<decltype(value)>;
- if constexpr (is_integral<T> || std::is_same_v<T, integer_literal>)
+ if constexpr (std::is_same_v<T, integer_literal>)
{
return constant_value{ ~value };
}
@@ -472,9 +471,7 @@ namespace elna::boot
template<typename T>
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, constant_aggregate<ordered_map>>
- || std::is_same_v<T, constant_aggregate<std::vector>>)
+ if constexpr (std::is_same_v<T, std::nullptr_t>)
{
switch (operation)
{
@@ -487,19 +484,6 @@ namespace elna::boot
return std::nullopt;
}
}
- else if constexpr (std::is_same_v<T, global_address>)
- {
- switch (operation)
- {
- using enum binary_operator;
- case equals:
- return constant_value{ lhs == rhs };
- case not_equals:
- return constant_value{ lhs != rhs };
- default:
- return std::nullopt;
- }
- }
else
{
switch (operation)
@@ -513,7 +497,7 @@ namespace elna::boot
return constant_value{ result.value() };
}
}
- else if constexpr (is_arithmetic<T>)
+ else if constexpr (std::is_floating_point_v<T>)
{
if (auto result = add_overflow(lhs, rhs))
{
@@ -529,7 +513,7 @@ namespace elna::boot
return constant_value{ result.value() };
}
}
- else if constexpr (is_arithmetic<T>)
+ else if constexpr (std::is_floating_point_v<T>)
{
if (auto result = sub_overflow(lhs, rhs))
{
@@ -545,7 +529,7 @@ namespace elna::boot
return constant_value{ result.value() };
}
}
- else if constexpr (is_arithmetic<T>)
+ else if constexpr (std::is_floating_point_v<T>)
{
if (auto result = mul_overflow(lhs, rhs))
{
@@ -561,7 +545,7 @@ namespace elna::boot
return constant_value{ result.value() };
}
}
- else if constexpr (is_arithmetic<T>)
+ else if constexpr (std::is_floating_point_v<T>)
{
if (rhs != static_cast<T>(0))
{
@@ -577,31 +561,24 @@ namespace elna::boot
return constant_value{ result.value() };
}
}
- else if constexpr (is_integral<T>)
- {
- if (rhs != static_cast<T>(0))
- {
- return constant_value{ lhs % rhs };
- }
- }
return std::nullopt;
case disjunction:
case bitwise_disjunction:
- if constexpr (is_integral<T> || std::is_same_v<T, integer_literal>)
+ if constexpr (std::is_same_v<T, integer_literal>)
{
return constant_value{ lhs | rhs };
}
return std::nullopt;
case conjunction:
case bitwise_conjunction:
- if constexpr (is_integral<T> || std::is_same_v<T, integer_literal>)
+ if constexpr (std::is_same_v<T, integer_literal>)
{
return constant_value{ lhs & rhs };
}
return std::nullopt;
case exclusive_disjunction:
case bitwise_exclusive_disjunction:
- if constexpr (is_integral<T> || std::is_same_v<T, integer_literal>)
+ if constexpr (std::is_same_v<T, integer_literal>)
{
return constant_value{ lhs ^ rhs };
}
@@ -632,14 +609,6 @@ namespace elna::boot
return constant_value{ result.value() };
}
}
- else if constexpr (is_integral<T>)
- {
- if (rhs < 0 || static_cast<std::make_unsigned_t<T>>(rhs) >= std::numeric_limits<T>::digits)
- {
- return std::nullopt;
- }
- return constant_value{ lhs << rhs };
- }
return std::nullopt;
case shift_right:
if constexpr (std::is_same_v<T, integer_literal>)
@@ -649,35 +618,31 @@ namespace elna::boot
return constant_value{ result.value() };
}
}
- else if constexpr (std::is_integral_v<T>)
- {
- return constant_value{ lhs >> rhs };
- }
return std::nullopt;
case equals:
return constant_value{ lhs == rhs };
case not_equals:
return constant_value{ lhs != rhs };
case less:
- if constexpr (is_arithmetic<T> || std::is_same_v<T, integer_literal>)
+ if constexpr (std::is_floating_point_v<T> || std::is_same_v<T, integer_literal>)
{
return constant_value{ lhs < rhs };
}
return std::nullopt;
case greater:
- if constexpr (is_arithmetic<T> || std::is_same_v<T, integer_literal>)
+ if constexpr (std::is_floating_point_v<T> || std::is_same_v<T, integer_literal>)
{
return constant_value{ lhs > rhs };
}
return std::nullopt;
case less_equal:
- if constexpr (is_arithmetic<T> || std::is_same_v<T, integer_literal>)
+ if constexpr (std::is_floating_point_v<T> || std::is_same_v<T, integer_literal>)
{
return constant_value{ lhs <= rhs };
}
return std::nullopt;
case greater_equal:
- if constexpr (is_arithmetic<T> || std::is_same_v<T, integer_literal>)
+ if constexpr (std::is_floating_point_v<T> || std::is_same_v<T, integer_literal>)
{
return constant_value{ lhs >= rhs };
}
@@ -755,11 +720,11 @@ namespace elna::boot
if (is_primitive_type(resolved, "Int"))
{
- return constant_value{ std::numeric_limits<std::int32_t>::min() };
+ return constant_value{ integer_literal::from(std::numeric_limits<std::int32_t>::min()) };
}
if (is_primitive_type(resolved, "Word"))
{
- return constant_value{ integer_literal::from(static_cast<std::uint32_t>(0)) };
+ return constant_value{ integer_literal::from<std::uint32_t>(0) };
}
if (is_primitive_type(resolved, "Char"))
{
@@ -775,7 +740,7 @@ namespace elna::boot
}
if (auto enumeration = resolved.get<enumeration_type>())
{
- return constant_value{ 1 };
+ return constant_value{ integer_literal::from<std::int32_t>(1) };
}
}
else if (subject.name.name() == "max")
@@ -784,7 +749,7 @@ namespace elna::boot
if (is_primitive_type(resolved, "Int"))
{
- return constant_value{ std::numeric_limits<std::int32_t>::max() };
+ return constant_value{ integer_literal::from(std::numeric_limits<std::int32_t>::max()) };
}
if (is_primitive_type(resolved, "Word"))
{
@@ -804,7 +769,7 @@ namespace elna::boot
}
if (auto enumeration = resolved.get<enumeration_type>())
{
- return constant_value{ static_cast<std::int32_t>(enumeration->members.size()) };
+ return constant_value{ integer_literal::from(static_cast<std::int32_t>(enumeration->members.size())) };
}
}
else if (subject.name.name() == "offset")