3#include <unordered_map>
9 int nextVarIdx,
bool replMode)
30 if (numExpr->value.find(
'.') != std::string::npos)
32 outValue =
Value(std::stod(numExpr->value));
36 outValue =
Value(
static_cast<int64_t
>(std::stoll(numExpr->value)));
47 outValue =
Value(strExpr->value);
52 outValue =
Value(boolExpr->value);
91 if (
const auto *varDecl =
dynamic_cast<const AST::VarDecl *
>(stmt))
99 else if (
const auto *printStmt =
dynamic_cast<const AST::PrintStmt *
>(stmt))
107 else if (
const auto *importStmt =
dynamic_cast<const AST::ImportStmt *
>(stmt))
111 else if (
const auto *exportStmt =
dynamic_cast<const AST::ExportStmt *
>(stmt))
115 else if (
const auto *blockStmt =
dynamic_cast<const AST::BlockStmt *
>(stmt))
119 else if (
const auto *ifStmt =
dynamic_cast<const AST::IfStmt *
>(stmt))
123 else if (
const auto *whileStmt =
dynamic_cast<const AST::WhileStmt *
>(stmt))
127 else if (
const auto *forStmt =
dynamic_cast<const AST::ForStmt *
>(stmt))
131 else if (
const auto *returnStmt =
dynamic_cast<const AST::ReturnStmt *
>(stmt))
143 else if (
const auto *structDecl =
dynamic_cast<const AST::StructDecl *
>(stmt))
155 else if (
const auto *switchStmt =
dynamic_cast<const AST::SwitchStmt *
>(stmt))
161 throw std::runtime_error(
"Unknown statement type in code generation");
171 else if (
const auto *strExpr =
dynamic_cast<const AST::StringExpr *
>(expr))
179 else if (
const auto *unaryExpr =
dynamic_cast<const AST::UnaryExpr *
>(expr))
183 else if (
const auto *callExpr =
dynamic_cast<const AST::CallExpr *
>(expr))
187 else if (
const auto *binExpr =
dynamic_cast<const AST::BinaryExpr *
>(expr))
191 else if (
const auto *boolExpr =
dynamic_cast<const AST::BooleanExpr *
>(expr))
195 else if (
const auto *nullExpr =
dynamic_cast<const AST::NullExpr *
>(expr))
211 else if (
const auto *postfixExpr =
dynamic_cast<const AST::PostfixExpr *
>(expr))
217 throw std::runtime_error(
"Unknown expression type in code generation");
303 if (numExpr->
value.find(
'.') != std::string::npos)
305 double d = std::stod(numExpr->
value);
311 int64_t i = std::stoll(numExpr->
value);
318 throw std::runtime_error(
"Invalid number format: " + numExpr->
value);
330 int varIndex =
bytecode.getOrCreateVar(identExpr->
name);
340 switch (unaryExpr->
op)
366 auto len = (int64_t)strExpr->value.length();
382 if (numExpr->value ==
"1" || numExpr->value ==
"1.0")
401 if (callExpr->
callee ==
"starts_with" && callExpr->
arguments.size() == 2)
405 if ((
s !=
nullptr) && (p !=
nullptr))
407 bool result =
s->value.length() >= p->value.length() &&
s->value.starts_with(p->value);
413 if (callExpr->
callee ==
"ends_with" && callExpr->
arguments.size() == 2)
417 if ((
s !=
nullptr) && (suffix !=
nullptr))
419 bool result =
s->value.length() >= suffix->value.length() &&
s->value.ends_with(suffix->value);
425 for (
const auto &arg : callExpr->
arguments)
436 if (entryIt !=
bytecode.functionEntries.end())
439 auto itParam =
bytecode.functionParamCounts.find(callExpr->
callee);
440 if (itParam !=
bytecode.functionParamCounts.end())
442 int expected = itParam->second;
443 int got =
static_cast<int>(callExpr->
arguments.size());
446 std::cerr <<
"ERROR: calling function '" << callExpr->
callee <<
"' with " << got
447 <<
" arguments but it expects " << expected <<
"\n";
472 result = leftVal + rightVal;
475 result = leftVal - rightVal;
478 result = leftVal * rightVal;
481 result = leftVal / rightVal;
484 result = leftVal % rightVal;
493 result =
Value(leftVal == rightVal);
496 result =
Value(leftVal != rightVal);
499 result =
Value(leftVal < rightVal);
502 result =
Value(leftVal > rightVal);
505 result =
Value(leftVal <= rightVal);
508 result =
Value(leftVal >= rightVal);
528 int constIndex =
bytecode.addConstant(result);
535 std::cerr <<
"Unknown error in Phasor::CodeGenerator::generateBinaryExpr().\n";
542 int jumpToFalseIndex =
static_cast<int>(
bytecode.instructions.size());
545 int jumpToEndIndex =
static_cast<int>(
bytecode.instructions.size());
547 bytecode.instructions[jumpToFalseIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
549 bytecode.instructions[jumpToEndIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
555 int jumpToTrueIndex =
static_cast<int>(
bytecode.instructions.size());
558 int jumpToEndIndex =
static_cast<int>(
bytecode.instructions.size());
560 bytecode.instructions[jumpToTrueIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
562 bytecode.instructions[jumpToEndIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
575 int constIndex =
bytecode.addConstant(leftLiteral);
588 int constIndex =
bytecode.addConstant(rightLiteral);
613 bool leftKnownInt = exprIsKnownInt(binExpr->
left.get(), leftIsLiteral, leftLiteral);
614 bool rightKnownInt = exprIsKnownInt(binExpr->
right.get(), rightIsLiteral, rightLiteral);
617 if (leftKnownInt && rightKnownInt)
717 for (
const auto &stmt : blockStmt->
statements)
728 int jumpToElseIndex =
static_cast<int>(
bytecode.instructions.size());
733 int jumpToEndIndex =
static_cast<int>(
bytecode.instructions.size());
737 bytecode.instructions[jumpToElseIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
745 bytecode.instructions[jumpToEndIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
750 int loopStartIndex =
static_cast<int>(
bytecode.instructions.size());
759 int jumpToEndIndex =
static_cast<int>(
bytecode.instructions.size());
767 bytecode.instructions[continueJump].operand1 = loopStartIndex;
773 int endIndex =
static_cast<int>(
bytecode.instructions.size());
774 bytecode.instructions[jumpToEndIndex].operand1 = endIndex;
777 bytecode.instructions[breakJump].operand1 = endIndex;
794 int loopStartIndex =
static_cast<int>(
bytecode.instructions.size());
802 int jumpToEndIndex = -1;
806 jumpToEndIndex =
static_cast<int>(
bytecode.instructions.size());
814 int incrementIndex =
static_cast<int>(
bytecode.instructions.size());
817 bytecode.instructions[continueJump].operand1 = incrementIndex;
840 int endIndex =
static_cast<int>(
bytecode.instructions.size());
841 if (jumpToEndIndex != -1)
843 bytecode.instructions[jumpToEndIndex].operand1 = endIndex;
847 bytecode.instructions[breakJump].operand1 = endIndex;
860 throw std::runtime_error(
"'break' statement outside of loop");
863 int jumpIndex =
static_cast<int>(
bytecode.instructions.size());
872 throw std::runtime_error(
"'continue' statement outside of loop");
875 int jumpIndex =
static_cast<int>(
bytecode.instructions.size());
882 if (returnStmt->
value)
901 int jumpOverIndex =
static_cast<int>(
bytecode.instructions.size());
905 int entryPoint =
static_cast<int>(
bytecode.instructions.size());
909 bytecode.functionParamCounts[funcDecl->
name] =
static_cast<int>(funcDecl->
params.size());
915 for (
auto it = funcDecl->
params.rbegin(); it != funcDecl->
params.rend(); ++it)
917 int varIndex =
bytecode.getOrCreateVar(it->name);
929 bytecode.instructions[jumpOverIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
974 int varIndex =
bytecode.getOrCreateVar(identExpr->name);
988 int fieldNameIndex =
bytecode.addStringConstant(fieldExpr->fieldName);
997 throw std::runtime_error(
"Invalid assignment target. Only variables and struct fields are supported.");
1005 if (it !=
bytecode.structEntries.end())
1007 int structIndex = it->second;
1012 for (
const auto &[fieldName, fieldValue] : expr->
fieldValues)
1015 int fieldNameIndex =
bytecode.addStringConstant(fieldName);
1025 for (
const auto &[fieldName, fieldValue] : expr->
fieldValues)
1028 int fieldNameIndex =
bytecode.addStringConstant(fieldName);
1044 if (identExpr ==
nullptr)
1045 throw std::runtime_error(
"Postfix operators only supported on variables");
1047 int varIndex =
bytecode.getOrCreateVar(identExpr->name);
1054 int oneIndex =
bytecode.addConstant(
Value(
static_cast<int64_t
>(1)));
1069 std::string structDef =
"struct " + decl->
name +
" {";
1070 for (
const auto &field : decl->
fields)
1072 structDef +=
" " + field.name +
":" + field.type->name +
",";
1074 if (!decl->
fields.empty())
1076 structDef.pop_back();
1081 int firstConstIndex =
static_cast<int>(
bytecode.constants.size());
1082 for (
const auto &field : decl->
fields)
1092 for (
const auto &field : decl->
fields)
1100 int index =
static_cast<int>(
bytecode.structs.size());
1101 bytecode.structs.push_back(std::move(info));
1109 std::string tempName =
"__switch_" + std::to_string(
switchCounter++);
1110 int tempVarIndex =
bytecode.getOrCreateVar(tempName);
1113 std::vector<int> endJumps;
1115 for (
const auto &caseClause : switchStmt->
cases)
1122 int skipJump =
static_cast<int>(
bytecode.instructions.size());
1125 for (
const auto &stmt : caseClause.statements)
1130 int endJump =
static_cast<int>(
bytecode.instructions.size());
1132 endJumps.push_back(endJump);
1135 bytecode.instructions[skipJump].operand1 =
static_cast<int>(
bytecode.instructions.size());
1143 int endIndex =
static_cast<int>(
bytecode.instructions.size());
1144 for (
int jumpIdx : endJumps)
1146 bytecode.instructions[jumpIdx].operand1 = endIndex;
void generateForStmt(const AST::ForStmt *forStmt)
Generate bytecode from For Statement.
Bytecode bytecode
Generated bytecode.
void generateCallExpr(const AST::CallExpr *callExpr)
Generate bytecode from Call Expression.
void generateVarDecl(const AST::VarDecl *varDecl)
Generate bytecode from Variable Declaration.
void generateIfStmt(const AST::IfStmt *ifStmt)
Generate bytecode from If Statement.
void generatePostfixExpr(const AST::PostfixExpr *expr, bool resultNeeded=true)
std::vector< std::vector< int > > breakJumpsStack
void generateContinueStmt()
void generateUnaryExpr(const AST::UnaryExpr *unaryExpr)
Generate bytecode from Unary Expression.
void generateStructInstanceExpr(const AST::StructInstanceExpr *expr)
void generateNullExpr(const AST::NullExpr *nullExpr)
Generate bytecode from Null Expression.
void generateFunctionDecl(const AST::FunctionDecl *funcDecl)
Generate bytecode from Function Declaration.
std::unordered_map< std::string, ValueType > inferredTypes
Bytecode generate(const AST::Program &program, const std::unordered_map< std::string, int > &existingVars={}, int nextVarIdx=0, bool replMode=false)
Generate bytecode from program.
void generateWhileStmt(const AST::WhileStmt *whileStmt)
Generate bytecode from While Statement.
void generateSwitchStmt(const AST::SwitchStmt *switchStmt)
void generateBlockStmt(const AST::BlockStmt *blockStmt)
Generate bytecode from Block Statement.
void generateBooleanExpr(const AST::BooleanExpr *boolExpr)
Generate bytecode from Boolean Expression.
void generateStructDecl(const AST::StructDecl *decl)
uint8_t allocateRegister()
Allocate a new register.
std::vector< int > loopStartStack
void generatePrintStmt(const AST::PrintStmt *printStmt)
Generate bytecode from Print Statement.
void generateStringExpr(const AST::StringExpr *strExpr)
Generate bytecode from String Expression.
void generateExpression(const AST::Expression *expr, bool resultNeeded=true)
Generate bytecode from Expression.
void freeRegister(uint8_t reg)
Free a register.
ValueType inferExpressionType(const AST::Expression *expr, bool &known)
Simple expression type inference (conservative).
std::vector< std::vector< int > > continueJumpsStack
void generateExportStmt(const AST::ExportStmt *exportStmt)
Generate bytecode from Export Statement.
void generateUnsafeBlockStmt(const AST::UnsafeBlockStmt *unsafeStmt)
Generate bytecode from Unsafe Block Statement.
void generateBinaryExpr(const AST::BinaryExpr *binExpr)
Generate bytecode from Binary Expression.
void generateExpressionStmt(const AST::ExpressionStmt *exprStmt)
Generate bytecode from Expression Statement.
void generateImportStmt(const AST::ImportStmt *importStmt)
Generate bytecode from Import Statement.
void generateStatement(const AST::Statement *stmt)
Generate bytecode from Statement.
static bool isLiteralExpression(const AST::Expression *expr, Value &outValue)
Check if expression is a compile-time literal.
void generateIdentifierExpr(const AST::IdentifierExpr *identExpr)
Generate bytecode from Identifier Expression.
void generateAssignmentExpr(const AST::AssignmentExpr *assignExpr)
Generate bytecode from Assignment Expression.
void generateNumberExpr(const AST::NumberExpr *numExpr)
Generate bytecode from Numeral Expression.
void generateFieldAccessExpr(const AST::FieldAccessExpr *expr)
void generateReturnStmt(const AST::ReturnStmt *returnStmt)
Generate bytecode from Return Statement.
A value in the Phasor VM.
bool isNull() const noexcept
Check if the value is null.
ValueType getType() const noexcept
Get the type of the value.
bool asBool() const noexcept
Get the value as a boolean.
Value logicalOr(const Value &other) const noexcept
Logical OR.
Value logicalAnd(const Value &other) const noexcept
Logical AND.
bool isBool() const noexcept
The Phasor Programming Language and Runtime.
@ FLMOD_R
R[rA] = R[rB] % R[rC].
@ IAND_R
R[rA] = R[rB] && R[rC].
@ FLMUL_R
R[rA] = R[rB] * R[rC].
@ IADD
Pop b, pop a, push a + b.
@ FLGE_R
R[rA] = R[rB] >= R[rC].
@ PUSH_CONST
Push constant from constant pool.
@ JUMP_IF_TRUE
Jump if top of stack is true (pops value).
@ FLGT_R
R[rA] = R[rB] > R[rC].
@ PUSH_R
Push register to stack: push(R[rA]).
@ POP_R
Pop stack to register: R[rA] = pop().
@ FLEQUAL
Pop b, pop a, push a == b.
@ FLADD_R
R[rA] = R[rB] + R[rC].
@ LOAD_CONST_R
Load constant to register: R[rA] = constants[immediate].
@ FLADD
Pop b, pop a, push a + b.
@ JUMP
Unconditional jump to offset.
@ FLLT_R
R[rA] = R[rB] < R[rC].
@ SET_FIELD
Pop struct, pop field name, pop value, set field value.
@ CHAR_AT
Pop index, pop s, push s[index].
@ IMUL_R
R[rA] = R[rB] * R[rC].
@ FLLE_R
R[rA] = R[rB] <= R[rC].
@ ISUB_R
R[rA] = R[rB] - R[rC].
@ FLDIV_R
R[rA] = R[rB] / R[rC].
@ CALL_NATIVE
Call a native function: operand is index of function name in constants.
@ ISUBTRACT
Pop b, pop a, push a - b.
@ NEW_STRUCT_INSTANCE_STATIC
Create new struct instance using struct section metadata (structIndex).
@ STORE_VAR
Pop top of stack, store in variable slot.
@ ILE_R
R[rA] = R[rB] <= R[rC].
@ FLAND_R
R[rA] = R[rB] && R[rC].
@ JUMP_IF_FALSE
Jump if top of stack is false (pops value).
@ FLEQ_R
R[rA] = R[rB] == R[rC].
@ LOAD_VAR
Push variable value onto stack.
@ RETURN
Return from function.
@ IGT_R
R[rA] = R[rB] > R[rC].
@ FLSUBTRACT
Pop b, pop a, push a - b.
@ IADD_R
R[rA] = R[rB] + R[rC].
@ IDIV_R
R[rA] = R[rB] / R[rC].
@ FLSUB_R
R[rA] = R[rB] - R[rC].
@ JUMP_BACK
Jump backwards (for loops).
@ FLOR_R
R[rA] = R[rB] || R[rC].
@ CALL
Call a user function: operand is index of function name in constants.
@ INE_R
R[rA] = R[rB] != R[rC].
@ FLNE_R
R[rA] = R[rB] != R[rC].
@ GET_FIELD
Pop struct, pop field name, push field value.
@ IMPORT
Import a module: operand is index of module path in constants.
@ NEW_STRUCT
Create new struct: operand is index of struct name in constants.
@ IOR_R
R[rA] = R[rB] || R[rC].
@ ILT_R
R[rA] = R[rB] < R[rC].
@ IMOD_R
R[rA] = R[rB] % R[rC].
@ PRINT
Pop top of stack and print.
@ IEQ_R
R[rA] = R[rB] == R[rC].
@ IGE_R
R[rA] = R[rB] >= R[rC].
ValueType
Runtime value types for the VM.
Assignment Expression Node.
std::unique_ptr< Expression > target
std::unique_ptr< Expression > value
std::unique_ptr< Expression > right
std::unique_ptr< Expression > left
std::vector< std::unique_ptr< Statement > > statements
std::vector< std::unique_ptr< Expression > > arguments
std::unique_ptr< Statement > declaration
Expression Statement Node.
std::unique_ptr< Expression > expression
Field Access Expression Node.
std::unique_ptr< Expression > object
std::unique_ptr< Statement > initializer
std::unique_ptr< Expression > increment
std::unique_ptr< Statement > body
std::unique_ptr< Expression > condition
Function Declaration Node.
std::vector< Param > params
std::unique_ptr< BlockStmt > body
Identifier Expression Node.
std::unique_ptr< Statement > elseBranch
std::unique_ptr< Expression > condition
std::unique_ptr< Statement > thenBranch
std::unique_ptr< Expression > operand
std::unique_ptr< Expression > expression
std::vector< std::unique_ptr< Statement > > statements
std::unique_ptr< Expression > value
std::vector< StructField > fields
Struct Instance Expression Node.
std::vector< std::pair< std::string, std::unique_ptr< Expression > > > fieldValues
std::vector< CaseClause > cases
std::vector< std::unique_ptr< Statement > > defaultStmts
std::unique_ptr< Expression > expr
std::unique_ptr< Expression > operand
Unsafe Block Statement Node.
std::unique_ptr< BlockStmt > block
Variable Declaration Node.
std::unique_ptr< Expression > initializer
std::unique_ptr< Expression > condition
std::unique_ptr< Statement > body
Complete bytecode structure.
Struct metadata stored alongside bytecode (struct section).
int firstConstIndex
Index into constants for the first default value.
std::vector< std::string > fieldNames
Field names in declaration order.
int fieldCount
Number of fields in this struct.
std::string name
Struct name.