Mako/compiler/bytecode.go

250 lines
6.7 KiB
Go

package compiler
// Opcode represents a single bytecode instruction
type Opcode uint8
const (
// Stack Operations
OpLoadConst Opcode = iota // Load constant onto stack [idx]
OpLoadLocal // Load local variable [slot]
OpStoreLocal // Store top of stack to local [slot]
OpLoadGlobal // Load global variable [idx]
OpStoreGlobal // Store top of stack to global [idx]
OpPop // Pop top value from stack
OpDup // Duplicate top value on stack
// Arithmetic Operations
OpAdd // a + b
OpSub // a - b
OpMul // a * b
OpDiv // a / b
OpNeg // -a
OpMod // a % b
// Comparison Operations
OpEq // a == b
OpNeq // a != b
OpLt // a < b
OpLte // a <= b
OpGt // a > b
OpGte // a >= b
// Logical Operations
OpNot // not a
OpAnd // a and b
OpOr // a or b
// Control Flow
OpJump // Unconditional jump [offset]
OpJumpIfTrue // Jump if top of stack is true [offset]
OpJumpIfFalse // Jump if top of stack is false [offset]
OpCall // Call function [argCount]
OpReturn // Return from function
OpReturnNil // Return nil from function
// Table Operations
OpNewTable // Create new empty table
OpGetIndex // table[key] -> value
OpSetIndex // table[key] = value
OpGetField // table.field -> value [fieldIdx]
OpSetField // table.field = value [fieldIdx]
OpTableInsert // Insert value into table at next index
// Struct Operations
OpNewStruct // Create new struct instance [structId]
OpGetProperty // struct.field -> value [fieldIdx]
OpSetProperty // struct.field = value [fieldIdx]
OpCallMethod // Call method on struct [methodIdx, argCount]
// Function Operations
OpClosure // Create closure from function [funcIdx, upvalueCount]
OpGetUpvalue // Get upvalue [idx]
OpSetUpvalue // Set upvalue [idx]
OpCloseUpvalue // Close upvalue (move to heap)
// Array Operations
OpNewArray // Create new array with size [size]
OpArrayAppend // Append value to array
// Type Operations
OpGetType // Get type of value on stack
OpCast // Cast value to type [typeId]
// I/O Operations
OpEcho // Echo value to output
OpExit // Exit with code
// Special Operations
OpNoop // No operation
OpBreak // Break from loop
OpContinue // Continue loop iteration
// Debug Operations
OpDebugPrint // Debug print stack top
OpDebugStack // Debug print entire stack
)
// Instruction represents a single bytecode instruction with operands
type Instruction struct {
Op Opcode
Operands []uint16 // Variable length operands
}
// Chunk represents a compiled chunk of bytecode
type Chunk struct {
Code []uint8 // Raw bytecode stream
Constants []Value // Constant pool
Lines []int // Line numbers for debugging
Functions []Function // Function definitions
Structs []Struct // Struct definitions
}
// Value represents a runtime value in the VM
type Value struct {
Type ValueType
Data any // Actual value data
}
// ValueType represents the type of a runtime value
type ValueType uint8
const (
ValueNil ValueType = iota
ValueBool
ValueNumber
ValueString
ValueTable
ValueFunction
ValueStruct
ValueArray
ValueUpvalue
)
// Function represents a compiled function
type Function struct {
Name string // Function name (empty for anonymous)
Arity int // Number of parameters
Variadic bool // Whether function accepts variable args
LocalCount int // Number of local variable slots
UpvalCount int // Number of upvalues
Chunk Chunk // Function bytecode
Defaults []Value // Default parameter values
}
// Struct represents a compiled struct definition
type Struct struct {
Name string // Struct name
Fields []StructField // Field definitions
Methods map[string]uint16 // Method name -> function index
ID uint16 // Unique struct identifier
}
// StructField represents a field in a struct
type StructField struct {
Name string // Field name
Type ValueType // Field type
Offset uint16 // Offset in struct layout
}
// Table represents a key-value table/map
type Table struct {
Array map[int]Value // Array part (integer keys)
Hash map[string]Value // Hash part (string keys)
Meta *Table // Metatable for operations
}
// Array represents a dynamic array
type Array struct {
Elements []Value // Array elements
Count int // Current element count
Capacity int // Current capacity
}
// StructInstance represents an instance of a struct
type StructInstance struct {
StructID uint16 // Reference to struct definition
Fields map[string]Value // Field values
}
// Upvalue represents a captured variable
type Upvalue struct {
Location *Value // Pointer to actual value location
Closed Value // Closed-over value (when moved to heap)
IsClosed bool // Whether upvalue has been closed
}
// Instruction encoding helpers
// EncodeInstruction encodes an instruction into bytecode
func EncodeInstruction(op Opcode, operands ...uint16) []uint8 {
bytes := []uint8{uint8(op)}
for _, operand := range operands {
bytes = append(bytes, uint8(operand&0xFF), uint8(operand>>8))
}
return bytes
}
// DecodeInstruction decodes bytecode into instruction
func DecodeInstruction(code []uint8, offset int) (Opcode, []uint16, int) {
if offset >= len(code) {
return OpNoop, nil, offset
}
op := Opcode(code[offset])
operands := []uint16{}
nextOffset := offset + 1
// Decode operands based on instruction type
operandCount := GetOperandCount(op)
for range operandCount {
if nextOffset+1 >= len(code) {
break
}
operand := uint16(code[nextOffset]) | (uint16(code[nextOffset+1]) << 8)
operands = append(operands, operand)
nextOffset += 2
}
return op, operands, nextOffset
}
// GetOperandCount returns the number of operands for an instruction
func GetOperandCount(op Opcode) int {
switch op {
case OpLoadConst, OpLoadLocal, OpStoreLocal, OpLoadGlobal, OpStoreGlobal:
return 1
case OpJump, OpJumpIfTrue, OpJumpIfFalse:
return 1
case OpCall, OpNewStruct, OpGetField, OpSetField, OpGetProperty, OpSetProperty:
return 1
case OpCallMethod:
return 2
case OpClosure:
return 2
case OpNewArray, OpCast:
return 1
default:
return 0
}
}
// Instruction size calculation
func InstructionSize(op Opcode) int {
return 1 + (GetOperandCount(op) * 2) // 1 byte opcode + 2 bytes per operand
}
var opcodeNames = map[Opcode]string{
OpLoadConst: "OP_LOAD_CONST",
OpLoadLocal: "OP_LOAD_LOCAL",
OpStoreLocal: "OP_STORE_LOCAL",
OpAdd: "OP_ADD",
OpSub: "OP_SUB",
OpMul: "OP_MUL",
OpDiv: "OP_DIV",
OpJump: "OP_JUMP",
OpJumpIfTrue: "OP_JUMP_TRUE",
OpJumpIfFalse: "OP_JUMP_FALSE",
OpReturn: "OP_RETURN",
OpEcho: "OP_ECHO",
}