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