aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/elna/boot/dependency.h4
-rw-r--r--include/elna/boot/evaluator.h54
-rw-r--r--include/elna/boot/name_analysis.h4
-rw-r--r--include/elna/boot/result.h131
-rw-r--r--include/elna/boot/symbol.h26
-rw-r--r--include/elna/boot/type_check.h1
-rw-r--r--include/elna/gcc/elna-generic.h6
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);