Phasor 3.3.0
Stack VM based Programming Language
Loading...
Searching...
No Matches
CodeGen.cpp
Go to the documentation of this file.
1#include "CodeGen.hpp"
2#include <iostream>
3#include <unordered_map>
4#include <phsint.hpp>
5
6namespace Phasor
7{
8
9Bytecode CodeGenerator::generate(const AST::Program &program, const std::unordered_map<std::string, int> &existingVars,
10 int nextVarIdx, bool replMode)
11{
12 bytecode = Bytecode(); // Reset bytecode
13 bytecode.variables = existingVars;
14 bytecode.nextVarIndex = nextVarIdx;
15 isRepl = replMode;
16
17 for (const auto &stmt : program.statements)
18 {
19 generateStatement(stmt.get());
20 }
22 return bytecode;
23}
24
26{
27 if (const auto *numExpr = dynamic_cast<const AST::NumberExpr *>(expr))
28 {
29 try
30 {
31 if (numExpr->value.find('.') != std::string::npos)
32 {
33 outValue = Value(std::stod(numExpr->value));
34 }
35 else
36 {
37 outValue = Value(static_cast<i64>(std::stoll(numExpr->value)));
38 }
39 return true;
40 }
41 catch (...)
42 {
43 return false;
44 }
45 }
46 if (const auto *strExpr = dynamic_cast<const AST::StringExpr *>(expr))
47 {
48 outValue = Value(strExpr->value);
49 return true;
50 }
51 if (const auto *boolExpr = dynamic_cast<const AST::BooleanExpr *>(expr))
52 {
53 outValue = Value(boolExpr->value);
54 return true;
55 }
56 if (dynamic_cast<const AST::NullExpr *>(expr) != nullptr)
57 {
58 outValue = Value();
59 return true;
60 }
61 return false;
62}
63
65{
66 // If literal, we know the type immediately
67 Value lit;
68 if (isLiteralExpression(expr, lit))
69 {
70 known = true;
71 return lit.getType();
72 }
73
74 // If identifier and we've inferred its type previously, return that
75 if (const auto *ident = dynamic_cast<const AST::IdentifierExpr *>(expr))
76 {
77 auto it = inferredTypes.find(ident->name);
78 if (it != inferredTypes.end())
79 {
80 known = true;
81 return it->second;
82 }
83 }
84
85 // Unknown
86 known = false;
87 return ValueType::Float; // default when unknown (not used unless known==true)
88}
89
91{
92 if (const auto *varDecl = dynamic_cast<const AST::VarDecl *>(stmt))
93 {
94 generateVarDecl(varDecl);
95 }
96 else if (const auto *exprStmt = dynamic_cast<const AST::ExpressionStmt *>(stmt))
97 {
98 generateExpressionStmt(exprStmt);
99 }
100 else if (const auto *printStmt = dynamic_cast<const AST::PrintStmt *>(stmt))
101 {
102 generatePrintStmt(printStmt);
103 }
104 else if (dynamic_cast<const AST::IncludeStmt *>(stmt) != nullptr)
105 {
106 // preprocessor include
107 }
108 else if (const auto *importStmt = dynamic_cast<const AST::ImportStmt *>(stmt))
109 {
110 generateImportStmt(importStmt);
111 }
112 else if (const auto *exportStmt = dynamic_cast<const AST::ExportStmt *>(stmt))
113 {
114 generateExportStmt(exportStmt);
115 }
116 else if (const auto *blockStmt = dynamic_cast<const AST::BlockStmt *>(stmt))
117 {
118 generateBlockStmt(blockStmt);
119 }
120 else if (const auto *ifStmt = dynamic_cast<const AST::IfStmt *>(stmt))
121 {
122 generateIfStmt(ifStmt);
123 }
124 else if (const auto *whileStmt = dynamic_cast<const AST::WhileStmt *>(stmt))
125 {
126 generateWhileStmt(whileStmt);
127 }
128 else if (const auto *forStmt = dynamic_cast<const AST::ForStmt *>(stmt))
129 {
130 generateForStmt(forStmt);
131 }
132 else if (const auto *returnStmt = dynamic_cast<const AST::ReturnStmt *>(stmt))
133 {
134 generateReturnStmt(returnStmt);
135 }
136 else if (const auto *unsafeStmt = dynamic_cast<const AST::UnsafeBlockStmt *>(stmt))
137 {
138 generateUnsafeBlockStmt(unsafeStmt);
139 }
140 else if (const auto *funcDecl = dynamic_cast<const AST::FunctionDecl *>(stmt))
141 {
142 generateFunctionDecl(funcDecl);
143 }
144 else if (const auto *structDecl = dynamic_cast<const AST::StructDecl *>(stmt))
145 {
146 generateStructDecl(structDecl);
147 }
148 else if (dynamic_cast<const AST::BreakStmt *>(stmt) != nullptr)
149 {
151 }
152 else if (dynamic_cast<const AST::ContinueStmt *>(stmt) != nullptr)
153 {
155 }
156 else if (const auto *switchStmt = dynamic_cast<const AST::SwitchStmt *>(stmt))
157 {
158 generateSwitchStmt(switchStmt);
159 }
160 else
161 {
162 throw std::runtime_error("Unknown statement type in code generation");
163 }
164}
165
166void CodeGenerator::generateExpression(const AST::Expression *expr, bool resultNeeded)
167{
168 if (const auto *numExpr = dynamic_cast<const AST::NumberExpr *>(expr))
169 {
170 generateNumberExpr(numExpr);
171 }
172 else if (const auto *strExpr = dynamic_cast<const AST::StringExpr *>(expr))
173 {
174 generateStringExpr(strExpr);
175 }
176 else if (const auto *identExpr = dynamic_cast<const AST::IdentifierExpr *>(expr))
177 {
178 generateIdentifierExpr(identExpr);
179 }
180 else if (const auto *unaryExpr = dynamic_cast<const AST::UnaryExpr *>(expr))
181 {
182 generateUnaryExpr(unaryExpr);
183 }
184 else if (const auto *callExpr = dynamic_cast<const AST::CallExpr *>(expr))
185 {
186 generateCallExpr(callExpr);
187 }
188 else if (const auto *binExpr = dynamic_cast<const AST::BinaryExpr *>(expr))
189 {
190 generateBinaryExpr(binExpr);
191 }
192 else if (const auto *boolExpr = dynamic_cast<const AST::BooleanExpr *>(expr))
193 {
194 generateBooleanExpr(boolExpr);
195 }
196 else if (const auto *nullExpr = dynamic_cast<const AST::NullExpr *>(expr))
197 {
198 generateNullExpr(nullExpr);
199 }
200 else if (const auto *assignExpr = dynamic_cast<const AST::AssignmentExpr *>(expr))
201 {
202 generateAssignmentExpr(assignExpr);
203 }
204 else if (const auto *structExpr = dynamic_cast<const AST::StructInstanceExpr *>(expr))
205 {
206 generateStructInstanceExpr(structExpr);
207 }
208 else if (const auto *fieldAccessExpr = dynamic_cast<const AST::FieldAccessExpr *>(expr))
209 {
210 generateFieldAccessExpr(fieldAccessExpr);
211 }
212 else if (const auto *postfixExpr = dynamic_cast<const AST::PostfixExpr *>(expr))
213 {
214 generatePostfixExpr(postfixExpr, resultNeeded);
215 }
216 else if (const auto *arrayLit = dynamic_cast<const AST::ArrayLiteralExpr *>(expr))
217 {
218 generateArrayLiteralExpr(arrayLit, resultNeeded);
219 }
220 else if (const auto *arrayAccess = dynamic_cast<const AST::ArrayAccessExpr *>(expr))
221 {
222 generateArrayAccessExpr(arrayAccess, resultNeeded);
223 }
224 else
225 {
226 throw std::runtime_error("Unknown expression type in code generation");
227 }
228}
229
231{
232 if (varDecl->initializer)
233 {
234 // Generate initializer code
235 generateExpression(varDecl->initializer.get());
236 // Try to infer type from initializer
237 Value initVal;
238 if (isLiteralExpression(varDecl->initializer.get(), initVal))
239 {
240 inferredTypes[varDecl->name] = initVal.getType();
241 }
242 else if (const auto *ident = dynamic_cast<const AST::IdentifierExpr *>(varDecl->initializer.get()))
243 {
244 // propagate known type from another variable
245 auto it = inferredTypes.find(ident->name);
246 if (it != inferredTypes.end())
247 {
248 inferredTypes[varDecl->name] = it->second;
249 }
250 }
251
252 int varIndex = bytecode.getOrCreateVar(varDecl->name);
253 bytecode.emit(OpCode::STORE_VAR, varIndex);
254 }
255 else
256 {
257 // Store null value for uninitialized variable
258 int constIndex = bytecode.addConstant(Value());
259 bytecode.emit(OpCode::PUSH_CONST, constIndex);
260 int varIndex = bytecode.getOrCreateVar(varDecl->name);
261 bytecode.emit(OpCode::STORE_VAR, varIndex);
262 }
263}
264
266{
267 if (isRepl)
268 {
269 generateExpression(exprStmt->expression.get(), true);
271 return;
272 }
273
274 // In statement context the result is always discarded.
275 // For postfix specifically: resultNeeded=false skips saving the old value,
276 // and STORE_VAR already pops the result — stack is clean, no POP needed.
277 if (const auto *postfix = dynamic_cast<const AST::PostfixExpr *>(exprStmt->expression.get()))
278 {
279 generatePostfixExpr(postfix, false);
280 }
281 else
282 {
283 generateExpression(exprStmt->expression.get());
284 bytecode.emit(OpCode::POP);
285 }
286}
287
289{
290 generateExpression(printStmt->expression.get());
292}
293
295{
296 int constIndex = bytecode.addStringConstant(importStmt->modulePath);
297 bytecode.emit(OpCode::IMPORT, constIndex);
298}
299
301{
302 // For now, export just executes the declaration in the current scope
303 generateStatement(exportStmt->declaration.get());
304}
305
307{
308 // Try to parse as integer first, then as float
309 try
310 {
311 // Check if it has a decimal point
312 if (numExpr->value.find('.') != std::string::npos)
313 {
314 f64 d = std::stod(numExpr->value);
315 int constIndex = bytecode.addConstant(Value(d));
316 bytecode.emit(OpCode::PUSH_CONST, constIndex);
317 }
318 else
319 {
320 i64 i = std::stoll(numExpr->value);
321 int constIndex = bytecode.addConstant(Value(i));
322 bytecode.emit(OpCode::PUSH_CONST, constIndex);
323 }
324 }
325 catch (...)
326 {
327 throw std::runtime_error("Invalid number format: " + numExpr->value);
328 }
329}
330
332{
333 int constIndex = bytecode.addConstant(Value(strExpr->value));
334 bytecode.emit(OpCode::PUSH_CONST, constIndex);
335}
336
338{
339 int varIndex = bytecode.getOrCreateVar(identExpr->name);
340 bytecode.emit(OpCode::LOAD_VAR, varIndex);
341}
342
344{
345 // Generate operand
346 generateExpression(unaryExpr->operand.get());
347
348 // Emit operation
349 switch (unaryExpr->op)
350 {
353 break;
355 bytecode.emit(OpCode::NOT);
356 break;
358 // Not implemented
359 // bytecode.emit(OpCode::ADROF);
360 [[fallthrough]]; // for now
362 // bytecode.emit(OpCode::DREF);
363 break;
364 }
365}
366
368{
369 // Optimizations
370 if (callExpr->callee == "len" && callExpr->arguments.size() == 1)
371 {
372 if (const auto *strExpr = dynamic_cast<const AST::StringExpr *>(callExpr->arguments[0].get()))
373 {
374 // Constant fold len("literal")
375 auto len = (i64)strExpr->value.length();
376 int constIndex = bytecode.addConstant(Value(len));
377 bytecode.emit(OpCode::PUSH_CONST, constIndex);
378 return;
379 }
380 // Emit specialized opcode for variable strings
381 generateExpression(callExpr->arguments[0].get());
382 bytecode.emit(OpCode::LEN);
383 return;
384 }
385
386 if (callExpr->callee == "substr" && callExpr->arguments.size() == 3)
387 {
388 // Check for substr(s, i, 1) -> char_at(s, i)
389 if (const auto *numExpr = dynamic_cast<const AST::NumberExpr *>(callExpr->arguments[2].get()))
390 {
391 if (numExpr->value == "1" || numExpr->value == "1.0")
392 {
393 // Redirect to char_at opcode
394 generateExpression(callExpr->arguments[0].get());
395 generateExpression(callExpr->arguments[1].get());
397 return;
398 }
399 }
400 }
401
402 if (callExpr->callee == "char_at" && callExpr->arguments.size() == 2)
403 {
404 generateExpression(callExpr->arguments[0].get());
405 generateExpression(callExpr->arguments[1].get());
407 return;
408 }
409
410 if (callExpr->callee == "starts_with" && callExpr->arguments.size() == 2)
411 {
412 const auto *s = dynamic_cast<const AST::StringExpr *>(callExpr->arguments[0].get());
413 const auto *p = dynamic_cast<const AST::StringExpr *>(callExpr->arguments[1].get());
414 if ((s != nullptr) && (p != nullptr))
415 {
416 bool result = s->value.length() >= p->value.length() && s->value.starts_with(p->value);
417 bytecode.emit(result ? OpCode::TRUE_P : OpCode::FALSE_P);
418 return;
419 }
420 }
421
422 if (callExpr->callee == "ends_with" && callExpr->arguments.size() == 2)
423 {
424 const auto *s = dynamic_cast<const AST::StringExpr *>(callExpr->arguments[0].get());
425 const auto *suffix = dynamic_cast<const AST::StringExpr *>(callExpr->arguments[1].get());
426 if ((s != nullptr) && (suffix != nullptr))
427 {
428 bool result = s->value.length() >= suffix->value.length() && s->value.ends_with(suffix->value);
429 bytecode.emit(result ? OpCode::TRUE_P : OpCode::FALSE_P);
430 return;
431 }
432 }
433 // Push arguments
434 for (const auto &arg : callExpr->arguments)
435 {
436 generateExpression(arg.get());
437 }
438
439 // Push argument count
440 int constIndex = bytecode.addConstant(Value(static_cast<i64>(callExpr->arguments.size())));
441 bytecode.emit(OpCode::PUSH_CONST, constIndex);
442
443 // Check if it's a user function
444 auto entryIt = bytecode.functionEntries.find(callExpr->callee);
445 if (entryIt != bytecode.functionEntries.end())
446 {
447 int nameIndex = bytecode.addStringConstant(callExpr->callee);
448 auto itParam = bytecode.functionParamCounts.find(callExpr->callee);
449 if (itParam != bytecode.functionParamCounts.end())
450 {
451 int expected = itParam->second;
452 int got = static_cast<int>(callExpr->arguments.size());
453 if (expected != got)
454 {
455 std::cerr << "ERROR: calling function '" << callExpr->callee << "' with " << got
456 << " arguments but it expects " << expected << "\n";
457 std::exit(1);
458 }
459 }
460 bytecode.emit(OpCode::CALL, nameIndex);
461 }
462 else
463 {
464 int nameIndex = bytecode.addStringConstant(callExpr->callee);
465 bytecode.emit(OpCode::CALL_NATIVE, nameIndex);
466 }
467}
468
470{
471 Value leftVal;
472 Value rightVal;
473 if (isLiteralExpression(binExpr->left.get(), leftVal) && isLiteralExpression(binExpr->right.get(), rightVal))
474 {
475 try
476 {
477 Value result;
478 switch (binExpr->op)
479 {
481 result = leftVal + rightVal;
482 break;
484 result = leftVal - rightVal;
485 break;
487 result = leftVal * rightVal;
488 break;
490 result = leftVal / rightVal;
491 break;
493 result = leftVal % rightVal;
494 break;
496 result = leftVal.logicalAnd(rightVal);
497 break;
499 result = leftVal.logicalOr(rightVal);
500 break;
502 result = Value(leftVal == rightVal);
503 break;
505 result = Value(leftVal != rightVal);
506 break;
508 result = Value(leftVal < rightVal);
509 break;
511 result = Value(leftVal > rightVal);
512 break;
514 result = Value(leftVal <= rightVal);
515 break;
517 result = Value(leftVal >= rightVal);
518 break;
519 }
520 if (result.isBool())
521 {
522 if (result.asBool())
523 {
525 }
526 else
527 {
529 }
530 }
531 else if (result.isNull())
532 {
534 }
535 else
536 {
537 int constIndex = bytecode.addConstant(result);
538 bytecode.emit(OpCode::PUSH_CONST, constIndex);
539 }
540 return;
541 }
542 catch (...)
543 {
544 std::cerr << "Unknown error in Phasor::CodeGenerator::generateBinaryExpr().\n";
545 }
546 }
547
548 if (binExpr->op == AST::BinaryOp::And)
549 {
550 generateExpression(binExpr->left.get());
551 int jumpToFalseIndex = static_cast<int>(bytecode.instructions.size());
553 generateExpression(binExpr->right.get());
554 int jumpToEndIndex = static_cast<int>(bytecode.instructions.size());
555 bytecode.emit(OpCode::JUMP, 0);
556 bytecode.instructions[jumpToFalseIndex].operand1 = static_cast<int>(bytecode.instructions.size());
558 bytecode.instructions[jumpToEndIndex].operand1 = static_cast<int>(bytecode.instructions.size());
559 return;
560 }
561 if (binExpr->op == AST::BinaryOp::Or)
562 {
563 generateExpression(binExpr->left.get());
564 int jumpToTrueIndex = static_cast<int>(bytecode.instructions.size());
566 generateExpression(binExpr->right.get());
567 int jumpToEndIndex = static_cast<int>(bytecode.instructions.size());
568 bytecode.emit(OpCode::JUMP, 0);
569 bytecode.instructions[jumpToTrueIndex].operand1 = static_cast<int>(bytecode.instructions.size());
571 bytecode.instructions[jumpToEndIndex].operand1 = static_cast<int>(bytecode.instructions.size());
572 return;
573 }
574
575 u8 rLeft = allocateRegister();
576 u8 rRight = allocateRegister();
577 u8 rResult = allocateRegister();
578
579 // Reuse literal detection done here to choose appropriate register opcodes.
580 Value leftLiteral;
581 bool leftIsLiteral = isLiteralExpression(binExpr->left.get(), leftLiteral);
582 if (leftIsLiteral)
583 {
584 int constIndex = bytecode.addConstant(leftLiteral);
585 bytecode.emit(OpCode::LOAD_CONST_R, rLeft, constIndex);
586 }
587 else
588 {
589 generateExpression(binExpr->left.get());
590 bytecode.emit(OpCode::POP_R, rLeft);
591 }
592
593 Value rightLiteral;
594 bool rightIsLiteral = isLiteralExpression(binExpr->right.get(), rightLiteral);
595 if (rightIsLiteral)
596 {
597 int constIndex = bytecode.addConstant(rightLiteral);
598 bytecode.emit(OpCode::LOAD_CONST_R, rRight, constIndex);
599 }
600 else
601 {
602 generateExpression(binExpr->right.get());
603 bytecode.emit(OpCode::POP_R, rRight);
604 }
605
606 // Conservative integer decision:
607 // treat operand as known-int if it's an integer literal or a variable previously inferred as Int.
608 auto exprIsKnownInt = [&](const AST::Expression *e, bool isLiteral, const Value &lit) -> bool {
609 if (isLiteral)
610 {
611 return lit.isInt();
612 }
613 // variable case
614 if (const auto *ident = dynamic_cast<const AST::IdentifierExpr *>(e))
615 {
616 auto it = inferredTypes.find(ident->name);
617 return it != inferredTypes.end() && it->second == ValueType::Int;
618 }
619 return false;
620 };
621
622 bool leftKnownInt = exprIsKnownInt(binExpr->left.get(), leftIsLiteral, leftLiteral);
623 bool rightKnownInt = exprIsKnownInt(binExpr->right.get(), rightIsLiteral, rightLiteral);
624
625 // Choose integer ops only when both operands are known ints.
626 if (leftKnownInt && rightKnownInt)
627 {
628 switch (binExpr->op)
629 {
631 bytecode.emit(OpCode::IADD_R, rResult, rLeft, rRight);
632 break;
634 bytecode.emit(OpCode::ISUB_R, rResult, rLeft, rRight);
635 break;
637 bytecode.emit(OpCode::IMUL_R, rResult, rLeft, rRight);
638 break;
640 bytecode.emit(OpCode::IDIV_R, rResult, rLeft, rRight);
641 break;
643 bytecode.emit(OpCode::IMOD_R, rResult, rLeft, rRight);
644 break;
646 bytecode.emit(OpCode::IAND_R, rResult, rLeft, rRight);
647 break;
649 bytecode.emit(OpCode::IOR_R, rResult, rLeft, rRight);
650 break;
652 bytecode.emit(OpCode::IEQ_R, rResult, rLeft, rRight);
653 break;
655 bytecode.emit(OpCode::INE_R, rResult, rLeft, rRight);
656 break;
658 bytecode.emit(OpCode::ILT_R, rResult, rLeft, rRight);
659 break;
661 bytecode.emit(OpCode::IGT_R, rResult, rLeft, rRight);
662 break;
664 bytecode.emit(OpCode::ILE_R, rResult, rLeft, rRight);
665 break;
667 bytecode.emit(OpCode::IGE_R, rResult, rLeft, rRight);
668 break;
669 }
670 }
671 else
672 {
673 // Fallback to float ops when we don't know both operands are integers.
674 switch (binExpr->op)
675 {
677 bytecode.emit(OpCode::FLADD_R, rResult, rLeft, rRight);
678 break;
680 bytecode.emit(OpCode::FLSUB_R, rResult, rLeft, rRight);
681 break;
683 bytecode.emit(OpCode::FLMUL_R, rResult, rLeft, rRight);
684 break;
686 bytecode.emit(OpCode::FLDIV_R, rResult, rLeft, rRight);
687 break;
689 bytecode.emit(OpCode::FLMOD_R, rResult, rLeft, rRight);
690 break;
692 bytecode.emit(OpCode::FLAND_R, rResult, rLeft, rRight);
693 break;
695 bytecode.emit(OpCode::FLOR_R, rResult, rLeft, rRight);
696 break;
698 bytecode.emit(OpCode::FLEQ_R, rResult, rLeft, rRight);
699 break;
701 bytecode.emit(OpCode::FLNE_R, rResult, rLeft, rRight);
702 break;
704 bytecode.emit(OpCode::FLLT_R, rResult, rLeft, rRight);
705 break;
707 bytecode.emit(OpCode::FLGT_R, rResult, rLeft, rRight);
708 break;
710 bytecode.emit(OpCode::FLLE_R, rResult, rLeft, rRight);
711 break;
713 bytecode.emit(OpCode::FLGE_R, rResult, rLeft, rRight);
714 break;
715 }
716 }
717
718 freeRegister(rLeft);
719 freeRegister(rRight);
720 bytecode.emit(OpCode::PUSH_R, rResult);
721 freeRegister(rResult);
722}
723
725{
726 for (const auto &stmt : blockStmt->statements)
727 {
728 generateStatement(stmt.get());
729 }
730}
731
733{
734 generateExpression(ifStmt->condition.get());
735
736 // Jump to else if false
737 int jumpToElseIndex = static_cast<int>(bytecode.instructions.size());
739
740 generateStatement(ifStmt->thenBranch.get());
741
742 int jumpToEndIndex = static_cast<int>(bytecode.instructions.size());
743 bytecode.emit(OpCode::JUMP, 0);
744
745 // Patch jump to else
746 bytecode.instructions[jumpToElseIndex].operand1 = static_cast<int>(bytecode.instructions.size());
747
748 if (ifStmt->elseBranch)
749 {
750 generateStatement(ifStmt->elseBranch.get());
751 }
752
753 // Patch jump to end
754 bytecode.instructions[jumpToEndIndex].operand1 = static_cast<int>(bytecode.instructions.size());
755}
756
758{
759 int loopStartIndex = static_cast<int>(bytecode.instructions.size());
760
761 // Push loop context
762 loopStartStack.push_back(loopStartIndex);
763 breakJumpsStack.emplace_back();
764 continueJumpsStack.emplace_back();
765
766 generateExpression(whileStmt->condition.get());
767
768 int jumpToEndIndex = static_cast<int>(bytecode.instructions.size());
770
771 generateStatement(whileStmt->body.get());
772
773 // Patch continue jumps to loop start
774 for (int continueJump : continueJumpsStack.back())
775 {
776 bytecode.instructions[continueJump].operand1 = loopStartIndex;
777 }
778
779 bytecode.emit(OpCode::JUMP_BACK, loopStartIndex);
780
781 // Patch jump to end and break jumps
782 int endIndex = static_cast<int>(bytecode.instructions.size());
783 bytecode.instructions[jumpToEndIndex].operand1 = endIndex;
784 for (int breakJump : breakJumpsStack.back())
785 {
786 bytecode.instructions[breakJump].operand1 = endIndex;
787 }
788
789 // Pop loop context
790 loopStartStack.pop_back();
791 breakJumpsStack.pop_back();
792 continueJumpsStack.pop_back();
793}
794
796{
797 // Generate initializer
798 if (forStmt->initializer)
799 {
800 generateStatement(forStmt->initializer.get());
801 }
802
803 int loopStartIndex = static_cast<int>(bytecode.instructions.size());
804
805 // Push loop context
806 loopStartStack.push_back(loopStartIndex);
807 breakJumpsStack.emplace_back();
808 continueJumpsStack.emplace_back();
809
810 // Generate condition (if present)
811 int jumpToEndIndex = -1;
812 if (forStmt->condition)
813 {
814 generateExpression(forStmt->condition.get());
815 jumpToEndIndex = static_cast<int>(bytecode.instructions.size());
817 }
818
819 // Generate body
820 generateStatement(forStmt->body.get());
821
822 // Continue jumps to increment (or loop start if no increment)
823 int incrementIndex = static_cast<int>(bytecode.instructions.size());
824 for (int continueJump : continueJumpsStack.back())
825 {
826 bytecode.instructions[continueJump].operand1 = incrementIndex;
827 }
828
829 // Generate increment
830 if (forStmt->increment)
831 {
832 if (const auto *postfix = dynamic_cast<const AST::PostfixExpr *>(forStmt->increment.get()))
833 {
834 // resultNeeded=false: skips the old-value LOAD_VAR, and STORE_VAR
835 // already pops the result — stack is clean, no POP needed.
836 generatePostfixExpr(postfix, false);
837 }
838 else
839 {
840 generateExpression(forStmt->increment.get());
841 bytecode.emit(OpCode::POP); // discard result
842 }
843 }
844
845 // Jump back to condition check
846 bytecode.emit(OpCode::JUMP_BACK, loopStartIndex);
847
848 // Patch jump to end and break jumps
849 int endIndex = static_cast<int>(bytecode.instructions.size());
850 if (jumpToEndIndex != -1)
851 {
852 bytecode.instructions[jumpToEndIndex].operand1 = endIndex;
853 }
854 for (int breakJump : breakJumpsStack.back())
855 {
856 bytecode.instructions[breakJump].operand1 = endIndex;
857 }
858
859 // Pop loop context
860 loopStartStack.pop_back();
861 breakJumpsStack.pop_back();
862 continueJumpsStack.pop_back();
863}
864
866{
867 if (breakJumpsStack.empty())
868 {
869 throw std::runtime_error("'break' statement outside of loop");
870 }
871 // Emit jump with placeholder, will be patched later
872 int jumpIndex = static_cast<int>(bytecode.instructions.size());
873 bytecode.emit(OpCode::JUMP, 0);
874 breakJumpsStack.back().push_back(jumpIndex);
875}
876
878{
879 if (continueJumpsStack.empty())
880 {
881 throw std::runtime_error("'continue' statement outside of loop");
882 }
883 // Emit jump with placeholder, will be patched later
884 int jumpIndex = static_cast<int>(bytecode.instructions.size());
885 bytecode.emit(OpCode::JUMP, 0);
886 continueJumpsStack.back().push_back(jumpIndex);
887}
888
890{
891 if (returnStmt->value)
892 {
893 generateExpression(returnStmt->value.get());
894 }
895 else
896 {
898 }
900}
901
903{
904 generateBlockStmt(unsafeStmt->block.get());
905}
906
908{
909 // Jump over function body
910 int jumpOverIndex = static_cast<int>(bytecode.instructions.size());
911 bytecode.emit(OpCode::JUMP, 0);
912
913 // Record entry point
914 int entryPoint = static_cast<int>(bytecode.instructions.size());
915 bytecode.functionEntries[funcDecl->name] = entryPoint;
916
917 // Record parameter count
918 bytecode.functionParamCounts[funcDecl->name] = static_cast<int>(funcDecl->params.size());
919
920 // Pop argument count (it's on the stack when function is called)
921 bytecode.emit(OpCode::POP);
922
923 // Pop parameters in reverse order and store in variables
924 for (auto it = funcDecl->params.rbegin(); it != funcDecl->params.rend(); ++it)
925 {
926 int varIndex = bytecode.getOrCreateVar(it->name);
927 bytecode.emit(OpCode::STORE_VAR, varIndex);
928 }
929
930 // Generate body
931 generateBlockStmt(funcDecl->body.get());
932
933 // Ensure return
936
937 // Patch jump over
938 bytecode.instructions[jumpOverIndex].operand1 = static_cast<int>(bytecode.instructions.size());
939}
940
942{
943 if (boolExpr->value)
944 {
946 }
947 else
948 {
950 }
951}
952
957
959{
960 // Support assignments to variables, struct fields, and array elements.
961 if (const auto *identExpr = dynamic_cast<const AST::IdentifierExpr *>(assignExpr->target.get()))
962 {
963 // Variable assignment: a = value
964 // 1. Generate value (pushes value to stack)
965 generateExpression(assignExpr->value.get());
966
967 // Try to infer and record type
968 Value val;
969 if (isLiteralExpression(assignExpr->value.get(), val))
970 {
971 inferredTypes[identExpr->name] = val.getType();
972 }
973 else if (const auto *identRhs = dynamic_cast<const AST::IdentifierExpr *>(assignExpr->value.get()))
974 {
975 auto it = inferredTypes.find(identRhs->name);
976 if (it != inferredTypes.end())
977 {
978 inferredTypes[identExpr->name] = it->second;
979 }
980 }
981
982 // 2. Store in variable (pops value)
983 int varIndex = bytecode.getOrCreateVar(identExpr->name);
984 bytecode.emit(OpCode::STORE_VAR, varIndex);
985
986 // 3. Load it back (assignment is an expression that returns the value)
987 bytecode.emit(OpCode::LOAD_VAR, varIndex);
988 }
989 else if (const auto *fieldExpr = dynamic_cast<const AST::FieldAccessExpr *>(assignExpr->target.get()))
990 {
991 generateExpression(fieldExpr->object.get());
992 generateExpression(assignExpr->value.get());
993
994 int fieldNameIndex = bytecode.addStringConstant(fieldExpr->fieldName);
995
996 bytecode.emit(OpCode::SET_FIELD, fieldNameIndex);
997 bytecode.emit(OpCode::GET_FIELD, fieldNameIndex);
998 }
999 else if (const auto *arrayAccess = dynamic_cast<const AST::ArrayAccessExpr *>(assignExpr->target.get()))
1000 {
1001 // a[i] = value
1002 generateExpression(arrayAccess->array.get()); // array
1003 generateExpression(arrayAccess->index.get()); // index
1004 generateExpression(assignExpr->value.get()); // value
1005
1006 int countIdx = bytecode.addConstant(Value(static_cast<i64>(3)));
1007 bytecode.emit(OpCode::PUSH_CONST, countIdx); // count for __set_elem
1008
1009 int setIdx = bytecode.addStringConstant("__set_elem");
1010
1011 bytecode.emit(OpCode::CALL_NATIVE, setIdx);
1012 }
1013 else
1014 {
1015 throw std::runtime_error("Invalid assignment target. Only variables, struct fields, and array elements are supported.");
1016 }
1017}
1018
1020{
1021 // Prefer static struct instantiation when we have metadata in the struct section.
1022 auto it = bytecode.structEntries.find(expr->structName);
1023 if (it != bytecode.structEntries.end())
1024 {
1025 int structIndex = it->second;
1026 // Create instance with defaults from Bytecode::structs / constants
1028
1029 // Apply any explicit field initializers as overrides using dynamic SET_FIELD.
1030 for (const auto &[fieldName, fieldValue] : expr->fieldValues)
1031 {
1032 generateExpression(fieldValue.get());
1033 int fieldNameIndex = bytecode.addStringConstant(fieldName);
1034 bytecode.emit(OpCode::SET_FIELD, fieldNameIndex);
1035 }
1036 }
1037 else
1038 {
1039 // Fallback
1040 int structNameIndex = bytecode.addStringConstant(expr->structName);
1041 bytecode.emit(OpCode::NEW_STRUCT, structNameIndex);
1042
1043 for (const auto &[fieldName, fieldValue] : expr->fieldValues)
1044 {
1045 generateExpression(fieldValue.get());
1046 int fieldNameIndex = bytecode.addStringConstant(fieldName);
1047 bytecode.emit(OpCode::SET_FIELD, fieldNameIndex);
1048 }
1049 }
1050}
1051
1053{
1054 generateExpression(expr->object.get());
1055 int fieldNameIndex = bytecode.addStringConstant(expr->fieldName);
1056 bytecode.emit(OpCode::GET_FIELD, fieldNameIndex);
1057}
1058
1059void CodeGenerator::generatePostfixExpr(const AST::PostfixExpr *expr, bool resultNeeded)
1060{
1061 const auto *identExpr = dynamic_cast<const AST::IdentifierExpr *>(expr->operand.get());
1062 if (identExpr == nullptr)
1063 throw std::runtime_error("Postfix operators only supported on variables");
1064
1065 int varIndex = bytecode.getOrCreateVar(identExpr->name);
1066
1067 if (resultNeeded)
1068 bytecode.emit(OpCode::LOAD_VAR, varIndex);
1069
1070 bytecode.emit(OpCode::LOAD_VAR, varIndex);
1071
1072 int oneIndex = bytecode.addConstant(Value(static_cast<i64>(1)));
1073 bytecode.emit(OpCode::PUSH_CONST, oneIndex);
1074
1075 auto it = inferredTypes.find(identExpr->name);
1076 bool varIsInt = (it != inferredTypes.end() && it->second == ValueType::Int);
1077 if (expr->op == AST::PostfixOp::Increment)
1078 bytecode.emit(varIsInt ? OpCode::IADD : OpCode::FLADD);
1079 else
1081
1082 bytecode.emit(OpCode::STORE_VAR, varIndex);
1083}
1084
1086{
1087 std::string structDef = "struct " + decl->name + " {";
1088 for (const auto &field : decl->fields)
1089 {
1090 structDef += " " + field.name + ":" + field.type->name + ",";
1091 }
1092 if (!decl->fields.empty())
1093 {
1094 structDef.pop_back(); // Remove trailing comma
1095 }
1096 structDef += " }";
1097 bytecode.addConstant(Value(structDef));
1098 // reg metadata
1099 int firstConstIndex = static_cast<int>(bytecode.constants.size());
1100 for (const auto &field : decl->fields)
1101 {
1102 (void)field;
1103 bytecode.addConstant(Value());
1104 }
1105
1106 StructInfo info;
1107 info.name = decl->name;
1108 info.firstConstIndex = firstConstIndex;
1109 info.fieldCount = static_cast<int>(decl->fields.size());
1110 for (const auto &field : decl->fields)
1111 {
1112 info.fieldNames.push_back(field.name);
1113 }
1114
1115 // If a struct with this name already exists, do not overwrite it.
1116 if (!bytecode.structEntries.contains(decl->name))
1117 {
1118 int index = static_cast<int>(bytecode.structs.size());
1119 bytecode.structs.push_back(std::move(info));
1120 bytecode.structEntries[decl->name] = index;
1121 }
1122}
1123
1125{
1126 generateExpression(switchStmt->expr.get());
1127 std::string tempName = "__switch_" + std::to_string(switchCounter++);
1128 int tempVarIndex = bytecode.getOrCreateVar(tempName);
1129 bytecode.emit(OpCode::STORE_VAR, tempVarIndex);
1130
1131 std::vector<int> endJumps; // one per case, all patched to end
1132
1133 for (const auto &caseClause : switchStmt->cases)
1134 {
1135 // Reload switch value for every comparison
1136 bytecode.emit(OpCode::LOAD_VAR, tempVarIndex);
1137 generateExpression(caseClause.value.get());
1139
1140 int skipJump = static_cast<int>(bytecode.instructions.size());
1141 bytecode.emit(OpCode::JUMP_IF_FALSE, 0); // skip this case if no match
1142
1143 for (const auto &stmt : caseClause.statements)
1144 {
1145 generateStatement(stmt.get());
1146 }
1147
1148 int endJump = static_cast<int>(bytecode.instructions.size());
1149 bytecode.emit(OpCode::JUMP, 0); // after executing, jump to end
1150 endJumps.push_back(endJump);
1151
1152 // Patch skip jump to point at the next case
1153 bytecode.instructions[skipJump].operand1 = static_cast<int>(bytecode.instructions.size());
1154 }
1155
1156 for (const auto &stmt : switchStmt->defaultStmts)
1157 {
1158 generateStatement(stmt.get());
1159 }
1160
1161 int endIndex = static_cast<int>(bytecode.instructions.size());
1162 for (int jumpIdx : endJumps)
1163 {
1164 bytecode.instructions[jumpIdx].operand1 = endIndex;
1165 }
1166}
1167
1169{
1170 for (const auto &elem : arrayLit->elements)
1171 generateExpression(elem.get());
1172
1173 int count = static_cast<int>(arrayLit->elements.size());
1174 int countIdx = bytecode.addConstant(Value(static_cast<i64>(count)));
1175 bytecode.emit(OpCode::PUSH_CONST, countIdx);
1176
1177 int funcNameIdx = bytecode.addStringConstant("__array_literal");
1178 bytecode.emit(OpCode::CALL_NATIVE, funcNameIdx);
1179
1180 if (!resultNeeded)
1181 bytecode.emit(OpCode::POP);
1182}
1183
1184void CodeGenerator::generateArrayAccessExpr(const AST::ArrayAccessExpr *arrayAccess, bool resultNeeded)
1185{
1186 generateExpression(arrayAccess->array.get()); // array
1187 generateExpression(arrayAccess->index.get()); // index
1188 int countIdx = bytecode.addConstant(Value(static_cast<i64>(2)));
1189 bytecode.emit(OpCode::PUSH_CONST, countIdx); // count for __get_elem
1190 int funcIdx = bytecode.addStringConstant("__get_elem");
1191 bytecode.emit(OpCode::CALL_NATIVE, funcIdx);
1192 if (!resultNeeded)
1193 bytecode.emit(OpCode::POP);
1194}
1195
1196} // namespace Phasor
void generateForStmt(const AST::ForStmt *forStmt)
Generate bytecode from For Statement.
Definition CodeGen.cpp:795
Bytecode bytecode
Generated bytecode.
Definition CodeGen.hpp:123
void generateCallExpr(const AST::CallExpr *callExpr)
Generate bytecode from Call Expression.
Definition CodeGen.cpp:367
void generateVarDecl(const AST::VarDecl *varDecl)
Generate bytecode from Variable Declaration.
Definition CodeGen.cpp:230
void generateIfStmt(const AST::IfStmt *ifStmt)
Generate bytecode from If Statement.
Definition CodeGen.cpp:732
void generatePostfixExpr(const AST::PostfixExpr *expr, bool resultNeeded=true)
Definition CodeGen.cpp:1059
std::vector< std::vector< int > > breakJumpsStack
Definition CodeGen.hpp:212
void generateUnaryExpr(const AST::UnaryExpr *unaryExpr)
Generate bytecode from Unary Expression.
Definition CodeGen.cpp:343
void generateArrayLiteralExpr(const AST::ArrayLiteralExpr *arrayLit, bool resultNeeded)
Definition CodeGen.cpp:1168
void generateStructInstanceExpr(const AST::StructInstanceExpr *expr)
Definition CodeGen.cpp:1019
void generateNullExpr(const AST::NullExpr *nullExpr)
Generate bytecode from Null Expression.
Definition CodeGen.cpp:953
void generateFunctionDecl(const AST::FunctionDecl *funcDecl)
Generate bytecode from Function Declaration.
Definition CodeGen.cpp:907
std::unordered_map< std::string, ValueType > inferredTypes
Definition CodeGen.hpp:126
Bytecode generate(const AST::Program &program, const std::unordered_map< std::string, int > &existingVars={}, int nextVarIdx=0, bool replMode=false)
Generate bytecode from program.
Definition CodeGen.cpp:9
void generateArrayAccessExpr(const AST::ArrayAccessExpr *arrayAccess, bool resultNeeded)
Definition CodeGen.cpp:1184
void generateWhileStmt(const AST::WhileStmt *whileStmt)
Generate bytecode from While Statement.
Definition CodeGen.cpp:757
void generateSwitchStmt(const AST::SwitchStmt *switchStmt)
Definition CodeGen.cpp:1124
void generateBlockStmt(const AST::BlockStmt *blockStmt)
Generate bytecode from Block Statement.
Definition CodeGen.cpp:724
void generateBooleanExpr(const AST::BooleanExpr *boolExpr)
Generate bytecode from Boolean Expression.
Definition CodeGen.cpp:941
void generateStructDecl(const AST::StructDecl *decl)
Definition CodeGen.cpp:1085
std::vector< int > loopStartStack
Definition CodeGen.hpp:211
void generatePrintStmt(const AST::PrintStmt *printStmt)
Generate bytecode from Print Statement.
Definition CodeGen.cpp:288
void generateStringExpr(const AST::StringExpr *strExpr)
Generate bytecode from String Expression.
Definition CodeGen.cpp:331
void generateExpression(const AST::Expression *expr, bool resultNeeded=true)
Generate bytecode from Expression.
Definition CodeGen.cpp:166
ValueType inferExpressionType(const AST::Expression *expr, bool &known)
Simple expression type inference (conservative).
Definition CodeGen.cpp:64
std::vector< std::vector< int > > continueJumpsStack
Definition CodeGen.hpp:213
void generateExportStmt(const AST::ExportStmt *exportStmt)
Generate bytecode from Export Statement.
Definition CodeGen.cpp:300
void generateUnsafeBlockStmt(const AST::UnsafeBlockStmt *unsafeStmt)
Generate bytecode from Unsafe Block Statement.
Definition CodeGen.cpp:902
void freeRegister(u8 reg)
Free a register.
Definition CodeGen.hpp:151
void generateBinaryExpr(const AST::BinaryExpr *binExpr)
Generate bytecode from Binary Expression.
Definition CodeGen.cpp:469
void generateExpressionStmt(const AST::ExpressionStmt *exprStmt)
Generate bytecode from Expression Statement.
Definition CodeGen.cpp:265
void generateImportStmt(const AST::ImportStmt *importStmt)
Generate bytecode from Import Statement.
Definition CodeGen.cpp:294
void generateStatement(const AST::Statement *stmt)
Generate bytecode from Statement.
Definition CodeGen.cpp:90
static bool isLiteralExpression(const AST::Expression *expr, Value &outValue)
Check if expression is a compile-time literal.
Definition CodeGen.cpp:25
void generateIdentifierExpr(const AST::IdentifierExpr *identExpr)
Generate bytecode from Identifier Expression.
Definition CodeGen.cpp:337
bool isRepl
REPL mode.
Definition CodeGen.hpp:124
void generateAssignmentExpr(const AST::AssignmentExpr *assignExpr)
Generate bytecode from Assignment Expression.
Definition CodeGen.cpp:958
void generateNumberExpr(const AST::NumberExpr *numExpr)
Generate bytecode from Numeral Expression.
Definition CodeGen.cpp:306
u8 allocateRegister()
Allocate a new register.
Definition CodeGen.hpp:133
void generateFieldAccessExpr(const AST::FieldAccessExpr *expr)
Definition CodeGen.cpp:1052
void generateReturnStmt(const AST::ReturnStmt *returnStmt)
Generate bytecode from Return Statement.
Definition CodeGen.cpp:889
A value in the Phasor VM.
Definition Value.hpp:59
bool isNull() const noexcept
Check if the value is null.
Definition Value.hpp:146
ValueType getType() const noexcept
Get the type of the value.
Definition Value.hpp:118
bool asBool() const noexcept
Get the value as a boolean.
Definition Value.hpp:159
Value logicalOr(const Value &other) const noexcept
Logical OR.
Definition Value.hpp:344
Value logicalAnd(const Value &other) const noexcept
Logical AND.
Definition Value.hpp:338
bool isBool() const noexcept
Definition Value.hpp:147
static Phasor::u64 s[2]
Definition random.cpp:7
The Phasor Programming Language and Runtime.
Definition AST.hpp:13
int64_t i64
Definition phsint.hpp:16
ValueType
Runtime value types for the VM.
Definition Value.hpp:43
uint8_t u8
Definition phsint.hpp:9
double f64
Definition phsint.hpp:7
@ FLMOD_R
R[rA] = R[rB] % R[rC].
Definition ISA.hpp:122
@ NOT
Pop a, push !a.
Definition ISA.hpp:38
@ NULL_VAL
Push null.
Definition ISA.hpp:86
@ 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
@ FLGE_R
R[rA] = R[rB] >= R[rC].
Definition ISA.hpp:147
@ 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
@ FLADD_R
R[rA] = R[rB] + R[rC].
Definition ISA.hpp:118
@ LOAD_CONST_R
Load constant to register: R[rA] = constants[immediate].
Definition ISA.hpp:104
@ 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
@ 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
@ FLLE_R
R[rA] = R[rB] <= R[rC].
Definition ISA.hpp:146
@ ISUB_R
R[rA] = R[rB] - R[rC].
Definition ISA.hpp:114
@ FLDIV_R
R[rA] = R[rB] / R[rC].
Definition ISA.hpp:121
@ 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
@ 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
@ 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
@ 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
@ FLEQ_R
R[rA] = R[rB] == R[rC].
Definition ISA.hpp:142
@ LOAD_VAR
Push variable value onto stack.
Definition ISA.hpp:68
@ RETURN
Return from function.
Definition ISA.hpp:81
@ 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
@ HALT
Stop execution.
Definition ISA.hpp:75
@ 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
@ GET_FIELD
Pop struct, pop field name, push field value.
Definition ISA.hpp:94
@ IMPORT
Import a module: operand is index of module path in constants.
Definition ISA.hpp:74
@ 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
@ POP
Pop top of stack.
Definition ISA.hpp:15
@ IMOD_R
R[rA] = R[rB] % R[rC].
Definition ISA.hpp:117
@ PRINT
Pop top of stack and print.
Definition ISA.hpp:71
@ IEQ_R
R[rA] = R[rB] == R[rC].
Definition ISA.hpp:134
@ IGE_R
R[rA] = R[rB] >= R[rC].
Definition ISA.hpp:139
Array Access Expression Node.
Definition AST.hpp:315
std::unique_ptr< Expression > array
Definition AST.hpp:316
std::unique_ptr< Expression > index
Definition AST.hpp:317
Array Literal Expression Node.
Definition AST.hpp:335
std::vector< std::unique_ptr< Expression > > elements
Definition AST.hpp:336
Assignment Expression Node.
Definition AST.hpp:390
std::unique_ptr< Expression > target
Definition AST.hpp:391
std::unique_ptr< Expression > value
Definition AST.hpp:392
Binary Expression Node.
Definition AST.hpp:253
std::unique_ptr< Expression > right
Definition AST.hpp:256
std::unique_ptr< Expression > left
Definition AST.hpp:254
Block Statement Node.
Definition AST.hpp:496
std::vector< std::unique_ptr< Statement > > statements
Definition AST.hpp:497
Boolean Expression Node.
Definition AST.hpp:139
Break Statement Node.
Definition AST.hpp:530
Call Expression Node.
Definition AST.hpp:369
std::string callee
Definition AST.hpp:370
std::vector< std::unique_ptr< Expression > > arguments
Definition AST.hpp:371
Continue Statement Node.
Definition AST.hpp:539
Export Statement Node.
Definition AST.hpp:482
std::unique_ptr< Statement > declaration
Definition AST.hpp:483
Expression Statement Node.
Definition AST.hpp:429
std::unique_ptr< Expression > expression
Definition AST.hpp:430
Expression Node.
Definition AST.hpp:55
Field Access Expression Node.
Definition AST.hpp:735
std::unique_ptr< Expression > object
Definition AST.hpp:736
For Statement Node.
Definition AST.hpp:592
std::unique_ptr< Statement > initializer
Definition AST.hpp:593
std::unique_ptr< Expression > increment
Definition AST.hpp:595
std::unique_ptr< Statement > body
Definition AST.hpp:596
std::unique_ptr< Expression > condition
Definition AST.hpp:594
Function Declaration Node.
Definition AST.hpp:639
std::vector< Param > params
Definition AST.hpp:646
std::unique_ptr< BlockStmt > body
Definition AST.hpp:648
Identifier Expression Node.
Definition AST.hpp:126
If Statement Node.
Definition AST.hpp:548
std::unique_ptr< Statement > elseBranch
Definition AST.hpp:551
std::unique_ptr< Expression > condition
Definition AST.hpp:549
std::unique_ptr< Statement > thenBranch
Definition AST.hpp:550
Import Statement Node.
Definition AST.hpp:469
std::string modulePath
Definition AST.hpp:470
Include Statement Node.
Definition AST.hpp:456
NULL Expression Node.
Definition AST.hpp:152
Numeral Expression Node.
Definition AST.hpp:99
std::string value
Definition AST.hpp:100
Postfix Expression Node.
Definition AST.hpp:195
std::unique_ptr< Expression > operand
Definition AST.hpp:197
Print Statement Node.
Definition AST.hpp:442
std::unique_ptr< Expression > expression
Definition AST.hpp:443
Program Node.
Definition AST.hpp:65
std::vector< std::unique_ptr< Statement > > statements
Definition AST.hpp:66
Return Statement Node.
Definition AST.hpp:513
std::unique_ptr< Expression > value
Definition AST.hpp:514
Statement Node.
Definition AST.hpp:60
String Expression Node.
Definition AST.hpp:112
std::string value
Definition AST.hpp:113
Struct Declaration Node.
Definition AST.hpp:692
std::vector< StructField > fields
Definition AST.hpp:694
std::string name
Definition AST.hpp:693
Struct Instance Expression Node.
Definition AST.hpp:713
std::vector< std::pair< std::string, std::unique_ptr< Expression > > > fieldValues
Definition AST.hpp:715
Switch Statement Node.
Definition AST.hpp:765
std::vector< CaseClause > cases
Definition AST.hpp:767
std::vector< std::unique_ptr< Statement > > defaultStmts
Definition AST.hpp:768
std::unique_ptr< Expression > expr
Definition AST.hpp:766
Unary Expression Node.
Definition AST.hpp:221
std::unique_ptr< Expression > operand
Definition AST.hpp:223
Unsafe Block Statement Node.
Definition AST.hpp:625
std::unique_ptr< BlockStmt > block
Definition AST.hpp:626
Variable Declaration Node.
Definition AST.hpp:411
std::string name
Definition AST.hpp:412
std::unique_ptr< Expression > initializer
Definition AST.hpp:413
While Statement Node.
Definition AST.hpp:573
std::unique_ptr< Expression > condition
Definition AST.hpp:574
std::unique_ptr< Statement > body
Definition AST.hpp:575
Complete bytecode structure.
Definition CodeGen.hpp:50
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