diff options
| author | Eugen Wissner <belka@caraus.de> | 2026-08-05 01:03:55 +0200 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2026-08-05 21:27:36 +0200 |
| commit | b2dee14873402ee3d13d59ae5579593796ea862f (patch) | |
| tree | 1f245eac1a23a73f45124498fc8274874e35750e /include | |
| parent | 1c2fb173ea3b674207badc721556ad72962b266e (diff) | |
| download | elna-b2dee14873402ee3d13d59ae5579593796ea862f.tar.gz | |
Check that constants are initialized
Diffstat (limited to 'include')
| -rw-r--r-- | include/elna/boot/ast.h | 21 | ||||
| -rw-r--r-- | include/elna/boot/driver.h | 2 | ||||
| -rw-r--r-- | include/elna/boot/evaluator.h | 28 | ||||
| -rw-r--r-- | include/elna/boot/name_analysis.h | 22 | ||||
| -rw-r--r-- | include/elna/boot/result.h | 46 | ||||
| -rw-r--r-- | include/elna/boot/symbol.h | 12 | ||||
| -rw-r--r-- | include/elna/boot/type_check.h | 8 | ||||
| -rw-r--r-- | include/elna/boot/validation.h | 20 |
8 files changed, 119 insertions, 40 deletions
diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index 996c58a..1ea17fb 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -17,7 +17,6 @@ along with GCC; see the file COPYING3. If not see #pragma once -#include <cstdint> #include <memory> #include <string> #include <vector> @@ -316,18 +315,19 @@ namespace elna::boot class array_type_expression : public type_expression { type_expression *m_base; + expression *m_dimensions; public: - const std::uint32_t size; array_type_expression(const source_position position, - type_expression *base, const std::uint32_t size); + type_expression *base, expression *dimensions); ~array_type_expression() override; void accept(parser_visitor *visitor) override; array_type_expression *is_array() override; - type_expression& base(); + type_expression& base() const; + expression& dimensions() const; }; class slice_type_expression : public type_expression @@ -415,7 +415,7 @@ namespace elna::boot { public: const identifier type_name; - std::vector<field_initializer> field_initializers; + const std::vector<field_initializer> field_initializers; record_constructor_expression(const source_position position, identifier&& type_name, @@ -426,17 +426,18 @@ namespace elna::boot class array_constructor_expression : public expression { + array_type_expression *m_element_type; + public: - const std::uint32_t size; - type_expression *const m_element_type; - std::vector<expression *> elements; + const std::vector<expression *> elements; array_constructor_expression(const source_position position, - std::uint32_t size, type_expression *element_type, - std::vector<expression *>&& elements); + array_type_expression *element_type, std::vector<expression *>&& elements); void accept(parser_visitor *visitor) override; array_constructor_expression *is_array_constructor() override; + array_type_expression& array_type() const; + ~array_constructor_expression() override; }; diff --git a/include/elna/boot/driver.h b/include/elna/boot/driver.h index 34a8c99..60d40fb 100644 --- a/include/elna/boot/driver.h +++ b/include/elna/boot/driver.h @@ -35,7 +35,7 @@ namespace elna::boot std::string what() const override; }; - class driver : public error_container + class driver final : public error_container { public: std::unique_ptr<unit> tree; diff --git a/include/elna/boot/evaluator.h b/include/elna/boot/evaluator.h index 84bd5ab..0d1a7c8 100644 --- a/include/elna/boot/evaluator.h +++ b/include/elna/boot/evaluator.h @@ -22,9 +22,35 @@ along with GCC; see the file COPYING3. If not see #include <memory> #include <optional> +#include <variant> namespace elna::boot { + class non_constant_expression_error final : public error + { + public: + struct initializer + { + std::vector<identifier> identifiers; + }; + struct case_label + { + }; + struct array_dimensions + { + type array_type; + }; + using payload_type = std::variant<initializer, case_label, array_dimensions>; + + non_constant_expression_error(const source_position position, payload_type payload); + + std::string what() const override; + std::optional<std::pair<std::string, source_position>> note() const override; + + private: + payload_type payload; + }; + std::optional<type_properties> get_type_properties(const type& subject, const target_info& target); /** @@ -53,7 +79,6 @@ namespace elna::boot std::optional<constant_value> evaluate_named(named_expression& subject); std::optional<constant_value> evaluate_array_access(array_access_expression& subject); std::optional<constant_value> evaluate_field_access(field_access_expression& subject); - std::optional<std::size_t> evaluate_index(expression& subject); std::optional<constant_value> evaluate_slicing(slicing_expression& subject); std::optional<constant_value> evaluate_unary(unary_expression& subject); std::optional<constant_value> evaluate_binary(binary_expression& subject); @@ -62,6 +87,7 @@ namespace elna::boot std::optional<std::size_t> evaluate_traits_alignment(const type& subject); public: + std::optional<std::size_t> evaluate_index(expression& subject); std::optional<constant_value> evaluate_traits(traits_expression& subject); explicit evaluator(symbol_bag& bag, const target_info& target); diff --git a/include/elna/boot/name_analysis.h b/include/elna/boot/name_analysis.h index 996c357..f6663ea 100644 --- a/include/elna/boot/name_analysis.h +++ b/include/elna/boot/name_analysis.h @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see #include "elna/boot/ast.h" #include "elna/boot/result.h" #include "elna/boot/symbol.h" +#include "elna/boot/evaluator.h" #include <string> #include <memory> @@ -32,7 +33,7 @@ namespace elna::boot * Error declaring or using a symbol (undeclared, redefinition, * local export). */ - class declaration_error : public error + class declaration_error final : public error { public: enum class kind { undeclared_type, undeclared_trait, undeclared_symbol, local_export }; @@ -56,7 +57,7 @@ namespace elna::boot * \c const qualifier used incorrectly — wrong position or * duplicate. */ - class const_qualifier_error : public error + class const_qualifier_error final : public error { public: enum class kind { array_position, duplicate }; @@ -72,7 +73,7 @@ namespace elna::boot /** * Error accessing or defining a member of a record or enumeration. */ - class member_error : public error + class member_error final : public error { public: enum class kind { not_found, field_on_type }; @@ -94,6 +95,17 @@ namespace elna::boot payload_type payload; }; + class not_initialized_error final : public error + { + std::vector<identifier> identifiers; + + public: + not_initialized_error(const source_position position, std::vector<identifier> identifiers); + + std::string what() const override; + std::optional<std::pair<std::string, source_position>> note() const override; + }; + /** * Origin of a field in a composite type. */ @@ -109,8 +121,8 @@ namespace elna::boot class name_analysis_visitor final : public walking_visitor, public error_container { type current_type; - symbol_bag bag; + evaluator constant_evaluator; std::pair<procedure_type, std::vector<std::string>> build_procedure( procedure_type_expression& expression); @@ -125,7 +137,7 @@ namespace elna::boot const type& element_type); public: - name_analysis_visitor(symbol_bag bag); + name_analysis_visitor(symbol_bag bag, const target_info& target); void visit(array_type_expression *expression) override; void visit(slice_type_expression *expression) override; diff --git a/include/elna/boot/result.h b/include/elna/boot/result.h index 36be8ee..3d01eb2 100644 --- a/include/elna/boot/result.h +++ b/include/elna/boot/result.h @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see #include <string> #include <deque> #include <memory> +#include <numeric> #include <optional> #include <utility> #include <variant> @@ -158,6 +159,8 @@ namespace elna::boot const std::string& name() const; const source_position& position() const; + std::string to_string() const; + bool operator==(const identifier& that) const; bool operator==(std::string_view that) const; @@ -181,6 +184,44 @@ namespace elna::boot }; /** + * Checks whether the givn object can be converted to a string using + * the .to_string() method. + */ + template<typename T> + concept has_to_string = requires(const T& stringable) { + { stringable.to_string() } -> std::convertible_to<std::string>; + }; + + /** + * Extracts identifiers (name and position) from identifier definitions and + * returns them in an allocated vector. + * + * \param identifiers Identifier definitions. + * \return Extracted identifiers. + */ + std::vector<identifier> extract_identifiers(const std::vector<identifier_definition>& identifiers); + + /** + * Joins an array of string-convertable objects (with a .t_string() method) + * into a delimiter separated list. + * + * \tparam T Array element type. + * \param identifiers Identifier array. + * \param delimiter List delimiter. + * \return Comma separted list. + */ + template<has_to_string T> + std::string join(const std::vector<T>& identifiers, std::string_view delimiter = ", ") + { + return std::accumulate(std::next(identifiers.begin()), identifiers.end(), + identifiers.front().to_string(), + [delimiter](const std::string& accumulator, const T& next) -> std::string { + return accumulator + std::string(delimiter) + next.to_string(); + } + ); + } + + /** * Checks whether \p T is a signed, std::int*_t type. * * \tparam T The examined type. @@ -271,6 +312,11 @@ namespace elna::boot std::string to_string(const std::uint8_t base = 10U) const; /** + * \return Whether the stored value is a negative integer. + */ + bool is_negative() const; + + /** * Exports the stored value as a host \c std::ptrdiff_t. * * \return The converted value, or \c std::nullopt if out of range. diff --git a/include/elna/boot/symbol.h b/include/elna/boot/symbol.h index 5000ab8..bd07a7e 100644 --- a/include/elna/boot/symbol.h +++ b/include/elna/boot/symbol.h @@ -494,11 +494,17 @@ namespace elna::boot */ void add_import(const symbol_bag& bag); - private: /** - * Returns a reduced symbol table with exported symbols, computed lazily - * and cached. + * Tells whether the current scope is the module global scope. + * + * The module scope is not the top-level scope, it's parent is the + * scope containing builtins. + * + * \return Whether the current scope is the global scope. */ + bool is_global() const; + + private: std::shared_ptr<symbol_table> exported_symbols() const; mutable std::shared_ptr<symbol_table> m_exported; diff --git a/include/elna/boot/type_check.h b/include/elna/boot/type_check.h index 82f0092..93e891a 100644 --- a/include/elna/boot/type_check.h +++ b/include/elna/boot/type_check.h @@ -30,7 +30,7 @@ namespace elna::boot /** * Expected type does not match the actual type of an expression. */ - class type_mismatch_error : public error + class type_mismatch_error final : public error { public: struct expected_type @@ -90,7 +90,7 @@ namespace elna::boot /** * Cyclic type declaration. */ - class cyclic_declaration_error : public error + class cyclic_declaration_error final : public error { std::vector<std::string> cycle; @@ -104,7 +104,7 @@ namespace elna::boot * Argument count in a procedure call or array constructor doesn't match * the expected number of parameters or elements. */ - class argument_count_error : public error + class argument_count_error final : public error { std::size_t expected; std::size_t actual; @@ -119,7 +119,7 @@ namespace elna::boot /** * A trait invocation is invalid. */ - class trait_error : public error + class trait_error final : public error { public: struct argument_count diff --git a/include/elna/boot/validation.h b/include/elna/boot/validation.h index c11a652..4a256fa 100644 --- a/include/elna/boot/validation.h +++ b/include/elna/boot/validation.h @@ -27,30 +27,20 @@ namespace elna::boot /** * Validation error. */ - class validation_error : public error + class validation_error final : public error { public: - struct non_constant_initializer - { - std::vector<identifier> identifiers; - }; struct duplicate_case { source_position first; }; - struct non_constant_case_label - { - }; - using payload_type = std::variant<non_constant_initializer, duplicate_case, non_constant_case_label>; + using payload_type = std::variant<duplicate_case>; validation_error(const source_position position, payload_type payload); std::string what() const override; std::optional<std::pair<std::string, source_position>> note() const override; - static validation_error non_constant_initializer_error(const source_position position, - const std::vector<identifier_definition>& identifiers); - private: payload_type payload; }; @@ -58,19 +48,17 @@ namespace elna::boot /** * Validates: * - case label uniqueness - * - Initializer constness. */ class validation_visitor final : public walking_visitor, public error_container { symbol_bag& bag; - const target_info& target; evaluator constant_evaluator; public: validation_visitor(symbol_bag& bag, const target_info& target); - void visit(variable_declaration* declaration) override; - void visit(procedure_declaration* declaration) override; + void visit(unit *unit) override; + void visit(procedure_declaration *declaration) override; void visit(case_statement *statement) override; }; } |
