diff options
Diffstat (limited to 'boot')
| -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 |
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 |
