diff options
| author | Eugen Wissner <belka@caraus.de> | 2026-07-19 02:08:06 +0200 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2026-07-19 02:08:06 +0200 |
| commit | 2e1e95dc716167853be4a4b6acaaee1688142744 (patch) | |
| tree | 343a27402a2aa0f1f83bc0ca05ad8803310e4959 /include | |
| parent | 349e84c693c1444606e877f4d8cdc1a39aa91634 (diff) | |
| download | elna-2e1e95dc716167853be4a4b6acaaee1688142744.tar.gz | |
Implement initializer evaluator
Diffstat (limited to 'include')
| -rw-r--r-- | include/elna/boot/ast.h | 4 | ||||
| -rw-r--r-- | include/elna/boot/dependency.h | 5 | ||||
| -rw-r--r-- | include/elna/boot/evaluator.h | 100 | ||||
| -rw-r--r-- | include/elna/boot/type_check.h | 20 | ||||
| -rw-r--r-- | include/elna/gcc/elna-generic.h | 4 |
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; |
