8 int nextVarIdx,
bool replMode)
29 if (numExpr->value.find(
'.') != std::string::npos)
31 outValue =
Value(std::stod(numExpr->value));
35 outValue =
Value(
static_cast<int64_t
>(std::stoll(numExpr->value)));
46 outValue =
Value(strExpr->value);
51 outValue =
Value(boolExpr->value);
90 if (
auto varDecl =
dynamic_cast<const AST::VarDecl *
>(stmt))
98 else if (
auto printStmt =
dynamic_cast<const AST::PrintStmt *
>(stmt))
106 else if (
auto importStmt =
dynamic_cast<const AST::ImportStmt *
>(stmt))
110 else if (
auto exportStmt =
dynamic_cast<const AST::ExportStmt *
>(stmt))
114 else if (
auto blockStmt =
dynamic_cast<const AST::BlockStmt *
>(stmt))
118 else if (
auto ifStmt =
dynamic_cast<const AST::IfStmt *
>(stmt))
122 else if (
auto whileStmt =
dynamic_cast<const AST::WhileStmt *
>(stmt))
126 else if (
auto forStmt =
dynamic_cast<const AST::ForStmt *
>(stmt))
130 else if (
auto returnStmt =
dynamic_cast<const AST::ReturnStmt *
>(stmt))
142 else if (
auto structDecl =
dynamic_cast<const AST::StructDecl *
>(stmt))
154 else if (
auto switchStmt =
dynamic_cast<const AST::SwitchStmt *
>(stmt))
160 throw std::runtime_error(
"Unknown statement type in code generation");
178 else if (
auto unaryExpr =
dynamic_cast<const AST::UnaryExpr *
>(expr))
182 else if (
auto callExpr =
dynamic_cast<const AST::CallExpr *
>(expr))
194 else if (
auto nullExpr =
dynamic_cast<const AST::NullExpr *
>(expr))
216 throw std::runtime_error(
"Unknown expression type in code generation");
292 if (numExpr->
value.find(
'.') != std::string::npos)
294 double d = std::stod(numExpr->
value);
300 int64_t i = std::stoll(numExpr->
value);
307 throw std::runtime_error(
"Invalid number format: " + numExpr->
value);
319 int varIndex =
bytecode.getOrCreateVar(identExpr->
name);
329 switch (unaryExpr->
op)
356 int64_t len = (int64_t)strExpr->value.length();
372 if (numExpr->value ==
"1" || numExpr->value ==
"1.0")
391 if (callExpr->
callee ==
"starts_with" && callExpr->
arguments.size() == 2)
398 s->value.length() >= p->value.length() && s->value.compare(0, p->value.length(), p->value) == 0;
404 if (callExpr->
callee ==
"ends_with" && callExpr->
arguments.size() == 2)
410 bool result = s->value.length() >= suffix->value.length() &&
411 s->value.compare(s->value.length() - suffix->value.length(), suffix->value.length(),
418 for (
const auto &arg : callExpr->
arguments)
433 auto itParam =
bytecode.functionParamCounts.find(callExpr->
callee);
434 if (itParam !=
bytecode.functionParamCounts.end())
436 int expected = itParam->second;
437 int got =
static_cast<int>(callExpr->
arguments.size());
440 std::cerr <<
"ERROR: calling function '" << callExpr->
callee <<
"' with " << got
441 <<
" arguments but it expects " << expected <<
"\n";
466 result = leftVal + rightVal;
469 result = leftVal - rightVal;
472 result = leftVal * rightVal;
475 result = leftVal / rightVal;
478 result = leftVal % rightVal;
487 result =
Value(leftVal == rightVal);
490 result =
Value(leftVal != rightVal);
493 result =
Value(leftVal < rightVal);
496 result =
Value(leftVal > rightVal);
499 result =
Value(leftVal <= rightVal);
502 result =
Value(leftVal >= rightVal);
522 int constIndex =
bytecode.addConstant(result);
529 std::cerr <<
"Unknown error in Phasor::CodeGenerator::generateBinaryExpr().\n";
536 int jumpToFalseIndex =
static_cast<int>(
bytecode.instructions.size());
539 int jumpToEndIndex =
static_cast<int>(
bytecode.instructions.size());
541 bytecode.instructions[jumpToFalseIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
543 bytecode.instructions[jumpToEndIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
549 int jumpToTrueIndex =
static_cast<int>(
bytecode.instructions.size());
552 int jumpToEndIndex =
static_cast<int>(
bytecode.instructions.size());
554 bytecode.instructions[jumpToTrueIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
556 bytecode.instructions[jumpToEndIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
569 int constIndex =
bytecode.addConstant(leftLiteral);
582 int constIndex =
bytecode.addConstant(rightLiteral);
605 bool leftKnownInt = exprIsKnownInt(binExpr->
left.get(), leftIsLiteral, leftLiteral);
606 bool rightKnownInt = exprIsKnownInt(binExpr->
right.get(), rightIsLiteral, rightLiteral);
609 if (leftKnownInt && rightKnownInt)
709 for (
const auto &stmt : blockStmt->
statements)
720 int jumpToElseIndex =
static_cast<int>(
bytecode.instructions.size());
725 int jumpToEndIndex =
static_cast<int>(
bytecode.instructions.size());
729 bytecode.instructions[jumpToElseIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
737 bytecode.instructions[jumpToEndIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
742 int loopStartIndex =
static_cast<int>(
bytecode.instructions.size());
751 int jumpToEndIndex =
static_cast<int>(
bytecode.instructions.size());
759 bytecode.instructions[continueJump].operand1 = loopStartIndex;
765 int endIndex =
static_cast<int>(
bytecode.instructions.size());
766 bytecode.instructions[jumpToEndIndex].operand1 = endIndex;
769 bytecode.instructions[breakJump].operand1 = endIndex;
786 int loopStartIndex =
static_cast<int>(
bytecode.instructions.size());
794 int jumpToEndIndex = -1;
798 jumpToEndIndex =
static_cast<int>(
bytecode.instructions.size());
806 int incrementIndex =
static_cast<int>(
bytecode.instructions.size());
809 bytecode.instructions[continueJump].operand1 = incrementIndex;
823 int endIndex =
static_cast<int>(
bytecode.instructions.size());
824 if (jumpToEndIndex != -1)
826 bytecode.instructions[jumpToEndIndex].operand1 = endIndex;
830 bytecode.instructions[breakJump].operand1 = endIndex;
843 throw std::runtime_error(
"'break' statement outside of loop");
846 int jumpIndex =
static_cast<int>(
bytecode.instructions.size());
855 throw std::runtime_error(
"'continue' statement outside of loop");
858 int jumpIndex =
static_cast<int>(
bytecode.instructions.size());
865 if (returnStmt->
value)
884 int jumpOverIndex =
static_cast<int>(
bytecode.instructions.size());
888 int entryPoint =
static_cast<int>(
bytecode.instructions.size());
892 bytecode.functionParamCounts[funcDecl->
name] =
static_cast<int>(funcDecl->
params.size());
898 for (
auto it = funcDecl->
params.rbegin(); it != funcDecl->
params.rend(); ++it)
900 int varIndex =
bytecode.getOrCreateVar(it->name);
912 bytecode.instructions[jumpOverIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
955 int varIndex =
bytecode.getOrCreateVar(identExpr->name);
969 int fieldNameIndex =
bytecode.addConstant(
Value(fieldExpr->fieldName));
978 throw std::runtime_error(
"Invalid assignment target. Only variables and struct fields are supported.");
986 if (it !=
bytecode.structEntries.end())
988 int structIndex = it->second;
993 for (
const auto &[fieldName, fieldValue] : expr->
fieldValues)
1006 for (
const auto &[fieldName, fieldValue] : expr->
fieldValues)
1009 int fieldNameIndex =
bytecode.addConstant(
Value(fieldName));
1033 throw std::runtime_error(
"Postfix operators only supported on variables");
1036 int varIndex =
bytecode.getOrCreateVar(identExpr->name);
1045 int oneIndex =
bytecode.addConstant(
Value(
static_cast<int64_t
>(1)));
1070 std::string structDef =
"struct " + decl->
name +
" {";
1071 for (
const auto &field : decl->
fields)
1073 structDef +=
" " + field.name +
":" + field.type->name +
",";
1075 if (!decl->
fields.empty())
1077 structDef.pop_back();
1084 int firstConstIndex =
static_cast<int>(
bytecode.constants.size());
1085 for (
const auto &field : decl->
fields)
1095 for (
const auto &field : decl->
fields)
1103 int index =
static_cast<int>(
bytecode.structs.size());
1104 bytecode.structs.push_back(std::move(info));
1113 std::vector<int> caseJumps;
1115 for (
const auto &caseClause : switchStmt->
cases)
1119 int jumpIndex =
static_cast<int>(
bytecode.instructions.size());
1121 caseJumps.push_back(jumpIndex);
1123 for (
const auto &stmt : caseClause.statements)
1128 int endJump =
static_cast<int>(
bytecode.instructions.size());
1130 bytecode.instructions[jumpIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
1131 caseJumps.back() = endJump;
1142 int endIndex =
static_cast<int>(
bytecode.instructions.size());
1143 for (
int jumpIdx : caseJumps)
1145 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.
std::map< std::string, ValueType > inferredTypes
void generateVarDecl(const AST::VarDecl *varDecl)
Generate bytecode from Variable Declaration.
void generateIfStmt(const AST::IfStmt *ifStmt)
Generate bytecode from If Statement.
std::vector< std::vector< int > > breakJumpsStack
void generateContinueStmt()
void generateUnaryExpr(const AST::UnaryExpr *unaryExpr)
Generate bytecode from Unary Expression.
void generatePostfixExpr(const AST::PostfixExpr *expr)
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.
void generateWhileStmt(const AST::WhileStmt *whileStmt)
Generate bytecode from While Statement.
void generateSwitchStmt(const AST::SwitchStmt *switchStmt)
Bytecode generate(const AST::Program &program, const std::map< std::string, int > &existingVars={}, int nextVarIdx=0, bool replMode=false)
Generate bytecode from program.
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 freeRegister(uint8_t reg)
Free a register.
ValueType inferExpressionType(const AST::Expression *expr, bool &known)
Simple expression type inference (conservative).
void generateExpression(const AST::Expression *expr)
Generate bytecode from Expression.
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.
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
Check if the value is null.
bool isBool() const
Check if the value is a boolean.
ValueType getType() const
Get the type of the value.
Value logicalAnd(const Value &other) const
Logical AND.
bool asBool() const
Get the value as a boolean.
Value logicalOr(const Value &other) const
Logical OR.
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.