aboutsummaryrefslogtreecommitdiff
path: root/boot/evaluator.cc
diff options
context:
space:
mode:
Diffstat (limited to 'boot/evaluator.cc')
-rw-r--r--boot/evaluator.cc224
1 files changed, 19 insertions, 205 deletions
diff --git a/boot/evaluator.cc b/boot/evaluator.cc
index 6d3153e..b49a9ec 100644
--- a/boot/evaluator.cc
+++ b/boot/evaluator.cc
@@ -16,25 +16,17 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "elna/boot/evaluator.h"
+
#include "elna/boot/ast.h"
#include <algorithm>
#include <cstddef>
+#include <cstdint>
#include <limits>
#include <ranges>
namespace elna::boot
{
- non_constant_initializer_error::non_constant_initializer_error(const source_position position)
- : error(position)
- {
- }
-
- std::string non_constant_initializer_error::what() const
- {
- return "Variable initializers must be constant expressions";
- }
-
std::optional<type_properties> get_type_properties(const type& subject, const target_info& target)
{
auto resolved = resolve_underlying_type(subject);
@@ -304,6 +296,23 @@ namespace elna::boot
std::optional<constant_value> evaluator::evaluate_field_access(field_access_expression& subject)
{
+ auto type_to_check = subject.base().type_decoration;
+ if (type_to_check.empty())
+ {
+ type_to_check = subject.type_decoration;
+ }
+ auto resolved_base = resolve_underlying_type(type_to_check);
+ if (auto enumeration = resolved_base.get<enumeration_type>())
+ {
+ auto member_iterator = std::ranges::find(enumeration->members, subject.field().name());
+ if (member_iterator != enumeration->members.end())
+ {
+ return constant_value{
+ static_cast<std::int32_t>(std::distance(enumeration->members.begin(), member_iterator) + 1)
+ };
+ }
+ return std::nullopt;
+ }
auto base = evaluate(subject.base());
if (!base.has_value())
{
@@ -770,199 +779,4 @@ namespace elna::boot
return std::nullopt;
}
- /**
- * Converts a constant_value to an AST literal expression.
- *
- * \param value Evaluated constant to convert.
- * \param position Source position for the new literal node.
- * \param decoration Type decoration to apply to the literal.
- * \return A new literal expression, or \c nullptr if \p value
- * is an aggregate (handled separately by the caller).
- */
- static expression *value_to_expression(const constant_value& value,
- const source_position& position, const type& decoration)
- {
- return std::visit([&position, &decoration](auto&& value) -> expression*
- {
- using T = std::decay_t<decltype(value)>;
-
- if constexpr (std::is_same_v<T, std::int32_t>)
- {
- auto *lit = new literal<std::int32_t>(position, value);
- lit->type_decoration = decoration;
- return lit;
- }
- else if constexpr (std::is_same_v<T, std::uint32_t>)
- {
- auto *lit = new literal<std::uint32_t>(position, value);
- lit->type_decoration = decoration;
- return lit;
- }
- else if constexpr (std::is_same_v<T, double>)
- {
- auto *lit = new literal<double>(position, value);
- lit->type_decoration = decoration;
- return lit;
- }
- else if constexpr (std::is_same_v<T, bool>)
- {
- auto *lit = new literal<bool>(position, value);
- lit->type_decoration = decoration;
- return lit;
- }
- else if constexpr (std::is_same_v<T, unsigned char>)
- {
- auto *lit = new literal<unsigned char>(position, value);
- lit->type_decoration = decoration;
- return lit;
- }
- else if constexpr (std::is_same_v<T, std::nullptr_t>
- || std::is_same_v<T, global_address>)
- {
- auto *lit = new literal<std::nullptr_t>(position, nullptr);
- lit->type_decoration = decoration;
- return lit;
- }
- else
- {
- return nullptr;
- }
- }, value);
- }
-
- expression *evaluator::fold(expression& original)
- {
- auto value = evaluate(original);
- if (!value.has_value())
- {
- return &original;
- }
- if (expression *literal = value_to_expression(value.value(), original.position(), original.type_decoration))
- {
- delete &original;
- return literal;
- }
- if (auto *record = original.is_record_constructor())
- {
- for (auto& field_init : record->field_initializers)
- {
- fold_aggregate_field(field_init);
- }
- }
- else if (auto *array = original.is_array_constructor())
- {
- for (auto& element : array->elements)
- {
- element = fold(*element);
- }
- }
- return &original;
- }
-
- void evaluator::fold_aggregate_field(field_initializer& field_init)
- {
- auto value = evaluate(field_init.value());
- if (!value.has_value())
- {
- return;
- }
- expression *literal = value_to_expression(value.value(),
- field_init.value().position(), field_init.value().type_decoration);
- if (literal != nullptr)
- {
- field_init.value(*literal);
- return;
- }
- expression *folded = fold(field_init.value());
- if (folded != &field_init.value())
- {
- field_init.value(*folded);
- }
- }
-
- constant_folder::constant_folder(symbol_bag& bag, const target_info& target)
- : bag(bag), target(target), constant_evaluator(this->bag, this->target)
- {
- }
-
- void constant_folder::visit(variable_declaration* declaration)
- {
- if (declaration->initializer == nullptr || has_errors())
- {
- return;
- }
- auto computed = this->constant_evaluator.evaluate(*declaration->initializer);
- if (!computed)
- {
- add_error<non_constant_initializer_error>(declaration->initializer->position());
- return;
- }
- declaration->initializer = this->constant_evaluator.fold(*declaration->initializer);
-
- for (const auto& identifier : declaration->identifiers)
- {
- auto symbol = this->bag.lookup(identifier.name());
- if (symbol == nullptr)
- {
- continue;
- }
- if (auto var = symbol->is_variable();
- resolve_aliases(var->symbol).get<constant_type>() != nullptr)
- {
- var->value = computed;
- }
- }
- }
-
- void constant_folder::visit(cast_expression *expr)
- {
- expr->target().accept(this);
- expr->value().accept(this);
- expr->value(fold_trait(expr->value()));
- }
-
- void constant_folder::visit(binary_expression *expr)
- {
- expr->lhs().accept(this);
- expr->lhs(fold_trait(expr->lhs()));
- expr->rhs().accept(this);
- expr->rhs(fold_trait(expr->rhs()));
- }
-
- void constant_folder::visit(unary_expression *expr)
- {
- expr->operand().accept(this);
- expr->operand(fold_trait(expr->operand()));
- }
-
- void constant_folder::visit(procedure_call *call)
- {
- call->callable().accept(this);
- for (auto& argument : call->arguments)
- {
- argument->accept(this);
- expression& folded = fold_trait(*argument);
- if (&folded != argument)
- {
- delete argument;
- argument = &folded;
- }
- }
- }
-
- expression& constant_folder::fold_trait(expression& expr)
- {
- if (auto *trait = expr.is_traits())
- {
- if (auto value = this->constant_evaluator.evaluate_traits(*trait))
- {
- if (auto *literal = value_to_expression(value.value(), trait->position(), trait->type_decoration))
- {
- return *literal;
- }
- }
- }
- return expr;
- }
-
}