A simple scripting language in C++
Ferenc Szontágh
2025-04-13 86904d513734134beffc29c6f4012d53a99f25c5
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
#ifndef SCRIPTINTERPRETERHELPERS_HPP
#define SCRIPTINTERPRETERHELPERS_HPP
 
#include <iostream>
#include <ostream>
#include <vector>
 
#include "ScriptExceptionMacros.h"
#include "Token.hpp"
#include "Value.hpp"
 
#define EXPECT_SEMICOLON(tokens, i, message) \
    ScriptInterpreterHelpers::expectSemicolon(tokens, i, message, __FILE__, __LINE__)
 
namespace ScriptInterpreterHelpers {
 
static std::string extractSubstring(const std::string & str, size_t start, size_t end) {
    if (start >= 0 && start < str.length() && end >= start && end < str.length()) {
        return str.substr(start, end - start + 1);
    }
    return "";
}
 
static void expectSemicolon(const std::vector<Token> & tokens, std::size_t & i, const std::string & message,
                            const std::string & file = __FILE__, int line = __LINE__) {
    if (i >= tokens.size() || tokens[i].type != TokenType::Semicolon) {
        THROW_UNEXPECTED_TOKEN_ERROR_HELPER(tokens[i - 1], "; " + message, file, line);
    }
    i++;  // Skip ';'
}
 
[[nodiscard]] static std::vector<Value> parseFunctionDeclarationArguments(const std::vector<Token> & tokens,
                                                                          std::size_t &              i,
                                                                          const std::string &        file = __FILE__,
                                                                          int                        line = __LINE__) {
    std::vector<Value> arguments;
 
    // check the arguments types
    if (tokens[i].type != TokenType::StringDeclaration && tokens[i].type != TokenType::BooleanDeclaration &&
        tokens[i].type != TokenType::IntDeclaration && tokens[i].type != TokenType::DoubleDeclaration) {
        THROW_UNEXPECTED_TOKEN_ERROR_HELPER(tokens[i], "variable declaration", file, line);
    }
    const auto parameter_type = getVariableTypeFromTokenTypeDeclaration(tokens[i].type);
    if (parameter_type == Variables::Type::VT_NOT_DEFINED) {
        THROW_UNEXPECTED_TOKEN_ERROR_HELPER(tokens[i], "valid type identifier", file, line);
    }
 
    if (parameter_type == Variables::Type::VT_FUNCTION) {
        THROW_UNEXPECTED_TOKEN_ERROR_HELPER(tokens[i], "valid type identifier", file, line);
    }
 
    if (parameter_type == Variables::Type::VT_NULL) {
        THROW_UNEXPECTED_TOKEN_ERROR_HELPER(tokens[i], "valid type identifier", file, line);
    }
 
    Value val;
    val.type  = parameter_type;
    val.token = tokens[i];
 
    arguments.emplace_back(std::move(val));
    i++;  // Skip variable declaration
 
    if (tokens[i].type != TokenType::RightParenthesis) {
        THROW_UNEXPECTED_TOKEN_ERROR_HELPER(tokens[i], ") - Only one argument is allowed", file, line);
    }
    i++;  // Skip ')'
 
    return arguments;
}
 
[[nodiscard]] static std::string getFunctionBody(const std::vector<Token> & tokens, std::size_t & i) {
    const size_t first_index = i;
    if (i >= tokens.size() || tokens[i].type != TokenType::LeftCurlyBracket) {
        THROW_UNEXPECTED_TOKEN_ERROR(tokens[i], "{");
    }
    i++;  // Skip '{'
    std::string lines;
 
    while (i < tokens.size() && tokens[i].type != TokenType::RightCurlyBracket) {
        if (tokens[i].type == TokenType::EndOfLine) {
            lines += "\n";
            i++;
            continue;
        }
        if (tokens[i].type == TokenType::EndOfFile) {
            throw std::runtime_error("Unexpected end of file");
            break;
        }
        lines += tokens[i].lexeme + " ";
        i++;
    }
 
    if (i >= tokens.size() || tokens[i].type != TokenType::RightCurlyBracket) {
        THROW_UNEXPECTED_TOKEN_ERROR(tokens[i], "}");
    }
    return lines;
};
 
};  // namespace ScriptInterpreterHelpers
 
#endif  // SCRIPTINTERPRETERHELPERS_HPP