3#include <unordered_map>
10 int nextVarIdx,
bool replMode)
31 if (numExpr->value.find(
'.') != std::string::npos)
33 outValue =
Value(std::stod(numExpr->value));
37 outValue =
Value(
static_cast<i64>(std::stoll(numExpr->value)));
48 outValue =
Value(strExpr->value);
53 outValue =
Value(boolExpr->value);
92 if (
const auto *varDecl =
dynamic_cast<const AST::VarDecl *
>(stmt))
100 else if (
const auto *printStmt =
dynamic_cast<const AST::PrintStmt *
>(stmt))
108 else if (
const auto *importStmt =
dynamic_cast<const AST::ImportStmt *
>(stmt))
112 else if (
const auto *exportStmt =
dynamic_cast<const AST::ExportStmt *
>(stmt))
116 else if (
const auto *blockStmt =
dynamic_cast<const AST::BlockStmt *
>(stmt))
120 else if (
const auto *ifStmt =
dynamic_cast<const AST::IfStmt *
>(stmt))
124 else if (
const auto *whileStmt =
dynamic_cast<const AST::WhileStmt *
>(stmt))
128 else if (
const auto *forStmt =
dynamic_cast<const AST::ForStmt *
>(stmt))
132 else if (
const auto *returnStmt =
dynamic_cast<const AST::ReturnStmt *
>(stmt))
144 else if (
const auto *structDecl =
dynamic_cast<const AST::StructDecl *
>(stmt))
156 else if (
const auto *switchStmt =
dynamic_cast<const AST::SwitchStmt *
>(stmt))
162 throw std::runtime_error(
"Unknown statement type in code generation");
172 else if (
const auto *strExpr =
dynamic_cast<const AST::StringExpr *
>(expr))
180 else if (
const auto *unaryExpr =
dynamic_cast<const AST::UnaryExpr *
>(expr))
184 else if (
const auto *callExpr =
dynamic_cast<const AST::CallExpr *
>(expr))
188 else if (
const auto *binExpr =
dynamic_cast<const AST::BinaryExpr *
>(expr))
192 else if (
const auto *boolExpr =
dynamic_cast<const AST::BooleanExpr *
>(expr))
196 else if (
const auto *nullExpr =
dynamic_cast<const AST::NullExpr *
>(expr))
212 else if (
const auto *postfixExpr =
dynamic_cast<const AST::PostfixExpr *
>(expr))
226 throw std::runtime_error(
"Unknown expression type in code generation");
312 if (numExpr->
value.find(
'.') != std::string::npos)
327 throw std::runtime_error(
"Invalid number format: " + numExpr->
value);
339 int varIndex =
bytecode.getOrCreateVar(identExpr->
name);
349 switch (unaryExpr->
op)
375 auto len = (
i64)strExpr->value.length();
391 if (numExpr->value ==
"1" || numExpr->value ==
"1.0")
410 if (callExpr->
callee ==
"starts_with" && callExpr->
arguments.size() == 2)
414 if ((
s !=
nullptr) && (p !=
nullptr))
416 bool result =
s->value.length() >= p->value.length() &&
s->value.starts_with(p->value);
422 if (callExpr->
callee ==
"ends_with" && callExpr->
arguments.size() == 2)
426 if ((
s !=
nullptr) && (suffix !=
nullptr))
428 bool result =
s->value.length() >= suffix->value.length() &&
s->value.ends_with(suffix->value);
434 for (
const auto &arg : callExpr->
arguments)
445 if (entryIt !=
bytecode.functionEntries.end())
448 auto itParam =
bytecode.functionParamCounts.find(callExpr->
callee);
449 if (itParam !=
bytecode.functionParamCounts.end())
451 int expected = itParam->second;
452 int got =
static_cast<int>(callExpr->
arguments.size());
455 std::cerr <<
"ERROR: calling function '" << callExpr->
callee <<
"' with " << got
456 <<
" arguments but it expects " << expected <<
"\n";
481 result = leftVal + rightVal;
484 result = leftVal - rightVal;
487 result = leftVal * rightVal;
490 result = leftVal / rightVal;
493 result = leftVal % rightVal;
502 result =
Value(leftVal == rightVal);
505 result =
Value(leftVal != rightVal);
508 result =
Value(leftVal < rightVal);
511 result =
Value(leftVal > rightVal);
514 result =
Value(leftVal <= rightVal);
517 result =
Value(leftVal >= rightVal);
537 int constIndex =
bytecode.addConstant(result);
544 std::cerr <<
"Unknown error in Phasor::CodeGenerator::generateBinaryExpr().\n";
551 int jumpToFalseIndex =
static_cast<int>(
bytecode.instructions.size());
554 int jumpToEndIndex =
static_cast<int>(
bytecode.instructions.size());
556 bytecode.instructions[jumpToFalseIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
558 bytecode.instructions[jumpToEndIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
564 int jumpToTrueIndex =
static_cast<int>(
bytecode.instructions.size());
567 int jumpToEndIndex =
static_cast<int>(
bytecode.instructions.size());
569 bytecode.instructions[jumpToTrueIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
571 bytecode.instructions[jumpToEndIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
584 int constIndex =
bytecode.addConstant(leftLiteral);
597 int constIndex =
bytecode.addConstant(rightLiteral);
622 bool leftKnownInt = exprIsKnownInt(binExpr->
left.get(), leftIsLiteral, leftLiteral);
623 bool rightKnownInt = exprIsKnownInt(binExpr->
right.get(), rightIsLiteral, rightLiteral);
626 if (leftKnownInt && rightKnownInt)
726 for (
const auto &stmt : blockStmt->
statements)
737 int jumpToElseIndex =
static_cast<int>(
bytecode.instructions.size());
742 int jumpToEndIndex =
static_cast<int>(
bytecode.instructions.size());
746 bytecode.instructions[jumpToElseIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
754 bytecode.instructions[jumpToEndIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
759 int loopStartIndex =
static_cast<int>(
bytecode.instructions.size());
768 int jumpToEndIndex =
static_cast<int>(
bytecode.instructions.size());
776 bytecode.instructions[continueJump].operand1 = loopStartIndex;
782 int endIndex =
static_cast<int>(
bytecode.instructions.size());
783 bytecode.instructions[jumpToEndIndex].operand1 = endIndex;
786 bytecode.instructions[breakJump].operand1 = endIndex;
803 int loopStartIndex =
static_cast<int>(
bytecode.instructions.size());
811 int jumpToEndIndex = -1;
815 jumpToEndIndex =
static_cast<int>(
bytecode.instructions.size());
823 int incrementIndex =
static_cast<int>(
bytecode.instructions.size());
826 bytecode.instructions[continueJump].operand1 = incrementIndex;
849 int endIndex =
static_cast<int>(
bytecode.instructions.size());
850 if (jumpToEndIndex != -1)
852 bytecode.instructions[jumpToEndIndex].operand1 = endIndex;
856 bytecode.instructions[breakJump].operand1 = endIndex;
869 throw std::runtime_error(
"'break' statement outside of loop");
872 int jumpIndex =
static_cast<int>(
bytecode.instructions.size());
881 throw std::runtime_error(
"'continue' statement outside of loop");
884 int jumpIndex =
static_cast<int>(
bytecode.instructions.size());
891 if (returnStmt->
value)
910 int jumpOverIndex =
static_cast<int>(
bytecode.instructions.size());
914 int entryPoint =
static_cast<int>(
bytecode.instructions.size());
918 bytecode.functionParamCounts[funcDecl->
name] =
static_cast<int>(funcDecl->
params.size());
924 for (
auto it = funcDecl->
params.rbegin(); it != funcDecl->
params.rend(); ++it)
926 int varIndex =
bytecode.getOrCreateVar(it->name);
938 bytecode.instructions[jumpOverIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
983 int varIndex =
bytecode.getOrCreateVar(identExpr->name);
994 int fieldNameIndex =
bytecode.addStringConstant(fieldExpr->fieldName);
1009 int setIdx =
bytecode.addStringConstant(
"__set_elem");
1015 throw std::runtime_error(
"Invalid assignment target. Only variables, struct fields, and array elements are supported.");
1023 if (it !=
bytecode.structEntries.end())
1025 int structIndex = it->second;
1030 for (
const auto &[fieldName, fieldValue] : expr->
fieldValues)
1033 int fieldNameIndex =
bytecode.addStringConstant(fieldName);
1043 for (
const auto &[fieldName, fieldValue] : expr->
fieldValues)
1046 int fieldNameIndex =
bytecode.addStringConstant(fieldName);
1062 if (identExpr ==
nullptr)
1063 throw std::runtime_error(
"Postfix operators only supported on variables");
1065 int varIndex =
bytecode.getOrCreateVar(identExpr->name);
1087 std::string structDef =
"struct " + decl->
name +
" {";
1088 for (
const auto &field : decl->
fields)
1090 structDef +=
" " + field.name +
":" + field.type->name +
",";
1092 if (!decl->
fields.empty())
1094 structDef.pop_back();
1099 int firstConstIndex =
static_cast<int>(
bytecode.constants.size());
1100 for (
const auto &field : decl->
fields)
1110 for (
const auto &field : decl->
fields)
1118 int index =
static_cast<int>(
bytecode.structs.size());
1119 bytecode.structs.push_back(std::move(info));
1127 std::string tempName =
"__switch_" + std::to_string(
switchCounter++);
1128 int tempVarIndex =
bytecode.getOrCreateVar(tempName);
1131 std::vector<int> endJumps;
1133 for (
const auto &caseClause : switchStmt->
cases)
1140 int skipJump =
static_cast<int>(
bytecode.instructions.size());
1143 for (
const auto &stmt : caseClause.statements)
1148 int endJump =
static_cast<int>(
bytecode.instructions.size());
1150 endJumps.push_back(endJump);
1153 bytecode.instructions[skipJump].operand1 =
static_cast<int>(
bytecode.instructions.size());
1161 int endIndex =
static_cast<int>(
bytecode.instructions.size());
1162 for (
int jumpIdx : endJumps)
1164 bytecode.instructions[jumpIdx].operand1 = endIndex;
1170 for (
const auto &elem : arrayLit->
elements)
1173 int count =
static_cast<int>(arrayLit->
elements.size());
1177 int funcNameIdx =
bytecode.addStringConstant(
"__array_literal");
1190 int funcIdx =
bytecode.addStringConstant(
"__get_elem");
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 generateArrayLiteralExpr(const AST::ArrayLiteralExpr *arrayLit, bool resultNeeded)
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 generateArrayAccessExpr(const AST::ArrayAccessExpr *arrayAccess, bool resultNeeded)
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)
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.
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 freeRegister(u8 reg)
Free a register.
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.
u8 allocateRegister()
Allocate a new register.
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.
ValueType
Runtime value types for the VM.
@ 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].
Array Access Expression Node.
std::unique_ptr< Expression > array
std::unique_ptr< Expression > index
Array Literal Expression Node.
std::vector< std::unique_ptr< Expression > > elements
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.