aboutsummaryrefslogtreecommitdiff
path: root/include/elna/boot/symbol.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/elna/boot/symbol.h')
-rw-r--r--include/elna/boot/symbol.h457
1 files changed, 457 insertions, 0 deletions
diff --git a/include/elna/boot/symbol.h b/include/elna/boot/symbol.h
new file mode 100644
index 0000000..5ef917e
--- /dev/null
+++ b/include/elna/boot/symbol.h
@@ -0,0 +1,457 @@
+/* Symbol definitions.
+ 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 <unordered_map>
+#include <string>
+#include <memory>
+#include <vector>
+#include <forward_list>
+
+#include "elna/boot/result.h"
+
+namespace elna::boot
+{
+ class alias_type;
+ class primitive_type;
+ class record_type;
+ class union_type;
+ class pointer_type;
+ class array_type;
+ class procedure_type;
+ class enumeration_type;
+
+ class type
+ {
+ enum class type_tag
+ {
+ empty,
+ alias,
+ primitive,
+ record,
+ _union,
+ pointer,
+ array,
+ procedure,
+ enumeration
+ };
+ type_tag tag{ type_tag::empty };
+ union
+ {
+ std::weak_ptr<alias_type> alias;
+ std::shared_ptr<primitive_type> primitive;
+ std::shared_ptr<record_type> record;
+ std::shared_ptr<union_type> _union;
+ std::shared_ptr<pointer_type> pointer;
+ std::shared_ptr<array_type> array;
+ std::shared_ptr<procedure_type> procedure;
+ std::shared_ptr<enumeration_type> enumeration;
+ };
+
+ void copy(const type& other);
+ void move(type&& other);
+
+ public:
+ type();
+ explicit type(std::shared_ptr<alias_type> alias);
+ explicit type(std::shared_ptr<primitive_type> primitive);
+ explicit type(std::shared_ptr<record_type> record);
+ explicit type(std::shared_ptr<union_type> _union);
+ explicit type(std::shared_ptr<pointer_type> pointer);
+ explicit type(std::shared_ptr<array_type> array);
+ explicit type(std::shared_ptr<procedure_type> procedure);
+ explicit type(std::shared_ptr<enumeration_type> enumeration);
+
+ type(const type& other);
+ type& operator=(const type& other);
+
+ type(type&& other);
+ type& operator=(type&& other);
+
+ bool operator==(const std::nullptr_t&);
+
+ ~type();
+
+ template<typename T>
+ std::shared_ptr<T> get() const;
+
+ bool empty() const;
+ };
+
+ struct alias_type
+ {
+ const std::string name;
+ type reference;
+
+ explicit alias_type(const std::string& name);
+ };
+
+ struct pointer_type
+ {
+ const type base;
+
+ explicit pointer_type(type base);
+ };
+
+ struct array_type
+ {
+ const type base;
+ const std::uint64_t size;
+
+ array_type(type base, std::uint64_t size);
+ };
+
+ struct primitive_type
+ {
+ const std::string identifier;
+
+ explicit primitive_type(const std::string& identifier);
+ };
+
+ using type_field = std::pair<std::string, type>;
+
+ struct record_type
+ {
+ std::vector<type_field> fields;
+ };
+
+ struct union_type
+ {
+ std::vector<type_field> fields;
+ };
+
+ struct procedure_type
+ {
+ using return_t = return_declaration<type>;
+
+ std::vector<type> parameters;
+ const return_t return_type;
+
+ procedure_type(return_t return_type = return_t());
+ };
+
+ struct enumeration_type
+ {
+ std::vector<std::string> members;
+
+ explicit enumeration_type(const std::vector<std::string>& members);
+ };
+
+ class type_info;
+ class procedure_info;
+ class constant_info;
+ class variable_info;
+
+ class info : public std::enable_shared_from_this<info>
+ {
+ public:
+ bool exported{ false };
+
+ virtual ~info() = 0;
+
+ virtual std::shared_ptr<type_info> is_type();
+ virtual std::shared_ptr<procedure_info> is_procedure();
+ virtual std::shared_ptr<constant_info> is_constant();
+ virtual std::shared_ptr<variable_info> is_variable();
+ };
+
+ /**
+ * Symbol table.
+ */
+ template<typename T, typename U, U nothing>
+ class symbol_map
+ {
+ public:
+ using symbol_ptr = typename std::enable_if<
+ std::is_convertible<U, T>::value || std::is_assignable<T, U>::value,
+ T
+ >::type;
+ using iterator = typename std::unordered_map<std::string, symbol_ptr>::iterator;
+ using const_iterator = typename std::unordered_map<std::string, symbol_ptr>::const_iterator;
+
+ private:
+ std::unordered_map<std::string, symbol_ptr> entries;
+ std::shared_ptr<symbol_map> outer_scope;
+
+ public:
+ /**
+ * Constructs a new symbol with an optional outer scope.
+ *
+ * \param scope Outer scope.
+ */
+ explicit symbol_map(std::shared_ptr<symbol_map> scope = nullptr)
+ : outer_scope(scope)
+ {
+ }
+
+ iterator begin()
+ {
+ return this->entries.begin();
+ }
+
+ iterator end()
+ {
+ return this->entries.end();
+ }
+
+ const_iterator cbegin() const
+ {
+ return this->entries.cbegin();
+ }
+
+ const_iterator cend() const
+ {
+ return this->entries.cend();
+ }
+
+ /**
+ * \return Symbol count in the current scope.
+ */
+ std::size_t size() const
+ {
+ return this->entries.size();
+ }
+
+ /**
+ * Looks for symbol in the table by name. Returns nothing if the symbol
+ * can not be found.
+ *
+ * \param name Symbol name.
+ *
+ * \return Symbol from the table if found.
+ */
+ symbol_ptr lookup(const std::string& name)
+ {
+ auto entry = entries.find(name);
+
+ if (entry != entries.cend())
+ {
+ return entry->second;
+ }
+ if (this->outer_scope != nullptr)
+ {
+ return this->outer_scope->lookup(name);
+ }
+ return nothing;
+ }
+
+ /**
+ * \param name Symbol name.
+ *
+ * \return Whether the table contains a symbol with the given name.
+ */
+ bool contains(const std::string& name)
+ {
+ return lookup(name) != nothing;
+ }
+
+ /**
+ * Registers new symbol.
+ *
+ * \param name Symbol name.
+ * \param entry Symbol information.
+ *
+ * \return Whether the insertion took place.
+ */
+ bool enter(const std::string& name, symbol_ptr entry)
+ {
+ return lookup(name) == nothing && entries.insert({ name, entry }).second;
+ }
+
+ /**
+ * Returns the outer scope or nullptr if the this is the global scope.
+ *
+ * \return Outer scope.
+ */
+ std::shared_ptr<symbol_map> scope()
+ {
+ return this->outer_scope;
+ }
+ };
+
+ using symbol_table = symbol_map<std::shared_ptr<info>, std::nullptr_t, nullptr>;
+ using forward_table = std::unordered_map<std::string, std::shared_ptr<alias_type>>;
+
+ class type_info : public info
+ {
+ public:
+ const type symbol;
+
+ explicit type_info(const type symbol);
+ std::shared_ptr<type_info> is_type() override;
+ };
+
+ /**
+ * Procedure symbol information.
+ */
+ class procedure_info : public info
+ {
+ public:
+ /// Procedure type.
+ const procedure_type symbol;
+
+ /// Parameter names.
+ const std::vector<std::string> names;
+
+ /// Local definitions.
+ std::shared_ptr<symbol_table> scope;
+
+ /**
+ * Constructs procedure symbol information.
+ *
+ * \param symbol Procedure type.
+ * \param names Parameter names.
+ * \param scope Local definition (is `nullptr` for extern symbols).
+ */
+ procedure_info(const procedure_type symbol, const std::vector<std::string> names,
+ std::shared_ptr<symbol_table> scope = nullptr);
+
+ std::shared_ptr<procedure_info> is_procedure() override;
+
+ /**
+ * \return Whether this is an extern symbol.
+ */
+ bool is_extern() const;
+ };
+
+ class constant_info : public info
+ {
+ public:
+ using variant = typename
+ std::variant<std::int32_t, std::uint32_t, double, bool, unsigned char, std::nullptr_t, std::string>;
+
+ const variant symbol;
+
+ explicit constant_info(const variant& symbol);
+ std::shared_ptr<constant_info> is_constant() override;
+ };
+
+ /**
+ * Variable symbol information.
+ */
+ class variable_info : public info
+ {
+ public:
+ /// Variable type.
+ const type symbol;
+
+ /// Whether this is an extern symbol.
+ const bool is_extern;
+
+ /**
+ * Constructs a variable symbol information.
+ *
+ * \param symbol Variable type.
+ * \param is_extern Whether this is an extern symbol.
+ */
+ variable_info(const type symbol, bool is_extern);
+
+ std::shared_ptr<variable_info> is_variable() override;
+ };
+
+ std::shared_ptr<symbol_table> builtin_symbol_table();
+
+ /**
+ * Symbol bag contains:
+ *
+ * - the symbol table of a module itself
+ * - symbol tables of imported modules
+ * - forward declarations
+ */
+ class symbol_bag
+ {
+ std::shared_ptr<symbol_table> symbols;
+ std::forward_list<std::shared_ptr<symbol_table>> imports;
+ forward_table unresolved;
+
+ public:
+
+ /**
+ * \param unresolved Forward declarations collected in the previous step.
+ * \param global_table Global symbols.
+ */
+ symbol_bag(forward_table&& unresolved, std::shared_ptr<symbol_table> global_table);
+
+ /**
+ * Looks up a symbol in the current and imported modules.
+ *
+ * \param name Symbol name to look up.
+ *
+ * \return Symbol from one of the symbol tables if found.
+ */
+ std::shared_ptr<info> lookup(const std::string& name);
+
+ /**
+ * Inserts a symbol into the current scope.
+ *
+ * \param name Symbol name.
+ * \param entry Symbol info.
+ *
+ * \return Whether the insertion took place.
+ */
+ bool enter(const std::string& name, std::shared_ptr<info> entry);
+
+ /**
+ * Enters a new scope.
+ *
+ * \return Reference to the allocated scope.
+ */
+ std::shared_ptr<symbol_table> enter();
+
+ /**
+ * Sets the current scope to \a child.
+ *
+ * \param child New scope.
+ */
+ void enter(std::shared_ptr<symbol_table> child);
+
+ /**
+ * Leave the current scope.
+ *
+ * \return Left scope.
+ */
+ std::shared_ptr<symbol_table> leave();
+
+ /**
+ * Checks whether there is a forward declaration \a symbol_name and
+ * returns it if so.
+ *
+ * \param symbol_name Type name to look up.
+ * \return Forward declaration or `nullptr` if the symbol is not declared.
+ */
+ std::shared_ptr<alias_type> declared(const std::string& symbol_name);
+
+ /**
+ * Completes the forward-declared type \a symbol_name and defines it to
+ * be \a resolution.
+ *
+ * \param symbol_name Type name.
+ * \param resolution Type definition.
+ * \return Alias to the defined type.
+ */
+ std::shared_ptr<alias_type> resolve(const std::string& symbol_name, type& resolution);
+
+ /**
+ * Add imported symbols to the scope.
+ *
+ * \param bag Symbol bag of another module.
+ */
+ void add_import(const symbol_bag& bag);
+ };
+}