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