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