Phasor 2.2.0
Stack VM based Programming Language
Loading...
Searching...
No Matches
PhasorIR.cpp
Go to the documentation of this file.
1#include "PhasorIR.hpp"
2#include <cstring>
3#include <fstream>
4#include <iomanip>
5#include <iostream>
6#include <sstream>
7#include <stdexcept>
8
9#if defined(_MSC_VER)
10#define COMPILE_MESSAGE(msg) __pragma(message(msg))
11#elif defined(__GNUC__) || defined(__clang__)
12#define DO_PRAGMA(x) _Pragma(#x)
13#define COMPILE_MESSAGE(msg) DO_PRAGMA(message msg)
14#else
15#define COMPILE_MESSAGE(msg)
16#endif
17#define STR2(x) #x
18#define STR(x) STR2(x)
19
20namespace Phasor
21{
22
23const std::unordered_map<OpCode, std::string> PhasorIR::opCodeToStringMap = {
24 {OpCode::PUSH_CONST, "PUSH_CONST"},
25 {OpCode::POP, "POP"},
26 {OpCode::IADD, "IADD"},
27 {OpCode::ISUBTRACT, "ISUBTRACT"},
28 {OpCode::IMULTIPLY, "IMULTIPLY"},
29 {OpCode::IDIVIDE, "IDIVIDE"},
30 {OpCode::IMODULO, "IMODULO"},
31 {OpCode::FLADD, "FLADD"},
32 {OpCode::FLSUBTRACT, "FLSUBTRACT"},
33 {OpCode::FLMULTIPLY, "FLMULTIPLY"},
34 {OpCode::FLDIVIDE, "FLDIVIDE"},
35 {OpCode::FLMODULO, "FLMODULO"},
36 {OpCode::SQRT, "SQRT"},
37 {OpCode::POW, "POW"},
38 {OpCode::LOG, "LOG"},
39 {OpCode::EXP, "EXP"},
40 {OpCode::SIN, "SIN"},
41 {OpCode::COS, "COS"},
42 {OpCode::TAN, "TAN"},
43 {OpCode::NEGATE, "NEGATE"},
44 {OpCode::NOT, "NOT"},
45 {OpCode::IAND, "IAND"},
46 {OpCode::IOR, "IOR"},
47 {OpCode::IEQUAL, "IEQUAL"},
48 {OpCode::INOT_EQUAL, "INOT_EQUAL"},
49 {OpCode::ILESS_THAN, "ILESS_THAN"},
50 {OpCode::IGREATER_THAN, "IGREATER_THAN"},
51 {OpCode::ILESS_EQUAL, "ILESS_EQUAL"},
52 {OpCode::IGREATER_EQUAL, "IGREATER_EQUAL"},
53 {OpCode::FLAND, "FLAND"},
54 {OpCode::FLOR, "FLOR"},
55 {OpCode::FLEQUAL, "FLEQUAL"},
56 {OpCode::FLNOT_EQUAL, "FLNOT_EQUAL"},
57 {OpCode::FLLESS_THAN, "FLLESS_THAN"},
58 {OpCode::FLGREATER_THAN, "FLGREATER_THAN"},
59 {OpCode::FLLESS_EQUAL, "FLLESS_EQUAL"},
60 {OpCode::FLGREATER_EQUAL, "FLGREATER_EQUAL"},
61 {OpCode::JUMP, "JUMP"},
62 {OpCode::JUMP_IF_FALSE, "JUMP_IF_FALSE"},
63 {OpCode::JUMP_IF_TRUE, "JUMP_IF_TRUE"},
64 {OpCode::JUMP_BACK, "JUMP_BACK"},
65 {OpCode::STORE_VAR, "STORE_VAR"},
66 {OpCode::LOAD_VAR, "LOAD_VAR"},
67 {OpCode::PRINT, "PRINT"},
68 {OpCode::PRINTERROR, "PRINTERROR"},
69 {OpCode::READLINE, "READLINE"},
70 {OpCode::IMPORT, "IMPORT"},
71 {OpCode::HALT, "HALT"},
72 {OpCode::CALL_NATIVE, "CALL_NATIVE"},
73 {OpCode::CALL, "CALL"},
74 {OpCode::SYSTEM, "SYSTEM"},
75 {OpCode::SYSTEM_OUT, "SYSTEM_OUT"},
76 {OpCode::SYSTEM_ERR, "SYSTEM_ERR"},
77 {OpCode::RETURN, "RETURN"},
78 {OpCode::TRUE_P, "TRUE"},
79 {OpCode::FALSE_P, "FALSE"},
80 {OpCode::NULL_VAL, "NULL_VAL"},
81 {OpCode::LEN, "LEN"},
82 {OpCode::CHAR_AT, "CHAR_AT"},
83 {OpCode::SUBSTR, "SUBSTR"},
84 {OpCode::MOV, "MOV"},
85 {OpCode::LOAD_CONST_R, "LOAD_CONST_R"},
86 {OpCode::LOAD_VAR_R, "LOAD_VAR_R"},
87 {OpCode::STORE_VAR_R, "STORE_VAR_R"},
88 {OpCode::IADD_R, "IADD_R"},
89 {OpCode::ISUB_R, "ISUB_R"},
90 {OpCode::IMUL_R, "IMUL_R"},
91 {OpCode::IDIV_R, "IDIV_R"},
92 {OpCode::IMOD_R, "IMOD_R"},
93 {OpCode::FLADD_R, "FLADD_R"},
94 {OpCode::FLSUB_R, "FLSUB_R"},
95 {OpCode::FLMUL_R, "FLMUL_R"},
96 {OpCode::FLDIV_R, "FLDIV_R"},
97 {OpCode::FLMOD_R, "FLMOD_R"},
98 {OpCode::SQRT_R, "SQRT_R"},
99 {OpCode::POW_R, "POW_R"},
100 {OpCode::LOG_R, "LOG_R"},
101 {OpCode::EXP_R, "EXP_R"},
102 {OpCode::SIN_R, "SIN_R"},
103 {OpCode::COS_R, "COS_R"},
104 {OpCode::TAN_R, "TAN_R"},
105 {OpCode::IAND_R, "IAND_R"},
106 {OpCode::IOR_R, "IOR_R"},
107 {OpCode::IEQ_R, "IEQ_R"},
108 {OpCode::INE_R, "INE_R"},
109 {OpCode::ILT_R, "ILT_R"},
110 {OpCode::IGT_R, "IGT_R"},
111 {OpCode::ILE_R, "ILE_R"},
112 {OpCode::IGE_R, "IGE_R"},
113 {OpCode::FLAND_R, "FLAND_R"},
114 {OpCode::FLOR_R, "FLOR_R"},
115 {OpCode::FLEQ_R, "FLEQ_R"},
116 {OpCode::FLNE_R, "FLNE_R"},
117 {OpCode::FLLT_R, "FLLT_R"},
118 {OpCode::FLGT_R, "FLGT_R"},
119 {OpCode::FLLE_R, "FLLE_R"},
120 {OpCode::FLGE_R, "FLGE_R"},
121 {OpCode::PUSH_R, "PUSH_R"},
122 {OpCode::PUSH2_R, "PUSH2_R"},
123 {OpCode::POP_R, "POP_R"},
124 {OpCode::POP2_R, "POP2_R"},
125 {OpCode::NEG_R, "NEG_R"},
126 {OpCode::NOT_R, "NOT_R"},
127 {OpCode::PRINT_R, "PRINT_R"},
128 {OpCode::PRINTERROR_R, "PRINTERROR_R"},
129 {OpCode::READLINE_R, "READLINE_R"},
130 {OpCode::SYSTEM_R, "SYSTEM_R"},
131 {OpCode::SYSTEM_OUT_R, "SYSTEM_OUT_R"},
132 {OpCode::SYSTEM_ERR_R, "SYSTEM_ERR_R"}};
133
134const std::unordered_map<std::string, OpCode> PhasorIR::stringToOpCodeMap = [] {
135 std::unordered_map<std::string, OpCode> map;
136 for (const auto &pair : PhasorIR::opCodeToStringMap)
137 {
138 map[pair.second] = pair.first;
139 }
140 return map;
141}();
142
144{
145 switch (op)
146 {
147 // 0 operands
148 case OpCode::POP:
149 case OpCode::IADD:
152 case OpCode::IDIVIDE:
153 case OpCode::IMODULO:
154 case OpCode::FLADD:
157 case OpCode::FLDIVIDE:
158 case OpCode::FLMODULO:
159 case OpCode::SQRT:
160 case OpCode::POW:
161 case OpCode::LOG:
162 case OpCode::EXP:
163 case OpCode::SIN:
164 case OpCode::COS:
165 case OpCode::TAN:
166 case OpCode::NEGATE:
167 case OpCode::NOT:
168 case OpCode::IAND:
169 case OpCode::IOR:
170 case OpCode::IEQUAL:
176 case OpCode::FLEQUAL:
182 case OpCode::PRINT:
184 case OpCode::READLINE:
185 case OpCode::HALT:
186 case OpCode::RETURN:
187 case OpCode::TRUE_P:
188 case OpCode::FALSE_P:
189 case OpCode::NULL_VAL:
190 case OpCode::LEN:
191 case OpCode::CHAR_AT:
192 case OpCode::SUBSTR:
193 return 0;
194
195 // 1 operand
197 case OpCode::JUMP:
202 case OpCode::LOAD_VAR:
203 case OpCode::IMPORT:
205 case OpCode::CALL:
206 case OpCode::SYSTEM:
209 case OpCode::PUSH_R:
210 case OpCode::POP_R:
211 case OpCode::PRINT_R:
214 case OpCode::SYSTEM_R:
221 return 1;
222
223 // 2 operands
224 case OpCode::MOV:
228 case OpCode::SQRT_R:
229 case OpCode::LOG_R:
230 case OpCode::EXP_R:
231 case OpCode::SIN_R:
232 case OpCode::COS_R:
233 case OpCode::TAN_R:
234 case OpCode::NEG_R:
235 case OpCode::NOT_R:
236 case OpCode::PUSH2_R:
237 case OpCode::POP2_R:
240 return 2;
241
242 // 3 operands
243 case OpCode::IADD_R:
244 case OpCode::ISUB_R:
245 case OpCode::IMUL_R:
246 case OpCode::IDIV_R:
247 case OpCode::IMOD_R:
248 case OpCode::FLADD_R:
249 case OpCode::FLSUB_R:
250 case OpCode::FLMUL_R:
251 case OpCode::FLDIV_R:
252 case OpCode::FLMOD_R:
253 case OpCode::POW_R:
254 case OpCode::IAND_R:
255 case OpCode::IOR_R:
256 case OpCode::IEQ_R:
257 case OpCode::INE_R:
258 case OpCode::ILT_R:
259 case OpCode::IGT_R:
260 case OpCode::ILE_R:
261 case OpCode::IGE_R:
262 case OpCode::FLAND_R:
263 case OpCode::FLOR_R:
264 case OpCode::FLEQ_R:
265 case OpCode::FLNE_R:
266 case OpCode::FLLT_R:
267 case OpCode::FLGT_R:
268 case OpCode::FLLE_R:
269 case OpCode::FLGE_R:
270 return 3;
271
272 default:
273 return 0;
274 }
275}
276
278{
279 // Stack operations with special indices
280 if (op == OpCode::PUSH_CONST && operandIndex == 0)
282 if (op == OpCode::STORE_VAR && operandIndex == 0)
284 if (op == OpCode::LOAD_VAR && operandIndex == 0)
286 if (op == OpCode::IMPORT && operandIndex == 0)
288 if (op == OpCode::CALL_NATIVE && operandIndex == 0)
290 if (op == OpCode::CALL && operandIndex == 0)
292 if (op == OpCode::SYSTEM && operandIndex == 0)
294
295 // Register operations with mixed types
296 if (op == OpCode::LOAD_CONST_R)
297 {
298 if (operandIndex == 0)
300 if (operandIndex == 1)
302 }
303 if (op == OpCode::LOAD_VAR_R)
304 {
305 if (operandIndex == 0)
307 if (operandIndex == 1)
309 }
310 if (op == OpCode::STORE_VAR_R)
311 {
312 if (operandIndex == 0)
314 if (operandIndex == 1)
316 }
317
318 // JUMP instructions take an offset (INT)
320 {
321 return OperandType::INT;
322 }
323
324 // Register ops use REGISTER for all operands
325 if (static_cast<int>(op) >= static_cast<int>(OpCode::MOV))
326 {
328 }
329
330 return OperandType::INT;
331}
332
334{
335 auto it = opCodeToStringMap.find(op);
336 if (it != opCodeToStringMap.end())
337 {
338 return it->second;
339 }
340 return "UNKNOWN";
341}
342
343OpCode PhasorIR::stringToOpCode(const std::string &str)
344{
345 auto it = stringToOpCodeMap.find(str);
346 if (it != stringToOpCodeMap.end())
347 {
348 return it->second;
349 }
350 throw std::runtime_error("Unknown opcode string: " + str);
351}
352
353std::string PhasorIR::escapeString(const std::string &str)
354{
355 std::stringstream ss;
356 for (char c : str)
357 {
358 switch (c)
359 {
360 case '\n':
361 ss << "\\n";
362 break;
363 case '\r':
364 ss << "\\r";
365 break;
366 case '\t':
367 ss << "\\t";
368 break;
369 case '\\':
370 ss << "\\\\";
371 break;
372 case '"':
373 ss << "\\\"";
374 break;
375 default:
376 ss << c;
377 break;
378 }
379 }
380 return ss.str();
381}
382
383std::string PhasorIR::unescapeString(const std::string &str)
384{
385 std::string result;
386 for (size_t i = 0; i < str.length(); ++i)
387 {
388 if (str[i] == '\\' && i + 1 < str.length())
389 {
390 switch (str[i + 1])
391 {
392 case 'n':
393 result += '\n';
394 break;
395 case 'r':
396 result += '\r';
397 break;
398 case 't':
399 result += '\t';
400 break;
401 case '\\':
402 result += '\\';
403 break;
404 case '"':
405 result += '"';
406 break;
407 default:
408 result += str[i];
409 result += str[i + 1];
410 break;
411 }
412 i++;
413 }
414 else
415 {
416 result += str[i];
417 }
418 }
419 return result;
420}
421
422std::vector<uint8_t> PhasorIR::serialize(const Bytecode &bytecode)
423{
424 std::stringstream ss;
425
426 // Write Header
427 ss << ".PHIR 3.0.0" << "\n";
428
429 // Build reverse lookup maps for inline comments
430 std::map<int, std::string> indexToVarName;
431 for (const auto &[name, index] : bytecode.variables)
432 {
433 indexToVarName[index] = name;
434 }
435 std::map<int, std::string> addressToFuncName;
436 for (const auto &[name, address] : bytecode.functionEntries)
437 {
438 addressToFuncName[address] = name;
439 }
440
441 // Constants Section
442 ss << ".CONSTANTS " << bytecode.constants.size() << "\n";
443 for (const auto &val : bytecode.constants)
444 {
445 switch (val.getType())
446 {
447 case ValueType::Null:
448 ss << "NULL\n";
449 break;
450 case ValueType::Bool:
451 ss << "BOOL " << (val.asBool() ? "true" : "false") << "\n";
452 break;
453 case ValueType::Int:
454 ss << "INT " << val.asInt() << "\n";
455 break;
456 case ValueType::Float:
457 ss << "FLOAT " << val.asFloat() << "\n";
458 break;
460 ss << "STRING \"" << escapeString(val.asString()) << "\"\n";
461 break;
463COMPILE_MESSAGE("Warning: PHS_01 Structs have not been fully implemented! Line " STR(__LINE__))
464 throw std::runtime_error("Structs not implemented!");
465 break;
466 case ValueType::Array:
467COMPILE_MESSAGE("Warning: PHS_02 Arrays have not been implemented! Line " STR(__LINE__))
468 throw std::runtime_error("Arrays not implemented!");
469 }
470 }
471
472 // Variables Section
473 ss << ".VARIABLES " << bytecode.variables.size() << " " << bytecode.nextVarIndex << "\n";
474 for (const auto &[name, index] : bytecode.variables)
475 {
476 ss << name << " " << index << "\n";
477 }
478
479 // Functions Section
480 ss << ".FUNCTIONS " << bytecode.functionEntries.size() << "\n";
481 for (const auto &[name, address] : bytecode.functionEntries)
482 {
483 ss << name << " " << address << "\n";
484 }
485
486 // Structs Section
487 ss << ".STRUCTS " << bytecode.structs.size() << "\n";
488 for (const auto &info : bytecode.structs)
489 {
490 // name firstConstIndex fieldCount fieldName0 fieldName1 ...
491 ss << info.name << " " << info.firstConstIndex << " " << info.fieldCount;
492 for (const auto &fieldName : info.fieldNames)
493 {
494 ss << " " << fieldName;
495 }
496 ss << "\n";
497 }
498
499 // Instructions Section
500 ss << ".INSTRUCTIONS " << bytecode.instructions.size() << "\n";
501 for (const auto &instr : bytecode.instructions)
502 {
503 std::stringstream instrLine;
504 instrLine << opCodeToString(instr.op);
505
506 int operandCount = getOperandCount(instr.op);
507 int32_t operands[5] = {instr.operand1, instr.operand2, instr.operand3, instr.operand4, instr.operand5};
508
509 std::string comment;
510
511 for (int i = 0; i < operandCount; ++i)
512 {
513 OperandType type = getOperandType(instr.op, i);
514
515 // Add comma separator for operands after the first
516 if (i > 0)
517 instrLine << ",";
518 instrLine << " ";
519
520 switch (type)
521 {
523 instrLine << "r" << operands[i];
524 break;
526 instrLine << operands[i];
527 // Add constant value to comment
528 if (operands[i] >= 0 && operands[i] < static_cast<int>(bytecode.constants.size()))
529 {
530 const Value &val = bytecode.constants[operands[i]];
531 if (val.getType() == ValueType::String)
532 {
533 std::string str = val.asString();
534 if (str.length() > 20)
535 str = str.substr(0, 20) + "...";
536 comment = "const[" + std::to_string(operands[i]) + "]=\"" + str + "\"";
537 }
538 else if (val.getType() == ValueType::Int)
539 {
540 comment = "const[" + std::to_string(operands[i]) + "]=" + std::to_string(val.asInt());
541 }
542 }
543 break;
545 instrLine << operands[i];
546 // Add variable name to comment
547 if (indexToVarName.count(operands[i]))
548 {
549 comment = "var=" + indexToVarName[operands[i]];
550 }
551 break;
553 instrLine << operands[i];
554 // Add function name to comment
555 if (addressToFuncName.count(operands[i]))
556 {
557 comment = "func=" + addressToFuncName[operands[i]];
558 }
559 break;
560 default:
561 instrLine << operands[i];
562 break;
563 }
564 }
565
566 // Pad to column 40 for aligned comments
567 std::string lineStr = instrLine.str();
568 if (!comment.empty())
569 {
570 const size_t commentColumn = 40;
571 if (lineStr.length() < commentColumn)
572 {
573 lineStr.append(commentColumn - lineStr.length(), ' ');
574 }
575 else
576 {
577 lineStr += " ";
578 }
579
580 lineStr += "; " + escapeString(comment);
581 }
582 ss << lineStr << "\n";
583 }
584
585 std::string textData = ss.str();
586 std::vector<uint8_t> buffer;
587
588 // Append text data
589 buffer.insert(buffer.end(), textData.begin(), textData.end());
590
591 return buffer;
592}
593
594Bytecode PhasorIR::deserialize(const std::vector<uint8_t> &data)
595{
596 if (data.size() < 8)
597 {
598 throw std::runtime_error("Invalid Phasor IR file: too small");
599 }
600
601 // Parse text data
602 std::string textData(data.begin() + 8, data.end());
603 std::stringstream ss(textData);
604 std::string line;
605 Bytecode bytecode;
606
607 std::string section;
608 while (ss >> section)
609 {
610 if (section == ".PHIR")
611 {
612 std::string version;
613 ss >> version;
614 if (version < "1.0.0")
615 {
616 throw std::runtime_error("Incompatible Phasor IR version");
617 }
618 }
619 if (section == ".CONSTANTS")
620 {
621 int count;
622 ss >> count;
623 bytecode.constants.reserve(count);
624 for (int i = 0; i < count; ++i)
625 {
626 std::string type;
627 ss >> type;
628 if (type == "NULL")
629 {
630 bytecode.constants.push_back(Value());
631 }
632 else if (type == "BOOL")
633 {
634 std::string valStr;
635 ss >> valStr;
636 bytecode.constants.push_back(Value(valStr == "true"));
637 }
638 else if (type == "INT")
639 {
640 int64_t val;
641 ss >> val;
642 bytecode.constants.push_back(Value(val));
643 }
644 else if (type == "FLOAT")
645 {
646 double val;
647 ss >> val;
648 bytecode.constants.push_back(Value(val));
649 }
650 else if (type == "STRING")
651 {
652 std::string valStr;
653 // Read quoted string, potentially with spaces
654 char c;
655 while (ss.get(c) && c != '"')
656 ; // Skip until opening quote
657 std::getline(ss, valStr, '"'); // Read until closing quote
658 bytecode.constants.push_back(Value(unescapeString(valStr)));
659 }
660 }
661 }
662 else if (section == ".VARIABLES")
663 {
664 int count;
665 ss >> count >> bytecode.nextVarIndex;
666 for (int i = 0; i < count; ++i)
667 {
668 std::string name;
669 int index;
670 ss >> name >> index;
671 bytecode.variables[name] = index;
672 }
673 }
674 else if (section == ".FUNCTIONS")
675 {
676 int count;
677 ss >> count;
678 for (int i = 0; i < count; ++i)
679 {
680 std::string name;
681 int address;
682 ss >> name >> address;
683 bytecode.functionEntries[name] = address;
684 }
685 }
686 else if (section == ".STRUCTS")
687 {
688 int count;
689 ss >> count;
690 for (int i = 0; i < count; ++i)
691 {
692 StructInfo info;
693 ss >> info.name >> info.firstConstIndex >> info.fieldCount;
694 info.fieldNames.clear();
695 for (int f = 0; f < info.fieldCount; ++f)
696 {
697 std::string fieldName;
698 ss >> fieldName;
699 info.fieldNames.push_back(fieldName);
700 }
701 int index = static_cast<int>(bytecode.structs.size());
702 bytecode.structs.push_back(std::move(info));
703 bytecode.structEntries[bytecode.structs.back().name] = index;
704 }
705 }
706 else if (section == ".INSTRUCTIONS")
707 {
708 int count;
709 ss >> count;
710 bytecode.instructions.reserve(count);
711 for (int i = 0; i < count; ++i)
712 {
713 std::string opStr;
714 ss >> opStr;
715
716 OpCode op = stringToOpCode(opStr);
717 int operandCount = getOperandCount(op);
718 int32_t operands[5] = {0, 0, 0, 0, 0};
719
720 for (int j = 0; j < operandCount; ++j)
721 {
722 std::string token;
723 ss >> token;
724
725 // Skip if we hit a comment
726 if (token.empty() || token[0] == ';')
727 {
728 // Skip rest of line
729 std::getline(ss, token);
730 break;
731 }
732
733 // Strip trailing comma if present
734 if (!token.empty() && token.back() == ',')
735 {
736 token.pop_back();
737 }
738
739 // Parse register format "rN" or plain integer
740 if (!token.empty() && token[0] == 'r')
741 {
742 operands[j] = std::stoi(token.substr(1));
743 }
744 else
745 {
746 operands[j] = std::stoi(token);
747 }
748 }
749
750 // Skip any remaining content on the line (comments)
751 char c;
752 while (ss.get(c) && c != '\n')
753 ;
754
755 bytecode.instructions.push_back(
756 Instruction(op, operands[0], operands[1], operands[2], operands[3], operands[4]));
757 }
758 }
759 }
760
761 return bytecode;
762}
763
764bool PhasorIR::saveToFile(const Bytecode &bytecode, const std::filesystem::path &filename)
765{
766 try
767 {
768 std::vector<uint8_t> data = serialize(bytecode);
769 std::ofstream file(filename, std::ios::binary);
770 if (!file.is_open())
771 return false;
772 file.write(reinterpret_cast<const char *>(data.data()), data.size());
773 return true;
774 }
775 catch (...)
776 {
777 return false;
778 }
779}
780
781Bytecode PhasorIR::loadFromFile(const std::filesystem::path &filename)
782{
783 std::ifstream file(filename, std::ios::binary | std::ios::ate);
784 if (!file.is_open())
785 throw std::runtime_error("Cannot open file");
786 std::streamsize size = file.tellg();
787 file.seekg(0, std::ios::beg);
788 std::vector<uint8_t> buffer(size);
789 if (!file.read(reinterpret_cast<char *>(buffer.data()), size))
790 throw std::runtime_error("Cannot read file");
791 return deserialize(buffer);
792}
793} // namespace Phasor
#define COMPILE_MESSAGE(msg)
#define STR(x)
static std::vector< uint8_t > serialize(const Bytecode &bytecode)
Serialize bytecode to Phasor IR format.
Definition PhasorIR.cpp:422
static std::string unescapeString(const std::string &str)
Helper to unescape strings from text format.
Definition PhasorIR.cpp:383
static const std::unordered_map< OpCode, std::string > opCodeToStringMap
Definition PhasorIR.hpp:57
static Bytecode deserialize(const std::vector< uint8_t > &data)
Deserialize Phasor IR format to bytecode.
Definition PhasorIR.cpp:594
static const std::unordered_map< std::string, OpCode > stringToOpCodeMap
Definition PhasorIR.hpp:58
static OperandType getOperandType(OpCode op, int operandIndex)
Definition PhasorIR.cpp:277
static Bytecode loadFromFile(const std::filesystem::path &filename)
Load bytecode from .phir file.
Definition PhasorIR.cpp:781
static std::string opCodeToString(OpCode op)
Helper to convert OpCode to string.
Definition PhasorIR.cpp:333
static int getOperandCount(OpCode op)
Definition PhasorIR.cpp:143
static std::string escapeString(const std::string &str)
Helper to escape strings for text format.
Definition PhasorIR.cpp:353
static bool saveToFile(const Bytecode &bytecode, const std::filesystem::path &filename)
Save bytecode to .phir file.
Definition PhasorIR.cpp:764
static OpCode stringToOpCode(const std::string &str)
Helper to convert string to OpCode.
Definition PhasorIR.cpp:343
A value in the Phasor VM.
Definition Value.hpp:33
std::string asString() const
Get the value as a string.
Definition Value.hpp:166
int64_t asInt() const
Get the value as an integer.
Definition Value.hpp:148
ValueType getType() const
Get the type of the value.
Definition Value.hpp:87
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
std::vector< StructInfo > structs
List of struct descriptors.
Definition CodeGen.hpp:209
std::vector< Value > constants
Constant pool.
Definition CodeGen.hpp:203
std::map< std::string, int > functionEntries
Function name -> instruction index mapping.
Definition CodeGen.hpp:205
int nextVarIndex
Next available variable index.
Definition CodeGen.hpp:206
std::map< std::string, int > structEntries
Struct name -> index in structs.
Definition CodeGen.hpp:210
std::map< std::string, int > variables
Variable name -> index mapping.
Definition CodeGen.hpp:204
std::vector< Instruction > instructions
List of instructions.
Definition CodeGen.hpp:202
Instruction with up to 5 operands Format: instruction operand1, operand2, operand3,...
Definition CodeGen.hpp:170
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