A simple scripting language in C++
Ferenc Szontágh
2025-04-19 c8f8dbada301cd66d8c40cd0bd8ea0e8ae669644
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
// StringModule.hpp
#ifndef MODULES_STRINGMODULE_HPP
#define MODULES_STRINGMODULE_HPP
 
#include <string>
#include <vector>
#include <stdexcept>
#include "Modules/BaseModule.hpp"
#include "Modules/ModuleManager.hpp"
#include "Symbols/Value.hpp"
#include "Symbols/VariableTypes.hpp"
 
namespace Modules {
 
/**
 * @brief Module providing string helper functions.
 * Functions:
 *   string_length(string $in) -> length of the string
 *   string_replace(string $in, string $from, string $to, bool $replace_all)
 *   string_substr(string $in, int from, int length) -> substring
 */
class StringModule : public BaseModule {
 public:
    void registerModule() override {
        auto &mgr = ModuleManager::instance();
        // string_length
        mgr.registerFunction("string_length", [](const std::vector<Symbols::Value> &args) {
            using namespace Symbols;
            if (args.size() != 1) {
                throw std::runtime_error("string_length expects exactly one argument");
            }
            if (args[0].getType() != Variables::Type::STRING) {
                throw std::runtime_error("string_length expects a string argument");
            }
            const std::string &s = args[0].get<std::string>();
            return Value(static_cast<int>(s.size()));
        });
        // string_replace
        mgr.registerFunction("string_replace", [](const std::vector<Symbols::Value> &args) {
            using namespace Symbols;
            if (args.size() != 4) {
                throw std::runtime_error("string_replace expects 4 arguments");
            }
            if (args[0].getType() != Variables::Type::STRING ||
                args[1].getType() != Variables::Type::STRING ||
                args[2].getType() != Variables::Type::STRING ||
                args[3].getType() != Variables::Type::BOOLEAN) {
                throw std::runtime_error("string_replace argument types must be (string, string, string, boolean)");
            }
            std::string in = args[0].get<std::string>();
            const std::string &from = args[1].get<std::string>();
            const std::string &to = args[2].get<std::string>();
            bool replace_all = args[3].get<bool>();
            if (from.empty()) {
                throw std::runtime_error("string_replace: 'from' cannot be empty");
            }
            size_t pos = 0;
            if (replace_all) {
                while ((pos = in.find(from, pos)) != std::string::npos) {
                    in.replace(pos, from.length(), to);
                    pos += to.length();
                }
            } else {
                pos = in.find(from);
                if (pos != std::string::npos) {
                    in.replace(pos, from.length(), to);
                }
            }
            return Value(in);
        });
        // string_substr
        mgr.registerFunction("string_substr", [](const std::vector<Symbols::Value> &args) {
            using namespace Symbols;
            if (args.size() != 3) {
                throw std::runtime_error("string_substr expects 3 arguments");
            }
            if (args[0].getType() != Variables::Type::STRING ||
                args[1].getType() != Variables::Type::INTEGER ||
                args[2].getType() != Variables::Type::INTEGER) {
                throw std::runtime_error("string_substr argument types must be (string, int, int)");
            }
            const std::string &s = args[0].get<std::string>();
            int from = args[1].get<int>();
            int length = args[2].get<int>();
            if (from < 0 || length < 0) {
                throw std::runtime_error("string_substr: 'from' and 'length' must be non-negative");
            }
            size_t pos = static_cast<size_t>(from);
            if (pos > s.size()) {
                throw std::runtime_error("string_substr: 'from' out of range");
            }
            size_t len = static_cast<size_t>(length);
            std::string sub = s.substr(pos, len);
            return Value(sub);
        });
    }
};
 
} // namespace Modules
 
#endif // MODULES_STRINGMODULE_HPP