diff options
Diffstat (limited to 'include/elna/boot/symbol.h')
| -rw-r--r-- | include/elna/boot/symbol.h | 457 |
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); + }; +} |
