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