#ifndef SYMBOL_TABLE_HPP #define SYMBOL_TABLE_HPP #include <language/ast/ASTNodeDataType.hpp> #include <language/utils/DataVariant.hpp> #include <language/utils/EmbedderTable.hpp> #include <language/utils/FunctionTable.hpp> #include <utils/PugsMacros.hpp> #include <pegtl/position.hpp> #include <iostream> class TypeDescriptor; class IBuiltinFunctionEmbedder; class SymbolTable { public: class Attributes { private: TAO_PEGTL_NAMESPACE::position m_position; int32_t m_context_id; bool m_is_initialized{false}; ASTNodeDataType m_data_type; DataVariant m_value; public: bool hasLocalContext() const { return m_context_id != -1; } const int32_t& contextId() const { return m_context_id; } auto& value() { return m_value; } const auto& value() const { return m_value; } const bool& isInitialized() const { return m_is_initialized; } void setIsInitialized() { m_is_initialized = true; } const ASTNodeDataType& dataType() const { return m_data_type; } auto position() const { return m_position; } void setDataType(const ASTNodeDataType& data_type) { Assert(m_data_type == ASTNodeDataType::undefined_t, "data type has already been defined!"); m_data_type = data_type; } friend std::ostream& operator<<(std::ostream& os, const Attributes& attributes) { os << rang::fg::green; if (attributes.m_data_type == ASTNodeDataType::function_t) { os << "function_id"; } else { os << dataTypeName(attributes.dataType()); } os << rang::style::reset << ':' << attributes.m_value; return os; } Attributes(const TAO_PEGTL_NAMESPACE::position& position, int32_t context_id) : m_position{position}, m_context_id{context_id} {} Attributes(const Attributes&) = default; }; class Symbol // LCOV_EXCL_LINE { private: std::string m_name; Attributes m_attributes; public: PUGS_INLINE const std::string& name() const { return m_name; } PUGS_INLINE const Attributes& attributes() const { return m_attributes; } PUGS_INLINE Attributes& attributes() { return m_attributes; } Symbol(const std::string& name, const Attributes& attributes) : m_name(name), m_attributes(attributes) {} Symbol& operator=(Symbol&&) = default; Symbol& operator=(const Symbol&) = default; Symbol(const Symbol&) = default; Symbol(Symbol&&) = default; ~Symbol() = default; }; class Context { private: inline static int32_t next_context_id{0}; int32_t m_id; size_t m_size{0}; public: PUGS_INLINE int32_t id() const { return m_id; } PUGS_INLINE size_t size() const { return m_size; } PUGS_INLINE size_t getNextSymbolId() { return m_size++; } Context() : m_id{next_context_id++} {} Context& operator=(const Context&) = default; // clazy:exclude=function-args-by-value Context& operator=(Context&&) = default; Context(const Context&) = default; Context(Context&&) = default; ~Context() = default; }; private: std::vector<Symbol> m_symbol_list; std::shared_ptr<SymbolTable> m_parent_table; std::shared_ptr<Context> m_context; std::shared_ptr<FunctionTable> m_function_table; std::shared_ptr<EmbedderTable<IBuiltinFunctionEmbedder>> m_builtin_function_embedder_table; std::shared_ptr<EmbedderTable<TypeDescriptor>> m_type_embedder_table; public: bool hasContext() const { return bool{m_context}; } const Context& context() const { Assert(m_context); return *m_context; } const FunctionTable& functionTable() const { Assert(m_function_table); return *m_function_table; } FunctionTable& functionTable() { Assert(m_function_table); return *m_function_table; } const auto& builtinFunctionEmbedderTable() const { Assert(m_builtin_function_embedder_table); return *m_builtin_function_embedder_table; } auto& builtinFunctionEmbedderTable() { Assert(m_builtin_function_embedder_table); return *m_builtin_function_embedder_table; } auto& typeEmbedderTable() { Assert(m_type_embedder_table); return *m_type_embedder_table; } const auto& typeEmbedderTable() const { Assert(m_type_embedder_table); return *m_type_embedder_table; } friend std::ostream& operator<<(std::ostream& os, const SymbolTable& symbol_table) { os << "-- Symbol table state -- parent : " << symbol_table.m_parent_table.get() << "\n"; for (auto i_symbol : symbol_table.m_symbol_list) { if (i_symbol.attributes().dataType() != ASTNodeDataType::builtin_function_t) { os << ' ' << i_symbol.name() << ": " << std::boolalpha << i_symbol.attributes() << '\n'; } } os << "------------------------\n"; return os; } void clearValues() { for (auto& symbol : m_symbol_list) { std::visit( [](auto&& value) { using T = std::decay_t<decltype(value)>; value = T{}; }, symbol.attributes().value()); } } auto find(const std::string& symbol, const TAO_PEGTL_NAMESPACE::position& use_position) { auto i_symbol = m_symbol_list.end(); for (auto i_stored_symbol = m_symbol_list.begin(); i_stored_symbol != m_symbol_list.end(); ++i_stored_symbol) { if (i_stored_symbol->name() == symbol) { i_symbol = i_stored_symbol; break; } } if (i_symbol != m_symbol_list.end() and (use_position.byte >= i_symbol->attributes().position().byte)) { return std::make_pair(i_symbol, true); } else { if (m_parent_table) { return m_parent_table->find(symbol, use_position); } else { return std::make_pair(i_symbol, false); } } } auto add(const std::string& symbol_name, const TAO_PEGTL_NAMESPACE::position& symbol_position) { for (auto i_stored_symbol = m_symbol_list.begin(); i_stored_symbol != m_symbol_list.end(); ++i_stored_symbol) { if (i_stored_symbol->name() == symbol_name) { return std::make_pair(i_stored_symbol, false); } } int32_t context_id = this->hasContext() ? m_context->id() : -1; auto i_symbol = m_symbol_list.emplace(m_symbol_list.end(), Symbol{symbol_name, Attributes{symbol_position, context_id}}); if (this->hasContext()) { i_symbol->attributes().value() = m_context->getNextSymbolId(); } return std::make_pair(i_symbol, true); } SymbolTable(const std::shared_ptr<SymbolTable>& parent_table, const std::shared_ptr<Context>& context) : m_parent_table{parent_table}, m_context{context}, m_function_table{parent_table->m_function_table}, m_builtin_function_embedder_table{parent_table->m_builtin_function_embedder_table}, m_type_embedder_table{parent_table->m_type_embedder_table} { ; } SymbolTable(const std::shared_ptr<SymbolTable>& parent_table) : SymbolTable{parent_table, parent_table->m_context} { ; } SymbolTable() : m_parent_table{nullptr}, m_context{nullptr}, m_function_table{std::make_shared<FunctionTable>()}, m_builtin_function_embedder_table{std::make_shared<EmbedderTable<IBuiltinFunctionEmbedder>>()}, m_type_embedder_table{std::make_shared<EmbedderTable<TypeDescriptor>>()} { ; } }; #endif // SYMBOL_TABLE_HPP