A simple scripting language in C++
Ferenc Szontágh
2025-04-18 17b3739f756a1e713704b22cce89307308cea2d8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#ifndef SYMBOL_CONTAINER_HPP
#define SYMBOL_CONTAINER_HPP
 
#include <iostream>
#include <memory>
#include <stdexcept>
#include <unordered_map>
 
#include "SymbolTable.hpp"
 
#define NSMGR Symbols::SymbolContainer::instance()
 
namespace Symbols {
 
class SymbolContainer {
    std::unordered_map<std::string, std::shared_ptr<SymbolTable>> scopes_;
    std::string                                                   currentScope_  = "global";
    std::string                                                   previousScope_ = "global";
 
  public:
    static SymbolContainer * instance() {
        static SymbolContainer instance_;
        return &instance_;
    }
 
    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 enter(const std::string & name) {
        auto it = scopes_.find(name);
        if (it != scopes_.end()) {
            previousScope_ = currentScope_;
            currentScope_  = name;
        } else {
            throw std::runtime_error("Scope does not exist: " + name);
        }
    }
 
    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;
    }
 
    // --- Symbol operations ---
 
    std::string add(const SymbolPtr & symbol) {
        const std::string ns = getNamespaceForSymbol(symbol);
        scopes_[currentScope_]->define(ns, symbol);
        return ns;
    }
 
    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> 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;
    }
 
    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->getKind()) {
            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
 
#endif