aboutsummaryrefslogtreecommitdiff
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
parent661c29a7835cf1755deaf21f91832f00e958a318 (diff)
downloadelna-8539c10542a4be1e1127daea60bf1b1e4c37e092.tar.gz
Fix compile-time negation and array access
-rw-r--r--boot/ast.cc11
-rw-r--r--boot/evaluator.cc159
-rw-r--r--boot/name_analysis.cc15
-rw-r--r--boot/parser.yy2
-rw-r--r--boot/result.cc55
-rw-r--r--gcc/gcc/elna-generic.cc8
-rw-r--r--gcc/gcc/elna-tree.cc18
-rw-r--r--include/elna/boot/ast.h5
-rw-r--r--include/elna/boot/evaluator.h1
-rw-r--r--include/elna/boot/name_analysis.h1
-rw-r--r--include/elna/boot/result.h42
-rw-r--r--include/elna/gcc/elna-generic.h1
-rw-r--r--testsuite/compilable/const_negation.elna8
-rw-r--r--testsuite/runnable/compile_time_array_access.elna7
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.