Compile to Bytecode
Compile to Bytecode
Lower a Program AST into stack-based bytecode.
This is the compiler step that produces a separate executable artifact. The VM will consume this bytecode later.
Function signature
func Compile(prog *Program) Bytecode
Bytecode types
Use the provided types:
BytecodewithMain []InstrandFunctions []FunctionFunctionwithName,Params, andCode []InstrInstrwithOp,Int, andStr
Int is used for numeric literals, jump targets, and arity. Str is used for names and string literals.
Instruction rules
Literals / variables
- number:
PUSH_NUM <int> - string:
PUSH_STR <string> - bool:
PUSH_BOOL <0|1> - nil:
PUSH_NIL - identifier:
LOAD <name>
Unary / binary
- unary
-:NEG - unary
!:NOT + - * / == != < <= > >=map to their matching opcodes
Statements
let/var: evaluate init (or push nil), thenDEFINE_VAR <name>const: evaluate init, thenDEFINE_CONST <name>- assignment: evaluate expr, then
STORE <name> - expression statement: evaluate expr, then
POP - block:
ENTER_SCOPE, compile statements,EXIT_SCOPE - return: evaluate expr (or push nil), then
RETURN
Control flow
if:- compile condition
JUMP_IF_FALSE <else>- compile then-block
JUMP <end>- compile else-block (if any)
while:- loop start label
- compile condition
JUMP_IF_FALSE <end>- compile body
JUMP <start>
Jumps use absolute instruction indexes in the current code slice.
Functions
- Each function declaration becomes a
FunctioninBytecode.Functions. - Function bodies are compiled like statement lists (no extra scope wrapper).
- If the last instruction is not
RETURN, appendPUSH_NIL+RETURN. - Top-level statements compile into
Bytecode.Main.
Notes
- Assume the AST is already valid.
- Keep the compiler readable and straightforward.
Run tests to see results
No issues detected