From 1e0f89df48ba10cdde80bd623b84e20fb48b977d Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Fri, 24 Jul 2026 21:28:33 +0200 Subject: Accept any constant types in case labels --- include/elna/boot/dependency.h | 4 +- include/elna/boot/evaluator.h | 54 +++++++++++++--- include/elna/boot/name_analysis.h | 4 +- include/elna/boot/result.h | 131 ++++++++++++++++++++++++++++++++++++++ include/elna/boot/symbol.h | 26 ++++++-- include/elna/boot/type_check.h | 1 + include/elna/gcc/elna-generic.h | 6 +- 7 files changed, 208 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/include/elna/boot/dependency.h b/include/elna/boot/dependency.h index 24ded26..e6cfb36 100644 --- a/include/elna/boot/dependency.h +++ b/include/elna/boot/dependency.h @@ -79,12 +79,12 @@ namespace elna::boot return this->cache.end(); } - const_iterator cbegin() const + const_iterator begin() const { return this->cache.cbegin(); } - const_iterator cend() const + const_iterator end() const { return this->cache.cend(); } diff --git a/include/elna/boot/evaluator.h b/include/elna/boot/evaluator.h index b8a9956..015a2c7 100644 --- a/include/elna/boot/evaluator.h +++ b/include/elna/boot/evaluator.h @@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see #include #include +#include #include #include #include @@ -47,16 +48,14 @@ namespace elna::boot std::size_t bool_alignment{0}; }; - /** - * For aggregate values (arrays, records) signals that every sub-expression - * is constant without storing the full aggregate. - */ - struct compound_constant - { - }; + template typename C, template typename Alloc = std::allocator> + class constant_aggregate; /** * Typed constant value produced by the constant expression evaluator. + * + * Record constructors are stored as ordered_map keyed by field name, + * array constructors as a vector of elements. */ using constant_value = std::variant< std::int32_t, @@ -65,9 +64,48 @@ namespace elna::boot bool, unsigned char, std::nullptr_t, - compound_constant + constant_aggregate, + constant_aggregate >; + template typename C, template typename Alloc> + class constant_aggregate + { + using Container = C>; + std::shared_ptr container; + + public: + explicit constant_aggregate(const Container& value) + : container(std::make_shared(value)) + { + } + + explicit constant_aggregate(const Container&& value) + : container(std::make_shared(std::move(value))) + { + } + + constant_value& operator*() + { + return *this->container; + } + + constant_value& operator*() const + { + return *this->container; + } + + constant_value *operator->() + { + return this->container.get(); + } + + constant_value *operator->() const + { + return this->container.get(); + } + }; + /** * Called on-demand. */ diff --git a/include/elna/boot/name_analysis.h b/include/elna/boot/name_analysis.h index 68fe6da..a4f550d 100644 --- a/include/elna/boot/name_analysis.h +++ b/include/elna/boot/name_analysis.h @@ -130,8 +130,8 @@ namespace elna::boot std::pair> build_procedure( procedure_type_expression& expression); - std::vector build_composite_type(const std::vector& fields, - std::map& field_names, + ordered_map build_composite_type(const std::vector& fields, + ordered_map& field_names, const type& aggregate); std::shared_ptr register_variable(const std::string& name, const bool is_extern, const source_position position); diff --git a/include/elna/boot/result.h b/include/elna/boot/result.h index 328e44e..1f22baf 100644 --- a/include/elna/boot/result.h +++ b/include/elna/boot/result.h @@ -24,6 +24,9 @@ along with GCC; see the file COPYING3. If not see #include #include #include +#include +#include +#include namespace elna::boot { @@ -174,6 +177,134 @@ namespace elna::boot identifier m_identifier; bool m_exported{ false }; }; + + /** + * An associative container that contains key-value pairs with unique keys. + * Keys preserve the insertion order. + */ + template> + class ordered_map + { + using vector_alloc = std::allocator_traits::template + rebind_alloc>; + using map_alloc = std::allocator_traits::template + rebind_alloc>; + + std::unordered_map, std::equal_to<>, map_alloc> index_map; + std::vector, vector_alloc> payload; + + public: + using key_type = std::string; + using mapped_type = V; + using value_type = std::pair; + using iterator = std::vector::iterator; + using const_iterator = std::vector::const_iterator; + + /** + * Finds element with specific key. + * + * \param key Key value of the element to search for. + * \return An iterator to the requested element. If no such element is + * found, past-the-end (see #end()) iterator is returned. + */ + iterator find(const key_type& key) + { + auto search_result = this->index_map.find(key); + if (search_result == this->index_map.cend()) + { + return this->payload.end(); + } + else + { + return this->payload.at(search_result->second); + } + } + + /** + * \overload + */ + const_iterator find(const key_type& key) const + { + auto search_result = this->index_map.find(key); + if (search_result == this->index_map.cend()) + { + return this->payload.cend(); + } + else + { + return this->payload.at(search_result->second); + } + } + + /** + * Inserts elements. + * + * \param key Element key to insert. + * \param value Element value to insert. + * \return A pair consisting of an iterator to the inserted element (or + * to the element that prevented the insertion) and a \c bool + * value set to \c true if and only if the insertion took place. + */ + std::pair insert(const key_type& key, const mapped_type& value) + { + auto insert_result = this->index_map.emplace(key, this->payload.size()); + if (insert_result.second) + { + this->payload.emplace_back(key, value); + } + return { this->payload.begin() + insert_result.first->second, insert_result.second }; + } + + /** + * \overload + */ + std::pair insert(const key_type& key, mapped_type&& value) + { + auto insert_result = this->index_map.emplace(key, this->payload.size()); + if (insert_result.second) + { + this->payload.emplace_back(key, std::move(value)); + } + return { this->payload.begin() + insert_result.first->second, insert_result.second }; + } + + /** + * Returns an iterator to the beginning. + * + * \return Iterator to the first element. + */ + iterator begin() + { + return this->payload.begin(); + } + + /** + * \overload + */ + const_iterator begin() const + { + return this->payload.cbegin(); + } + + /** + * Returns an iterator to the end. + * + * \return Iterator to the element following the last element. + */ + iterator end() + { + return this->payload.end(); + } + + /** + * \overload + */ + const_iterator end() const + { + return this->payload.cend(); + } + }; } template<> diff --git a/include/elna/boot/symbol.h b/include/elna/boot/symbol.h index 4e97205..5b56904 100644 --- a/include/elna/boot/symbol.h +++ b/include/elna/boot/symbol.h @@ -132,7 +132,7 @@ namespace elna::boot struct record_type { - std::vector fields; + ordered_map fields; const type base; explicit record_type(type base = type()); @@ -201,21 +201,37 @@ namespace elna::boot { } + /** + * Returns an iterator to the beginning. + * + * \return Iterator to the first element. + */ iterator begin() { return this->entries.begin(); } - iterator end() + /** + * \overload + */ + const_iterator begin() const { - return this->entries.end(); + return this->entries.cbegin(); } - const_iterator begin() const + /** + * Returns an iterator to the end. + * + * \return Iterator to the element following the last element. + */ + iterator end() { - return this->entries.cbegin(); + return this->entries.end(); } + /** + * \overload + */ const_iterator end() const { return this->entries.cend(); diff --git a/include/elna/boot/type_check.h b/include/elna/boot/type_check.h index f95c72b..3a2b61d 100644 --- a/include/elna/boot/type_check.h +++ b/include/elna/boot/type_check.h @@ -225,6 +225,7 @@ namespace elna::boot * of type assignee. */ static bool is_assignable_from(const type& assignee, const type& assignment); + static bool is_equality_compatible(const type& left, const type& right); static bool check_unresolved_symbol(const std::shared_ptr& alias, std::vector& path); diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index 1ac829f..727c646 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -51,7 +51,11 @@ namespace elna::gcc tree make_if_branch(boot::conditional_statements& branch, tree next, tree goto_append = NULL_TREE); - tree build_equality_operation(boot::binary_expression *expression, tree left, tree right); + tree build_equality(boot::binary_expression *expression, tree left, tree right); + tree build_equality_comparison(location_t loc, tree left, tree right, + const boot::type& left_type, tree_code equality_code); + void build_case_integral(boot::case_statement *statement, tree condition_expression); + void build_case_general(boot::case_statement *statement, tree condition_expression); void build_procedure_call(location_t call_location, tree procedure_address, const std::vector& arguments); bool build_builtin_procedures(boot::procedure_call *call); -- cgit v1.2.3