From 8539c10542a4be1e1127daea60bf1b1e4c37e092 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Sat, 1 Aug 2026 09:30:39 +0200 Subject: Fix compile-time negation and array access --- boot/evaluator.cc | 159 +++++++++++++++++++++--------------------------------- 1 file changed, 62 insertions(+), 97 deletions(-) (limited to 'boot/evaluator.cc') 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&>(subject).value }; + return constant_value{ static_cast&>(subject).value }; } if (is_primitive_type(decoration, "Word")) { @@ -260,38 +260,18 @@ namespace elna::boot std::optional 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>(&base.value()); - if (array == nullptr) - { - return std::nullopt; - } - std::size_t position; - if (auto *int_index = std::get_if(&index.value())) - { - if (*int_index < 0) - { - return std::nullopt; - } - position = static_cast(*int_index); - } - else if (auto *word_index = std::get_if(&index.value())) - { - position = word_index->to(); - } - 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 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::distance(enumeration->members.begin(), member_iterator) + 1) + integer_literal::from(static_cast(enumeration_position)) }; } return std::nullopt; @@ -331,31 +312,47 @@ namespace elna::boot return pos->second; } - std::optional evaluator::evaluate_slicing(slicing_expression& subject) + std::optional 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>(&base.value()); - auto *start_idx = std::get_if(&start.value()); - auto *end_idx = std::get_if(&end.value()); - if (array == nullptr || start_idx == nullptr || end_idx == nullptr - || *start_idx < 0 || *end_idx < 0) + auto index_literal = std::get(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(signed_index.value()); + } + else + { + return index_literal.to_unsigned(); + } + } + + std::optional 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(*start_idx); - auto end_pos = static_cast(*end_idx); - if (start_pos > end_pos || end_pos > (*array)->size()) + auto *array = std::get_if>(&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(start_pos)); - auto slice_end = std::next((*array)->begin(), static_cast(end_pos)); + auto slice_begin = std::next((*array)->begin(), static_cast(start_index.value() - 1)); + auto slice_end = std::next((*array)->begin(), static_cast(end_index.value())); return constant_value{ constant_aggregate{ std::vector(slice_begin, slice_end) } @@ -386,11 +383,13 @@ namespace elna::boot return std::visit([](auto&& value) -> std::optional { using T = std::decay_t; - if constexpr (std::is_same_v) + if constexpr (std::is_same_v) { - return value == std::numeric_limits::min() - ? std::nullopt - : std::make_optional(constant_value{ -value }); + if (auto result = value.neg()) + { + return constant_value{ result.value() }; + } + return std::nullopt; } if constexpr (std::is_same_v) { @@ -416,7 +415,7 @@ namespace elna::boot return std::visit([](const auto& value) -> std::optional { using T = std::decay_t; - if constexpr (is_integral || std::is_same_v) + if constexpr (std::is_same_v) { return constant_value{ ~value }; } @@ -472,9 +471,7 @@ namespace elna::boot template static std::optional evaluate_operation(binary_operator operation, const T& lhs, const T& rhs) { - if constexpr (std::is_same_v - || std::is_same_v> - || std::is_same_v>) + if constexpr (std::is_same_v) { switch (operation) { @@ -487,19 +484,6 @@ namespace elna::boot return std::nullopt; } } - else if constexpr (std::is_same_v) - { - 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) + else if constexpr (std::is_floating_point_v) { if (auto result = add_overflow(lhs, rhs)) { @@ -529,7 +513,7 @@ namespace elna::boot return constant_value{ result.value() }; } } - else if constexpr (is_arithmetic) + else if constexpr (std::is_floating_point_v) { if (auto result = sub_overflow(lhs, rhs)) { @@ -545,7 +529,7 @@ namespace elna::boot return constant_value{ result.value() }; } } - else if constexpr (is_arithmetic) + else if constexpr (std::is_floating_point_v) { if (auto result = mul_overflow(lhs, rhs)) { @@ -561,7 +545,7 @@ namespace elna::boot return constant_value{ result.value() }; } } - else if constexpr (is_arithmetic) + else if constexpr (std::is_floating_point_v) { if (rhs != static_cast(0)) { @@ -577,31 +561,24 @@ namespace elna::boot return constant_value{ result.value() }; } } - else if constexpr (is_integral) - { - if (rhs != static_cast(0)) - { - return constant_value{ lhs % rhs }; - } - } return std::nullopt; case disjunction: case bitwise_disjunction: - if constexpr (is_integral || std::is_same_v) + if constexpr (std::is_same_v) { return constant_value{ lhs | rhs }; } return std::nullopt; case conjunction: case bitwise_conjunction: - if constexpr (is_integral || std::is_same_v) + if constexpr (std::is_same_v) { return constant_value{ lhs & rhs }; } return std::nullopt; case exclusive_disjunction: case bitwise_exclusive_disjunction: - if constexpr (is_integral || std::is_same_v) + if constexpr (std::is_same_v) { return constant_value{ lhs ^ rhs }; } @@ -632,14 +609,6 @@ namespace elna::boot return constant_value{ result.value() }; } } - else if constexpr (is_integral) - { - if (rhs < 0 || static_cast>(rhs) >= std::numeric_limits::digits) - { - return std::nullopt; - } - return constant_value{ lhs << rhs }; - } return std::nullopt; case shift_right: if constexpr (std::is_same_v) @@ -649,35 +618,31 @@ namespace elna::boot return constant_value{ result.value() }; } } - else if constexpr (std::is_integral_v) - { - 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 || std::is_same_v) + if constexpr (std::is_floating_point_v || std::is_same_v) { return constant_value{ lhs < rhs }; } return std::nullopt; case greater: - if constexpr (is_arithmetic || std::is_same_v) + if constexpr (std::is_floating_point_v || std::is_same_v) { return constant_value{ lhs > rhs }; } return std::nullopt; case less_equal: - if constexpr (is_arithmetic || std::is_same_v) + if constexpr (std::is_floating_point_v || std::is_same_v) { return constant_value{ lhs <= rhs }; } return std::nullopt; case greater_equal: - if constexpr (is_arithmetic || std::is_same_v) + if constexpr (std::is_floating_point_v || std::is_same_v) { return constant_value{ lhs >= rhs }; } @@ -755,11 +720,11 @@ namespace elna::boot if (is_primitive_type(resolved, "Int")) { - return constant_value{ std::numeric_limits::min() }; + return constant_value{ integer_literal::from(std::numeric_limits::min()) }; } if (is_primitive_type(resolved, "Word")) { - return constant_value{ integer_literal::from(static_cast(0)) }; + return constant_value{ integer_literal::from(0) }; } if (is_primitive_type(resolved, "Char")) { @@ -775,7 +740,7 @@ namespace elna::boot } if (auto enumeration = resolved.get()) { - return constant_value{ 1 }; + return constant_value{ integer_literal::from(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::max() }; + return constant_value{ integer_literal::from(std::numeric_limits::max()) }; } if (is_primitive_type(resolved, "Word")) { @@ -804,7 +769,7 @@ namespace elna::boot } if (auto enumeration = resolved.get()) { - return constant_value{ static_cast(enumeration->members.size()) }; + return constant_value{ integer_literal::from(static_cast(enumeration->members.size())) }; } } else if (subject.name.name() == "offset") -- cgit v1.2.3