Phasor 3.1.1
Stack VM based Programming Language
Loading...
Searching...
No Matches
Operations.cc.inl
Go to the documentation of this file.
1#ifndef OPS_ARE_INCLUDED
2#include "VM.hpp" // avoid breaking IDEs
3#endif
4
5namespace Phasor {
6
7Value VM::operation(const OpCode &op, const int &operand1, const int &operand2, const int &operand3, const int &, const int &)
8{
9 uint8_t rA = static_cast<uint8_t>(operand1);
10 uint8_t rB = static_cast<uint8_t>(operand2);
11 uint8_t rC = static_cast<uint8_t>(operand3);
12#ifdef TRACING
13 log(std::format("VM::{}({}, {}, {}, {})\n", __func__, opCodeToString(op), operand1, operand2, operand3));
14 flush();
15#endif
16 switch (op)
17 {
18 [[likely]] case OpCode::PUSH_CONST:
19 if (operand1 < 0 || operand1 >= static_cast<int>(m_bytecode->constants.size()))
20 throw std::runtime_error("Invalid constant index");
21 push(m_bytecode->constants[operand1]);
22 break;
23
24 [[likely]] case OpCode::POP:
25 pop();
26 break;
27
28 case OpCode::IADD: {
29 Value b = pop();
30 Value a = pop();
31 push(asm_iadd(a.asInt(), b.asInt()));
32 break;
33 }
34
35 case OpCode::ISUBTRACT: {
36 Value b = pop();
37 Value a = pop();
38 push(asm_isub(a.asInt(), b.asInt()));
39 break;
40 }
41
42 case OpCode::IMULTIPLY: {
43 Value b = pop();
44 Value a = pop();
45 push(asm_imul(a.asInt(), b.asInt()));
46 break;
47 }
48
49 case OpCode::IDIVIDE: {
50 Value b = pop();
51 Value a = pop();
52 push(asm_idiv(a.asInt(), b.asInt()));
53 break;
54 }
55
56 case OpCode::IMODULO: {
57 Value b = pop();
58 Value a = pop();
59 push(asm_imod(a.asInt(), b.asInt()));
60 break;
61 }
62
63 case OpCode::FLADD: {
64 Value b = pop();
65 Value a = pop();
66 push(asm_fladd(a.asFloat(), b.asFloat()));
67 break;
68 }
69
70 case OpCode::FLSUBTRACT: {
71 Value b = pop();
72 Value a = pop();
73 push(asm_flsub(a.asFloat(), b.asFloat()));
74 break;
75 }
76
77 case OpCode::FLMULTIPLY: {
78 Value b = pop();
79 Value a = pop();
80 push(asm_flmul(a.asFloat(), b.asFloat()));
81 break;
82 }
83
84 case OpCode::FLDIVIDE: {
85 Value b = pop();
86 Value a = pop();
87 push(asm_fldiv(a.asFloat(), b.asFloat()));
88 break;
89 }
90
91 case OpCode::FLMODULO: {
92 Value b = pop();
93 Value a = pop();
94 push(asm_flmod(a.asFloat(), b.asFloat()));
95 break;
96 }
97
98 case OpCode::SQRT: {
99 Value a = pop();
100 push(asm_sqrt(a.asFloat()));
101 break;
102 }
103
104 case OpCode::POW: {
105 Value b = pop();
106 Value a = pop();
107 push(asm_pow(a.asFloat(), b.asFloat()));
108 break;
109 }
110
111 case OpCode::LOG: {
112 Value a = pop();
113 push(asm_log(a.asFloat()));
114 break;
115 }
116
117 case OpCode::EXP: {
118 Value a = pop();
119 push(asm_exp(a.asFloat()));
120 break;
121 }
122
123 case OpCode::SIN: {
124 Value a = pop();
125 push(asm_sin(a.asFloat()));
126 break;
127 }
128
129 case OpCode::COS: {
130 Value a = pop();
131 push(asm_cos(a.asFloat()));
132 break;
133 }
134
135 case OpCode::TAN: {
136 Value a = pop();
137 push(asm_tan(a.asFloat()));
138 break;
139 }
140
141 case OpCode::NEGATE:
142 push(asm_flneg(pop().asFloat()));
143 break;
144
145 case OpCode::NOT:
146 push(Value(asm_flnot(pop().isTruthy() ? 1 : 0)));
147 break;
148
149 case OpCode::IAND: {
150 Value b = pop();
151 Value a = pop();
152 push(Value(asm_iand(a.isTruthy() ? 1 : 0, b.isTruthy() ? 1 : 0)));
153 break;
154 }
155
156 case OpCode::IOR: {
157 Value b = pop();
158 Value a = pop();
159 push(Value(asm_ior(a.isTruthy() ? 1 : 0, b.isTruthy() ? 1 : 0)));
160 break;
161 }
162
163 case OpCode::IEQUAL: {
164 Value b = pop();
165 Value a = pop();
166 push(a.isInt() && b.isInt() ? Value(asm_iequal(a.asInt(), b.asInt())) : Value(a == b));
167 break;
168 }
169
170 case OpCode::INOT_EQUAL: {
171 Value b = pop();
172 Value a = pop();
173 push(a.isInt() && b.isInt() ? Value(asm_inot_equal(a.asInt(), b.asInt())) : Value(a != b));
174 break;
175 }
176
177 case OpCode::ILESS_THAN: {
178 Value b = pop();
179 Value a = pop();
180 push(a.isInt() && b.isInt() ? Value(asm_iless_than(a.asInt(), b.asInt())) : Value(a < b));
181 break;
182 }
183
185 Value b = pop();
186 Value a = pop();
187 push(a.isInt() && b.isInt() ? Value(asm_igreater_than(a.asInt(), b.asInt())) : Value(a > b));
188 break;
189 }
190
191 case OpCode::ILESS_EQUAL: {
192 Value b = pop();
193 Value a = pop();
194 push(a.isInt() && b.isInt() ? Value(asm_iless_equal(a.asInt(), b.asInt())) : Value(a <= b));
195 break;
196 }
197
199 Value b = pop();
200 Value a = pop();
201 push(a.isInt() && b.isInt() ? Value(asm_igreater_equal(a.asInt(), b.asInt())) : Value(a >= b));
202 break;
203 }
204
205 case OpCode::FLAND: {
206 Value b = pop();
207 Value a = pop();
208 push(Value(asm_fland(a.isTruthy() ? 1 : 0, b.isTruthy() ? 1 : 0)));
209 break;
210 }
211
212 case OpCode::FLOR: {
213 Value b = pop();
214 Value a = pop();
215 push(Value(asm_flor(a.isTruthy() ? 1 : 0, b.isTruthy() ? 1 : 0)));
216 break;
217 }
218
219 case OpCode::FLEQUAL: {
220 Value b = pop();
221 Value a = pop();
222 push(a.isFloat() && b.isFloat() ? Value(asm_flequal(a.asFloat(), b.asFloat())) : Value(a == b));
223 break;
224 }
225
226 case OpCode::FLNOT_EQUAL: {
227 Value b = pop();
228 Value a = pop();
229 push(a.isFloat() && b.isFloat() ? Value(asm_flnot_equal(a.asFloat(), b.asFloat())) : Value(a != b));
230 break;
231 }
232
233 case OpCode::FLLESS_THAN: {
234 Value b = pop();
235 Value a = pop();
236 push(a.isFloat() && b.isFloat() ? Value(asm_flless_than(a.asFloat(), b.asFloat())) : Value(a < b));
237 break;
238 }
239
241 Value b = pop();
242 Value a = pop();
243 push(a.isFloat() && b.isFloat() ? Value(asm_flgreater_than(a.asFloat(), b.asFloat())) : Value(a > b));
244 break;
245 }
246
248 Value b = pop();
249 Value a = pop();
250 push(a.isFloat() && b.isFloat() ? Value(asm_flless_equal(a.asFloat(), b.asFloat())) : Value(a <= b));
251 break;
252 }
253
255 Value b = pop();
256 Value a = pop();
257 push(a.isFloat() && b.isFloat() ? Value(asm_flgreater_equal(a.asFloat(), b.asFloat())) : Value(a >= b));
258 break;
259 }
260
261 [[likely]] case OpCode::JUMP: {
262#ifdef TRACING
263 log(std::format("JUMP: {} -> {}\n", pc, operand1));
264 flush();
265#endif
266 pc = operand1;
267 break;
268 }
269
271 if (!pop().isTruthy())
272 pc = operand1;
273 break;
274
276 if (pop().isTruthy())
277 pc = operand1;
278 break;
279
281 pc = operand1;
282 break;
283
284 [[likely]] case OpCode::STORE_VAR:
285 if (operand1 < 0 || operand1 >= static_cast<int>(variables.size()))
286 throw std::runtime_error("Invalid variable index");
287 variables[operand1] = pop();
288 break;
289
290 [[likely]] case OpCode::LOAD_VAR:
291 if (operand1 < 0 || operand1 >= static_cast<int>(variables.size()))
292 throw std::runtime_error("Invalid variable index");
293 push(variables[operand1]);
294 break;
295
296 case OpCode::PRINT: {
297 Value v = pop();
298 std::string s = v.toString();
299#ifdef _TRACING
300 log(std::format("PRINT: (stdout) {:T}\n", v));
301#else
302 asm_print_stdout(s.c_str(), (int64_t)s.length());
303#endif
304 break;
305 }
306
307 [[unlikely]] case OpCode::PRINTERROR: {
308 Value v = pop();
309 std::string s = v.toString();
310#ifdef _TRACING
311 log(std::format("PRINTERROR: (stderr) {:T}\n", v));
312#else
313 asm_print_stderr(s.c_str(), (int64_t)s.length());
314#endif
315 flusherr();
316 break;
317 }
318
319 case OpCode::READLINE: {
320 std::string s;
321#ifdef TRACING
322 log("READLINE:");
323 flush();
324#endif
325 std::getline(std::cin, s);
326#ifdef TRACING
327 log(std::format("\nREADLINE: {}\n", s));
328#endif
329 push(s);
330 break;
331 }
332
333 [[unlikely]] case OpCode::IMPORT: {
334 Value pathVal = m_bytecode->constants[operand1];
335 std::string path = pathVal.asString();
336 if (importHandler)
337 importHandler(path);
338 else
339 throw std::runtime_error("Import handler not set");
340 break;
341 }
342 [[unlikely]] case OpCode::HALT:
343 pc = m_bytecode->instructions.size(); // stop execution
344 throw VM::Halt();
345 break;
346
347 [[likely]] case OpCode::CALL_NATIVE: {
348 Value funcNameVal = m_bytecode->constants[operand1];
349 std::string funcName = funcNameVal.asString();
350 auto it = nativeFunctions.find(funcName);
351 if (it == nativeFunctions.end())
352 throw std::runtime_error("Unknown native function: " + funcName);
353
354 int argCount = static_cast<int>(pop().asInt());
355 std::vector<Value> args(argCount);
356 for (int i = argCount - 1; i >= 0; --i)
357 args[i] = pop();
358
359#ifdef TRACING
360 std::string argsText;
361 for (auto &arg : args)
362 {
363 argsText += std::format("{:T}", arg);
364 if (arg != args.back())
365 argsText += ", ";
366 }
367 log(std::format("CALL_NATIVE: {}({})\n", funcName, argsText));
368 flush();
369#endif
370
371 push(it->second(args, this));
372
373 break;
374 }
375 case OpCode::TRUE_P:
376 push(Value(true));
377 break;
378
379 case OpCode::FALSE_P:
380 push(Value(false));
381 break;
382
383 case OpCode::NULL_VAL:
384 push(Value());
385 break;
386
387 [[likely]] case OpCode::CALL: {
388 Value funcNameVal = m_bytecode->constants[operand1];
389 std::string funcName = funcNameVal.asString();
390 auto it = m_bytecode->functionEntries.find(funcName);
391 if (it == m_bytecode->functionEntries.end())
392 throw std::runtime_error("Unknown function: " + funcName);
393
394 callStack.push_back(static_cast<int>(pc));
395 pc = it->second;
396 break;
397 }
398 [[likely]] case OpCode::RETURN: {
399 if (callStack.empty())
400 {
401 pc = m_bytecode->instructions.size();
402 break;
403 }
404 pc = callStack.back();
405 callStack.pop_back();
406 break;
407 }
408
409 case OpCode::SYSTEM: {
410#ifdef SANDBOXED
411 logerr("CANNOT ESCAPE SANDBOX");
412 push(Value());
413#else
414 #ifdef TRACING
415 Value cmd = pop();
416 int ret = asm_system(cmd.c_str());
417 log(std::format("SYSTEM: {:T} -> {}\n", cmd, ret));
418 push(ret);
419 #else
420 push(asm_system(pop().c_str()));
421 #endif
422#endif
423 break;
424 }
425
426 case OpCode::SYSTEM_OUT: {
427#ifdef SANDBOXED
428 logerr("CANNOT ESCAPE SANDBOX");
429 push(Value());
430#else
431 #ifdef TRACING
432 Value cmd = pop();
433 std::string ret = asm_system_out(cmd.c_str());
434 log(std::format("SYSTEM_OUT: {:T} -> {}\n", cmd, ret));
435 push(ret);
436 #else
437 push(asm_system_out(pop().c_str()));
438 #endif
439#endif
440 break;
441 }
442
443 case OpCode::SYSTEM_ERR: {
444#ifdef SANDBOXED
445 logerr("CANNOT ESCAPE SANDBOX");
446 push(Value());
447#else
448 #ifdef TRACING
449 Value cmd = pop();
450 std::string ret = asm_system_err(cmd.c_str());
451 log(std::format("SYSTEM_ERR: {:T} -> {}\n", cmd, ret));
452 push(ret);
453 #else
454 push(asm_system_err(pop().c_str()));
455 #endif
456#endif
457 break;
458 }
459
460 // Register-based operations (v2.0)
461 [[likely]] case OpCode::MOV: {
462 registers[rA] = registers[rB];
463 break;
464 }
465
466 [[likely]] case OpCode::LOAD_CONST_R: {
467 // LOAD_CONST_R rA, constIndex
468 auto constIndex = operand2;
469 if (constIndex < 0 || constIndex >= static_cast<int>(m_bytecode->constants.size()))
470 throw std::runtime_error("Invalid constant index");
471 registers[rA] = m_bytecode->constants[constIndex];
472 break;
473 }
474
475 [[likely]] case OpCode::LOAD_VAR_R: {
476 // LOAD_VAR_R rA, varIndex
477 auto varIndex = operand2;
478 if (varIndex < 0 || varIndex >= static_cast<int>(variables.size()))
479 throw std::runtime_error("Invalid variable index");
480 registers[rA] = variables[varIndex];
481 break;
482 }
483
484 [[likely]] case OpCode::STORE_VAR_R: {
485 // STORE_VAR_R rA, varIndex - store register rA to variable varIndex
486 auto varIndex = operand2;
487 if (varIndex < 0 || varIndex >= static_cast<int>(variables.size()))
488 throw std::runtime_error("Invalid variable index");
489 variables[varIndex] = registers[rA];
490 break;
491 }
492
493 // Register arithmetic (3-address code)
494 // Format: operand1=rA (dest), operand2=rB, operand3=rC
495 case OpCode::IADD_R: {
496 registers[rA] = Value(asm_iadd(registers[rB].asInt(), registers[rC].asInt()));
497 break;
498 }
499
500 case OpCode::ISUB_R: {
501 registers[rA] = Value(asm_isub(registers[rB].asInt(), registers[rC].asInt()));
502 break;
503 }
504
505 case OpCode::IMUL_R: {
506 registers[rA] = Value(asm_imul(registers[rB].asInt(), registers[rC].asInt()));
507 break;
508 }
509
510 case OpCode::IDIV_R: {
511 registers[rA] = Value(asm_idiv(registers[rB].asInt(), registers[rC].asInt()));
512 break;
513 }
514
515 case OpCode::IMOD_R: {
516 registers[rA] = Value(asm_imod(registers[rB].asInt(), registers[rC].asInt()));
517 break;
518 }
519
520 case OpCode::FLADD_R: {
521 registers[rA] = Value(asm_fladd(registers[rB].asFloat(), registers[rC].asFloat()));
522 break;
523 }
524
525 case OpCode::FLSUB_R: {
526 registers[rA] = Value(asm_flsub(registers[rB].asFloat(), registers[rC].asFloat()));
527 break;
528 }
529
530 case OpCode::FLMUL_R: {
531 registers[rA] = Value(asm_flmul(registers[rB].asFloat(), registers[rC].asFloat()));
532 break;
533 }
534
535 case OpCode::FLDIV_R: {
536 registers[rA] = Value(asm_fldiv(registers[rB].asFloat(), registers[rC].asFloat()));
537 break;
538 }
539
540 case OpCode::FLMOD_R: {
541 registers[rA] = Value(asm_flmod(registers[rB].asFloat(), registers[rC].asFloat()));
542 break;
543 }
544
545 case OpCode::SQRT_R: {
546 registers[rA] = Value(asm_sqrt(registers[rB].asFloat()));
547 break;
548 }
549
550 case OpCode::POW_R: {
551 registers[rA] = Value(asm_pow(registers[rB].asFloat(), registers[rC].asFloat()));
552 break;
553 }
554
555 case OpCode::LOG_R: {
556 registers[rA] = Value(asm_log(registers[rB].asFloat()));
557 break;
558 }
559
560 case OpCode::EXP_R: {
561 registers[rA] = Value(asm_exp(registers[rB].asFloat()));
562 break;
563 }
564
565 case OpCode::SIN_R: {
566 registers[rA] = Value(asm_sin(registers[rB].asFloat()));
567 break;
568 }
569
570 case OpCode::COS_R: {
571 registers[rA] = Value(asm_cos(registers[rB].asFloat()));
572 break;
573 }
574
575 case OpCode::TAN_R: {
576 registers[rA] = Value(asm_tan(registers[rB].asFloat()));
577 break;
578 }
579
580 // Register comparisons
581 // Format: operand1=rA (dest), operand2=rB, operand3=rC
582 case OpCode::IEQ_R: {
583 Value &b = registers[rB];
584 Value &c = registers[rC];
585 registers[rA] = (b.isInt() && c.isInt()) ? Value(asm_iequal(b.asInt(), c.asInt())) : Value(b == c);
586 break;
587 }
588
589 case OpCode::INE_R: {
590 Value &b = registers[rB];
591 Value &c = registers[rC];
592 registers[rA] = (b.isInt() && c.isInt()) ? Value(asm_inot_equal(b.asInt(), c.asInt())) : Value(b != c);
593 break;
594 }
595
596 case OpCode::ILT_R: {
597 Value &b = registers[rB];
598 Value &c = registers[rC];
599 registers[rA] = (b.isInt() && c.isInt()) ? Value(asm_iless_than(b.asInt(), c.asInt())) : Value(b < c);
600 break;
601 }
602
603 case OpCode::IGT_R: {
604 Value &b = registers[rB];
605 Value &c = registers[rC];
606 registers[rA] = (b.isInt() && c.isInt()) ? Value(asm_igreater_than(b.asInt(), c.asInt())) : Value(b > c);
607 break;
608 }
609
610 case OpCode::ILE_R: {
611 Value &b = registers[rB];
612 Value &c = registers[rC];
613 registers[rA] = (b.isInt() && c.isInt()) ? Value(asm_iless_equal(b.asInt(), c.asInt())) : Value(b <= c);
614 break;
615 }
616
617 case OpCode::IGE_R: {
618 Value &b = registers[rB];
619 Value &c = registers[rC];
620 registers[rA] = (b.isInt() && c.isInt()) ? Value(asm_igreater_equal(b.asInt(), c.asInt())) : Value(b >= c);
621 break;
622 }
623
624 case OpCode::IAND_R: {
625 Value &b = registers[rB];
626 Value &c = registers[rC];
627 registers[rA] = Value(asm_iand(b.isTruthy() ? 1 : 0, c.isTruthy() ? 1 : 0));
628 break;
629 }
630
631 case OpCode::IOR_R: {
632 Value &b = registers[rB];
633 Value &c = registers[rC];
634 registers[rA] = Value(asm_ior(b.isTruthy() ? 1 : 0, c.isTruthy() ? 1 : 0));
635 break;
636 }
637
638 case OpCode::FLEQ_R: {
639 Value &b = registers[rB];
640 Value &c = registers[rC];
641 registers[rA] = (b.isFloat() && c.isFloat()) ? Value(asm_flequal(b.asFloat(), c.asFloat())) : Value(b == c);
642 break;
643 }
644
645 case OpCode::FLNE_R: {
646 Value &b = registers[rB];
647 Value &c = registers[rC];
648 registers[rA] = (b.isFloat() && c.isFloat()) ? Value(asm_flnot_equal(b.asFloat(), c.asFloat())) : Value(b != c);
649 break;
650 }
651
652 case OpCode::FLLT_R: {
653 Value &b = registers[rB];
654 Value &c = registers[rC];
655 registers[rA] = (b.isFloat() && c.isFloat()) ? Value(asm_flless_than(b.asFloat(), c.asFloat())) : Value(b < c);
656 break;
657 }
658
659 case OpCode::FLGT_R: {
660 Value &b = registers[rB];
661 Value &c = registers[rC];
662 registers[rA] =
663 (b.isFloat() && c.isFloat()) ? Value(asm_flgreater_than(b.asFloat(), c.asFloat())) : Value(b > c);
664 break;
665 }
666
667 case OpCode::FLLE_R: {
668 Value &b = registers[rB];
669 Value &c = registers[rC];
670 registers[rA] =
671 (b.isFloat() && c.isFloat()) ? Value(asm_flless_equal(b.asFloat(), c.asFloat())) : Value(b <= c);
672 break;
673 }
674
675 case OpCode::FLGE_R: {
676 Value &b = registers[rB];
677 Value &c = registers[rC];
678 registers[rA] =
679 (b.isFloat() && c.isFloat()) ? Value(asm_flgreater_equal(b.asFloat(), c.asFloat())) : Value(b >= c);
680 break;
681 }
682
683 case OpCode::FLAND_R: {
684 Value &b = registers[rB];
685 Value &c = registers[rC];
686 registers[rA] = Value(asm_fland(b.isTruthy() ? 1 : 0, c.isTruthy() ? 1 : 0));
687 break;
688 }
689
690 case OpCode::FLOR_R: {
691 Value &b = registers[rB];
692 Value &c = registers[rC];
693 registers[rA] = Value(asm_flor(b.isTruthy() ? 1 : 0, c.isTruthy() ? 1 : 0));
694 break;
695 }
696
697 // Register-stack interaction
698 case OpCode::PUSH_R: {
699 push(registers[rA]);
700 break;
701 }
702
703 case OpCode::PUSH2_R: {
704 push(registers[rA]);
705 push(registers[rB]);
706 break;
707 }
708
709 case OpCode::POP_R: {
710 registers[rA] = pop();
711 break;
712 }
713
714 case OpCode::POP2_R: {
715 registers[rA] = pop();
716 registers[rB] = pop();
717 break;
718 }
719
720 // Register unary operations
721 case OpCode::NEG_R: {
722 // NEG_R rA, rB - rA = -rB
723 registers[rA] = Value(asm_flneg(registers[rB].asFloat()));
724 break;
725 }
726
727 case OpCode::NOT_R: {
728 // NOT_R rA, rB - rA = !rB
729 registers[rA] = Value(asm_flnot(registers[rB].isTruthy() ? 1 : 0));
730 break;
731 }
732
733 // Register I/O
734 case OpCode::PRINT_R: {
735 std::string s = registers[rA].toString();
736#ifdef TRACING
737 log(std::format("PRINT_R: (stdout) {:T}\n", registers[rA]));
738#else
739 asm_print_stdout(s.c_str(), (int64_t)s.length());
740#endif
741 break;
742 }
743
744 [[unlikely]] case OpCode::PRINTERROR_R: {
745 std::string s = registers[rA].toString();
746#ifdef TRACING
747 log(std::format("PRINTERROR_R: (stderr) {:T}\n", registers[rA]));
748#else
749 asm_print_stderr(s.c_str(), (int64_t)s.length());
750#endif
751 flusherr();
752 break;
753 }
754
755 case OpCode::READLINE_R: {
756 std::string s;
757#ifdef TRACING
758 log("READLINE_R:");
759 flush();
760#endif
761 std::getline(std::cin, s);
762#ifdef TRACING
763 log(std::format("\nREADLINE_R: {}\n", s));
764#endif
765 registers[rA] = s;
766 break;
767 }
768
769 case OpCode::SYSTEM_R: {
770#ifdef SANDBOXED
771 logerr("CANNOT ESCAPE SANDBOX");
772 registers[rA] = Value();
773#else
774 #ifdef TRACING
775 Value cmd = registers[rA];
776 int64_t ret = asm_system(cmd.c_str());
777 log(std::format("SYSTEM_R: {} -> {}\n", cmd, ret));
778 registers[rA] = ret;
779 #else
780 registers[rA] = asm_system(registers[rA].c_str());
781 #endif
782#endif
783 break;
784 }
785
787#ifdef SANDBOXED
788 logerr("CANNOT ESCAPE SANDBOX");
789 registers[rA] = Value();
790#else
791 #ifdef TRACING
792 Value cmd = registers[rA];
793 std::string ret = asm_system_out(cmd.c_str());
794 log(std::format("SYSTEM_R: {:T} -> {}\n", cmd, ret));
795 registers[rA] = ret;
796 #else
797 registers[rA] = asm_system_out(registers[rA].c_str());
798 #endif
799#endif
800 break;
801 }
802
804#ifdef SANDBOXED
805 logerr("CANNOT ESCAPE SANDBOX");
806 registers[rA] = Value();
807#else
808 #ifdef TRACING
809 Value cmd = registers[rA];
810 std::string ret = asm_system_err(cmd.c_str());
811 log(std::format("SYSTEM_ERR_R: {:T} -> {}\n", cmd, ret));
812 registers[rA] = ret;
813 #else
814 registers[rA] = asm_system_err(registers[rA].c_str());
815 #endif
816#endif
817 break;
818 }
819
820 case OpCode::LEN: {
821 Value v = pop();
822 push(Value(static_cast<int64_t>(v.asString().length())));
823 break;
824 }
825
826 case OpCode::CHAR_AT: {
827 Value idxVal = pop();
828 Value strVal = pop();
829
830 std::string s;
831 if (strVal.isString())
832 s = strVal.asString();
833 else
834 s = strVal.toString();
835
836 int64_t idx = 0;
837 if (idxVal.isInt())
838 idx = idxVal.asInt();
839 else if (idxVal.isFloat())
840 idx = static_cast<int64_t>(idxVal.asFloat());
841 else if (idxVal.isString())
842 {
843 try
844 {
845 idx = std::stoll(idxVal.asString());
846 }
847 catch (...)
848 {
849 throw std::runtime_error("char_at() expects index convertible to integer");
850 }
851 }
852 else
853 throw std::runtime_error("char_at() expects string and integer");
854
855 if (idx < 0 || idx >= static_cast<int64_t>(s.length()))
856 push(Value(""));
857 else
858 push(Value(std::string(1, s[static_cast<size_t>(idx)])));
859 break;
860 }
861
862 case OpCode::SUBSTR: {
863 Value lenVal = pop();
864 Value startVal = pop();
865 Value strVal = pop();
866
867 if (strVal.isString() && startVal.isInt() && lenVal.isInt())
868 {
869 const std::string &s = strVal.asString();
870 int64_t start = startVal.asInt();
871 int64_t len = lenVal.asInt();
872
873 if (start < 0 || start >= static_cast<int64_t>(s.length()))
874 {
875 push(Value(""));
876 }
877 else
878 {
879 push(Value(s.substr(start, len)));
880 }
881 }
882 else
883 {
884 throw std::runtime_error("substr() expects string, int, int");
885 }
886 break;
887 }
888
890 if (operand1 < 0 || operand1 >= static_cast<int>(m_bytecode->structs.size()))
891 throw std::runtime_error("Invalid struct index for NEW_STRUCT_INSTANCE_STATIC");
892
893 const StructInfo &info = m_bytecode->structs[operand1];
894 Value instance = Value::createStruct(info.name);
895 for (int i = 0; i < info.fieldCount; ++i)
896 {
897 int constIndex = info.firstConstIndex + i;
898 if (constIndex < 0 || constIndex >= static_cast<int>(m_bytecode->constants.size()))
899 throw std::runtime_error("Invalid default constant index for struct field");
900 const Value &defVal = m_bytecode->constants[constIndex];
901 const std::string &fieldName = info.fieldNames[i];
902 instance.setField(fieldName, defVal);
903 }
904 push(instance);
905 break;
906 }
907
909 if (operand1 < 0 || operand1 >= static_cast<int>(m_bytecode->structs.size()))
910 throw std::runtime_error("Invalid struct index for GET_FIELD_STATIC");
911 const StructInfo &info = m_bytecode->structs[operand1];
912 auto fieldOffset = operand2;
913 if (fieldOffset < 0 || fieldOffset >= info.fieldCount)
914 throw std::runtime_error("Invalid field offset for GET_FIELD_STATIC");
915 const std::string &fieldName = info.fieldNames[fieldOffset];
916 Value obj = pop();
917 push(obj.getField(fieldName));
918 break;
919 }
920
922 if (operand1 < 0 || operand1 >= static_cast<int>(m_bytecode->structs.size()))
923 throw std::runtime_error("Invalid struct index for SET_FIELD_STATIC");
924 const StructInfo &info = m_bytecode->structs[operand1];
925 auto fieldOffset = operand2;
926 if (fieldOffset < 0 || fieldOffset >= info.fieldCount)
927 throw std::runtime_error("Invalid field offset for SET_FIELD_STATIC");
928 const std::string &fieldName = info.fieldNames[fieldOffset];
929 Value value = pop();
930 Value obj = pop();
931 obj.setField(fieldName, value);
932 push(obj);
933 break;
934 }
935
936 case OpCode::NEW_STRUCT: {
937 if (operand1 < 0 || operand1 >= static_cast<int>(m_bytecode->constants.size()))
938 throw std::runtime_error("Invalid constant index for NEW_STRUCT");
939 Value nameVal = m_bytecode->constants[operand1];
940 std::string structName = nameVal.asString();
941 push(Value::createStruct(structName));
942 break;
943 }
944
945 case OpCode::SET_FIELD: {
946 if (operand1 < 0 || operand1 >= static_cast<int>(m_bytecode->constants.size()))
947 throw std::runtime_error("Invalid constant index for SET_FIELD");
948 std::string fieldName = m_bytecode->constants[operand1].asString();
949 Value value = pop();
950 Value obj = pop();
951 obj.setField(fieldName, value);
952 push(obj);
953 break;
954 }
955
956 case OpCode::GET_FIELD: {
957 if (operand1 < 0 || operand1 >= static_cast<int>(m_bytecode->constants.size()))
958 throw std::runtime_error("Invalid constant index for GET_FIELD");
959 std::string fieldName = m_bytecode->constants[operand1].asString();
960 Value obj = pop();
961 push(obj.getField(fieldName));
962 break;
963 }
964 default:
965 throw std::runtime_error("Unknown opcode");
966 return Value();
967 }
968 return Value(operand1);
969}
970
971} // namespace Phasor
char * asm_system_err(const char *cmd)
CRT system call, get err.
Definition IO.c:241
void asm_print_stdout(const char *s, int64_t len)
Native print function.
Definition IO.c:100
int64_t asm_system(const char *cmd)
CRT system call.
Definition IO.c:112
void asm_print_stderr(const char *s, int64_t len)
Native print error function.
Definition IO.c:106
char * asm_system_out(const char *cmd)
CRT system call, get out.
Definition IO.c:117
double asm_tan(double a)
Native tangent.
Definition crt.c:89
double asm_log(double a)
Native natural logarithm.
Definition crt.c:69
int64_t asm_isub(int64_t a, int64_t b)
Native subtraction.
Definition crt.c:13
double asm_flmod(double a, double b)
Definition crt.c:54
double asm_sqrt(double a)
Native square root.
Definition crt.c:59
double asm_fladd(double a, double b)
Definition crt.c:8
double asm_sin(double a)
Native sine.
Definition crt.c:79
int64_t asm_imod(int64_t a, int64_t b)
Native modulus.
Definition crt.c:50
int64_t asm_idiv(int64_t a, int64_t b)
Native division.
Definition crt.c:41
double asm_fldiv(double a, double b)
Definition crt.c:45
double asm_flsub(double a, double b)
Definition crt.c:17
int64_t asm_iadd(int64_t a, int64_t b)
Native addition.
Definition crt.c:4
double asm_exp(double a)
Native exponential.
Definition crt.c:74
double asm_flneg(double a)
Native negation.
Definition crt.c:36
double asm_cos(double a)
Native cosine.
Definition crt.c:84
int64_t asm_imul(int64_t a, int64_t b)
Native multiplication.
Definition crt.c:22
double asm_flmul(double a, double b)
Definition crt.c:26
double asm_pow(double a, double b)
Native power.
Definition crt.c:64
Throws when the HALT opcode is reached.
Definition VM.hpp:75
ImportHandler importHandler
Import handler for loading modules.
Definition VM.hpp:258
std::vector< Value > variables
Variable storage indexed by variable index.
Definition VM.hpp:270
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:182
const Bytecode * m_bytecode
Bytecode to execute.
Definition VM.hpp:273
std::vector< int > callStack
Call stack for function calls.
Definition VM.hpp:267
std::map< std::string, NativeFunction > nativeFunctions
Native function registry.
Definition VM.hpp:279
void log(const Value &msg)
Log a Value to stdout.
Definition Utility.cpp:176
std::array< Value, MAX_REGISTERS > registers
Virtual registers for register-based operations (v2.0).
Definition VM.hpp:261
void flush()
Flush stdout.
Definition Utility.cpp:188
size_t pc
Program counter.
Definition VM.hpp:276
void push(const Value &value)
Push a value onto the stack.
Definition Stack.cpp:8
Value operation(const OpCode &op, const int &operand1=0, const int &operand2=0, const int &operand3=0, const int &operand4=0, const int &operand5=0)
Execute a single operation.
void flusherr()
Flush stderr.
Definition Utility.cpp:193
A value in the Phasor VM.
Definition Value.hpp:67
bool isTruthy() const
Helper to determine truthiness.
Definition Value.hpp:332
const char * c_str() const
Convert to C Style String.
Definition Value.hpp:446
std::string toString() const
Convert to string for printing.
Definition Value.hpp:415
double asFloat() const
Get the value as a double.
Definition Value.hpp:214
std::string asString() const
Get the value as a string.
Definition Value.hpp:223
void setField(const std::string &name, Value value)
Definition Value.hpp:496
int64_t asInt() const
Get the value as an integer.
Definition Value.hpp:205
bool isFloat() const
Check if the value is a double.
Definition Value.hpp:179
static Value createStruct(const std::string &name)
Definition Value.hpp:475
Value getField(const std::string &name) const
Definition Value.hpp:485
bool isString() const
Check if the value is a string.
Definition Value.hpp:184
bool isInt() const
Check if the value is an integer.
Definition Value.hpp:174
int64_t asm_iless_than(int64_t a, int64_t b)
Native Less than comparison.
Definition crt.c:35
int64_t asm_flequal(double a, double b)
Definition crt.c:77
int64_t asm_flless_equal(double a, double b)
Definition crt.c:97
int64_t asm_flless_than(double a, double b)
Definition crt.c:87
int64_t asm_fland(double a, double b)
Definition crt.c:60
int64_t asm_flgreater_equal(double a, double b)
Definition crt.c:102
int64_t asm_igreater_equal(int64_t a, int64_t b)
Native Greater than or equal comparison.
Definition crt.c:50
int64_t asm_ior(int64_t a, int64_t b)
Native bitwise OR.
Definition crt.c:13
int64_t asm_igreater_than(int64_t a, int64_t b)
Native Greater than comparison.
Definition crt.c:40
int64_t asm_flnot_equal(double a, double b)
Definition crt.c:82
int64_t asm_flgreater_than(double a, double b)
Definition crt.c:92
int64_t asm_flnot(double a)
Native bitwise NOT.
Definition crt.c:55
int64_t asm_iand(int64_t a, int64_t b)
Native bitwise AND.
Definition crt.c:8
int64_t asm_flor(double a, double b)
Definition crt.c:65
int64_t asm_iequal(int64_t a, int64_t b)
Native Equality comparison.
Definition crt.c:25
int64_t asm_inot_equal(int64_t a, int64_t b)
Native Inequality comparison.
Definition crt.c:30
int64_t asm_iless_equal(int64_t a, int64_t b)
Native Less than or equal comparison.
Definition crt.c:45
The Phasor Programming Language and Runtime.
Definition AST.hpp:11
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
std::string opCodeToString(OpCode op)
Definition map.cpp:126
Struct metadata stored alongside bytecode (struct section).
Definition CodeGen.hpp:38
int firstConstIndex
Index into constants for the first default value.
Definition CodeGen.hpp:40
std::vector< std::string > fieldNames
Field names in declaration order.
Definition CodeGen.hpp:42
int fieldCount
Number of fields in this struct.
Definition CodeGen.hpp:41
std::string name
Struct name.
Definition CodeGen.hpp:39