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))
103 else if (
auto importStmt =
dynamic_cast<const AST::ImportStmt *
>(stmt))
107 else if (
auto exportStmt =
dynamic_cast<const AST::ExportStmt *
>(stmt))
111 else if (
auto blockStmt =
dynamic_cast<const AST::BlockStmt *
>(stmt))
115 else if (
auto ifStmt =
dynamic_cast<const AST::IfStmt *
>(stmt))
119 else if (
auto whileStmt =
dynamic_cast<const AST::WhileStmt *
>(stmt))
123 else if (
auto forStmt =
dynamic_cast<const AST::ForStmt *
>(stmt))
127 else if (
auto returnStmt =
dynamic_cast<const AST::ReturnStmt *
>(stmt))
139 else if (
auto structDecl =
dynamic_cast<const AST::StructDecl*
>(stmt)) {
148 else if (
auto switchStmt =
dynamic_cast<const AST::SwitchStmt*
>(stmt)) {
153 throw std::runtime_error(
"Unknown statement type in code generation");
171 else if (
auto unaryExpr =
dynamic_cast<const AST::UnaryExpr *
>(expr))
175 else if (
auto callExpr =
dynamic_cast<const AST::CallExpr *
>(expr))
187 else if (
auto nullExpr =
dynamic_cast<const AST::NullExpr *
>(expr))
204 throw std::runtime_error(
"Unknown expression type in code generation");
280 if (numExpr->
value.find(
'.') != std::string::npos)
282 double d = std::stod(numExpr->
value);
288 int64_t i = std::stoll(numExpr->
value);
295 throw std::runtime_error(
"Invalid number format: " + numExpr->
value);
307 int varIndex =
bytecode.getOrCreateVar(identExpr->
name);
317 switch (unaryExpr->
op)
344 int64_t len = strExpr->value.length();
360 if (numExpr->value ==
"1" || numExpr->value ==
"1.0")
379 if (callExpr->
callee ==
"starts_with" && callExpr->
arguments.size() == 2)
386 s->value.length() >= p->value.length() && s->value.compare(0, p->value.length(), p->value) == 0;
392 if (callExpr->
callee ==
"ends_with" && callExpr->
arguments.size() == 2)
398 bool result = s->value.length() >= suffix->value.length() &&
399 s->value.compare(s->value.length() - suffix->value.length(), suffix->value.length(),
406 for (
const auto &arg : callExpr->
arguments)
441 result = leftVal + rightVal;
444 result = leftVal - rightVal;
447 result = leftVal * rightVal;
450 result = leftVal / rightVal;
453 result = leftVal % rightVal;
462 result =
Value(leftVal == rightVal);
465 result =
Value(leftVal != rightVal);
468 result =
Value(leftVal < rightVal);
471 result =
Value(leftVal > rightVal);
474 result =
Value(leftVal <= rightVal);
477 result =
Value(leftVal >= rightVal);
497 int constIndex =
bytecode.addConstant(result);
510 int jumpToFalseIndex =
static_cast<int>(
bytecode.instructions.size());
513 int jumpToEndIndex =
static_cast<int>(
bytecode.instructions.size());
515 bytecode.instructions[jumpToFalseIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
517 bytecode.instructions[jumpToEndIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
523 int jumpToTrueIndex =
static_cast<int>(
bytecode.instructions.size());
526 int jumpToEndIndex =
static_cast<int>(
bytecode.instructions.size());
528 bytecode.instructions[jumpToTrueIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
530 bytecode.instructions[jumpToEndIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
543 int constIndex =
bytecode.addConstant(leftLiteral);
556 int constIndex =
bytecode.addConstant(rightLiteral);
579 bool leftKnownInt = exprIsKnownInt(binExpr->
left.get(), leftIsLiteral, leftLiteral);
580 bool rightKnownInt = exprIsKnownInt(binExpr->
right.get(), rightIsLiteral, rightLiteral);
583 if (leftKnownInt && rightKnownInt)
683 for (
const auto &stmt : blockStmt->
statements)
694 int jumpToElseIndex =
static_cast<int>(
bytecode.instructions.size());
699 int jumpToEndIndex =
static_cast<int>(
bytecode.instructions.size());
703 bytecode.instructions[jumpToElseIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
711 bytecode.instructions[jumpToEndIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
716 int loopStartIndex =
static_cast<int>(
bytecode.instructions.size());
725 int jumpToEndIndex =
static_cast<int>(
bytecode.instructions.size());
733 bytecode.instructions[continueJump].operand1 = loopStartIndex;
739 int endIndex =
static_cast<int>(
bytecode.instructions.size());
740 bytecode.instructions[jumpToEndIndex].operand1 = endIndex;
743 bytecode.instructions[breakJump].operand1 = endIndex;
760 int loopStartIndex =
static_cast<int>(
bytecode.instructions.size());
768 int jumpToEndIndex = -1;
772 jumpToEndIndex =
static_cast<int>(
bytecode.instructions.size());
780 int incrementIndex =
static_cast<int>(
bytecode.instructions.size());
783 bytecode.instructions[continueJump].operand1 = incrementIndex;
797 int endIndex =
static_cast<int>(
bytecode.instructions.size());
798 if (jumpToEndIndex != -1)
800 bytecode.instructions[jumpToEndIndex].operand1 = endIndex;
804 bytecode.instructions[breakJump].operand1 = endIndex;
817 throw std::runtime_error(
"'break' statement outside of loop");
820 int jumpIndex =
static_cast<int>(
bytecode.instructions.size());
829 throw std::runtime_error(
"'continue' statement outside of loop");
832 int jumpIndex =
static_cast<int>(
bytecode.instructions.size());
839 if (returnStmt->
value)
858 int jumpOverIndex =
static_cast<int>(
bytecode.instructions.size());
862 int entryPoint =
static_cast<int>(
bytecode.instructions.size());
869 for (
auto it = funcDecl->
params.rbegin(); it != funcDecl->
params.rend(); ++it)
871 int varIndex =
bytecode.getOrCreateVar(it->name);
883 bytecode.instructions[jumpOverIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
926 int varIndex =
bytecode.getOrCreateVar(identExpr->name);
940 int fieldNameIndex =
bytecode.addConstant(
Value(fieldExpr->fieldName));
949 throw std::runtime_error(
"Invalid assignment target. Only variables and struct fields are supported.");
957 if (it !=
bytecode.structEntries.end())
959 int structIndex = it->second;
964 for (
const auto &[fieldName, fieldValue] : expr->
fieldValues)
977 for (
const auto &[fieldName, fieldValue] : expr->
fieldValues)
1004 throw std::runtime_error(
"Postfix operators only supported on variables");
1007 int varIndex =
bytecode.getOrCreateVar(identExpr->name);
1016 int oneIndex =
bytecode.addConstant(
Value(
static_cast<int64_t
>(1)));
1041 std::string structDef =
"struct " + decl->
name +
" {";
1042 for (
const auto &field : decl->
fields)
1044 structDef +=
" " + field.name +
":" + field.type->name +
",";
1046 if (!decl->
fields.empty())
1048 structDef.pop_back();
1055 int firstConstIndex =
static_cast<int>(
bytecode.constants.size());
1056 for (
const auto &field : decl->
fields)
1066 for (
const auto &field : decl->
fields)
1074 int index =
static_cast<int>(
bytecode.structs.size());
1075 bytecode.structs.push_back(std::move(info));
1084 std::vector<int> caseJumps;
1086 for (
const auto& caseClause : switchStmt->
cases) {
1089 int jumpIndex =
static_cast<int>(
bytecode.instructions.size());
1091 caseJumps.push_back(jumpIndex);
1093 for (
const auto& stmt : caseClause.statements) {
1097 int endJump =
static_cast<int>(
bytecode.instructions.size());
1099 bytecode.instructions[jumpIndex].operand1 =
static_cast<int>(
bytecode.instructions.size());
1100 caseJumps.back() = endJump;
1109 int endIndex =
static_cast<int>(
bytecode.instructions.size());
1110 for (
int jumpIdx : caseJumps) {
1111 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.