diff options
| author | Eugen Wissner <belka@caraus.de> | 2026-08-01 09:30:39 +0200 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2026-08-01 09:34:21 +0200 |
| commit | 8539c10542a4be1e1127daea60bf1b1e4c37e092 (patch) | |
| tree | f04e3b0e97e4d201ee5ebdb0b2bd9079af4b1820 | |
| parent | 661c29a7835cf1755deaf21f91832f00e958a318 (diff) | |
| download | elna-8539c10542a4be1e1127daea60bf1b1e4c37e092.tar.gz | |
Fix compile-time negation and array access
| -rw-r--r-- | boot/ast.cc | 11 | ||||
| -rw-r--r-- | boot/evaluator.cc | 159 | ||||
| -rw-r--r-- | boot/name_analysis.cc | 15 | ||||
| -rw-r--r-- | boot/parser.yy | 2 | ||||
| -rw-r--r-- | boot/result.cc | 55 | ||||
| -rw-r--r-- | gcc/gcc/elna-generic.cc | 8 | ||||
| -rw-r--r-- | gcc/gcc/elna-tree.cc | 18 | ||||
| -rw-r--r-- | include/elna/boot/ast.h | 5 | ||||
| -rw-r--r-- | include/elna/boot/evaluator.h | 1 | ||||
| -rw-r--r-- | include/elna/boot/name_analysis.h | 1 | ||||
| -rw-r--r-- | include/elna/boot/result.h | 42 | ||||
| -rw-r--r-- | include/elna/gcc/elna-generic.h | 1 | ||||
| -rw-r--r-- | testsuite/compilable/const_negation.elna | 8 | ||||
| -rw-r--r-- | testsuite/runnable/compile_time_array_access.elna | 7 |
14 files changed, 180 insertions, 153 deletions
diff --git a/boot/ast.cc b/boot/ast.cc index 2a90d0e..7157315 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -181,11 +181,6 @@ namespace elna::boot __builtin_unreachable(); } - void empty_visitor::visit(literal<std::int32_t> *) - { - __builtin_unreachable(); - } - void empty_visitor::visit(literal<integer_literal> *) { __builtin_unreachable(); @@ -509,10 +504,6 @@ namespace elna::boot expression->base().accept(this); } - void walking_visitor::visit(literal<std::int32_t> *) - { - } - void walking_visitor::visit(literal<integer_literal> *) { } @@ -979,7 +970,7 @@ namespace elna::boot { } - procedure_body::procedure_body(procedure_body&& that) + procedure_body::procedure_body(procedure_body&& that) noexcept : variables(std::move(const_cast<std::vector<variable_declaration *>&>(that.variables))), entry_point(std::move(const_cast<std::vector<statement *>&>(that.entry_point))), return_expression(that.return_expression) 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") diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc index b8cd83e..7ced7ea 100644 --- a/boot/name_analysis.cc +++ b/boot/name_analysis.cc @@ -789,15 +789,16 @@ namespace elna::boot } } - void name_analysis_visitor::visit(literal<std::int32_t> *literal) - { - literal->type_decoration = lookup_primitive_type("Int"); - this->current_type = literal->type_decoration; - } - void name_analysis_visitor::visit(literal<integer_literal> *literal) { - literal->type_decoration = lookup_primitive_type("Word"); + if (literal->value.is_signed()) + { + literal->type_decoration = lookup_primitive_type("Int"); + } + else + { + literal->type_decoration = lookup_primitive_type("Word"); + } this->current_type = literal->type_decoration; } diff --git a/boot/parser.yy b/boot/parser.yy index 85fc454..670a265 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -235,7 +235,7 @@ procedure_return: "return" expression { $$ = $2; } | "return" { $$ = nullptr; } literal: - INTEGER { $$ = new boot::literal<std::int32_t>(boot::make_position(@$), $1); } + INTEGER { $$ = new boot::literal<boot::integer_literal>(boot::make_position(@$), boot::integer_literal::from($1)); } | WORD { $$ = new boot::literal<boot::integer_literal>(boot::make_position(@$), boot::integer_literal::from($1)); } | FLOAT { $$ = new boot::literal<double>(boot::make_position(@$), $1); } | BOOLEAN { $$ = new boot::literal<bool>(boot::make_position(@$), $1); } diff --git a/boot/result.cc b/boot/result.cc index f9f57db..4d4c20f 100644 --- a/boot/result.cc +++ b/boot/result.cc @@ -129,12 +129,14 @@ namespace elna::boot } integer_literal::integer_literal(integer_literal&& that) noexcept + : m_signed(that.is_signed()), m_size(that.size()) { mpz_init(this->raw); mpz_swap(this->raw, that.raw); } integer_literal::integer_literal(const integer_literal& that) + : m_signed(that.is_signed()), m_size(that.size()) { mpz_init(this->raw); mpz_set(this->raw, that.raw); @@ -293,10 +295,7 @@ namespace elna::boot integer_literal& integer_literal::operator=(integer_literal&& that) noexcept { - if (this != &that) - { - mpz_swap(this->raw, that.raw); - } + swap(*this, that); return *this; } @@ -304,11 +303,43 @@ namespace elna::boot { if (this != &that) { - mpz_set(this->raw, that.raw); + integer_literal temp(that); + + swap(*this, temp); } return *this; } + std::optional<std::ptrdiff_t> integer_literal::to_signed() const + { + if (!is_signed()) + { + return std::nullopt; + } + if (is_negative_minimum(sizeof(std::ptrdiff_t) * CHAR_BIT)) + { + return std::numeric_limits<ptrdiff_t>::min(); + } + auto [written, rop] = export_to_words<std::ptrdiff_t>(); + + if (written > 1 || rop < 0) + { + return std::nullopt; + } + return mpz_sgn(this->raw) < 0 ? -rop : rop; + } + + std::optional<std::size_t> integer_literal::to_unsigned() const + { + if (is_signed()) + { + return std::nullopt; + } + auto [written, rop] = export_to_words<std::size_t>(); + + return written > 1 ? std::nullopt : std::make_optional(rop); + } + bool integer_literal::is_signed() const { return this->m_signed; @@ -319,6 +350,13 @@ namespace elna::boot return this->m_size; } + void swap(integer_literal& lhs, integer_literal& rhs) noexcept + { + mpz_swap(lhs.raw, rhs.raw); + std::swap(lhs.m_signed, rhs.m_signed); + std::swap(lhs.m_size, rhs.m_size); + } + std::optional<integer_literal> integer_literal::check() && { std::size_t required_bits = mpz_sizeinbase(this->raw, 2); @@ -337,9 +375,14 @@ namespace elna::boot } } + bool integer_literal::is_negative_minimum(const std::size_t bits) const + { + return mpz_sgn(this->raw) < 0 && mpz_scan1(this->raw, 0) == bits - 1; + } + bool integer_literal::is_negative_minimum() const { - return mpz_sgn(this->raw) < 0 && mpz_scan1(this->raw, 0) == bits() - 1; + return is_negative_minimum(bits()); } std::size_t integer_literal::bits() const diff --git a/gcc/gcc/elna-generic.cc b/gcc/gcc/elna-generic.cc index 6da3f99..969e929 100644 --- a/gcc/gcc/elna-generic.cc +++ b/gcc/gcc/elna-generic.cc @@ -478,15 +478,9 @@ namespace elna::gcc cgraph_node::finalize_function(fndecl, true); } - void generic_visitor::visit(boot::literal<std::int32_t> *literal) - { - this->current_expression = constant_to_tree(boot::constant_value{ literal->value }, this->symbols); - } - void generic_visitor::visit(boot::literal<boot::integer_literal> *literal) { - this->current_expression = constant_to_tree( - boot::constant_value{ literal->value }, this->symbols); + this->current_expression = constant_to_tree(boot::constant_value{ literal->value }, this->symbols); } void generic_visitor::visit(boot::literal<double> *literal) diff --git a/gcc/gcc/elna-tree.cc b/gcc/gcc/elna-tree.cc index 4b3ef81..55e359b 100644 --- a/gcc/gcc/elna-tree.cc +++ b/gcc/gcc/elna-tree.cc @@ -283,14 +283,18 @@ namespace elna::gcc tree constant_to_tree(const boot::constant_value& constant_value, const std::shared_ptr<symbol_table>& symbols, tree type) { - if (std::holds_alternative<std::int32_t>(constant_value)) + if (std::holds_alternative<boot::integer_literal>(constant_value)) { - return build_int_cst(elna_int_type_node, std::get<std::int32_t>(constant_value)); - } - else if (std::holds_alternative<boot::integer_literal>(constant_value)) - { - return build_int_cstu(elna_word_type_node, - std::get<boot::integer_literal>(constant_value).to<std::uint32_t>()); + auto literal_value = std::get<boot::integer_literal>(constant_value); + + if (literal_value.is_signed()) + { + return build_int_cst(elna_int_type_node, literal_value.to<std::int32_t>()); + } + else + { + return build_int_cstu(elna_word_type_node, literal_value.to<std::uint32_t>()); + } } else if (std::holds_alternative<double>(constant_value)) { diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index 0eda1a3..996c58a 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -138,7 +138,6 @@ namespace elna::boot virtual void visit(array_access_expression *) = 0; virtual void visit(field_access_expression *) = 0; virtual void visit(dereference_expression *) = 0; - virtual void visit(literal<std::int32_t> *) = 0; virtual void visit(literal<integer_literal> *) = 0; virtual void visit(literal<double> *) = 0; virtual void visit(literal<bool> *) = 0; @@ -188,7 +187,6 @@ namespace elna::boot [[noreturn]] void visit(array_access_expression *) override; [[noreturn]] void visit(field_access_expression *) override; [[noreturn]] void visit(dereference_expression *) override; - [[noreturn]] void visit(literal<std::int32_t> *) override; [[noreturn]] void visit(literal<integer_literal> *) override; [[noreturn]] void visit(literal<double> *) override; [[noreturn]] void visit(literal<bool> *) override; @@ -236,7 +234,6 @@ namespace elna::boot void visit(array_access_expression *expression) override; void visit(field_access_expression *expression) override; void visit(dereference_expression *expression) override; - void visit(literal<std::int32_t> *) override; void visit(literal<integer_literal> *) override; void visit(literal<double> *) override; void visit(literal<bool> *) override; @@ -521,7 +518,7 @@ namespace elna::boot std::vector<statement *>&& entry_point, expression *return_expression = nullptr); procedure_body(const procedure_body&) = delete; - procedure_body(procedure_body&& that); + procedure_body(procedure_body&& that) noexcept; procedure_body& operator=(const procedure_body&) = delete; diff --git a/include/elna/boot/evaluator.h b/include/elna/boot/evaluator.h index 8b36e1b..84bd5ab 100644 --- a/include/elna/boot/evaluator.h +++ b/include/elna/boot/evaluator.h @@ -53,6 +53,7 @@ namespace elna::boot std::optional<constant_value> evaluate_named(named_expression& subject); std::optional<constant_value> evaluate_array_access(array_access_expression& subject); std::optional<constant_value> evaluate_field_access(field_access_expression& subject); + std::optional<std::size_t> evaluate_index(expression& subject); std::optional<constant_value> evaluate_slicing(slicing_expression& subject); std::optional<constant_value> evaluate_unary(unary_expression& subject); std::optional<constant_value> evaluate_binary(binary_expression& subject); diff --git a/include/elna/boot/name_analysis.h b/include/elna/boot/name_analysis.h index 5d43f67..ab86a44 100644 --- a/include/elna/boot/name_analysis.h +++ b/include/elna/boot/name_analysis.h @@ -157,7 +157,6 @@ namespace elna::boot void visit(for_statement *statement) override; - void visit(literal<std::int32_t> *literal) override; void visit(literal<integer_literal> *literal) override; void visit(literal<double> *literal) override; void visit(literal<bool> *literal) override; diff --git a/include/elna/boot/result.h b/include/elna/boot/result.h index 3e8dfdf..4c6046d 100644 --- a/include/elna/boot/result.h +++ b/include/elna/boot/result.h @@ -216,16 +216,6 @@ namespace elna::boot template<typename T> inline constexpr bool is_integral = is_signed<T> || is_unsigned<T>; - /** - * Checks whether \p T is an integral or floating point type. - * - * \tparam T The examined type. - * - * \see is_integral - */ - template<typename T> - inline constexpr bool is_arithmetic = is_integral<T> || std::is_floating_point_v<T>; - struct integer_literal { integer_literal(integer_literal&& that) noexcept; @@ -283,13 +273,27 @@ namespace elna::boot T to() const requires is_integral<T> { - T result; + T result{}; mpz_export(&result, nullptr, 1, sizeof(T), 0, 0, this->raw); return result; } + /** + * Exports the stored value as a host \c std::ptrdiff_t. + * + * \return The converted value, or \c std::nullopt if out of range. + */ + std::optional<std::ptrdiff_t> to_signed() const; + + /** + * Exports the stored value as a host \c std::size_t. + * + * \return The converted value, or \c std::nullopt if out of range. + */ + std::optional<std::size_t> to_unsigned() const; + template<typename T> static integer_literal from(T initial) requires is_integral<T> @@ -301,6 +305,8 @@ namespace elna::boot return result; } + friend void swap(integer_literal& lhs, integer_literal& rhs) noexcept; + private: bool m_signed; std::size_t m_size; @@ -308,8 +314,21 @@ namespace elna::boot integer_literal(bool is_signed, std::size_t size); std::optional<integer_literal> check() &&; + bool is_negative_minimum(const std::size_t bits) const; bool is_negative_minimum() const; std::size_t bits() const; + + template<typename T> + std::pair<std::size_t, T> export_to_words() const + { + constexpr std::size_t word_count = std::max<std::size_t>(1U, 8 / sizeof(T)); + std::array<T, word_count> rop{}; + std::size_t written{ 0 }; + + mpz_export(rop.data(), &written, 1, sizeof(T), 0, 0, this->raw); + + return { written, rop[0] }; + } }; /** @@ -503,7 +522,6 @@ namespace elna::boot * array constructors as a vector of elements. */ using constant_value = std::variant< - std::int32_t, integer_literal, double, bool, diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index 944c4d0..097a660 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -73,7 +73,6 @@ namespace elna::gcc void visit(boot::procedure_declaration *declaration) override; void visit(boot::procedure_call *call) override; void visit(boot::cast_expression *expression) override; - void visit(boot::literal<std::int32_t> *literal) override; void visit(boot::literal<boot::integer_literal> *literal) override; void visit(boot::literal<double> *literal) override; void visit(boot::literal<bool> *boolean) override; diff --git a/testsuite/compilable/const_negation.elna b/testsuite/compilable/const_negation.elna new file mode 100644 index 0000000..a62cc1e --- /dev/null +++ b/testsuite/compilable/const_negation.elna @@ -0,0 +1,8 @@ +var + x: const Int := -5 + y: const Int := -x + +begin + assert(x = -5); + assert(y = 5); +end. diff --git a/testsuite/runnable/compile_time_array_access.elna b/testsuite/runnable/compile_time_array_access.elna new file mode 100644 index 0000000..566f3be --- /dev/null +++ b/testsuite/runnable/compile_time_array_access.elna @@ -0,0 +1,7 @@ +var + array: const [3]Int := [3]Int{ 1, 2, 3 } + i: const Int := array[2] + +begin + assert(i = 2) +end. |
