aboutsummaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-07-31 10:20:56 +0200
committerEugen Wissner <belka@caraus.de>2026-07-31 10:20:56 +0200
commit661c29a7835cf1755deaf21f91832f00e958a318 (patch)
treedc048d1672e17beec2d8a81e2c748280277a191c /boot
parentf8daedce5c73e02dfb2fc59d75777190185584df (diff)
downloadelna-661c29a7835cf1755deaf21f91832f00e958a318.tar.gz
Review spaceship usage
Diffstat (limited to 'boot')
-rw-r--r--boot/ast.cc4
-rw-r--r--boot/evaluator.cc101
-rw-r--r--boot/name_analysis.cc2
-rw-r--r--boot/parser.yy2
-rw-r--r--boot/result.cc270
-rw-r--r--boot/validation.cc2
6 files changed, 312 insertions, 69 deletions
diff --git a/boot/ast.cc b/boot/ast.cc
index 7f34243..2a90d0e 100644
--- a/boot/ast.cc
+++ b/boot/ast.cc
@@ -186,7 +186,7 @@ namespace elna::boot
__builtin_unreachable();
}
- void empty_visitor::visit(literal<std::uint32_t> *)
+ void empty_visitor::visit(literal<integer_literal> *)
{
__builtin_unreachable();
}
@@ -513,7 +513,7 @@ namespace elna::boot
{
}
- void walking_visitor::visit(literal<std::uint32_t> *)
+ void walking_visitor::visit(literal<integer_literal> *)
{
}
diff --git a/boot/evaluator.cc b/boot/evaluator.cc
index b49a9ec..bff727d 100644
--- a/boot/evaluator.cc
+++ b/boot/evaluator.cc
@@ -218,7 +218,7 @@ namespace elna::boot
}
if (is_primitive_type(decoration, "Word"))
{
- return constant_value{ static_cast<literal<std::uint32_t>&>(subject).value };
+ return constant_value{ static_cast<literal<integer_literal>&>(subject).value };
}
if (is_primitive_type(decoration, "Float"))
{
@@ -279,9 +279,9 @@ namespace elna::boot
}
position = static_cast<std::size_t>(*int_index);
}
- else if (auto *word_index = std::get_if<std::uint32_t>(&index.value()))
+ else if (auto *word_index = std::get_if<integer_literal>(&index.value()))
{
- position = *word_index;
+ position = word_index->to<std::uint32_t>();
}
else
{
@@ -416,7 +416,7 @@ namespace elna::boot
return std::visit([](const auto& value) -> std::optional<constant_value> {
using T = std::decay_t<decltype(value)>;
- if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>)
+ if constexpr (is_integral<T> || std::is_same_v<T, integer_literal>)
{
return constant_value{ ~value };
}
@@ -433,7 +433,7 @@ namespace elna::boot
template<typename T>
static std::optional<T> add_overflow(T lhs, T rhs)
{
- if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>)
+ if constexpr (is_integral<T>)
{
T result;
return __builtin_add_overflow(lhs, rhs, &result)
@@ -446,7 +446,7 @@ namespace elna::boot
template<typename T>
static std::optional<T> sub_overflow(T lhs, T rhs)
{
- if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>)
+ if constexpr (is_integral<T>)
{
T result;
return __builtin_sub_overflow(lhs, rhs, &result)
@@ -459,7 +459,7 @@ namespace elna::boot
template<typename T>
static std::optional<T> mul_overflow(T lhs, T rhs)
{
- if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>)
+ if constexpr (is_integral<T>)
{
T result;
return __builtin_mul_overflow(lhs, rhs, &result)
@@ -506,7 +506,14 @@ namespace elna::boot
{
using enum binary_operator;
case sum:
- if constexpr (std::is_arithmetic_v<T> && !std::is_same_v<T, bool>)
+ if constexpr (std::is_same_v<T, integer_literal>)
+ {
+ if (auto result = lhs.add(rhs))
+ {
+ return constant_value{ result.value() };
+ }
+ }
+ else if constexpr (is_arithmetic<T>)
{
if (auto result = add_overflow(lhs, rhs))
{
@@ -515,7 +522,14 @@ namespace elna::boot
}
return std::nullopt;
case subtraction:
- if constexpr (std::is_arithmetic_v<T> && !std::is_same_v<T, bool>)
+ if constexpr (std::is_same_v<T, integer_literal>)
+ {
+ if (auto result = lhs.sub(rhs))
+ {
+ return constant_value{ result.value() };
+ }
+ }
+ else if constexpr (is_arithmetic<T>)
{
if (auto result = sub_overflow(lhs, rhs))
{
@@ -524,7 +538,14 @@ namespace elna::boot
}
return std::nullopt;
case multiplication:
- if constexpr (std::is_arithmetic_v<T> && !std::is_same_v<T, bool>)
+ if constexpr (std::is_same_v<T, integer_literal>)
+ {
+ if (auto result = lhs.mul(rhs))
+ {
+ return constant_value{ result.value() };
+ }
+ }
+ else if constexpr (is_arithmetic<T>)
{
if (auto result = mul_overflow(lhs, rhs))
{
@@ -533,7 +554,14 @@ namespace elna::boot
}
return std::nullopt;
case division:
- if constexpr (std::is_arithmetic_v<T> && !std::is_same_v<T, bool>)
+ if constexpr (std::is_same_v<T, integer_literal>)
+ {
+ if (auto result = lhs.div(rhs))
+ {
+ return constant_value{ result.value() };
+ }
+ }
+ else if constexpr (is_arithmetic<T>)
{
if (rhs != static_cast<T>(0))
{
@@ -542,7 +570,14 @@ namespace elna::boot
}
return std::nullopt;
case remainder:
- if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>)
+ if constexpr (std::is_same_v<T, integer_literal>)
+ {
+ if (auto result = lhs.mod(rhs))
+ {
+ return constant_value{ result.value() };
+ }
+ }
+ else if constexpr (is_integral<T>)
{
if (rhs != static_cast<T>(0))
{
@@ -552,21 +587,21 @@ namespace elna::boot
return std::nullopt;
case disjunction:
case bitwise_disjunction:
- if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>)
+ if constexpr (is_integral<T> || std::is_same_v<T, integer_literal>)
{
return constant_value{ lhs | rhs };
}
return std::nullopt;
case conjunction:
case bitwise_conjunction:
- if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>)
+ if constexpr (is_integral<T> || std::is_same_v<T, integer_literal>)
{
return constant_value{ lhs & rhs };
}
return std::nullopt;
case exclusive_disjunction:
case bitwise_exclusive_disjunction:
- if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>)
+ if constexpr (is_integral<T> || std::is_same_v<T, integer_literal>)
{
return constant_value{ lhs ^ rhs };
}
@@ -590,7 +625,14 @@ namespace elna::boot
}
return std::nullopt;
case shift_left:
- if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>)
+ if constexpr (std::is_same_v<T, integer_literal>)
+ {
+ if (auto result = lhs.shl(rhs))
+ {
+ 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)
{
@@ -600,7 +642,14 @@ namespace elna::boot
}
return std::nullopt;
case shift_right:
- if constexpr (std::is_integral_v<T>)
+ if constexpr (std::is_same_v<T, integer_literal>)
+ {
+ if (auto result = lhs.shr(rhs))
+ {
+ return constant_value{ result.value() };
+ }
+ }
+ else if constexpr (std::is_integral_v<T>)
{
return constant_value{ lhs >> rhs };
}
@@ -610,25 +659,25 @@ namespace elna::boot
case not_equals:
return constant_value{ lhs != rhs };
case less:
- if constexpr (std::is_arithmetic_v<T> && !std::is_same_v<T, bool>)
+ if constexpr (is_arithmetic<T> || std::is_same_v<T, integer_literal>)
{
return constant_value{ lhs < rhs };
}
return std::nullopt;
case greater:
- if constexpr (std::is_arithmetic_v<T> && !std::is_same_v<T, bool>)
+ if constexpr (is_arithmetic<T> || std::is_same_v<T, integer_literal>)
{
return constant_value{ lhs > rhs };
}
return std::nullopt;
case less_equal:
- if constexpr (std::is_arithmetic_v<T> && !std::is_same_v<T, bool>)
+ if constexpr (is_arithmetic<T> || std::is_same_v<T, integer_literal>)
{
return constant_value{ lhs <= rhs };
}
return std::nullopt;
case greater_equal:
- if constexpr (std::is_arithmetic_v<T> && !std::is_same_v<T, bool>)
+ if constexpr (is_arithmetic<T> || std::is_same_v<T, integer_literal>)
{
return constant_value{ lhs >= rhs };
}
@@ -690,14 +739,14 @@ namespace elna::boot
{
if (auto size = evaluate_traits_size(subject.types.front()))
{
- return constant_value{ static_cast<std::uint32_t>(size.value()) };
+ return constant_value{ integer_literal::from(static_cast<std::uint32_t>(size.value())) };
}
}
else if (subject.name.name() == "alignment")
{
if (auto alignment = evaluate_traits_alignment(subject.types.front()))
{
- return constant_value{ static_cast<std::uint32_t>(alignment.value()) };
+ return constant_value{ integer_literal::from(static_cast<std::uint32_t>(alignment.value())) };
}
}
else if (subject.name.name() == "min")
@@ -710,7 +759,7 @@ namespace elna::boot
}
if (is_primitive_type(resolved, "Word"))
{
- return constant_value{ static_cast<std::uint32_t>(0) };
+ return constant_value{ integer_literal::from(static_cast<std::uint32_t>(0)) };
}
if (is_primitive_type(resolved, "Char"))
{
@@ -739,7 +788,7 @@ namespace elna::boot
}
if (is_primitive_type(resolved, "Word"))
{
- return constant_value{ std::numeric_limits<std::uint32_t>::max() };
+ return constant_value{ integer_literal::from(std::numeric_limits<std::uint32_t>::max()) };
}
if (is_primitive_type(resolved, "Char"))
{
@@ -772,7 +821,7 @@ namespace elna::boot
if (field_search != std::cend(record_layout.value().offset_map))
{
- return constant_value{ static_cast<std::uint32_t>(field_search->second) };
+ return constant_value{ integer_literal::from(static_cast<std::uint32_t>(field_search->second)) };
}
}
}
diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc
index 89353e9..b8cd83e 100644
--- a/boot/name_analysis.cc
+++ b/boot/name_analysis.cc
@@ -795,7 +795,7 @@ namespace elna::boot
this->current_type = literal->type_decoration;
}
- void name_analysis_visitor::visit(literal<std::uint32_t> *literal)
+ void name_analysis_visitor::visit(literal<integer_literal> *literal)
{
literal->type_decoration = lookup_primitive_type("Word");
this->current_type = literal->type_decoration;
diff --git a/boot/parser.yy b/boot/parser.yy
index 4fdbf84..85fc454 100644
--- a/boot/parser.yy
+++ b/boot/parser.yy
@@ -236,7 +236,7 @@ procedure_return:
| "return" { $$ = nullptr; }
literal:
INTEGER { $$ = new boot::literal<std::int32_t>(boot::make_position(@$), $1); }
- | WORD { $$ = new boot::literal<std::uint32_t>(boot::make_position(@$), $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); }
| CHARACTER { $$ = new boot::literal<unsigned char>(boot::make_position(@$), $1.at(0)); }
diff --git a/boot/result.cc b/boot/result.cc
index 0eb5c12..f9f57db 100644
--- a/boot/result.cc
+++ b/boot/result.cc
@@ -91,22 +91,9 @@ namespace elna::boot
return this->m_position;
}
- std::strong_ordering identifier::operator<=>(const identifier& that) const
+ bool identifier::operator==(const identifier& that) const
{
- auto comparison = this->m_name.compare(that.name());
-
- if (comparison < 0)
- {
- return std::strong_ordering::less;
- }
- else if (comparison > 0)
- {
- return std::strong_ordering::greater;
- }
- else
- {
- return std::strong_ordering::equal;
- }
+ return this->m_name == that;
}
bool identifier::operator==(std::string_view that) const
@@ -114,11 +101,6 @@ namespace elna::boot
return this->m_name == that;
}
- bool identifier::operator!=(std::string_view that) const
- {
- return !(*this == that);
- }
-
identifier_definition::identifier_definition(const std::string& name,
const source_position& position, const bool exported)
: m_identifier(name, position), m_exported(exported)
@@ -140,6 +122,231 @@ namespace elna::boot
return this->m_exported;
}
+ integer_literal::integer_literal(bool is_signed, std::size_t size)
+ : m_signed(is_signed), m_size(size)
+ {
+ mpz_init(this->raw);
+ }
+
+ integer_literal::integer_literal(integer_literal&& that) noexcept
+ {
+ mpz_init(this->raw);
+ mpz_swap(this->raw, that.raw);
+ }
+
+ integer_literal::integer_literal(const integer_literal& that)
+ {
+ mpz_init(this->raw);
+ mpz_set(this->raw, that.raw);
+ }
+
+ integer_literal::~integer_literal()
+ {
+ mpz_clear(this->raw);
+ }
+
+ std::optional<integer_literal> integer_literal::add(const integer_literal& that) const
+ {
+ integer_literal result = *this;
+
+ mpz_add(result.raw, this->raw, that.raw);
+
+ return std::move(result).check();
+ }
+
+ std::optional<integer_literal> integer_literal::sub(const integer_literal& that) const
+ {
+ integer_literal result = *this;
+
+ mpz_sub(result.raw, this->raw, that.raw);
+
+ return std::move(result).check();
+ }
+
+ std::optional<integer_literal> integer_literal::mul(const integer_literal& that) const
+ {
+ integer_literal result = *this;
+
+ mpz_mul(result.raw, this->raw, that.raw);
+
+ return std::move(result).check();
+ }
+
+ std::optional<integer_literal> integer_literal::div(const integer_literal& that) const
+ {
+ if (mpz_cmp_ui(that.raw, 0U) == 0)
+ {
+ return std::nullopt;
+ }
+ else
+ {
+ integer_literal result = *this;
+
+ mpz_div(result.raw, this->raw, that.raw);
+
+ return std::make_optional(std::move(result));
+ }
+ }
+
+ std::optional<integer_literal> integer_literal::mod(const integer_literal& that) const
+ {
+ if (mpz_cmp_ui(that.raw, 0U) == 0)
+ {
+ return std::nullopt;
+ }
+ else
+ {
+ integer_literal result = *this;
+
+ mpz_mod(result.raw, this->raw, that.raw);
+
+ return std::make_optional(std::move(result));
+ }
+ }
+
+ std::optional<integer_literal> integer_literal::neg() const
+ {
+ if (!is_signed() || is_negative_minimum())
+ {
+ return std::nullopt;
+ }
+ integer_literal result = *this;
+
+ mpz_neg(result.raw, this->raw);
+
+ return result;
+ }
+
+ std::optional<integer_literal> integer_literal::shl(const integer_literal& that) const
+ {
+ if (that >= bits())
+ {
+ return std::nullopt;
+ }
+ integer_literal result = *this;
+
+ mpz_mul_2exp(result.raw, this->raw, static_cast<mp_bitcnt_t>(mpz_get_ui(that.raw)));
+
+ return std::move(result).check();
+ }
+
+ std::optional<integer_literal> integer_literal::shr(const integer_literal& that) const
+ {
+ integer_literal result = *this;
+
+ if (that >= bits())
+ {
+ mpz_set_si(result.raw, *this > 0 ? 0 : -1);
+ }
+ else
+ {
+ mpz_fdiv_q_2exp(result.raw, this->raw, static_cast<mp_bitcnt_t>(mpz_get_ui(that.raw)));
+ }
+ return std::make_optional(std::move(result));
+ }
+
+ integer_literal integer_literal::operator|(const integer_literal& that) const
+ {
+ integer_literal result = *this;
+
+ mpz_ior(result.raw, this->raw, that.raw);
+
+ return result;
+ }
+
+ integer_literal integer_literal::operator&(const integer_literal& that) const
+ {
+ integer_literal result = *this;
+
+ mpz_and(result.raw, this->raw, that.raw);
+
+ return result;
+ }
+
+ integer_literal integer_literal::operator^(const integer_literal& that) const
+ {
+ integer_literal result = *this;
+
+ mpz_xor(result.raw, this->raw, that.raw);
+
+ return result;
+ }
+
+ integer_literal integer_literal::operator~() const
+ {
+ integer_literal result = *this;
+
+ mpz_com(result.raw, this->raw);
+
+ return result;
+ }
+
+ bool integer_literal::operator==(const integer_literal& that) const
+ {
+ return mpz_cmp(this->raw, that.raw) == 0;
+ }
+
+ std::weak_ordering integer_literal::operator<=>(const integer_literal& that) const
+ {
+ return mpz_cmp(this->raw, that.raw) <=> 0;
+ }
+
+ integer_literal& integer_literal::operator=(integer_literal&& that) noexcept
+ {
+ if (this != &that)
+ {
+ mpz_swap(this->raw, that.raw);
+ }
+ return *this;
+ }
+
+ integer_literal& integer_literal::operator=(const integer_literal& that)
+ {
+ if (this != &that)
+ {
+ mpz_set(this->raw, that.raw);
+ }
+ return *this;
+ }
+
+ bool integer_literal::is_signed() const
+ {
+ return this->m_signed;
+ }
+
+ std::size_t integer_literal::size() const
+ {
+ return this->m_size;
+ }
+
+ std::optional<integer_literal> integer_literal::check() &&
+ {
+ std::size_t required_bits = mpz_sizeinbase(this->raw, 2);
+
+ if (!is_negative_minimum())
+ {
+ ++required_bits; // Add one bit for the sign.
+ }
+ if (required_bits > bits() || (mpz_sgn(this->raw) < 0 && !is_signed()))
+ {
+ return std::nullopt;
+ }
+ else
+ {
+ return std::move(*this);
+ }
+ }
+
+ bool integer_literal::is_negative_minimum() const
+ {
+ return mpz_sgn(this->raw) < 0 && mpz_scan1(this->raw, 0) == bits() - 1;
+ }
+
+ std::size_t integer_literal::bits() const
+ {
+ return size() * CHAR_BIT;
+ }
+
std::size_t constant_value_hash::operator()(const elna::boot::constant_value& value) const noexcept
{
return std::visit([](auto&& alternative) -> std::size_t {
@@ -149,24 +356,6 @@ namespace elna::boot
}, value);
}
- bool constant_value_hash::operator()(const elna::boot::constant_value& lhs,
- const elna::boot::constant_value& rhs) const noexcept
- {
- return std::visit([](auto&& first, auto&& second) -> bool {
- using T = std::decay_t<decltype(first)>;
- using U = std::decay_t<decltype(second)>;
-
- if constexpr (std::is_same_v<T, U>)
- {
- return first == second;
- }
- else
- {
- return false;
- }
- }, lhs, rhs);
- }
-
hash_accumulator hash_accumulator::operator+(const std::size_t& that) const
{
hash_accumulator result{};
@@ -219,3 +408,8 @@ std::size_t std::hash<elna::boot::constant_aggregate<elna::boot::ordered_map>>::
return hash.seed();
}
+
+std::size_t std::hash<elna::boot::integer_literal>::operator()(const elna::boot::integer_literal& key) const noexcept
+{
+ return std::hash<std::uint32_t>{}(key.to<std::uint32_t>());
+}
diff --git a/boot/validation.cc b/boot/validation.cc
index ccc8865..dc4b5b0 100644
--- a/boot/validation.cc
+++ b/boot/validation.cc
@@ -131,7 +131,7 @@ namespace elna::boot
void validation_visitor::visit(case_statement *statement)
{
walking_visitor::visit(statement);
- std::unordered_map<constant_value, source_position, constant_value_hash, constant_value_hash> seen;
+ std::unordered_map<constant_value, source_position, constant_value_hash> seen;
for (const auto& case_block : statement->cases)
{
for (auto *label : case_block.labels)