From 2e1e95dc716167853be4a4b6acaaee1688142744 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Sun, 19 Jul 2026 02:08:06 +0200 Subject: Implement initializer evaluator --- include/elna/boot/ast.h | 4 ++ include/elna/boot/dependency.h | 5 +- include/elna/boot/evaluator.h | 100 ++++++++++++++++++++++++++++++++++++++++ include/elna/boot/type_check.h | 20 +++++++- include/elna/gcc/elna-generic.h | 4 +- 5 files changed, 128 insertions(+), 5 deletions(-) create mode 100644 include/elna/boot/evaluator.h (limited to 'include') 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_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&& 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 #include +#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& segments); - error_list analyze_semantics(std::unique_ptr& tree, symbol_bag bag); + error_list analyze_semantics(std::unique_ptr& tree, symbol_bag bag, + const target_info& target); template 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 +. */ + +#pragma once + +#include +#include +#include +#include +#include + +#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& evaluated_initializers; + + std::optional evaluate_literal(literal_expression& subject); + std::optional evaluate_named(named_expression& subject); + std::optional evaluate_unary(unary_expression& subject); + std::optional evaluate_binary(binary_expression& subject); + std::optional evaluate_cast(cast_expression& subject); + std::optional evaluate_traits(traits_expression& subject); + std::optional evaluate_traits_size(const type& subject); + std::optional evaluate_traits_alignment(const type& subject); + + public: + explicit evaluator(symbol_bag& bag, const target_info& target, + const std::map& 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 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 #include "elna/boot/ast.h" +#include "elna/boot/evaluator.h" #include "elna/boot/result.h" #include "elna/boot/symbol.h" @@ -162,6 +163,17 @@ namespace elna::boot std::string what() const override; }; + /** + * 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. * @@ -199,6 +211,10 @@ namespace elna::boot { symbol_bag bag; std::shared_ptr current_procedure; + const target_info& target; + + // Map from const variable name to its initializer, for chaining. + std::map evaluated_initializers; /* * Whether an expression of type assignment can be assigned to a variable @@ -209,7 +225,7 @@ namespace elna::boot std::vector& 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 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, elna::boot::symbol_bag bag); + generic_visitor(std::shared_ptr 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; -- cgit v1.2.3