A simple scripting language in C++
Ferenc Szontágh
2025-04-18 e2e9e07a9f50dc1f7a967280a3d1d8ef7fcaa153
add built-in modules
3 files modified
3 files added
4 files deleted
352 ■■■■ changed files
src/Builtins/BaseFunction.hpp 77 ●●●●● patch | view | raw | blame | history
src/Builtins/MathUtilsModule.hpp 28 ●●●●● patch | view | raw | blame | history
src/Builtins/PrintModule.hpp 44 ●●●●● patch | view | raw | blame | history
src/Builtins/SleepModule.hpp 43 ●●●●● patch | view | raw | blame | history
src/Interpreter/CallStatementNode.hpp 9 ●●●●● patch | view | raw | blame | history
src/Modules/BaseModule.hpp 27 ●●●●● patch | view | raw | blame | history
src/Modules/ModuleManager.hpp 82 ●●●●● patch | view | raw | blame | history
src/Modules/PrintModule.hpp 30 ●●●●● patch | view | raw | blame | history
src/VoidScript.hpp 6 ●●●●● patch | view | raw | blame | history
test_scripts/test2.vs 6 ●●●● patch | view | raw | blame | history
src/Builtins/BaseFunction.hpp
File was deleted
src/Builtins/MathUtilsModule.hpp
File was deleted
src/Builtins/PrintModule.hpp
File was deleted
src/Builtins/SleepModule.hpp
File was deleted
src/Interpreter/CallStatementNode.hpp
@@ -13,6 +13,7 @@
#include "Symbols/SymbolContainer.hpp"
#include "Symbols/SymbolFactory.hpp"
#include "Symbols/Value.hpp"
#include "Modules/ModuleManager.hpp"
namespace Interpreter {
@@ -39,6 +40,14 @@
            argValues.push_back(expr->evaluate(interpreter));
        }
        // Handle built-in function callbacks
        {
            auto &mgr = Modules::ModuleManager::instance();
            if (mgr.hasFunction(functionName_)) {
                mgr.callFunction(functionName_, argValues);
                return;
            }
        }
        // Lookup function symbol in functions namespace
        SymbolContainer * sc        = SymbolContainer::instance();
        const std::string currentNs = sc->currentScopeName();
src/Modules/BaseModule.hpp
New file
@@ -0,0 +1,27 @@
// BaseModule.hpp
#ifndef MODULES_BASEMODULE_HPP
#define MODULES_BASEMODULE_HPP
#include <string>
#include "Symbols/SymbolContainer.hpp"
#include "Symbols/SymbolFactory.hpp"
namespace Modules {
/**
 * @brief Base class for modules that can register functions and variables into the symbol table.
 */
class BaseModule {
  public:
    BaseModule() = default;
    virtual ~BaseModule() = default;
    /**
     * @brief Register this module's symbols (functions, variables) into the global symbol container.
     * Modules should use Symbols::SymbolContainer::instance() and SymbolFactory to add symbols.
     */
    virtual void registerModule() = 0;
};
} // namespace Modules
#endif // MODULES_BASEMODULE_HPP
src/Modules/ModuleManager.hpp
New file
@@ -0,0 +1,82 @@
// ModuleManager.hpp
#ifndef MODULES_MODULEMANAGER_HPP
#define MODULES_MODULEMANAGER_HPP
#include <memory>
#include <vector>
#include "BaseModule.hpp"
#include <functional>
#include <unordered_map>
#include "Symbols/Value.hpp"
namespace Modules {
/**
 * @brief Manager for registering and invoking modules.
 */
class ModuleManager {
  public:
    /**
     * @brief Get singleton instance of ModuleManager.
     */
    static ModuleManager &instance() {
        static ModuleManager mgr;
        return mgr;
    }
    /**
     * @brief Add a module to the manager.
     * @param module Unique pointer to a BaseModule.
     */
    void addModule(std::unique_ptr<BaseModule> module) {
        modules_.push_back(std::move(module));
    }
    /**
     * @brief Invoke all registered modules to register their symbols.
     */
    void registerAll() {
        for (const auto &module : modules_) {
            module->registerModule();
        }
    }
  private:
    ModuleManager() = default;
    std::vector<std::unique_ptr<BaseModule>> modules_;
    // Built-in function callbacks: name -> function
    std::unordered_map<std::string,
        std::function<Symbols::Value(const std::vector<Symbols::Value>&)>> callbacks_;
  public:
    /**
     * @brief Register a built-in function callback.
     * @param name Name of the function.
     * @param cb Callable taking argument values and returning a Value.
     */
    void registerFunction(const std::string &name,
                          std::function<Symbols::Value(const std::vector<Symbols::Value>&)> cb) {
        callbacks_[name] = std::move(cb);
    }
    /**
     * @brief Check if a built-in function is registered.
     */
    bool hasFunction(const std::string &name) const {
        return callbacks_.find(name) != callbacks_.end();
    }
    /**
     * @brief Call a built-in function callback.
     */
    Symbols::Value callFunction(const std::string &name,
                                const std::vector<Symbols::Value> &args) const {
        auto it = callbacks_.find(name);
        if (it == callbacks_.end()) {
            throw std::runtime_error("Built-in function callback not found: " + name);
        }
        return it->second(args);
    }
};
} // namespace Modules
#endif // MODULES_MODULEMANAGER_HPP
src/Modules/PrintModule.hpp
New file
@@ -0,0 +1,30 @@
// PrintModule.hpp
#ifndef MODULES_PRINTMODULE_HPP
#define MODULES_PRINTMODULE_HPP
#include <iostream>
#include "BaseModule.hpp"
#include "ModuleManager.hpp"
#include "Symbols/Value.hpp"
namespace Modules {
/**
 * @brief Module that provides a built-in print function.
 */
class PrintModule : public BaseModule {
  public:
    void registerModule() override {
        auto &mgr = ModuleManager::instance();
        mgr.registerFunction("print", [](const std::vector<Symbols::Value> &args) {
            for (const auto &v : args) {
                std::cout << Symbols::Value::to_string(v);
            }
            std::cout << std::endl;
            return Symbols::Value();
        });
    }
};
} // namespace Modules
#endif // MODULES_PRINTMODULE_HPP
src/VoidScript.hpp
@@ -7,6 +7,8 @@
#include "Interpreter/Interpreter.hpp"
#include "Lexer/Lexer.hpp"
#include "Parser/Parser.hpp"
#include "Modules/ModuleManager.hpp"
#include "Modules/PrintModule.hpp"
class VoidScript {
  private:
@@ -33,6 +35,8 @@
        lexer(std::make_shared<Lexer::Lexer>()),
        parser(std::make_shared<Parser::Parser>()) {
        // Register built-in modules (print, etc.)
        Modules::ModuleManager::instance().addModule(std::make_unique<Modules::PrintModule>());
        this->files.emplace(this->files.begin(), file);
        lexer->setKeyWords(Parser::Parser::keywords);
@@ -40,6 +44,8 @@
    int run() {
        try {
            // Register all built-in modules before execution
            Modules::ModuleManager::instance().registerAll();
            while (!files.empty()) {
                std::string       file         = files.back();
                const std::string file_content = readFile(file);
test_scripts/test2.vs
@@ -8,5 +8,9 @@
    int $result = $i + 1;
}
function increment = (int $i) int {
    return $i + 1;
}
test(5);
test(1);