A simple scripting language in C++
Ferenc Szontágh
2025-04-17 ba9a9199d01b0fdd4bf9a54914f8058bf71f30c5
src/Symbols/SymbolContainer.hpp
@@ -1,51 +1,141 @@
// SymbolContainer.hpp
#ifndef SYMBOL_CONTAINER_HPP
#define SYMBOL_CONTAINER_HPP
#include <memory>
#include <stdexcept>
#include <unordered_map>
#include "SymbolTable.hpp"
#define NSMGR Symbols::SymbolContainer::instance()
namespace Symbols {
class SymbolContainer {
    std::shared_ptr<SymbolTable> globalScope_;
    std::shared_ptr<SymbolTable> currentScope_;
    std::unordered_map<std::string, std::shared_ptr<SymbolTable>> scopes_;
    std::string                                                   currentScope_  = "global";
    std::string                                                   previousScope_ = "global";
public:
    SymbolContainer() {
        globalScope_ = std::make_shared<SymbolTable>();
        currentScope_ = globalScope_;
  public:
    static SymbolContainer * instance() {
        static SymbolContainer instance_;
        return &instance_;
    }
    void enterScope() {
        currentScope_ = std::make_shared<SymbolTable>(currentScope_);
    explicit SymbolContainer(const std::string & default_scope_name = "global") { create(default_scope_name); }
    // --- Scope management ---
    void create(const std::string & name) {
        scopes_[name]  = std::make_shared<SymbolTable>();
        previousScope_ = currentScope_;
        currentScope_  = name;
    }
    void leaveScope() {
        if (currentScope_->getParent()) {
            currentScope_ = currentScope_->getParent();
    void enter(const std::string & name) {
        if (scopes_.contains(name)) {
            previousScope_ = currentScope_;
            currentScope_  = name;
        } else {
            throw std::runtime_error("Scope does not exist: " + name);
        }
    }
    void define(const std::string& ns, const SymbolPtr& symbol) {
        currentScope_->define(ns, symbol);
    void enterPreviousScope() { currentScope_ = previousScope_; }
    [[nodiscard]] std::string currentScopeName() const { return currentScope_; }
    std::vector<std::string> getScopeNames() const {
        std::vector<std::string> result;
        result.reserve(scopes_.size());
        for (const auto & [scopeName, _] : scopes_) {
            result.push_back(scopeName);
        }
        return result;
    }
    SymbolPtr resolve(const std::string& ns, const std::string& name) const {
        return currentScope_->get(ns, name);
    // --- Symbol operations ---
    std::string add(const SymbolPtr & symbol) {
        const std::string ns = getNamespaceForSymbol(symbol);
        scopes_[currentScope_]->define(ns, symbol);
        return ns;
    }
    bool exists(const std::string& ns, const std::string& name) const {
        return currentScope_->exists(ns, name);
    std::vector<std::string> getNameSpaces(const std::string & scopeName) const {
        std::vector<std::string> result;
        auto                     it = scopes_.find(scopeName);
        if (it != scopes_.end()) {
            return it->second->listNSs();
        }
        return result;
    }
    std::vector<SymbolPtr> listNamespace(const std::string& ns) const {
        return currentScope_->listAll(ns);
    std::vector<SymbolPtr> getAll(const std::string & ns = "") const {
        std::vector<SymbolPtr> result;
        for (const auto & [_, table] : scopes_) {
            auto symbols = ns.empty() ? table->listAll() : table->listAll(ns);
            result.insert(result.end(), symbols.begin(), symbols.end());
        }
        return result;
    }
    std::shared_ptr<SymbolTable> getGlobalScope() const { return globalScope_; }
    std::shared_ptr<SymbolTable> getCurrentScope() const { return currentScope_; }
    bool exists(const std::string & name, std::string fullNamespace = "") const {
        if (fullNamespace.empty()) {
            fullNamespace = currentScope_;
        }
        for (const auto & [_, table] : scopes_) {
            if (table->exists(fullNamespace, name)) {
                return true;
            }
        }
        return false;
    }
    SymbolPtr get(const std::string & fullNamespace, const std::string & name) const {
        for (const auto & [_, table] : scopes_) {
            auto sym = table->get(fullNamespace, name);
            if (sym) {
                return sym;
            }
        }
        return nullptr;
    }
    static std::string dump() {
        std::string result = "";
        std::cout << "\n--- Defined Scopes ---" << '\n';
        for (const auto & scope_name : instance()->getScopeNames()) {
            result += scope_name + '\n';
            for (const auto & sname : instance()->getNameSpaces(scope_name)) {
                result += "\t -" + sname + '\n';
                for (const auto & symbol : instance()->getAll(sname)) {
                    result += symbol->dump() + '\n';
                }
            }
        }
        return result;
    }
  private:
    std::string getNamespaceForSymbol(const SymbolPtr & symbol) const {
        std::string base = symbol->context().empty() ? currentScope_ : symbol->context();
        switch (symbol->type()) {
            case Symbols::Kind::Variable:
                return base + ".variables";
            case Symbols::Kind::Function:
                return base + ".functions";
            case Symbols::Kind::Constant:
                return base + ".constants";
            default:
                return base + ".others";
        }
    }
};
} // namespace Symbols
}  // namespace Symbols
#endif