-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvm.cpp
More file actions
166 lines (154 loc) · 7.57 KB
/
vm.cpp
File metadata and controls
166 lines (154 loc) · 7.57 KB
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#include <ranges>
#include <vector>
#include <iostream>
#include <type_traits>
#include "bc_def.hpp"
#include "expr_engine.hpp"
using namespace std;
int executor(vector<Instr> bc) {
vector<itx_types> stack;
vector<unordered_map<string, itx_types>> scope{{}};
int currentScope{};
int lastPos;
auto findVar = [&](const string& varName) {
lastPos=0;
for (auto lastScope = scope.begin(); lastScope != scope.end(); ++lastScope) {
if (lastScope->contains(varName)) {
lastPos = static_cast<int>(std::distance(scope.begin(), lastScope));
return true;
}
}
return false;
};
auto getVar = [&](const string& varName) {
for (auto& lastScope : std::ranges::reverse_view(scope)) if (lastScope.contains(varName)) return lastScope[varName];
return itx_types{varName};
};
for (const auto& symbol : compile_time_constants) scope[0].insert(symbol);
cout << boolalpha;
int i{};
itx_types operand1, operand2;
while (i < bc.size()) {
operand1 = stack.size() == 2 ? stack[0] : "";
operand2 = stack.size() == 2 ? stack[1] : "";
switch (auto b = bc[i]; b.code) {
case PULL: stack.push_back(getVar(get<string>(b.value))); break;
case PUSH: stack.push_back(b.value); break;
case STORE:
if (compile_time_constants.contains(std::get<string>(b.value))) callErr("Cannot re-assign a constant", -1);
if (findVar(std::get<string>(b.value))) scope[lastPos][std::get<string>(b.value)] = stack.back();
else scope[currentScope].insert({get<string>(b.value), stack.back()});
stack.clear();
break;
case LOOP_START:
case IF_TRUE:
if (holds_alternative<string>(b.value) && get<string>(b.value) == "table") {
if (!holds_alternative<bool>(stack.back())) {cerr << "Expected a boolean but didn't receive one\n"; return 1;}
if (!get<bool>(stack.back())) {i = b.jump; continue;}
}
else { if (!get<bool>(b.value)) {i = b.jump; continue;} }
if (b.code == LOOP_START) stack.clear();
scope.emplace_back();
currentScope++;
break;
case LOOP_END:
case FORCE_JUMP: i = b.jump; goto skip_itr;
case MATH_:
// checks for variables
if (holds_alternative<string>(operand1)) operand1 = getVar(get<string>(operand1));
if (holds_alternative<string>(operand2)) operand2 = getVar(std::get<string>(operand2));
visit([b, &stack](auto&& op1, auto&& op2) {
using L = decay_t<decltype(op1)>;
using R = decay_t<decltype(op2)>;
if constexpr (is_same_v<L, int> && is_same_v<R, float>) op1 = static_cast<float>(op1);
if constexpr (is_same_v<R, int> && is_same_v<L, float>) op2 = static_cast<float>(op2);
stack.clear();
if constexpr (is_same_v<L, R>)
switch (b.sub_code) {
case ADD: stack.emplace_back(op1 + op2); break;
case SUB:
if constexpr (is_same_v<L, string>) callErr("Could not perform a subtraction between two strings", -1);
else stack.emplace_back(op1 - op2);
break;
case DIV:
if constexpr (is_same_v<L, string>) callErr("Could not perform division between two strings", -1);
else stack.emplace_back(op1 / op2);
break;
case MOD:
if constexpr (is_same_v<L, string>) callErr("Could not perform modulo between two strings", -1);
else stack.emplace_back(static_cast<float>(std::fmod(op1, op2)));
break;
default:
if constexpr (is_same_v<L, string>) callErr("Could not perform multiplication between two strings", -1);
else stack.emplace_back(op1 * op2);
break;
}
}, operand1, operand2);
break;
case OR:
case AND:
if (!holds_alternative<bool>(stack.front()) || !holds_alternative<bool>(stack.back())) callErr("Didn't find a boolean in a boolean expression\n", -1);
stack.clear();
stack.emplace_back(b.code == OR ? get<bool>(stack.front()) || get<bool>(stack.back()) : get<bool>(stack.front()) && get<bool>(stack.back()));
break;
case IS_EQUAL_TO: {
auto res = visit([](auto&& front, auto&& back) {
using L = decay_t<decltype(&front)>;
using R = decay_t<decltype(&back)>;
if constexpr (is_same_v<L, int*> && is_same_v<R, float*>) front = static_cast<float>(front);
if constexpr (is_same_v<R, int*> && is_same_v<L, float*>) back = static_cast<float>(back);
if constexpr (is_same_v<L, R>) return front == back;
else return false;
}, stack.front(), stack.back());
stack.clear();
stack.emplace_back(res);
}
break;
case GREATER_THAN: {
bool res = visit([b](auto&& front, auto&& back) {
using L = decay_t<decltype(&front)>;
using R = decay_t<decltype(&back)>;
if constexpr (is_same_v<L, int> && is_same_v<R, float>) front = static_cast<float>(front);
if constexpr (is_same_v<R, int> && is_same_v<L, float>) back = static_cast<float>(back);
if constexpr ((!is_same_v<L, float*> || !is_same_v<R, float*>) && (!is_same_v<L, int*> || !is_same_v<R, int*>)) callErr("Could not do greater than (>/>=) between non-floats or non-ints", -1); else
if (b.sub_code != IS_EQUAL) return front > back; else return front >= back;
return false; // Yes, I know it's unreachable, but it prevents an error
}, stack.front(), stack.back());
stack.clear();
stack.emplace_back(res);
}
break;
case LESS_THAN: {
bool res = visit([b](auto&& front, auto&& back) {
using L = std::decay_t<decltype(&front)>;
using R = std::decay_t<decltype(&back)>;
if constexpr (is_same_v<L, int> && is_same_v<R, float>) front = static_cast<float>(front);
if constexpr (is_same_v<R, int> && is_same_v<L, float>) back = static_cast<float>(back);
if constexpr ((std::is_same_v<L, float*> && std::is_same_v<R, float*>) || (std::is_same_v<L, int*> && std::is_same_v<R, int*>)) {
if (b.sub_code != IS_EQUAL)return front < back;
return front <= back;
} else callErr("Could not do less than (</<=) between non-floats or non-ints", -1);
return false;
}, stack.front(), stack.back());
stack.clear();
stack.emplace_back(res);
}
break;
case PRINT:
if (holds_alternative<string>(b.value) && get<string>(b.value) == "table") {
visit([](auto&& val) {cout << val << endl;}, stack.back());
stack.clear();
} else visit([](auto&& val) {cout << val << endl;}, b.value);
break;
case SCOPE_END:
scope.pop_back();
currentScope--;
break;
case EXPR_START: break; // Jump labels will do nothing
default: return 0;
}
i++;
skip_itr:;
}
return 0;
}