aboutsummaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
Diffstat (limited to 'boot')
-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
5 files changed, 121 insertions, 121 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