Phasor 3.3.0
Stack VM based Programming Language
Loading...
Searching...
No Matches
Operations.cpp
Go to the documentation of this file.
1#ifndef CMAKE_PCH
2#include "VM.hpp" // avoid breaking IDEs
3#endif
4#include <phsint.hpp>
5
6namespace Phasor
7{
8
10{
11#if defined(__GNUC__) || defined(__clang__)
12#pragma GCC diagnostic push
13#pragma GCC diagnostic ignored "-Wpedantic"
14
15 if (pc >= m_bytecode->instructions.size()) return;
16
17#ifdef TRACING
18#define TRACE_INSTR(_op) \
19 do { \
20 log(std::format("\nVM::evalLoop(): RUN (pc={})\n", pc - 1)); \
21 log(std::format("VM::evalLoop({}, {}, {}, {})\n", \
22 opCodeToString(_op), operand1, operand2, operand3)); \
23 flush(); \
24 } while (0)
25#else
26#define TRACE_INSTR(_op) do {} while (0)
27#endif
28
29 static constexpr unsigned TABLE_SIZE = 512;
30 static void* s_table[TABLE_SIZE];
31 static bool s_ready = false;
32
33 if (!s_ready) [[unlikely]]
34 {
35 for (auto& e : s_table) e = &&LABEL_UNKNOWN;
36
37 s_table[(unsigned)OpCode::JUMP] = &&LABEL_JUMP;
38 s_table[(unsigned)OpCode::CALL] = &&LABEL_CALL;
39 s_table[(unsigned)OpCode::RETURN] = &&LABEL_RETURN;
40 s_table[(unsigned)OpCode::CALL_NATIVE] = &&LABEL_CALL_NATIVE;
41 s_table[(unsigned)OpCode::JUMP_IF_FALSE] = &&LABEL_JUMP_IF_FALSE;
42 s_table[(unsigned)OpCode::JUMP_IF_TRUE] = &&LABEL_JUMP_IF_TRUE;
43 s_table[(unsigned)OpCode::JUMP_BACK] = &&LABEL_JUMP_BACK;
44 s_table[(unsigned)OpCode::IMPORT] = &&LABEL_IMPORT;
45 s_table[(unsigned)OpCode::HALT] = &&LABEL_HALT;
46
47 s_table[(unsigned)OpCode::PUSH_CONST] = &&LABEL_PUSH_CONST;
48 s_table[(unsigned)OpCode::POP] = &&LABEL_POP;
49 s_table[(unsigned)OpCode::STORE_VAR] = &&LABEL_STORE_VAR;
50 s_table[(unsigned)OpCode::LOAD_VAR] = &&LABEL_LOAD_VAR;
51 s_table[(unsigned)OpCode::TRUE_P] = &&LABEL_TRUE_P;
52 s_table[(unsigned)OpCode::FALSE_P] = &&LABEL_FALSE_P;
53 s_table[(unsigned)OpCode::NULL_VAL] = &&LABEL_NULL_VAL;
54
55 s_table[(unsigned)OpCode::IADD] = &&LABEL_IADD;
56 s_table[(unsigned)OpCode::ISUBTRACT] = &&LABEL_ISUBTRACT;
57 s_table[(unsigned)OpCode::IMULTIPLY] = &&LABEL_IMULTIPLY;
58 s_table[(unsigned)OpCode::IDIVIDE] = &&LABEL_IDIVIDE;
59 s_table[(unsigned)OpCode::IMODULO] = &&LABEL_IMODULO;
60 s_table[(unsigned)OpCode::FLADD] = &&LABEL_FLADD;
61 s_table[(unsigned)OpCode::FLSUBTRACT] = &&LABEL_FLSUBTRACT;
62 s_table[(unsigned)OpCode::FLMULTIPLY] = &&LABEL_FLMULTIPLY;
63 s_table[(unsigned)OpCode::FLDIVIDE] = &&LABEL_FLDIVIDE;
64 s_table[(unsigned)OpCode::FLMODULO] = &&LABEL_FLMODULO;
65 s_table[(unsigned)OpCode::SQRT] = &&LABEL_SQRT;
66 s_table[(unsigned)OpCode::POW] = &&LABEL_POW;
67 s_table[(unsigned)OpCode::LOG] = &&LABEL_LOG;
68 s_table[(unsigned)OpCode::EXP] = &&LABEL_EXP;
69 s_table[(unsigned)OpCode::SIN] = &&LABEL_SIN;
70 s_table[(unsigned)OpCode::COS] = &&LABEL_COS;
71 s_table[(unsigned)OpCode::TAN] = &&LABEL_TAN;
72
73 s_table[(unsigned)OpCode::NEGATE] = &&LABEL_NEGATE;
74 s_table[(unsigned)OpCode::NOT] = &&LABEL_NOT;
75 s_table[(unsigned)OpCode::IAND] = &&LABEL_IAND;
76 s_table[(unsigned)OpCode::IOR] = &&LABEL_IOR;
77 s_table[(unsigned)OpCode::IEQUAL] = &&LABEL_IEQUAL;
78 s_table[(unsigned)OpCode::INOT_EQUAL] = &&LABEL_INOT_EQUAL;
79 s_table[(unsigned)OpCode::ILESS_THAN] = &&LABEL_ILESS_THAN;
80 s_table[(unsigned)OpCode::IGREATER_THAN] = &&LABEL_IGREATER_THAN;
81 s_table[(unsigned)OpCode::ILESS_EQUAL] = &&LABEL_ILESS_EQUAL;
82 s_table[(unsigned)OpCode::IGREATER_EQUAL] = &&LABEL_IGREATER_EQUAL;
83 s_table[(unsigned)OpCode::FLAND] = &&LABEL_FLAND;
84 s_table[(unsigned)OpCode::FLOR] = &&LABEL_FLOR;
85 s_table[(unsigned)OpCode::FLEQUAL] = &&LABEL_FLEQUAL;
86 s_table[(unsigned)OpCode::FLNOT_EQUAL] = &&LABEL_FLNOT_EQUAL;
87 s_table[(unsigned)OpCode::FLLESS_THAN] = &&LABEL_FLLESS_THAN;
88 s_table[(unsigned)OpCode::FLGREATER_THAN] = &&LABEL_FLGREATER_THAN;
89 s_table[(unsigned)OpCode::FLLESS_EQUAL] = &&LABEL_FLLESS_EQUAL;
90 s_table[(unsigned)OpCode::FLGREATER_EQUAL] = &&LABEL_FLGREATER_EQUAL;
91
92 s_table[(unsigned)OpCode::PRINT] = &&LABEL_PRINT;
93 s_table[(unsigned)OpCode::PRINTERROR] = &&LABEL_PRINTERROR;
94 s_table[(unsigned)OpCode::READLINE] = &&LABEL_READLINE;
95
96 s_table[(unsigned)OpCode::SYSTEM] = &&LABEL_SYSTEM;
97 s_table[(unsigned)OpCode::SYSTEM_OUT] = &&LABEL_SYSTEM_OUT;
98 s_table[(unsigned)OpCode::SYSTEM_ERR] = &&LABEL_SYSTEM_ERR;
99
100 s_table[(unsigned)OpCode::LEN] = &&LABEL_LEN;
101 s_table[(unsigned)OpCode::CHAR_AT] = &&LABEL_CHAR_AT;
102 s_table[(unsigned)OpCode::SUBSTR] = &&LABEL_SUBSTR;
103
104 s_table[(unsigned)OpCode::NEW_STRUCT_INSTANCE_STATIC] = &&LABEL_NEW_STRUCT_INSTANCE_STATIC;
105 s_table[(unsigned)OpCode::GET_FIELD_STATIC] = &&LABEL_GET_FIELD_STATIC;
106 s_table[(unsigned)OpCode::SET_FIELD_STATIC] = &&LABEL_SET_FIELD_STATIC;
107 s_table[(unsigned)OpCode::NEW_STRUCT] = &&LABEL_NEW_STRUCT;
108 s_table[(unsigned)OpCode::SET_FIELD] = &&LABEL_SET_FIELD;
109 s_table[(unsigned)OpCode::GET_FIELD] = &&LABEL_GET_FIELD;
110
111 s_table[(unsigned)OpCode::MOV] = &&LABEL_MOV;
112 s_table[(unsigned)OpCode::LOAD_CONST_R] = &&LABEL_LOAD_CONST_R;
113 s_table[(unsigned)OpCode::LOAD_VAR_R] = &&LABEL_LOAD_VAR_R;
114 s_table[(unsigned)OpCode::STORE_VAR_R] = &&LABEL_STORE_VAR_R;
115 s_table[(unsigned)OpCode::PUSH_R] = &&LABEL_PUSH_R;
116 s_table[(unsigned)OpCode::PUSH2_R] = &&LABEL_PUSH2_R;
117 s_table[(unsigned)OpCode::POP_R] = &&LABEL_POP_R;
118 s_table[(unsigned)OpCode::POP2_R] = &&LABEL_POP2_R;
119
120 s_table[(unsigned)OpCode::IADD_R] = &&LABEL_IADD_R;
121 s_table[(unsigned)OpCode::ISUB_R] = &&LABEL_ISUB_R;
122 s_table[(unsigned)OpCode::IMUL_R] = &&LABEL_IMUL_R;
123 s_table[(unsigned)OpCode::IDIV_R] = &&LABEL_IDIV_R;
124 s_table[(unsigned)OpCode::IMOD_R] = &&LABEL_IMOD_R;
125 s_table[(unsigned)OpCode::FLADD_R] = &&LABEL_FLADD_R;
126 s_table[(unsigned)OpCode::FLSUB_R] = &&LABEL_FLSUB_R;
127 s_table[(unsigned)OpCode::FLMUL_R] = &&LABEL_FLMUL_R;
128 s_table[(unsigned)OpCode::FLDIV_R] = &&LABEL_FLDIV_R;
129 s_table[(unsigned)OpCode::FLMOD_R] = &&LABEL_FLMOD_R;
130 s_table[(unsigned)OpCode::SQRT_R] = &&LABEL_SQRT_R;
131 s_table[(unsigned)OpCode::POW_R] = &&LABEL_POW_R;
132 s_table[(unsigned)OpCode::LOG_R] = &&LABEL_LOG_R;
133 s_table[(unsigned)OpCode::EXP_R] = &&LABEL_EXP_R;
134 s_table[(unsigned)OpCode::SIN_R] = &&LABEL_SIN_R;
135 s_table[(unsigned)OpCode::COS_R] = &&LABEL_COS_R;
136 s_table[(unsigned)OpCode::TAN_R] = &&LABEL_TAN_R;
137
138 s_table[(unsigned)OpCode::NEG_R] = &&LABEL_NEG_R;
139 s_table[(unsigned)OpCode::NOT_R] = &&LABEL_NOT_R;
140 s_table[(unsigned)OpCode::IEQ_R] = &&LABEL_IEQ_R;
141 s_table[(unsigned)OpCode::INE_R] = &&LABEL_INE_R;
142 s_table[(unsigned)OpCode::ILT_R] = &&LABEL_ILT_R;
143 s_table[(unsigned)OpCode::IGT_R] = &&LABEL_IGT_R;
144 s_table[(unsigned)OpCode::ILE_R] = &&LABEL_ILE_R;
145 s_table[(unsigned)OpCode::IGE_R] = &&LABEL_IGE_R;
146 s_table[(unsigned)OpCode::IAND_R] = &&LABEL_IAND_R;
147 s_table[(unsigned)OpCode::IOR_R] = &&LABEL_IOR_R;
148 s_table[(unsigned)OpCode::FLEQ_R] = &&LABEL_FLEQ_R;
149 s_table[(unsigned)OpCode::FLNE_R] = &&LABEL_FLNE_R;
150 s_table[(unsigned)OpCode::FLLT_R] = &&LABEL_FLLT_R;
151 s_table[(unsigned)OpCode::FLGT_R] = &&LABEL_FLGT_R;
152 s_table[(unsigned)OpCode::FLLE_R] = &&LABEL_FLLE_R;
153 s_table[(unsigned)OpCode::FLGE_R] = &&LABEL_FLGE_R;
154 s_table[(unsigned)OpCode::FLAND_R] = &&LABEL_FLAND_R;
155 s_table[(unsigned)OpCode::FLOR_R] = &&LABEL_FLOR_R;
156
157 s_table[(unsigned)OpCode::PRINT_R] = &&LABEL_PRINT_R;
158 s_table[(unsigned)OpCode::PRINTERROR_R] = &&LABEL_PRINTERROR_R;
159 s_table[(unsigned)OpCode::READLINE_R] = &&LABEL_READLINE_R;
160
161 s_table[(unsigned)OpCode::SYSTEM_R] = &&LABEL_SYSTEM_R;
162 s_table[(unsigned)OpCode::SYSTEM_OUT_R] = &&LABEL_SYSTEM_OUT_R;
163 s_table[(unsigned)OpCode::SYSTEM_ERR_R] = &&LABEL_SYSTEM_ERR_R;
164
165 s_ready = true;
166 }
167
168 int operand1 = 0, operand2 = 0, operand3 = 0;
169 u8 rA = 0, rB = 0, rC = 0;
170
171#define NEXT() \
172 do { \
173 if (pc >= m_bytecode->instructions.size()) [[unlikely]] return; \
174 { \
175 const Instruction& _i = m_bytecode->instructions[pc++]; \
176 operand1 = _i.operand1; \
177 operand2 = _i.operand2; \
178 operand3 = _i.operand3; \
179 rA = static_cast<u8>(operand1); \
180 rB = static_cast<u8>(operand2); \
181 rC = static_cast<u8>(operand3); \
182 TRACE_INSTR(_i.op); \
183 const unsigned _op = static_cast<unsigned>(_i.op); \
184 goto *(_op < TABLE_SIZE ? s_table[_op] : &&LABEL_UNKNOWN); \
185 } \
186 } while (0)
187
188 NEXT();
189
190
191 LABEL_JUMP:
192 {
193#ifdef TRACING
194 log(std::format("JUMP: {} -> {}\n", pc - 1, operand1));
195 flush();
196#endif
197 pc = operand1;
198 NEXT();
199 }
200
201 LABEL_CALL:
202 {
203 {
204 Value funcNameVal = m_bytecode->constants[operand1];
205 std::string funcName = funcNameVal.asString();
206 auto it = m_bytecode->functionEntries.find(funcName);
207 if (it == m_bytecode->functionEntries.end())
208 throw std::runtime_error("Unknown function: " + funcName);
209#ifdef TRACING
210 log(std::format("CALL: {} -> {}: {}\n", pc - 1, funcName, it->second));
211 flush();
212#endif
213 callStack.push_back(static_cast<int>(pc));
214 pc = it->second;
215 }
216 NEXT();
217 }
218
219 LABEL_RETURN:
220 {
221 if (isDirectCall)
222 {
223 pc = 0;
224 throw VM::Halt();
225 }
226 if (callStack.empty()) [[unlikely]]
227 {
228 pc = m_bytecode->instructions.size();
229 throw std::runtime_error("Cannot return from outside a function");
230 }
231#ifdef TRACING
232 log(std::format("RETURN: {} -> {}\n", pc - 1, callStack.back()));
233 flush();
234#endif
235 pc = callStack.back();
236 callStack.pop_back();
237 NEXT();
238 }
239
240 LABEL_CALL_NATIVE:
241 {
242 {
243 Value funcNameVal = m_bytecode->constants[operand1];
244 std::string funcName = funcNameVal.asString();
245 auto it = nativeFunctions.find(funcName);
246 if (it == nativeFunctions.end())
247 throw std::runtime_error("Unknown native function: " + funcName);
248
249 int argCount = static_cast<int>(pop().asInt());
250 std::vector<Value> args(argCount);
251 for (int i = argCount - 1; i >= 0; --i)
252 args[i] = pop();
253
254#ifdef TRACING
255 std::string argsText;
256 for (auto& arg : args)
257 {
258 argsText += std::format("{:T}", arg);
259 if (arg != args.back()) argsText += ", ";
260 }
261 log(std::format("CALL_NATIVE: {}({})\n", funcName, argsText));
262 flush();
263#endif
264 push(it->second(args, this));
265 }
266 NEXT();
267 }
268
269 LABEL_JUMP_IF_FALSE:
270 {
271#ifdef TRACING
272 log(std::format("JUMP_IF_FALSE: {} {} -> {}\n",
273 peek().isTruthy() ? "TRUE" : "FALSE", pc - 1, operand1));
274 flush();
275#endif
276 if (!pop().isTruthy()) pc = operand1;
277 NEXT();
278 }
279
280 LABEL_JUMP_IF_TRUE:
281 {
282#ifdef TRACING
283 log(std::format("JUMP_IF_TRUE: {} {} -> {}\n",
284 peek().isTruthy() ? "TRUE" : "FALSE", pc - 1, operand1));
285 flush();
286#endif
287 if (pop().isTruthy()) pc = operand1;
288 NEXT();
289 }
290
291 LABEL_JUMP_BACK:
292 {
293#ifdef TRACING
294 log(std::format("JUMP_BACK: {} -> {}\n", pc - 1, operand1));
295 flush();
296#endif
297 pc = operand1;
298 NEXT();
299 }
300
301 LABEL_IMPORT:
302 {
303 {
304 Value pathVal = m_bytecode->constants[operand1];
305 std::string path = pathVal.asString();
306 if (importHandler)
307 importHandler(path);
308 else
309 throw std::runtime_error("Import handler not set");
310 }
311 NEXT();
312 }
313
314 LABEL_HALT:
315 {
316 pc = m_bytecode->instructions.size();
317 throw VM::Halt();
318 }
319
320 LABEL_PUSH_CONST:
321 {
322 if (operand1 < 0 || operand1 >= static_cast<int>(m_bytecode->constants.size()))
323 throw std::runtime_error("Invalid constant index");
324 push(m_bytecode->constants[operand1]);
325 NEXT();
326 }
327
328 LABEL_POP:
329 {
330 pop();
331 NEXT();
332 }
333
334 LABEL_STORE_VAR:
335 {
336 if (operand1 < 0 || operand1 >= static_cast<int>(variables.size()))
337 throw std::runtime_error("Invalid variable index");
338 variables[operand1] = pop();
339 NEXT();
340 }
341
342 LABEL_LOAD_VAR:
343 {
344 if (operand1 < 0 || operand1 >= static_cast<int>(variables.size()))
345 throw std::runtime_error("Invalid variable index");
346 push(variables[operand1]);
347 NEXT();
348 }
349
350 LABEL_TRUE_P: { push(Value(true)); NEXT(); }
351 LABEL_FALSE_P: { push(Value(false)); NEXT(); }
352 LABEL_NULL_VAL: { push(Value()); NEXT(); }
353
354 // STACK ARITHMETIC
355
356 LABEL_IADD: { { Value b = pop(), a = pop(); push(asm_iadd(a.asInt(), b.asInt())); } NEXT(); }
357 LABEL_ISUBTRACT: { { Value b = pop(), a = pop(); push(asm_isub(a.asInt(), b.asInt())); } NEXT(); }
358 LABEL_IMULTIPLY: { { Value b = pop(), a = pop(); push(asm_imul(a.asInt(), b.asInt())); } NEXT(); }
359 LABEL_IDIVIDE: { { Value b = pop(), a = pop(); push(asm_idiv(a.asInt(), b.asInt())); } NEXT(); }
360 LABEL_IMODULO: { { Value b = pop(), a = pop(); push(asm_imod(a.asInt(), b.asInt())); } NEXT(); }
361 LABEL_FLADD: { { Value b = pop(), a = pop(); push(asm_fladd(a.asFloat(), b.asFloat())); } NEXT(); }
362 LABEL_FLSUBTRACT:{ { Value b = pop(), a = pop(); push(asm_flsub(a.asFloat(), b.asFloat())); } NEXT(); }
363 LABEL_FLMULTIPLY:{ { Value b = pop(), a = pop(); push(asm_flmul(a.asFloat(), b.asFloat())); } NEXT(); }
364 LABEL_FLDIVIDE: { { Value b = pop(), a = pop(); push(asm_fldiv(a.asFloat(), b.asFloat())); } NEXT(); }
365 LABEL_FLMODULO: { { Value b = pop(), a = pop(); push(asm_flmod(a.asFloat(), b.asFloat())); } NEXT(); }
366 LABEL_SQRT: { push(asm_sqrt(pop().asFloat())); NEXT(); }
367 LABEL_POW: { { Value b = pop(), a = pop(); push(asm_pow(a.asFloat(), b.asFloat())); } NEXT(); }
368 LABEL_LOG: { push(asm_log(pop().asFloat())); NEXT(); }
369 LABEL_EXP: { push(asm_exp(pop().asFloat())); NEXT(); }
370 LABEL_SIN: { push(asm_sin(pop().asFloat())); NEXT(); }
371 LABEL_COS: { push(asm_cos(pop().asFloat())); NEXT(); }
372 LABEL_TAN: { push(asm_tan(pop().asFloat())); NEXT(); }
373
374 // STACK LOGICAL
375
376 LABEL_NEGATE: { push(asm_flneg(pop().asFloat())); NEXT(); }
377 LABEL_NOT: { push(Value(asm_flnot(pop().isTruthy() ? 1 : 0))); NEXT(); }
378
379 LABEL_IAND: { { Value b=pop(),a=pop(); push(Value(asm_iand(a.isTruthy()?1:0, b.isTruthy()?1:0))); } NEXT(); }
380 LABEL_IOR: { { Value b=pop(),a=pop(); push(Value(asm_ior (a.isTruthy()?1:0, b.isTruthy()?1:0))); } NEXT(); }
381
382 LABEL_IEQUAL: { { Value b=pop(),a=pop(); push(a.isInt()&&b.isInt() ? Value(asm_iequal(a.asInt(),b.asInt())) : Value(a==b)); } NEXT(); }
383 LABEL_INOT_EQUAL: { { Value b=pop(),a=pop(); push(a.isInt()&&b.isInt() ? Value(asm_inot_equal(a.asInt(),b.asInt())) : Value(a!=b)); } NEXT(); }
384 LABEL_ILESS_THAN: { { Value b=pop(),a=pop(); push(a.isInt()&&b.isInt() ? Value(asm_iless_than(a.asInt(),b.asInt())) : Value(a< b)); } NEXT(); }
385 LABEL_IGREATER_THAN: { { Value b=pop(),a=pop(); push(a.isInt()&&b.isInt() ? Value(asm_igreater_than(a.asInt(),b.asInt())) : Value(a> b)); } NEXT(); }
386 LABEL_ILESS_EQUAL: { { Value b=pop(),a=pop(); push(a.isInt()&&b.isInt() ? Value(asm_iless_equal(a.asInt(),b.asInt())) : Value(a<=b)); } NEXT(); }
387 LABEL_IGREATER_EQUAL: { { Value b=pop(),a=pop(); push(a.isInt()&&b.isInt() ? Value(asm_igreater_equal(a.asInt(),b.asInt())) : Value(a>=b)); } NEXT(); }
388
389 LABEL_FLAND: { { Value b=pop(),a=pop(); push(Value(asm_fland(a.isTruthy()?1:0, b.isTruthy()?1:0))); } NEXT(); }
390 LABEL_FLOR: { { Value b=pop(),a=pop(); push(Value(asm_flor (a.isTruthy()?1:0, b.isTruthy()?1:0))); } NEXT(); }
391 LABEL_FLEQUAL: { { Value b=pop(),a=pop(); push(a.isFloat()&&b.isFloat() ? Value(asm_flequal(a.asFloat(),b.asFloat())) : Value(a==b)); } NEXT(); }
392 LABEL_FLNOT_EQUAL: { { Value b=pop(),a=pop(); push(a.isFloat()&&b.isFloat() ? Value(asm_flnot_equal(a.asFloat(),b.asFloat())) : Value(a!=b)); } NEXT(); }
393 LABEL_FLLESS_THAN: { { Value b=pop(),a=pop(); push(a.isFloat()&&b.isFloat() ? Value(asm_flless_than(a.asFloat(),b.asFloat())) : Value(a< b)); } NEXT(); }
394 LABEL_FLGREATER_THAN: { { Value b=pop(),a=pop(); push(a.isFloat()&&b.isFloat() ? Value(asm_flgreater_than(a.asFloat(),b.asFloat())) : Value(a> b)); } NEXT(); }
395 LABEL_FLLESS_EQUAL: { { Value b=pop(),a=pop(); push(a.isFloat()&&b.isFloat() ? Value(asm_flless_equal(a.asFloat(),b.asFloat())) : Value(a<=b)); } NEXT(); }
396 LABEL_FLGREATER_EQUAL:{ { Value b=pop(),a=pop(); push(a.isFloat()&&b.isFloat() ? Value(asm_flgreater_equal(a.asFloat(),b.asFloat())) : Value(a>=b)); } NEXT(); }
397
398 // STACK I/O
399
400 LABEL_PRINT:
401 {
402 {
403 Value v = pop();
404 std::string s = v.toString();
405#ifdef TRACING
406 log(std::format("PRINT: (stdout) {:T}\n", v));
407#else
408 c_print_stdout(s.c_str(), (i64)s.length());
409#endif
410 flush();
411 }
412 NEXT();
413 }
414
415 LABEL_PRINTERROR:
416 {
417 {
418 Value v = pop();
419 std::string s = v.toString();
420#ifdef TRACING
421 log(std::format("PRINTERROR: (stderr) {:T}\n", v));
422#else
423 c_print_stderr(s.c_str(), (i64)s.length());
424#endif
425 flusherr();
426 }
427 NEXT();
428 }
429
430 LABEL_READLINE:
431 {
432 {
433 std::string s;
434#ifdef TRACING
435 log("READLINE:");
436 flush();
437#endif
438 std::getline(std::cin, s);
439#ifdef TRACING
440 log(std::format("\nREADLINE: {}\n", s));
441#endif
442 push(s);
443 }
444 NEXT();
445 }
446
447 // STACK SYSTEM
448
449 LABEL_SYSTEM:
450 {
451#ifdef SANDBOXED
452 logerr("CANNOT ESCAPE SANDBOX");
453 push(Value());
454#else
455 {
456#ifdef TRACING
457 Value cmd = pop();
458 int ret = c_system(cmd.c_str());
459 log(std::format("SYSTEM: {:T} -> {}\n", cmd, ret));
460 push(ret);
461#else
462 push(c_system(pop().c_str()));
463#endif
464 }
465#endif
466 NEXT();
467 }
468
469 LABEL_SYSTEM_OUT:
470 {
471#ifdef SANDBOXED
472 logerr("CANNOT ESCAPE SANDBOX");
473 push(Value());
474#else
475 {
476#ifdef TRACING
477 Value cmd = pop();
478 std::string ret = c_system_out(cmd.c_str());
479 log(std::format("SYSTEM_OUT: {:T} -> {}\n", cmd, ret));
480 push(ret);
481#else
482 push(c_system_out(pop().c_str()));
483#endif
484 }
485#endif
486 NEXT();
487 }
488
489 LABEL_SYSTEM_ERR:
490 {
491#ifdef SANDBOXED
492 logerr("CANNOT ESCAPE SANDBOX");
493 push(Value());
494#else
495 {
496#ifdef TRACING
497 Value cmd = pop();
498 std::string ret = c_system_err(cmd.c_str());
499 log(std::format("SYSTEM_ERR: {:T} -> {}\n", cmd, ret));
500 push(ret);
501#else
502 push(c_system_err(pop().c_str()));
503#endif
504 }
505#endif
506 NEXT();
507 }
508
509
510 // STACK STRING
511
512
513 LABEL_LEN:
514 {
515 {
516 Value v = pop();
517 if (v.isArray())
518 {
519 push(Value(static_cast<i64>(v.asArray()->size())));
520 }
521 else
522 {
523 push(Value(static_cast<i64>(v.asString().length())));
524 }
525 }
526 NEXT();
527 }
528
529 LABEL_CHAR_AT:
530 {
531 {
532 Value idxVal = pop();
533 Value strVal = pop();
534 std::string s;
535 if (strVal.isString()) s = strVal.asString();
536 else s = strVal.toString();
537
538 i64 idx = 0;
539 if (idxVal.isInt()) idx = idxVal.asInt();
540 else if (idxVal.isFloat()) idx = static_cast<i64>(idxVal.asFloat());
541 else if (idxVal.isString())
542 {
543 try { idx = std::stoll(idxVal.asString()); }
544 catch (...) { throw std::runtime_error("char_at() expects index convertible to integer"); }
545 }
546 else throw std::runtime_error("char_at() expects string and integer");
547
548 if (idx < 0 || idx >= static_cast<i64>(s.length()))
549 push(Value(""));
550 else
551 push(Value(std::string(1, s[static_cast<size_t>(idx)])));
552 }
553 NEXT();
554 }
555
556 LABEL_SUBSTR:
557 {
558 {
559 Value lenVal = pop();
560 Value startVal = pop();
561 Value strVal = pop();
562 if (strVal.isString() && startVal.isInt() && lenVal.isInt())
563 {
564 const std::string& s = strVal.asString();
565 i64 start = startVal.asInt();
566 i64 len = lenVal.asInt();
567 if (start < 0 || start >= static_cast<i64>(s.length()))
568 push(Value(""));
569 else
570 push(Value(s.substr(start, len)));
571 }
572 else
573 {
574 throw std::runtime_error("substr() expects string, int, int");
575 }
576 }
577 NEXT();
578 }
579
580
581 // STACK STRUCT
582
583
584 LABEL_NEW_STRUCT_INSTANCE_STATIC:
585 {
586 {
587 if (operand1 < 0 || operand1 >= static_cast<int>(m_bytecode->structs.size()))
588 throw std::runtime_error("Invalid struct index for NEW_STRUCT_INSTANCE_STATIC");
589 const StructInfo& info = m_bytecode->structs[operand1];
590 Value instance = Value::createStruct(info.name);
591 for (int i = 0; i < info.fieldCount; ++i)
592 {
593 int constIndex = info.firstConstIndex + i;
594 if (constIndex < 0 || constIndex >= static_cast<int>(m_bytecode->constants.size()))
595 throw std::runtime_error("Invalid default constant index for struct field");
596 instance.setField(info.fieldNames[i], m_bytecode->constants[constIndex]);
597 }
598 push(instance);
599 }
600 NEXT();
601 }
602
603 LABEL_GET_FIELD_STATIC:
604 {
605 {
606 if (operand1 < 0 || operand1 >= static_cast<int>(m_bytecode->structs.size()))
607 throw std::runtime_error("Invalid struct index for GET_FIELD_STATIC");
608 const StructInfo& info = m_bytecode->structs[operand1];
609 int fieldOffset = operand2;
610 if (fieldOffset < 0 || fieldOffset >= info.fieldCount)
611 throw std::runtime_error("Invalid field offset for GET_FIELD_STATIC");
612 Value obj = pop();
613 push(obj.getField(info.fieldNames[fieldOffset]));
614 }
615 NEXT();
616 }
617
618 LABEL_SET_FIELD_STATIC:
619 {
620 {
621 if (operand1 < 0 || operand1 >= static_cast<int>(m_bytecode->structs.size()))
622 throw std::runtime_error("Invalid struct index for SET_FIELD_STATIC");
623 const StructInfo& info = m_bytecode->structs[operand1];
624 int fieldOffset = operand2;
625 if (fieldOffset < 0 || fieldOffset >= info.fieldCount)
626 throw std::runtime_error("Invalid field offset for SET_FIELD_STATIC");
627 Value value = pop();
628 Value obj = pop();
629 obj.setField(info.fieldNames[fieldOffset], value);
630 push(obj);
631 }
632 NEXT();
633 }
634
635 LABEL_NEW_STRUCT:
636 {
637 if (operand1 < 0 || operand1 >= static_cast<int>(m_bytecode->constants.size()))
638 throw std::runtime_error("Invalid constant index for NEW_STRUCT");
639 push(Value::createStruct(m_bytecode->constants[operand1].asString()));
640 NEXT();
641 }
642
643 LABEL_SET_FIELD:
644 {
645 {
646 if (operand1 < 0 || operand1 >= static_cast<int>(m_bytecode->constants.size()))
647 throw std::runtime_error("Invalid constant index for SET_FIELD");
648 std::string fieldName = m_bytecode->constants[operand1].asString();
649 Value value = pop();
650 Value obj = pop();
651 obj.setField(fieldName, value);
652 push(obj);
653 }
654 NEXT();
655 }
656
657 LABEL_GET_FIELD:
658 {
659 {
660 if (operand1 < 0 || operand1 >= static_cast<int>(m_bytecode->constants.size()))
661 throw std::runtime_error("Invalid constant index for GET_FIELD");
662 Value obj = pop();
663 push(obj.getField(m_bytecode->constants[operand1].asString()));
664 }
665 NEXT();
666 }
667
668
669 // REGISTER CORE
670
671
672 LABEL_MOV: { registers[rA] = registers[rB]; NEXT(); }
673
674 LABEL_LOAD_CONST_R:
675 {
676 int constIndex = operand2;
677 if (constIndex < 0 || constIndex >= static_cast<int>(m_bytecode->constants.size()))
678 throw std::runtime_error("Invalid constant index");
679 registers[rA] = m_bytecode->constants[constIndex];
680 NEXT();
681 }
682
683 LABEL_LOAD_VAR_R:
684 {
685 int varIndex = operand2;
686 if (varIndex < 0 || varIndex >= static_cast<int>(variables.size()))
687 throw std::runtime_error("Invalid variable index");
688 registers[rA] = variables[varIndex];
689 NEXT();
690 }
691
692 LABEL_STORE_VAR_R:
693 {
694 int varIndex = operand2;
695 if (varIndex < 0 || varIndex >= static_cast<int>(variables.size()))
696 throw std::runtime_error("Invalid variable index");
697 variables[varIndex] = registers[rA];
698 NEXT();
699 }
700
701 LABEL_PUSH_R: { push(registers[rA]); NEXT(); }
702 LABEL_PUSH2_R: { push(registers[rA]); push(registers[rB]); NEXT(); }
703 LABEL_POP_R: { registers[rA] = pop(); NEXT(); }
704 LABEL_POP2_R: { registers[rA] = pop(); registers[rB] = pop();NEXT(); }
705
706
707 // REGISTER ARITHMETIC
708
709
710 LABEL_IADD_R: { registers[rA] = Value(asm_iadd (registers[rB].asInt(), registers[rC].asInt())); NEXT(); }
711 LABEL_ISUB_R: { registers[rA] = Value(asm_isub (registers[rB].asInt(), registers[rC].asInt())); NEXT(); }
712 LABEL_IMUL_R: { registers[rA] = Value(asm_imul (registers[rB].asInt(), registers[rC].asInt())); NEXT(); }
713 LABEL_IDIV_R: { registers[rA] = Value(asm_idiv (registers[rB].asInt(), registers[rC].asInt())); NEXT(); }
714 LABEL_IMOD_R: { registers[rA] = Value(asm_imod (registers[rB].asInt(), registers[rC].asInt())); NEXT(); }
715 LABEL_FLADD_R: { registers[rA] = Value(asm_fladd(registers[rB].asFloat(), registers[rC].asFloat())); NEXT(); }
716 LABEL_FLSUB_R: { registers[rA] = Value(asm_flsub(registers[rB].asFloat(), registers[rC].asFloat())); NEXT(); }
717 LABEL_FLMUL_R: { registers[rA] = Value(asm_flmul(registers[rB].asFloat(), registers[rC].asFloat())); NEXT(); }
718 LABEL_FLDIV_R: { registers[rA] = Value(asm_fldiv(registers[rB].asFloat(), registers[rC].asFloat())); NEXT(); }
719 LABEL_FLMOD_R: { registers[rA] = Value(asm_flmod(registers[rB].asFloat(), registers[rC].asFloat())); NEXT(); }
720 LABEL_SQRT_R: { registers[rA] = Value(asm_sqrt (registers[rB].asFloat())); NEXT(); }
721 LABEL_POW_R: { registers[rA] = Value(asm_pow (registers[rB].asFloat(), registers[rC].asFloat())); NEXT(); }
722 LABEL_LOG_R: { registers[rA] = Value(asm_log (registers[rB].asFloat())); NEXT(); }
723 LABEL_EXP_R: { registers[rA] = Value(asm_exp (registers[rB].asFloat())); NEXT(); }
724 LABEL_SIN_R: { registers[rA] = Value(asm_sin (registers[rB].asFloat())); NEXT(); }
725 LABEL_COS_R: { registers[rA] = Value(asm_cos (registers[rB].asFloat())); NEXT(); }
726 LABEL_TAN_R: { registers[rA] = Value(asm_tan (registers[rB].asFloat())); NEXT(); }
727
728
729 // REGISTER LOGICAL
730
731
732 LABEL_NEG_R: { registers[rA] = Value(asm_flneg(registers[rB].asFloat())); NEXT(); }
733 LABEL_NOT_R: { registers[rA] = Value(asm_flnot(registers[rB].isTruthy() ? 1 : 0)); NEXT(); }
734 LABEL_IAND_R: { Value &b=registers[rB],&c=registers[rC]; registers[rA]=Value(asm_iand(b.isTruthy()?1:0,c.isTruthy()?1:0)); NEXT(); }
735 LABEL_IOR_R: { Value &b=registers[rB],&c=registers[rC]; registers[rA]=Value(asm_ior (b.isTruthy()?1:0,c.isTruthy()?1:0)); NEXT(); }
736
737 LABEL_IEQ_R: { Value &b=registers[rB],&c=registers[rC]; registers[rA]=(b.isInt()&&c.isInt()) ? Value(asm_iequal(b.asInt(),c.asInt())) : Value(b==c); NEXT(); }
738 LABEL_INE_R: { Value &b=registers[rB],&c=registers[rC]; registers[rA]=(b.isInt()&&c.isInt()) ? Value(asm_inot_equal(b.asInt(),c.asInt())) : Value(b!=c); NEXT(); }
739 LABEL_ILT_R: { Value &b=registers[rB],&c=registers[rC]; registers[rA]=(b.isInt()&&c.isInt()) ? Value(asm_iless_than(b.asInt(),c.asInt())) : Value(b< c); NEXT(); }
740 LABEL_IGT_R: { Value &b=registers[rB],&c=registers[rC]; registers[rA]=(b.isInt()&&c.isInt()) ? Value(asm_igreater_than(b.asInt(),c.asInt())) : Value(b> c); NEXT(); }
741 LABEL_ILE_R: { Value &b=registers[rB],&c=registers[rC]; registers[rA]=(b.isInt()&&c.isInt()) ? Value(asm_iless_equal(b.asInt(),c.asInt())) : Value(b<=c); NEXT(); }
742 LABEL_IGE_R: { Value &b=registers[rB],&c=registers[rC]; registers[rA]=(b.isInt()&&c.isInt()) ? Value(asm_igreater_equal(b.asInt(),c.asInt())) : Value(b>=c); NEXT(); }
743 LABEL_FLEQ_R: { Value &b=registers[rB],&c=registers[rC]; registers[rA]=(b.isFloat()&&c.isFloat()) ? Value(asm_flequal(b.asFloat(),c.asFloat())) : Value(b==c); NEXT(); }
744 LABEL_FLNE_R: { Value &b=registers[rB],&c=registers[rC]; registers[rA]=(b.isFloat()&&c.isFloat()) ? Value(asm_flnot_equal(b.asFloat(),c.asFloat())) : Value(b!=c); NEXT(); }
745 LABEL_FLLT_R: { Value &b=registers[rB],&c=registers[rC]; registers[rA]=(b.isFloat()&&c.isFloat()) ? Value(asm_flless_than(b.asFloat(),c.asFloat())) : Value(b< c); NEXT(); }
746 LABEL_FLGT_R: { Value &b=registers[rB],&c=registers[rC]; registers[rA]=(b.isFloat()&&c.isFloat()) ? Value(asm_flgreater_than(b.asFloat(),c.asFloat())) : Value(b> c); NEXT(); }
747 LABEL_FLLE_R: { Value &b=registers[rB],&c=registers[rC]; registers[rA]=(b.isFloat()&&c.isFloat()) ? Value(asm_flless_equal(b.asFloat(),c.asFloat())) : Value(b<=c); NEXT(); }
748 LABEL_FLGE_R: { Value &b=registers[rB],&c=registers[rC]; registers[rA]=(b.isFloat()&&c.isFloat()) ? Value(asm_flgreater_equal(b.asFloat(),c.asFloat())): Value(b>=c); NEXT(); }
749 LABEL_FLAND_R: { Value &b=registers[rB],&c=registers[rC]; registers[rA]=Value(asm_fland(b.isTruthy()?1:0,c.isTruthy()?1:0)); NEXT(); }
750 LABEL_FLOR_R: { Value &b=registers[rB],&c=registers[rC]; registers[rA]=Value(asm_flor (b.isTruthy()?1:0,c.isTruthy()?1:0)); NEXT(); }
751
752
753 // REGISTER I/O
754
755
756 LABEL_PRINT_R:
757 {
758 {
759 std::string s = registers[rA].toString();
760#ifdef TRACING
761 log(std::format("PRINT_R: (stdout) {:T}\n", registers[rA]));
762#else
763 c_print_stdout(s.c_str(), (i64)s.length());
764#endif
765 flush();
766 }
767 NEXT();
768 }
769
770 LABEL_PRINTERROR_R:
771 {
772 {
773 std::string s = registers[rA].toString();
774#ifdef TRACING
775 log(std::format("PRINTERROR_R: (stderr) {:T}\n", registers[rA]));
776#else
777 c_print_stderr(s.c_str(), (i64)s.length());
778#endif
779 flusherr();
780 }
781 NEXT();
782 }
783
784 LABEL_READLINE_R:
785 {
786 {
787 std::string s;
788#ifdef TRACING
789 log("READLINE_R:");
790 flush();
791#endif
792 std::getline(std::cin, s);
793#ifdef TRACING
794 log(std::format("\nREADLINE_R: {}\n", s));
795#endif
796 registers[rA] = s;
797 }
798 NEXT();
799 }
800
801 // REGISTER SYSTEM
802
803 LABEL_SYSTEM_R:
804 {
805#ifdef SANDBOXED
806 logerr("CANNOT ESCAPE SANDBOX");
807 registers[rA] = Value();
808#else
809 {
810#ifdef TRACING
811 Value cmd = registers[rA];
812 i64 ret = c_system(cmd.c_str());
813 log(std::format("SYSTEM_R: {} -> {}\n", cmd, ret));
814 registers[rA] = ret;
815#else
816 registers[rA] = c_system(registers[rA].c_str());
817#endif
818 }
819#endif
820 NEXT();
821 }
822
823 LABEL_SYSTEM_OUT_R:
824 {
825#ifdef SANDBOXED
826 logerr("CANNOT ESCAPE SANDBOX");
827 registers[rA] = Value();
828#else
829 {
830#ifdef TRACING
831 Value cmd = registers[rA];
832 std::string ret = c_system_out(cmd.c_str());
833 log(std::format("SYSTEM_R: {:T} -> {}\n", cmd, ret));
834 registers[rA] = ret;
835#else
836 registers[rA] = c_system_out(registers[rA].c_str());
837#endif
838 }
839#endif
840 NEXT();
841 }
842
843 LABEL_SYSTEM_ERR_R:
844 {
845#ifdef SANDBOXED
846 logerr("CANNOT ESCAPE SANDBOX");
847 registers[rA] = Value();
848#else
849 {
850#ifdef TRACING
851 Value cmd = registers[rA];
852 std::string ret = c_system_err(cmd.c_str());
853 log(std::format("SYSTEM_ERR_R: {:T} -> {}\n", cmd, ret));
854 registers[rA] = ret;
855#else
856 registers[rA] = c_system_err(registers[rA].c_str());
857#endif
858 }
859#endif
860 NEXT();
861 }
862
863 // UNKNOWN
864
865 LABEL_UNKNOWN:
866 throw std::runtime_error("Unknown opcode");
867
868#undef NEXT
869#undef TRACE_INSTR
870
871#else
872 while (pc < m_bytecode->instructions.size())
873 {
874 const Instruction& instr = m_bytecode->instructions[pc++];
875#ifdef TRACING
876 log(std::format("\nVM::{}(): RUN (pc={})\n", __func__, pc - 1));
877 flush();
878#endif
879 operation(instr.op, instr.operand1, instr.operand2, instr.operand3);
880 }
881
882#pragma GCC diagnostic pop
883#endif // defined(__GNUC__) || defined(__clang__)
884}
885
886Value VM::operation(const OpCode &op, const int &operand1, const int &operand2, const int &operand3)
887{
888 u8 rA = static_cast<u8>(operand1);
889 u8 rB = static_cast<u8>(operand2);
890 u8 rC = static_cast<u8>(operand3);
891#ifdef TRACING
892 log(std::format("VM::{}({}, {}, {}, {})\n", __func__, opCodeToString(op), operand1, operand2, operand3));
893 flush();
894#endif
895 switch (op)
896 {
897
898#pragma region CONTROL FLOW
899
900 [[likely]] case OpCode::JUMP: {
901#ifdef TRACING
902 log(std::format("JUMP: {} -> {}\n", pc - 1, operand1));
903 flush();
904#endif
905 pc = operand1;
906 break;
907 }
908
909 [[likely]] case OpCode::CALL: {
910 Value funcNameVal = m_bytecode->constants[operand1];
911 std::string funcName = funcNameVal.asString();
912 auto it = m_bytecode->functionEntries.find(funcName);
913 if (it == m_bytecode->functionEntries.end())
914 throw std::runtime_error("Unknown function: " + funcName);
915#ifdef TRACING
916 log(std::format("CALL: {} -> {}: {}\n", pc - 1, funcName, it->second));
917 flush();
918#endif
919 callStack.push_back(static_cast<int>(pc));
920 pc = it->second;
921 break;
922 }
923 [[likely]] case OpCode::RETURN: {
924 if (isDirectCall)
925 {
926 pc = 0;
927 throw VM::Halt();
928 break;
929 }
930 if (callStack.empty()) [[unlikely]]
931 {
932 pc = m_bytecode->instructions.size();
933 throw std::runtime_error("Cannot return from outside a function");
934 break;
935 }
936#ifdef TRACING
937 log(std::format("RETURN: {} -> {}\n", pc - 1, callStack.back()));
938 flush();
939#endif
940 pc = callStack.back();
941 callStack.pop_back();
942 break;
943 }
944
945 [[likely]] case OpCode::CALL_NATIVE: {
946 Value funcNameVal = m_bytecode->constants[operand1];
947 std::string funcName = funcNameVal.asString();
948 auto it = nativeFunctions.find(funcName);
949 if (it == nativeFunctions.end())
950 throw std::runtime_error("Unknown native function: " + funcName);
951
952 int argCount = static_cast<int>(pop().asInt());
953 std::vector<Value> args(argCount);
954 for (int i = argCount - 1; i >= 0; --i)
955 args[i] = pop();
956
957#ifdef TRACING
958 std::string argsText;
959 for (auto &arg : args)
960 {
961 argsText += std::format("{:T}", arg);
962 if (arg != args.back())
963 argsText += ", ";
964 }
965 log(std::format("CALL_NATIVE: {}({})\n", funcName, argsText));
966 flush();
967#endif
968
969 push(it->second(args, this));
970
971 break;
972 }
973
975#ifdef TRACING
976 log(std::format("JUMP_IF_FALSE: {} {} -> {}\n", peek().isTruthy() ? "TRUE" : "FALSE", pc - 1, operand1));
977 flush();
978#endif
979 if (!pop().isTruthy())
980 pc = operand1;
981 break;
982 }
983
985#ifdef TRACING
986 log(std::format("JUMP_IF_TRUE: {} {} -> {}\n", peek().isTruthy() ? "TRUE" : "FALSE", pc - 1, operand1));
987 flush();
988#endif
989 if (pop().isTruthy())
990 pc = operand1;
991 break;
992 }
993
994 case OpCode::JUMP_BACK: {
995#ifdef TRACING
996 log(std::format("JUMP_BACK: {} -> {}\n", pc - 1, operand1));
997 flush();
998#endif
999 pc = operand1;
1000 break;
1001 }
1002
1003 [[unlikely]] case OpCode::IMPORT: {
1004 Value pathVal = m_bytecode->constants[operand1];
1005 std::string path = pathVal.asString();
1006 if (importHandler)
1007 importHandler(path);
1008 else
1009 throw std::runtime_error("Import handler not set");
1010 break;
1011 }
1012
1013 [[unlikely]] case OpCode::HALT: {
1014 pc = m_bytecode->instructions.size();
1015 throw VM::Halt();
1016 break;
1017 }
1018
1019#pragma endregion
1020#pragma region STACK CORE
1021
1022 [[likely]] case OpCode::PUSH_CONST: {
1023 if (operand1 < 0 || operand1 >= static_cast<int>(m_bytecode->constants.size()))
1024 throw std::runtime_error("Invalid constant index");
1025 push(m_bytecode->constants[operand1]);
1026 break;
1027 }
1028
1029 [[likely]] case OpCode::POP: {
1030 pop();
1031 break;
1032 }
1033
1034 [[likely]] case OpCode::STORE_VAR: {
1035 if (operand1 < 0 || operand1 >= static_cast<int>(variables.size()))
1036 throw std::runtime_error("Invalid variable index");
1037 variables[operand1] = pop();
1038 break;
1039 }
1040
1041 [[likely]] case OpCode::LOAD_VAR: {
1042 if (operand1 < 0 || operand1 >= static_cast<int>(variables.size()))
1043 throw std::runtime_error("Invalid variable index");
1044 push(variables[operand1]);
1045 break;
1046 }
1047
1048 case OpCode::TRUE_P: {
1049 push(Value(true));
1050 break;
1051 }
1052
1053 case OpCode::FALSE_P: {
1054 push(Value(false));
1055 break;
1056 }
1057
1058 case OpCode::NULL_VAL: {
1059 push(Value());
1060 break;
1061 }
1062
1063#pragma endregion
1064#pragma region STACK ARITHMETIC
1065
1066 case OpCode::IADD: {
1067 Value b = pop();
1068 Value a = pop();
1069 push(asm_iadd(a.asInt(), b.asInt()));
1070 break;
1071 }
1072
1073 case OpCode::ISUBTRACT: {
1074 Value b = pop();
1075 Value a = pop();
1076 push(asm_isub(a.asInt(), b.asInt()));
1077 break;
1078 }
1079
1080 case OpCode::IMULTIPLY: {
1081 Value b = pop();
1082 Value a = pop();
1083 push(asm_imul(a.asInt(), b.asInt()));
1084 break;
1085 }
1086
1087 case OpCode::IDIVIDE: {
1088 Value b = pop();
1089 Value a = pop();
1090 push(asm_idiv(a.asInt(), b.asInt()));
1091 break;
1092 }
1093
1094 case OpCode::IMODULO: {
1095 Value b = pop();
1096 Value a = pop();
1097 push(asm_imod(a.asInt(), b.asInt()));
1098 break;
1099 }
1100
1101 case OpCode::FLADD: {
1102 Value b = pop();
1103 Value a = pop();
1104 push(asm_fladd(a.asFloat(), b.asFloat()));
1105 break;
1106 }
1107
1108 case OpCode::FLSUBTRACT: {
1109 Value b = pop();
1110 Value a = pop();
1111 push(asm_flsub(a.asFloat(), b.asFloat()));
1112 break;
1113 }
1114
1115 case OpCode::FLMULTIPLY: {
1116 Value b = pop();
1117 Value a = pop();
1118 push(asm_flmul(a.asFloat(), b.asFloat()));
1119 break;
1120 }
1121
1122 case OpCode::FLDIVIDE: {
1123 Value b = pop();
1124 Value a = pop();
1125 push(asm_fldiv(a.asFloat(), b.asFloat()));
1126 break;
1127 }
1128
1129 case OpCode::FLMODULO: {
1130 Value b = pop();
1131 Value a = pop();
1132 push(asm_flmod(a.asFloat(), b.asFloat()));
1133 break;
1134 }
1135
1136 case OpCode::SQRT: {
1137 Value a = pop();
1138 push(asm_sqrt(a.asFloat()));
1139 break;
1140 }
1141
1142 case OpCode::POW: {
1143 Value b = pop();
1144 Value a = pop();
1145 push(asm_pow(a.asFloat(), b.asFloat()));
1146 break;
1147 }
1148
1149 case OpCode::LOG: {
1150 Value a = pop();
1151 push(asm_log(a.asFloat()));
1152 break;
1153 }
1154
1155 case OpCode::EXP: {
1156 Value a = pop();
1157 push(asm_exp(a.asFloat()));
1158 break;
1159 }
1160
1161 case OpCode::SIN: {
1162 Value a = pop();
1163 push(asm_sin(a.asFloat()));
1164 break;
1165 }
1166
1167 case OpCode::COS: {
1168 Value a = pop();
1169 push(asm_cos(a.asFloat()));
1170 break;
1171 }
1172
1173 case OpCode::TAN: {
1174 Value a = pop();
1175 push(asm_tan(a.asFloat()));
1176 break;
1177 }
1178
1179#pragma endregion
1180#pragma region STACK LOGICAL
1181
1182 case OpCode::NEGATE: {
1183 push(asm_flneg(pop().asFloat()));
1184 break;
1185 }
1186
1187 case OpCode::NOT: {
1188 push(Value(asm_flnot(pop().isTruthy() ? 1 : 0)));
1189 break;
1190 }
1191
1192 case OpCode::IAND: {
1193 Value b = pop();
1194 Value a = pop();
1195 push(Value(asm_iand(a.isTruthy() ? 1 : 0, b.isTruthy() ? 1 : 0)));
1196 break;
1197 }
1198
1199 case OpCode::IOR: {
1200 Value b = pop();
1201 Value a = pop();
1202 push(Value(asm_ior(a.isTruthy() ? 1 : 0, b.isTruthy() ? 1 : 0)));
1203 break;
1204 }
1205
1206 case OpCode::IEQUAL: {
1207 Value b = pop();
1208 Value a = pop();
1209 push(a.isInt() && b.isInt() ? Value(asm_iequal(a.asInt(), b.asInt())) : Value(a == b));
1210 break;
1211 }
1212
1213 case OpCode::INOT_EQUAL: {
1214 Value b = pop();
1215 Value a = pop();
1216 push(a.isInt() && b.isInt() ? Value(asm_inot_equal(a.asInt(), b.asInt())) : Value(a != b));
1217 break;
1218 }
1219
1220 case OpCode::ILESS_THAN: {
1221 Value b = pop();
1222 Value a = pop();
1223 push(a.isInt() && b.isInt() ? Value(asm_iless_than(a.asInt(), b.asInt())) : Value(a < b));
1224 break;
1225 }
1226
1227 case OpCode::IGREATER_THAN: {
1228 Value b = pop();
1229 Value a = pop();
1230 push(a.isInt() && b.isInt() ? Value(asm_igreater_than(a.asInt(), b.asInt())) : Value(a > b));
1231 break;
1232 }
1233
1234 case OpCode::ILESS_EQUAL: {
1235 Value b = pop();
1236 Value a = pop();
1237 push(a.isInt() && b.isInt() ? Value(asm_iless_equal(a.asInt(), b.asInt())) : Value(a <= b));
1238 break;
1239 }
1240
1242 Value b = pop();
1243 Value a = pop();
1244 push(a.isInt() && b.isInt() ? Value(asm_igreater_equal(a.asInt(), b.asInt())) : Value(a >= b));
1245 break;
1246 }
1247
1248 case OpCode::FLAND: {
1249 Value b = pop();
1250 Value a = pop();
1251 push(Value(asm_fland(a.isTruthy() ? 1 : 0, b.isTruthy() ? 1 : 0)));
1252 break;
1253 }
1254
1255 case OpCode::FLOR: {
1256 Value b = pop();
1257 Value a = pop();
1258 push(Value(asm_flor(a.isTruthy() ? 1 : 0, b.isTruthy() ? 1 : 0)));
1259 break;
1260 }
1261
1262 case OpCode::FLEQUAL: {
1263 Value b = pop();
1264 Value a = pop();
1265 push(a.isFloat() && b.isFloat() ? Value(asm_flequal(a.asFloat(), b.asFloat())) : Value(a == b));
1266 break;
1267 }
1268
1269 case OpCode::FLNOT_EQUAL: {
1270 Value b = pop();
1271 Value a = pop();
1272 push(a.isFloat() && b.isFloat() ? Value(asm_flnot_equal(a.asFloat(), b.asFloat())) : Value(a != b));
1273 break;
1274 }
1275
1276 case OpCode::FLLESS_THAN: {
1277 Value b = pop();
1278 Value a = pop();
1279 push(a.isFloat() && b.isFloat() ? Value(asm_flless_than(a.asFloat(), b.asFloat())) : Value(a < b));
1280 break;
1281 }
1282
1284 Value b = pop();
1285 Value a = pop();
1286 push(a.isFloat() && b.isFloat() ? Value(asm_flgreater_than(a.asFloat(), b.asFloat())) : Value(a > b));
1287 break;
1288 }
1289
1290 case OpCode::FLLESS_EQUAL: {
1291 Value b = pop();
1292 Value a = pop();
1293 push(a.isFloat() && b.isFloat() ? Value(asm_flless_equal(a.asFloat(), b.asFloat())) : Value(a <= b));
1294 break;
1295 }
1296
1298 Value b = pop();
1299 Value a = pop();
1300 push(a.isFloat() && b.isFloat() ? Value(asm_flgreater_equal(a.asFloat(), b.asFloat())) : Value(a >= b));
1301 break;
1302 }
1303
1304#pragma endregion
1305#pragma region STACK I/O
1306
1307 case OpCode::PRINT: {
1308 Value v = pop();
1309 std::string s = v.toString();
1310#ifdef TRACING
1311 log(std::format("PRINT: (stdout) {:T}\n", v));
1312#else
1313 c_print_stdout(s.c_str(), (i64)s.length());
1314#endif
1315 flush();
1316 break;
1317 }
1318
1319 [[unlikely]] case OpCode::PRINTERROR: {
1320 Value v = pop();
1321 std::string s = v.toString();
1322#ifdef TRACING
1323 log(std::format("PRINTERROR: (stderr) {:T}\n", v));
1324#else
1325 c_print_stderr(s.c_str(), (i64)s.length());
1326#endif
1327 flusherr();
1328 break;
1329 }
1330
1331 case OpCode::READLINE: {
1332 std::string s;
1333#ifdef TRACING
1334 log("READLINE:");
1335 flush();
1336#endif
1337 std::getline(std::cin, s);
1338#ifdef TRACING
1339 log(std::format("\nREADLINE: {}\n", s));
1340#endif
1341 push(s);
1342 break;
1343 }
1344
1345#pragma endregion
1346#pragma region STACK SYSTEM
1347
1348 case OpCode::SYSTEM: {
1349#ifdef SANDBOXED
1350 logerr("CANNOT ESCAPE SANDBOX");
1351 push(Value());
1352#else
1353#ifdef TRACING
1354 Value cmd = pop();
1355 int ret = c_system(cmd.c_str());
1356 log(std::format("SYSTEM: {:T} -> {}\n", cmd, ret));
1357 push(ret);
1358#else
1359 push(c_system(pop().c_str()));
1360#endif
1361#endif
1362 break;
1363 }
1364
1365 case OpCode::SYSTEM_OUT: {
1366#ifdef SANDBOXED
1367 logerr("CANNOT ESCAPE SANDBOX");
1368 push(Value());
1369#else
1370#ifdef TRACING
1371 Value cmd = pop();
1372 std::string ret = c_system_out(cmd.c_str());
1373 log(std::format("SYSTEM_OUT: {:T} -> {}\n", cmd, ret));
1374 push(ret);
1375#else
1376 push(c_system_out(pop().c_str()));
1377#endif
1378#endif
1379 break;
1380 }
1381
1382 case OpCode::SYSTEM_ERR: {
1383#ifdef SANDBOXED
1384 logerr("CANNOT ESCAPE SANDBOX");
1385 push(Value());
1386#else
1387#ifdef TRACING
1388 Value cmd = pop();
1389 std::string ret = c_system_err(cmd.c_str());
1390 log(std::format("SYSTEM_ERR: {:T} -> {}\n", cmd, ret));
1391 push(ret);
1392#else
1393 push(c_system_err(pop().c_str()));
1394#endif
1395#endif
1396 break;
1397 }
1398
1399#pragma endregion
1400#pragma region STACK STRING
1401
1402 case OpCode::LEN: {
1403 Value v = pop();
1404 if (v.isArray())
1405 {
1406 push(Value(static_cast<i64>(v.asArray()->size())));
1407 }
1408 else
1409 {
1410 push(Value(static_cast<i64>(v.asString().length())));
1411 }
1412 break;
1413 }
1414
1415 case OpCode::CHAR_AT: {
1416 Value idxVal = pop();
1417 Value strVal = pop();
1418
1419 std::string s;
1420 if (strVal.isString())
1421 s = strVal.asString();
1422 else
1423 s = strVal.toString();
1424
1425 i64 idx = 0;
1426 if (idxVal.isInt())
1427 idx = idxVal.asInt();
1428 else if (idxVal.isFloat())
1429 idx = static_cast<i64>(idxVal.asFloat());
1430 else if (idxVal.isString())
1431 {
1432 try
1433 {
1434 idx = std::stoll(idxVal.asString());
1435 }
1436 catch (...)
1437 {
1438 throw std::runtime_error("char_at() expects index convertible to integer");
1439 }
1440 }
1441 else
1442 throw std::runtime_error("char_at() expects string and integer");
1443
1444 if (idx < 0 || idx >= static_cast<i64>(s.length()))
1445 push(Value(""));
1446 else
1447 push(Value(std::string(1, s[static_cast<size_t>(idx)])));
1448 break;
1449 }
1450
1451 case OpCode::SUBSTR: {
1452 Value lenVal = pop();
1453 Value startVal = pop();
1454 Value strVal = pop();
1455
1456 if (strVal.isString() && startVal.isInt() && lenVal.isInt())
1457 {
1458 const std::string &s = strVal.asString();
1459 i64 start = startVal.asInt();
1460 i64 len = lenVal.asInt();
1461
1462 if (start < 0 || start >= static_cast<i64>(s.length()))
1463 {
1464 push(Value(""));
1465 }
1466 else
1467 {
1468 push(Value(s.substr(start, len)));
1469 }
1470 }
1471 else
1472 {
1473 throw std::runtime_error("substr() expects string, int, int");
1474 }
1475 break;
1476 }
1477
1478#pragma endregion
1479#pragma region STACK STRUCT
1480
1482 if (operand1 < 0 || operand1 >= static_cast<int>(m_bytecode->structs.size()))
1483 throw std::runtime_error("Invalid struct index for NEW_STRUCT_INSTANCE_STATIC");
1484
1485 const StructInfo &info = m_bytecode->structs[operand1];
1486 Value instance = Value::createStruct(info.name);
1487 for (int i = 0; i < info.fieldCount; ++i)
1488 {
1489 int constIndex = info.firstConstIndex + i;
1490 if (constIndex < 0 || constIndex >= static_cast<int>(m_bytecode->constants.size()))
1491 throw std::runtime_error("Invalid default constant index for struct field");
1492 const Value &defVal = m_bytecode->constants[constIndex];
1493 const std::string &fieldName = info.fieldNames[i];
1494 instance.setField(fieldName, defVal);
1495 }
1496 push(instance);
1497 break;
1498 }
1499
1501 if (operand1 < 0 || operand1 >= static_cast<int>(m_bytecode->structs.size()))
1502 throw std::runtime_error("Invalid struct index for GET_FIELD_STATIC");
1503 const StructInfo &info = m_bytecode->structs[operand1];
1504 int fieldOffset = operand2;
1505 if (fieldOffset < 0 || fieldOffset >= info.fieldCount)
1506 throw std::runtime_error("Invalid field offset for GET_FIELD_STATIC");
1507 const std::string &fieldName = info.fieldNames[fieldOffset];
1508 Value obj = pop();
1509 push(obj.getField(fieldName));
1510 break;
1511 }
1512
1514 if (operand1 < 0 || operand1 >= static_cast<int>(m_bytecode->structs.size()))
1515 throw std::runtime_error("Invalid struct index for SET_FIELD_STATIC");
1516 const StructInfo &info = m_bytecode->structs[operand1];
1517 int fieldOffset = operand2;
1518 if (fieldOffset < 0 || fieldOffset >= info.fieldCount)
1519 throw std::runtime_error("Invalid field offset for SET_FIELD_STATIC");
1520 const std::string &fieldName = info.fieldNames[fieldOffset];
1521 Value value = pop();
1522 Value obj = pop();
1523 obj.setField(fieldName, value);
1524 push(obj);
1525 break;
1526 }
1527
1528 case OpCode::NEW_STRUCT: {
1529 if (operand1 < 0 || operand1 >= static_cast<int>(m_bytecode->constants.size()))
1530 throw std::runtime_error("Invalid constant index for NEW_STRUCT");
1531 Value nameVal = m_bytecode->constants[operand1];
1532 std::string structName = nameVal.asString();
1533 push(Value::createStruct(structName));
1534 break;
1535 }
1536
1537 case OpCode::SET_FIELD: {
1538 if (operand1 < 0 || operand1 >= static_cast<int>(m_bytecode->constants.size()))
1539 throw std::runtime_error("Invalid constant index for SET_FIELD");
1540 std::string fieldName = m_bytecode->constants[operand1].asString();
1541 Value value = pop();
1542 Value obj = pop();
1543 obj.setField(fieldName, value);
1544 push(obj);
1545 break;
1546 }
1547
1548 case OpCode::GET_FIELD: {
1549 if (operand1 < 0 || operand1 >= static_cast<int>(m_bytecode->constants.size()))
1550 throw std::runtime_error("Invalid constant index for GET_FIELD");
1551 std::string fieldName = m_bytecode->constants[operand1].asString();
1552 Value obj = pop();
1553 push(obj.getField(fieldName));
1554 break;
1555 }
1556
1557#pragma endregion
1558#pragma region REGISTER CORE
1559
1560 [[likely]] case OpCode::MOV: {
1561 registers[rA] = registers[rB];
1562 break;
1563 }
1564
1565 [[likely]] case OpCode::LOAD_CONST_R: {
1566 int constIndex = operand2;
1567 if (constIndex < 0 || constIndex >= static_cast<int>(m_bytecode->constants.size()))
1568 throw std::runtime_error("Invalid constant index");
1569 registers[rA] = m_bytecode->constants[constIndex];
1570 break;
1571 }
1572
1573 [[likely]] case OpCode::LOAD_VAR_R: {
1574 int varIndex = operand2;
1575 if (varIndex < 0 || varIndex >= static_cast<int>(variables.size()))
1576 throw std::runtime_error("Invalid variable index");
1577 registers[rA] = variables[varIndex];
1578 break;
1579 }
1580
1581 [[likely]] case OpCode::STORE_VAR_R: {
1582 int varIndex = operand2;
1583 if (varIndex < 0 || varIndex >= static_cast<int>(variables.size()))
1584 throw std::runtime_error("Invalid variable index");
1585 variables[varIndex] = registers[rA];
1586 break;
1587 }
1588
1589 case OpCode::PUSH_R: {
1590 push(registers[rA]);
1591 break;
1592 }
1593
1594 case OpCode::PUSH2_R: {
1595 push(registers[rA]);
1596 push(registers[rB]);
1597 break;
1598 }
1599
1600 case OpCode::POP_R: {
1601 registers[rA] = pop();
1602 break;
1603 }
1604
1605 case OpCode::POP2_R: {
1606 registers[rA] = pop();
1607 registers[rB] = pop();
1608 break;
1609 }
1610
1611#pragma region REG ARITHMETIC
1612
1613 case OpCode::IADD_R: {
1614 registers[rA] = Value(asm_iadd(registers[rB].asInt(), registers[rC].asInt()));
1615 break;
1616 }
1617
1618 case OpCode::ISUB_R: {
1619 registers[rA] = Value(asm_isub(registers[rB].asInt(), registers[rC].asInt()));
1620 break;
1621 }
1622
1623 case OpCode::IMUL_R: {
1624 registers[rA] = Value(asm_imul(registers[rB].asInt(), registers[rC].asInt()));
1625 break;
1626 }
1627
1628 case OpCode::IDIV_R: {
1629 registers[rA] = Value(asm_idiv(registers[rB].asInt(), registers[rC].asInt()));
1630 break;
1631 }
1632
1633 case OpCode::IMOD_R: {
1634 registers[rA] = Value(asm_imod(registers[rB].asInt(), registers[rC].asInt()));
1635 break;
1636 }
1637
1638 case OpCode::FLADD_R: {
1639 registers[rA] = Value(asm_fladd(registers[rB].asFloat(), registers[rC].asFloat()));
1640 break;
1641 }
1642
1643 case OpCode::FLSUB_R: {
1644 registers[rA] = Value(asm_flsub(registers[rB].asFloat(), registers[rC].asFloat()));
1645 break;
1646 }
1647
1648 case OpCode::FLMUL_R: {
1649 registers[rA] = Value(asm_flmul(registers[rB].asFloat(), registers[rC].asFloat()));
1650 break;
1651 }
1652
1653 case OpCode::FLDIV_R: {
1654 registers[rA] = Value(asm_fldiv(registers[rB].asFloat(), registers[rC].asFloat()));
1655 break;
1656 }
1657
1658 case OpCode::FLMOD_R: {
1659 registers[rA] = Value(asm_flmod(registers[rB].asFloat(), registers[rC].asFloat()));
1660 break;
1661 }
1662
1663 case OpCode::SQRT_R: {
1664 registers[rA] = Value(asm_sqrt(registers[rB].asFloat()));
1665 break;
1666 }
1667
1668 case OpCode::POW_R: {
1669 registers[rA] = Value(asm_pow(registers[rB].asFloat(), registers[rC].asFloat()));
1670 break;
1671 }
1672
1673 case OpCode::LOG_R: {
1674 registers[rA] = Value(asm_log(registers[rB].asFloat()));
1675 break;
1676 }
1677
1678 case OpCode::EXP_R: {
1679 registers[rA] = Value(asm_exp(registers[rB].asFloat()));
1680 break;
1681 }
1682
1683 case OpCode::SIN_R: {
1684 registers[rA] = Value(asm_sin(registers[rB].asFloat()));
1685 break;
1686 }
1687
1688 case OpCode::COS_R: {
1689 registers[rA] = Value(asm_cos(registers[rB].asFloat()));
1690 break;
1691 }
1692
1693 case OpCode::TAN_R: {
1694 registers[rA] = Value(asm_tan(registers[rB].asFloat()));
1695 break;
1696 }
1697
1698#pragma endregion
1699#pragma region REG LOGICAL
1700
1701 case OpCode::NEG_R: {
1702 registers[rA] = Value(asm_flneg(registers[rB].asFloat()));
1703 break;
1704 }
1705
1706 case OpCode::NOT_R: {
1707 registers[rA] = Value(asm_flnot(registers[rB].isTruthy() ? 1 : 0));
1708 break;
1709 }
1710
1711 case OpCode::IEQ_R: {
1712 Value &b = registers[rB];
1713 Value &c = registers[rC];
1714 registers[rA] = (b.isInt() && c.isInt()) ? Value(asm_iequal(b.asInt(), c.asInt())) : Value(b == c);
1715 break;
1716 }
1717
1718 case OpCode::INE_R: {
1719 Value &b = registers[rB];
1720 Value &c = registers[rC];
1721 registers[rA] = (b.isInt() && c.isInt()) ? Value(asm_inot_equal(b.asInt(), c.asInt())) : Value(b != c);
1722 break;
1723 }
1724
1725 case OpCode::ILT_R: {
1726 Value &b = registers[rB];
1727 Value &c = registers[rC];
1728 registers[rA] = (b.isInt() && c.isInt()) ? Value(asm_iless_than(b.asInt(), c.asInt())) : Value(b < c);
1729 break;
1730 }
1731
1732 case OpCode::IGT_R: {
1733 Value &b = registers[rB];
1734 Value &c = registers[rC];
1735 registers[rA] = (b.isInt() && c.isInt()) ? Value(asm_igreater_than(b.asInt(), c.asInt())) : Value(b > c);
1736 break;
1737 }
1738
1739 case OpCode::ILE_R: {
1740 Value &b = registers[rB];
1741 Value &c = registers[rC];
1742 registers[rA] = (b.isInt() && c.isInt()) ? Value(asm_iless_equal(b.asInt(), c.asInt())) : Value(b <= c);
1743 break;
1744 }
1745
1746 case OpCode::IGE_R: {
1747 Value &b = registers[rB];
1748 Value &c = registers[rC];
1749 registers[rA] = (b.isInt() && c.isInt()) ? Value(asm_igreater_equal(b.asInt(), c.asInt())) : Value(b >= c);
1750 break;
1751 }
1752
1753 case OpCode::IAND_R: {
1754 Value &b = registers[rB];
1755 Value &c = registers[rC];
1756 registers[rA] = Value(asm_iand(b.isTruthy() ? 1 : 0, c.isTruthy() ? 1 : 0));
1757 break;
1758 }
1759
1760 case OpCode::IOR_R: {
1761 Value &b = registers[rB];
1762 Value &c = registers[rC];
1763 registers[rA] = Value(asm_ior(b.isTruthy() ? 1 : 0, c.isTruthy() ? 1 : 0));
1764 break;
1765 }
1766
1767 case OpCode::FLEQ_R: {
1768 Value &b = registers[rB];
1769 Value &c = registers[rC];
1770 registers[rA] = (b.isFloat() && c.isFloat()) ? Value(asm_flequal(b.asFloat(), c.asFloat())) : Value(b == c);
1771 break;
1772 }
1773
1774 case OpCode::FLNE_R: {
1775 Value &b = registers[rB];
1776 Value &c = registers[rC];
1777 registers[rA] = (b.isFloat() && c.isFloat()) ? Value(asm_flnot_equal(b.asFloat(), c.asFloat())) : Value(b != c);
1778 break;
1779 }
1780
1781 case OpCode::FLLT_R: {
1782 Value &b = registers[rB];
1783 Value &c = registers[rC];
1784 registers[rA] = (b.isFloat() && c.isFloat()) ? Value(asm_flless_than(b.asFloat(), c.asFloat())) : Value(b < c);
1785 break;
1786 }
1787
1788 case OpCode::FLGT_R: {
1789 Value &b = registers[rB];
1790 Value &c = registers[rC];
1791 registers[rA] =
1792 (b.isFloat() && c.isFloat()) ? Value(asm_flgreater_than(b.asFloat(), c.asFloat())) : Value(b > c);
1793 break;
1794 }
1795
1796 case OpCode::FLLE_R: {
1797 Value &b = registers[rB];
1798 Value &c = registers[rC];
1799 registers[rA] =
1800 (b.isFloat() && c.isFloat()) ? Value(asm_flless_equal(b.asFloat(), c.asFloat())) : Value(b <= c);
1801 break;
1802 }
1803
1804 case OpCode::FLGE_R: {
1805 Value &b = registers[rB];
1806 Value &c = registers[rC];
1807 registers[rA] =
1808 (b.isFloat() && c.isFloat()) ? Value(asm_flgreater_equal(b.asFloat(), c.asFloat())) : Value(b >= c);
1809 break;
1810 }
1811
1812 case OpCode::FLAND_R: {
1813 Value &b = registers[rB];
1814 Value &c = registers[rC];
1815 registers[rA] = Value(asm_fland(b.isTruthy() ? 1 : 0, c.isTruthy() ? 1 : 0));
1816 break;
1817 }
1818
1819 case OpCode::FLOR_R: {
1820 Value &b = registers[rB];
1821 Value &c = registers[rC];
1822 registers[rA] = Value(asm_flor(b.isTruthy() ? 1 : 0, c.isTruthy() ? 1 : 0));
1823 break;
1824 }
1825
1826#pragma endregion
1827#pragma region REG I/O
1828
1829 case OpCode::PRINT_R: {
1830 std::string s = registers[rA].toString();
1831#ifdef TRACING
1832 log(std::format("PRINT_R: (stdout) {:T}\n", registers[rA]));
1833#else
1834 c_print_stdout(s.c_str(), (i64)s.length());
1835#endif
1836 flush();
1837 break;
1838 }
1839
1840 [[unlikely]] case OpCode::PRINTERROR_R: {
1841 std::string s = registers[rA].toString();
1842#ifdef TRACING
1843 log(std::format("PRINTERROR_R: (stderr) {:T}\n", registers[rA]));
1844#else
1845 c_print_stderr(s.c_str(), (i64)s.length());
1846#endif
1847 flusherr();
1848 break;
1849 }
1850
1851 case OpCode::READLINE_R: {
1852 std::string s;
1853#ifdef TRACING
1854 log("READLINE_R:");
1855 flush();
1856#endif
1857 std::getline(std::cin, s);
1858#ifdef TRACING
1859 log(std::format("\nREADLINE_R: {}\n", s));
1860#endif
1861 registers[rA] = s;
1862 break;
1863 }
1864
1865#pragma endregion
1866#pragma region REG SYSTEM
1867
1868 case OpCode::SYSTEM_R: {
1869#ifdef SANDBOXED
1870 logerr("CANNOT ESCAPE SANDBOX");
1871 registers[rA] = Value();
1872#else
1873#ifdef TRACING
1874 Value cmd = registers[rA];
1875 i64 ret = c_system(cmd.c_str());
1876 log(std::format("SYSTEM_R: {} -> {}\n", cmd, ret));
1877 registers[rA] = ret;
1878#else
1879 registers[rA] = c_system(registers[rA].c_str());
1880#endif
1881#endif
1882 break;
1883 }
1884
1885 case OpCode::SYSTEM_OUT_R: {
1886#ifdef SANDBOXED
1887 logerr("CANNOT ESCAPE SANDBOX");
1888 registers[rA] = Value();
1889#else
1890#ifdef TRACING
1891 Value cmd = registers[rA];
1892 std::string ret = c_system_out(cmd.c_str());
1893 log(std::format("SYSTEM_R: {:T} -> {}\n", cmd, ret));
1894 registers[rA] = ret;
1895#else
1896 registers[rA] = c_system_out(registers[rA].c_str());
1897#endif
1898#endif
1899 break;
1900 }
1901
1902 case OpCode::SYSTEM_ERR_R: {
1903#ifdef SANDBOXED
1904 logerr("CANNOT ESCAPE SANDBOX");
1905 registers[rA] = Value();
1906#else
1907#ifdef TRACING
1908 Value cmd = registers[rA];
1909 std::string ret = c_system_err(cmd.c_str());
1910 log(std::format("SYSTEM_ERR_R: {:T} -> {}\n", cmd, ret));
1911 registers[rA] = ret;
1912#else
1913 registers[rA] = c_system_err(registers[rA].c_str());
1914#endif
1915#endif
1916 break;
1917 }
1918
1919#pragma endregion
1920
1921#pragma endregion
1922#pragma region DEFAULT
1923 default: {
1924 throw std::runtime_error("Unknown opcode");
1925 return Value();
1926 }
1927#pragma endregion
1928
1929 }
1930 return Value(operand1);
1931}
1932
1933} // namespace Phasor
void c_print_stderr(const char *s, int64_t len)
Native print error function.
Definition IO.c:105
int64_t c_system(const char *cmd)
CRT system call.
Definition IO.c:110
void c_print_stdout(const char *s, int64_t len)
Native print function.
Definition IO.c:100
char * c_system_out(const char *cmd)
CRT system call, get out.
Definition IO.c:115
char * c_system_err(const char *cmd)
CRT system call, get err.
Definition IO.c:240
double asm_tan(double a)
Native tangent.
Definition arithmetic.c:93
double asm_log(double a)
Native natural logarithm.
Definition arithmetic.c:73
int64_t asm_isub(int64_t a, int64_t b)
Native subtraction.
Definition arithmetic.c:13
double asm_flmod(double a, double b)
Definition arithmetic.c:58
double asm_sqrt(double a)
Native square root.
Definition arithmetic.c:63
double asm_fladd(double a, double b)
Definition arithmetic.c:8
double asm_sin(double a)
Native sine.
Definition arithmetic.c:83
int64_t asm_imod(int64_t a, int64_t b)
Native modulus.
Definition arithmetic.c:54
int64_t asm_idiv(int64_t a, int64_t b)
Native division.
Definition arithmetic.c:41
double asm_fldiv(double a, double b)
Definition arithmetic.c:49
double asm_flsub(double a, double b)
Definition arithmetic.c:17
int64_t asm_iadd(int64_t a, int64_t b)
Native addition.
Definition arithmetic.c:4
double asm_exp(double a)
Native exponential.
Definition arithmetic.c:78
double asm_flneg(double a)
Native negation.
Definition arithmetic.c:36
double asm_cos(double a)
Native cosine.
Definition arithmetic.c:88
int64_t asm_imul(int64_t a, int64_t b)
Native multiplication.
Definition arithmetic.c:22
double asm_flmul(double a, double b)
Definition arithmetic.c:26
double asm_pow(double a, double b)
Native power.
Definition arithmetic.c:68
std::size_t length() const noexcept
Throws when the HALT opcode is reached.
Definition VM.hpp:52
std::array< Value, MAX_REGISTERS > registers
Virtual registers for register-based operations (v2.0).
Definition VM.hpp:261
ImportHandler importHandler
Import handler for loading modules.
Definition VM.hpp:258
Value operation(const OpCode &op, const int &operand1=0, const int &operand2=0, const int &operand3=0)
Execute a single operation.
std::vector< Value > variables
Variable storage indexed by variable index, or simply: the managed heap.
Definition VM.hpp:271
Value pop()
Pop a value from the stack.
Definition Stack.cpp:17
void logerr(const Value &msg)
Log a Value to stderr.
Definition Utility.cpp:285
void evalLoop()
Definition Operations.cpp:9
bool isDirectCall
is a direct call to a function
Definition VM.hpp:245
std::vector< int > callStack
Call stack for function calls.
Definition VM.hpp:268
void log(const Value &msg)
Log a Value to stdout.
Definition Utility.cpp:279
void flush()
Flush stdout.
Definition Utility.cpp:291
size_t pc
Program counter.
Definition VM.hpp:277
void push(const Value &value)
Push a value onto the stack.
Definition Stack.cpp:8
std::map< std::string, NativeFunction > nativeFunctions
Native function registry.
Definition VM.hpp:280
const Bytecode * m_bytecode
Bytecode to execute.
Definition VM.hpp:274
Value peek()
Peek at the top value on the stack.
Definition Stack.cpp:38
void flusherr()
Flush stderr.
Definition Utility.cpp:296
A value in the Phasor VM.
Definition Value.hpp:59
PhsString asString() const noexcept
Get the value as a Small String.
Definition Value.hpp:199
const char * c_str() const
Convert to C Style String.
Definition Value.hpp:536
bool isTruthy() const noexcept
Helper to determine truthiness.
Definition Value.hpp:350
std::shared_ptr< ArrayInstance > asArray()
Get the value as an array.
Definition Value.hpp:208
bool isArray() const noexcept
Check if the value is an array.
Definition Value.hpp:153
bool isInt() const noexcept
Definition Value.hpp:148
static Value createStruct(const PhsString &name)
Definition Value.hpp:567
bool isFloat() const noexcept
Definition Value.hpp:149
void setField(const PhsString &name, Value value)
Definition Value.hpp:592
Value getField(const PhsString &name) const
Definition Value.hpp:577
f64 asFloat() const noexcept
Get the value as a f64.
Definition Value.hpp:177
i64 asInt() const noexcept
Get the value as an integer.
Definition Value.hpp:164
std::string toString() const noexcept
Convert to string for printing.
Definition Value.hpp:478
bool isString() const noexcept
Definition Value.hpp:150
static Phasor::u64 s[2]
Definition random.cpp:7
int64_t asm_iless_than(int64_t a, int64_t b)
Native Less than comparison.
Definition logical.c:35
int64_t asm_flequal(double a, double b)
Definition logical.c:77
int64_t asm_flless_equal(double a, double b)
Definition logical.c:97
int64_t asm_flless_than(double a, double b)
Definition logical.c:87
int64_t asm_fland(double a, double b)
Definition logical.c:60
int64_t asm_flgreater_equal(double a, double b)
Definition logical.c:102
int64_t asm_igreater_equal(int64_t a, int64_t b)
Native Greater than or equal comparison.
Definition logical.c:50
int64_t asm_ior(int64_t a, int64_t b)
Native bitwise OR.
Definition logical.c:13
int64_t asm_igreater_than(int64_t a, int64_t b)
Native Greater than comparison.
Definition logical.c:40
int64_t asm_flnot_equal(double a, double b)
Definition logical.c:82
int64_t asm_flgreater_than(double a, double b)
Definition logical.c:92
int64_t asm_flnot(double a)
Native bitwise NOT.
Definition logical.c:55
int64_t asm_iand(int64_t a, int64_t b)
Native bitwise AND.
Definition logical.c:8
int64_t asm_flor(double a, double b)
Definition logical.c:65
int64_t asm_iequal(int64_t a, int64_t b)
Native Equality comparison.
Definition logical.c:25
int64_t asm_inot_equal(int64_t a, int64_t b)
Native Inequality comparison.
Definition logical.c:30
int64_t asm_iless_equal(int64_t a, int64_t b)
Native Less than or equal comparison.
Definition logical.c:45
The Phasor Programming Language and Runtime.
Definition AST.hpp:13
int64_t i64
Definition phsint.hpp:16
uint8_t u8
Definition phsint.hpp:9
std::string opCodeToString(OpCode op)
Definition map.cpp:132
OpCode
Definition ISA.hpp:12
@ IGREATER_THAN
Pop b, pop a, push a > b.
Definition ISA.hpp:50
@ IEQUAL
Pop b, pop a, push a == b.
Definition ISA.hpp:47
@ SYSTEM_OUT
Call system function and push stdout.
Definition ISA.hpp:79
@ LOG_R
R[rA] = log(R[rB]).
Definition ISA.hpp:125
@ FLMOD_R
R[rA] = R[rB] % R[rC].
Definition ISA.hpp:122
@ SUBSTR
Pop len, pop start, pop s, push s.substr(start, len).
Definition ISA.hpp:91
@ IAND
Pop b, pop a, push a && b.
Definition ISA.hpp:41
@ NOT
Pop a, push !a.
Definition ISA.hpp:38
@ SET_FIELD_STATIC
Pop value and struct instance, set field by static offset.
Definition ISA.hpp:99
@ NULL_VAL
Push null.
Definition ISA.hpp:86
@ MOV
Copy register to register: R[rA] = R[rB].
Definition ISA.hpp:103
@ POW
pow()
Definition ISA.hpp:29
@ PRINTERROR_R
Print register to stderr: printerror(R[rA]).
Definition ISA.hpp:155
@ IAND_R
R[rA] = R[rB] && R[rC].
Definition ISA.hpp:132
@ FLMUL_R
R[rA] = R[rB] * R[rC].
Definition ISA.hpp:120
@ IADD
Pop b, pop a, push a + b.
Definition ISA.hpp:18
@ PUSH2_R
Push 2 registers to stack: push2(R[rA], R[rB]).
Definition ISA.hpp:108
@ FLGE_R
R[rA] = R[rB] >= R[rC].
Definition ISA.hpp:147
@ SYSTEM_R
Run an operating system shell command: system(R[rA]).
Definition ISA.hpp:157
@ PUSH_CONST
Push constant from constant pool.
Definition ISA.hpp:14
@ JUMP_IF_TRUE
Jump if top of stack is true (pops value).
Definition ISA.hpp:63
@ FLGT_R
R[rA] = R[rB] > R[rC].
Definition ISA.hpp:145
@ PUSH_R
Push register to stack: push(R[rA]).
Definition ISA.hpp:107
@ POP_R
Pop stack to register: R[rA] = pop().
Definition ISA.hpp:109
@ FLEQUAL
Pop b, pop a, push a == b.
Definition ISA.hpp:53
@ GET_FIELD_STATIC
Pop struct instance, push field by static offset (structIndex, fieldOffset).
Definition ISA.hpp:98
@ FLNOT_EQUAL
Pop b, pop a, push a != b.
Definition ISA.hpp:54
@ FLADD_R
R[rA] = R[rB] + R[rC].
Definition ISA.hpp:118
@ POP2_R
Pop 2 values from stack to registers: pop2(R[rA], R[rB]).
Definition ISA.hpp:110
@ LOAD_CONST_R
Load constant to register: R[rA] = constants[immediate].
Definition ISA.hpp:104
@ SQRT
sqrt()
Definition ISA.hpp:28
@ FLADD
Pop b, pop a, push a + b.
Definition ISA.hpp:23
@ JUMP
Unconditional jump to offset.
Definition ISA.hpp:61
@ FLLT_R
R[rA] = R[rB] < R[rC].
Definition ISA.hpp:144
@ SET_FIELD
Pop struct, pop field name, pop value, set field value.
Definition ISA.hpp:95
@ NOT_R
R[rA] = !R[rB].
Definition ISA.hpp:151
@ IMULTIPLY
Pop b, pop a, push a * b.
Definition ISA.hpp:20
@ READLINE_R
Read line into register: readline(R[rA]).
Definition ISA.hpp:156
@ LOG
log()
Definition ISA.hpp:30
@ CHAR_AT
Pop index, pop s, push s[index].
Definition ISA.hpp:90
@ IMUL_R
R[rA] = R[rB] * R[rC].
Definition ISA.hpp:115
@ FLGREATER_EQUAL
Pop b, pop a, push a >= b.
Definition ISA.hpp:58
@ FLLE_R
R[rA] = R[rB] <= R[rC].
Definition ISA.hpp:146
@ IGREATER_EQUAL
Pop b, pop a, push a >= b.
Definition ISA.hpp:52
@ SIN
sin()
Definition ISA.hpp:32
@ SYSTEM_ERR
Call system function and push stderr.
Definition ISA.hpp:80
@ SQRT_R
R[rA] = sqrt(R[rB]).
Definition ISA.hpp:123
@ ISUB_R
R[rA] = R[rB] - R[rC].
Definition ISA.hpp:114
@ FLDIV_R
R[rA] = R[rB] / R[rC].
Definition ISA.hpp:121
@ COS_R
R[rA] = cos(R[rB]).
Definition ISA.hpp:128
@ CALL_NATIVE
Call a native function: operand is index of function name in constants.
Definition ISA.hpp:76
@ ISUBTRACT
Pop b, pop a, push a - b.
Definition ISA.hpp:19
@ LEN
Pop s, push len(s).
Definition ISA.hpp:89
@ TAN
tan()
Definition ISA.hpp:34
@ FLMODULO
Pop b, pop a, push a % b.
Definition ISA.hpp:27
@ FALSE_P
Push false.
Definition ISA.hpp:85
@ NEW_STRUCT_INSTANCE_STATIC
Create new struct instance using struct section metadata (structIndex).
Definition ISA.hpp:97
@ NEG_R
R[rA] = -R[rB].
Definition ISA.hpp:150
@ IDIVIDE
Pop b, pop a, push a / b.
Definition ISA.hpp:21
@ FLOR
Pop b, pop a, push a || b.
Definition ISA.hpp:44
@ STORE_VAR
Pop top of stack, store in variable slot.
Definition ISA.hpp:67
@ ILE_R
R[rA] = R[rB] <= R[rC].
Definition ISA.hpp:138
@ FLDIVIDE
Pop b, pop a, push a / b.
Definition ISA.hpp:26
@ POW_R
R[rA] = pow(R[rB], R[rC]).
Definition ISA.hpp:124
@ EXP
exp()
Definition ISA.hpp:31
@ IMODULO
Pop b, pop a, push a % b.
Definition ISA.hpp:22
@ FLAND_R
R[rA] = R[rB] && R[rC].
Definition ISA.hpp:140
@ JUMP_IF_FALSE
Jump if top of stack is false (pops value).
Definition ISA.hpp:62
@ INOT_EQUAL
Pop b, pop a, push a != b.
Definition ISA.hpp:48
@ FLEQ_R
R[rA] = R[rB] == R[rC].
Definition ISA.hpp:142
@ LOAD_VAR
Push variable value onto stack.
Definition ISA.hpp:68
@ IOR
Pop b, pop a, push a || b.
Definition ISA.hpp:42
@ EXP_R
R[rA] = exp(R[rB]).
Definition ISA.hpp:126
@ RETURN
Return from function.
Definition ISA.hpp:81
@ STORE_VAR_R
Store register to varible: variables[immediate] = R[rA].
Definition ISA.hpp:106
@ READLINE
Read line from input and push onto stack.
Definition ISA.hpp:73
@ IGT_R
R[rA] = R[rB] > R[rC].
Definition ISA.hpp:137
@ FLSUBTRACT
Pop b, pop a, push a - b.
Definition ISA.hpp:24
@ IADD_R
R[rA] = R[rB] + R[rC].
Definition ISA.hpp:113
@ IDIV_R
R[rA] = R[rB] / R[rC].
Definition ISA.hpp:116
@ FLLESS_EQUAL
Pop b, pop a, push a <= b.
Definition ISA.hpp:57
@ SYSTEM_ERR_R
Run shell command and get output: system_out(R[rA], R[rB]).
Definition ISA.hpp:159
@ FLMULTIPLY
Pop b, pop a, push a * b.
Definition ISA.hpp:25
@ ILESS_EQUAL
Pop b, pop a, push a <= b.
Definition ISA.hpp:51
@ HALT
Stop execution.
Definition ISA.hpp:75
@ PRINT_R
Print register: print(R[rA]).
Definition ISA.hpp:154
@ PRINTERROR
Pop top of stack and print to stderr.
Definition ISA.hpp:72
@ TAN_R
R[rA] = tan(R[rB]).
Definition ISA.hpp:129
@ FLSUB_R
R[rA] = R[rB] - R[rC].
Definition ISA.hpp:119
@ JUMP_BACK
Jump backwards (for loops).
Definition ISA.hpp:64
@ FLOR_R
R[rA] = R[rB] || R[rC].
Definition ISA.hpp:141
@ CALL
Call a user function: operand is index of function name in constants.
Definition ISA.hpp:77
@ INE_R
R[rA] = R[rB] != R[rC].
Definition ISA.hpp:135
@ NEGATE
Pop a, push -a.
Definition ISA.hpp:37
@ FLNE_R
R[rA] = R[rB] != R[rC].
Definition ISA.hpp:143
@ FLGREATER_THAN
Pop b, pop a, push a > b.
Definition ISA.hpp:56
@ ILESS_THAN
Pop b, pop a, push a < b.
Definition ISA.hpp:49
@ GET_FIELD
Pop struct, pop field name, push field value.
Definition ISA.hpp:94
@ SIN_R
R[rA] = sin(R[rB]).
Definition ISA.hpp:127
@ IMPORT
Import a module: operand is index of module path in constants.
Definition ISA.hpp:74
@ LOAD_VAR_R
Load variable to register: R[rA] = variables[immediate].
Definition ISA.hpp:105
@ FLLESS_THAN
Pop b, pop a, push a < b.
Definition ISA.hpp:55
@ NEW_STRUCT
Create new struct: operand is index of struct name in constants.
Definition ISA.hpp:93
@ IOR_R
R[rA] = R[rB] || R[rC].
Definition ISA.hpp:133
@ ILT_R
R[rA] = R[rB] < R[rC].
Definition ISA.hpp:136
@ TRUE_P
Push true.
Definition ISA.hpp:84
@ COS
cos()
Definition ISA.hpp:33
@ POP
Pop top of stack.
Definition ISA.hpp:15
@ FLAND
Pop b, pop a, push a && b.
Definition ISA.hpp:43
@ IMOD_R
R[rA] = R[rB] % R[rC].
Definition ISA.hpp:117
@ PRINT
Pop top of stack and print.
Definition ISA.hpp:71
@ SYSTEM
Call a system function: operand is index of function name in constants.
Definition ISA.hpp:78
@ IEQ_R
R[rA] = R[rB] == R[rC].
Definition ISA.hpp:134
@ IGE_R
R[rA] = R[rB] >= R[rC].
Definition ISA.hpp:139
Instruction with up to 5 operands Format: instruction operand1, operand2, operand3 Each instruction u...
Definition CodeGen.hpp:21
i32 operand1
First operand.
Definition CodeGen.hpp:23
i32 operand2
Second operand.
Definition CodeGen.hpp:24
OpCode op
Operation code.
Definition CodeGen.hpp:22
i32 operand3
Third operand.
Definition CodeGen.hpp:25
Struct metadata stored alongside bytecode (struct section).
Definition CodeGen.hpp:41
int firstConstIndex
Index into constants for the first default value.
Definition CodeGen.hpp:43
std::vector< std::string > fieldNames
Field names in declaration order.
Definition CodeGen.hpp:45
int fieldCount
Number of fields in this struct.
Definition CodeGen.hpp:44
std::string name
Struct name.
Definition CodeGen.hpp:42