aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-07-19 02:08:06 +0200
committerEugen Wissner <belka@caraus.de>2026-07-19 02:08:06 +0200
commit2e1e95dc716167853be4a4b6acaaee1688142744 (patch)
tree343a27402a2aa0f1f83bc0ca05ad8803310e4959 /include
parent349e84c693c1444606e877f4d8cdc1a39aa91634 (diff)
downloadelna-2e1e95dc716167853be4a4b6acaaee1688142744.tar.gz
Implement initializer evaluator
Diffstat (limited to 'include')
-rw-r--r--include/elna/boot/ast.h4
-rw-r--r--include/elna/boot/dependency.h5
-rw-r--r--include/elna/boot/evaluator.h100
-rw-r--r--include/elna/boot/type_check.h20
-rw-r--r--include/elna/gcc/elna-generic.h4
5 files changed, 128 insertions, 5 deletions
diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h
index 42e7666..9d978a3 100644
--- a/include/elna/boot/ast.h
+++ b/include/elna/boot/ast.h
@@ -257,6 +257,8 @@ namespace elna::boot
virtual designator_expression *is_designator();
virtual procedure_call *is_call_expression();
virtual literal_expression *is_literal();
+ virtual record_constructor_expression *is_record_constructor();
+ virtual array_constructor_expression *is_array_constructor();
};
/**
@@ -378,6 +380,7 @@ namespace elna::boot
identifier&& type_name,
std::vector<field_initializer>&& field_initializers);
void accept(parser_visitor *visitor) override;
+ record_constructor_expression *is_record_constructor() override;
};
class array_constructor_expression : public expression
@@ -391,6 +394,7 @@ namespace elna::boot
std::uint32_t size, type_expression *element_type,
std::vector<expression *>&& elements);
void accept(parser_visitor *visitor) override;
+ array_constructor_expression *is_array_constructor() override;
virtual ~array_constructor_expression() override;
};
diff --git a/include/elna/boot/dependency.h b/include/elna/boot/dependency.h
index 5f6eba5..829b669 100644
--- a/include/elna/boot/dependency.h
+++ b/include/elna/boot/dependency.h
@@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see
#include <filesystem>
#include <fstream>
+#include "elna/boot/evaluator.h"
#include "elna/boot/result.h"
#include "elna/boot/ast.h"
#include "elna/boot/symbol.h"
@@ -38,7 +39,8 @@ namespace elna::boot
dependency read_source(std::istream& entry_point);
std::filesystem::path build_path(const std::vector<std::string>& segments);
- error_list analyze_semantics(std::unique_ptr<unit>& tree, symbol_bag bag);
+ error_list analyze_semantics(std::unique_ptr<unit>& tree, symbol_bag bag,
+ const target_info& target);
template<typename T>
class dependency_state
@@ -86,6 +88,5 @@ namespace elna::boot
{
return this->cache.cend();
}
-
};
}
diff --git a/include/elna/boot/evaluator.h b/include/elna/boot/evaluator.h
new file mode 100644
index 0000000..6e82777
--- /dev/null
+++ b/include/elna/boot/evaluator.h
@@ -0,0 +1,100 @@
+/* Constant expression evaluation.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <cstdint>
+#include <map>
+#include <optional>
+#include <string>
+#include <variant>
+
+#include "elna/boot/symbol.h"
+#include "elna/boot/ast.h"
+
+namespace elna::boot
+{
+ /**
+ * Target machine information, populated by the compiler backend glue layer.
+ */
+ struct target_info
+ {
+ std::size_t int_size{0};
+ std::size_t int_alignment{0};
+ std::size_t word_size{0};
+ std::size_t word_alignment{0};
+ std::size_t pointer_size{0};
+ std::size_t pointer_alignment{0};
+ std::size_t char_size{0};
+ std::size_t char_alignment{0};
+ std::size_t float_size{0};
+ std::size_t float_alignment{0};
+ };
+
+ /**
+ * For aggregate values (arrays, records) signals that every sub-expression
+ * is constant without storing the full aggregate.
+ */
+ struct compound_constant
+ {
+ };
+
+ /**
+ * Typed constant value produced by the constant expression evaluator.
+ */
+ using constant_value = std::variant<
+ std::int32_t,
+ std::uint32_t,
+ double,
+ bool,
+ unsigned char,
+ std::nullptr_t,
+ compound_constant
+ >;
+
+ /**
+ * Called on-demand.
+ */
+ class evaluator
+ {
+ symbol_bag& bag;
+ const target_info& target;
+ const std::map<std::string, expression*>& evaluated_initializers;
+
+ std::optional<constant_value> evaluate_literal(literal_expression& subject);
+ std::optional<constant_value> evaluate_named(named_expression& subject);
+ std::optional<constant_value> evaluate_unary(unary_expression& subject);
+ std::optional<constant_value> evaluate_binary(binary_expression& subject);
+ std::optional<constant_value> evaluate_cast(cast_expression& subject);
+ std::optional<constant_value> evaluate_traits(traits_expression& subject);
+ std::optional<std::size_t> evaluate_traits_size(const type& subject);
+ std::optional<std::size_t> evaluate_traits_alignment(const type& subject);
+
+ public:
+ explicit evaluator(symbol_bag& bag, const target_info& target,
+ const std::map<std::string, expression*>& evaluated_initializers);
+
+ /**
+ * Evaluates an expression at compile time.
+ *
+ * \param expr Expression to evaluate.
+ * \return Expression's constant value or \c std::nullopt if the
+ * expression is not constant.
+ */
+ std::optional<constant_value> evaluate(expression& subject);
+ };
+}
diff --git a/include/elna/boot/type_check.h b/include/elna/boot/type_check.h
index b250f48..5b6ed1c 100644
--- a/include/elna/boot/type_check.h
+++ b/include/elna/boot/type_check.h
@@ -1,4 +1,4 @@
-/* Type analysis.
+/* Type checking.
Copyright (C) 2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see
#include <vector>
#include "elna/boot/ast.h"
+#include "elna/boot/evaluator.h"
#include "elna/boot/result.h"
#include "elna/boot/symbol.h"
@@ -163,6 +164,17 @@ namespace elna::boot
};
/**
+ * A module-level variable initializer must be a constant expression.
+ */
+ class non_constant_initializer_error : public error
+ {
+ public:
+ explicit non_constant_initializer_error(const source_position position);
+
+ std::string what() const override;
+ };
+
+ /**
* Chain of responsibility for type compatibility checks.
*
* Populate \c ctx with pre-resolved types, then call \c run().
@@ -199,6 +211,10 @@ namespace elna::boot
{
symbol_bag bag;
std::shared_ptr<procedure_info> current_procedure;
+ const target_info& target;
+
+ // Map from const variable name to its initializer, for chaining.
+ std::map<std::string, expression*> evaluated_initializers;
/*
* Whether an expression of type assignment can be assigned to a variable
@@ -209,7 +225,7 @@ namespace elna::boot
std::vector<std::string>& path);
public:
- explicit type_analysis_visitor(symbol_bag bag);
+ explicit type_analysis_visitor(symbol_bag bag, const target_info& target);
void visit(procedure_declaration *declaration) override;
void visit(unit *unit) override;
diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h
index dd5c9ef..2a1425c 100644
--- a/include/elna/gcc/elna-generic.h
+++ b/include/elna/gcc/elna-generic.h
@@ -35,6 +35,7 @@ namespace elna::gcc
tree current_expression{ NULL_TREE };
elna::boot::symbol_bag bag;
std::shared_ptr<symbol_table> symbols;
+ const elna::boot::target_info& target;
void enter_scope();
tree leave_scope();
@@ -60,7 +61,8 @@ namespace elna::gcc
bool assert_constant(location_t expression_location);
public:
- generic_visitor(std::shared_ptr<symbol_table> symbol_table, elna::boot::symbol_bag bag);
+ generic_visitor(std::shared_ptr<symbol_table> symbol_table,
+ elna::boot::symbol_bag bag, const elna::boot::target_info& target);
void visit(boot::procedure_declaration *declaration) override;
void visit(boot::procedure_call *call) override;