diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/elna/boot/dependency.h | 4 | ||||
| -rw-r--r-- | include/elna/boot/evaluator.h | 54 | ||||
| -rw-r--r-- | include/elna/boot/name_analysis.h | 4 | ||||
| -rw-r--r-- | include/elna/boot/result.h | 131 | ||||
| -rw-r--r-- | include/elna/boot/symbol.h | 26 | ||||
| -rw-r--r-- | include/elna/boot/type_check.h | 1 | ||||
| -rw-r--r-- | include/elna/gcc/elna-generic.h | 6 |
7 files changed, 208 insertions, 18 deletions
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 <cstdint> #include <map> +#include <memory> #include <optional> #include <string> #include <variant> @@ -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<template<typename, typename> typename C, template<typename> 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<ordered_map>, + constant_aggregate<std::vector> >; + template<template<typename, typename> typename C, template<typename> typename Alloc> + class constant_aggregate + { + using Container = C<constant_value, Alloc<constant_value>>; + std::shared_ptr<Container> container; + + public: + explicit constant_aggregate(const Container& value) + : container(std::make_shared<Container>(value)) + { + } + + explicit constant_aggregate(const Container&& value) + : container(std::make_shared<Container>(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<procedure_type, std::vector<std::string>> build_procedure( procedure_type_expression& expression); - std::vector<type_field> build_composite_type(const std::vector<field_declaration>& fields, - std::map<std::string, field_origin>& field_names, + ordered_map<type> build_composite_type(const std::vector<field_declaration>& fields, + ordered_map<field_origin>& field_names, const type& aggregate); std::shared_ptr<variable_info> 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 <optional> #include <utility> #include <variant> +#include <vector> +#include <unordered_map> +#include <ranges> 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<typename V, typename Alloc = std::allocator<V>> + class ordered_map + { + using vector_alloc = std::allocator_traits<Alloc>::template + rebind_alloc<std::pair<std::string, V>>; + using map_alloc = std::allocator_traits<Alloc>::template + rebind_alloc<std::pair<const std::string, std::size_t>>; + + std::unordered_map<std::string, std::size_t, + std::hash<std::string>, std::equal_to<>, map_alloc> index_map; + std::vector<std::pair<std::string, V>, vector_alloc> payload; + + public: + using key_type = std::string; + using mapped_type = V; + using value_type = std::pair<key_type, mapped_type>; + using iterator = std::vector<value_type>::iterator; + using const_iterator = std::vector<value_type>::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<iterator, bool> 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<iterator, bool> 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<type_field> fields; + ordered_map<type> 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_type>& alias, std::vector<std::string>& 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<boot::expression *>& arguments); bool build_builtin_procedures(boot::procedure_call *call); |
