run functions
This commit is contained in:
115
vm/vm.go
115
vm/vm.go
@@ -9,30 +9,54 @@ import (
|
||||
|
||||
const StackSize = 2048
|
||||
const GlobalsSize = 65536
|
||||
const MaxFrames = 1024
|
||||
|
||||
var Null = &object.Null{}
|
||||
var True = &object.Boolean{Value: true}
|
||||
var False = &object.Boolean{Value: false}
|
||||
|
||||
type Frame struct {
|
||||
fn *object.CompiledFunction
|
||||
ip int
|
||||
}
|
||||
|
||||
func NewFrame(fn *object.CompiledFunction) *Frame {
|
||||
return &Frame{fn: fn, ip: -1}
|
||||
}
|
||||
|
||||
func (f *Frame) Instructions() code.Instructions {
|
||||
return f.fn.Instructions
|
||||
}
|
||||
|
||||
type VM struct {
|
||||
constants []object.Object
|
||||
instructions code.Instructions
|
||||
constants []object.Object
|
||||
|
||||
stack []object.Object
|
||||
sp int // Always points to the next value. Top of stack is stack[sp-1]
|
||||
|
||||
globals []object.Object
|
||||
|
||||
frames []*Frame
|
||||
framesIndex int
|
||||
}
|
||||
|
||||
func New(bytecode *compiler.Bytecode) *VM {
|
||||
mainFn := &object.CompiledFunction{Instructions: bytecode.Instructions}
|
||||
mainFrame := NewFrame(mainFn)
|
||||
|
||||
frames := make([]*Frame, MaxFrames)
|
||||
frames[0] = mainFrame
|
||||
|
||||
return &VM{
|
||||
constants: bytecode.Constants,
|
||||
instructions: bytecode.Instructions,
|
||||
constants: bytecode.Constants,
|
||||
|
||||
stack: make([]object.Object, StackSize),
|
||||
sp: 0,
|
||||
|
||||
globals: make([]object.Object, GlobalsSize),
|
||||
|
||||
frames: frames,
|
||||
framesIndex: 1,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,18 +66,40 @@ func NewWithGlobalState(bytecode *compiler.Bytecode, s []object.Object) *VM {
|
||||
return vm
|
||||
}
|
||||
|
||||
func (vm *VM) currentFrame() *Frame {
|
||||
return vm.frames[vm.framesIndex-1]
|
||||
}
|
||||
|
||||
func (vm *VM) pushFrame(f *Frame) {
|
||||
vm.frames[vm.framesIndex] = f
|
||||
vm.framesIndex++
|
||||
}
|
||||
|
||||
func (vm *VM) popFrame() *Frame {
|
||||
vm.framesIndex--
|
||||
return vm.frames[vm.framesIndex]
|
||||
}
|
||||
|
||||
func (vm *VM) LastPoppedStackElem() object.Object {
|
||||
return vm.stack[vm.sp]
|
||||
}
|
||||
|
||||
func (vm *VM) Run() error {
|
||||
for ip := 0; ip < len(vm.instructions); ip++ {
|
||||
op := code.Opcode(vm.instructions[ip])
|
||||
var ip int
|
||||
var ins code.Instructions
|
||||
var op code.Opcode
|
||||
|
||||
for vm.currentFrame().ip < len(vm.currentFrame().Instructions())-1 {
|
||||
vm.currentFrame().ip++
|
||||
|
||||
ip = vm.currentFrame().ip
|
||||
ins = vm.currentFrame().Instructions()
|
||||
op = code.Opcode(ins[ip])
|
||||
|
||||
switch op {
|
||||
case code.OpConstant:
|
||||
constIndex := code.ReadUint16(vm.instructions[ip+1:])
|
||||
ip += 2
|
||||
constIndex := code.ReadUint16(ins[ip+1:])
|
||||
vm.currentFrame().ip += 2
|
||||
|
||||
err := vm.push(vm.constants[constIndex])
|
||||
if err != nil {
|
||||
@@ -100,16 +146,16 @@ func (vm *VM) Run() error {
|
||||
}
|
||||
|
||||
case code.OpJump:
|
||||
pos := int(code.ReadUint16(vm.instructions[ip+1:]))
|
||||
ip = pos - 1
|
||||
pos := int(code.ReadUint16(ins[ip+1:]))
|
||||
vm.currentFrame().ip = pos - 1
|
||||
|
||||
case code.OpJumpNotTruthy:
|
||||
pos := int(code.ReadUint16(vm.instructions[ip+1:]))
|
||||
ip += 2
|
||||
pos := int(code.ReadUint16(ins[ip+1:]))
|
||||
vm.currentFrame().ip += 2
|
||||
|
||||
condition := vm.pop()
|
||||
if !isTruthy(condition) {
|
||||
ip = pos - 1
|
||||
vm.currentFrame().ip = pos - 1
|
||||
}
|
||||
|
||||
case code.OpNull:
|
||||
@@ -119,14 +165,14 @@ func (vm *VM) Run() error {
|
||||
}
|
||||
|
||||
case code.OpSetGlobal:
|
||||
globalIndex := code.ReadUint16(vm.instructions[ip+1:])
|
||||
ip += 2
|
||||
globalIndex := code.ReadUint16(ins[ip+1:])
|
||||
vm.currentFrame().ip += 2
|
||||
|
||||
vm.globals[globalIndex] = vm.pop()
|
||||
|
||||
case code.OpGetGlobal:
|
||||
globalIndex := code.ReadUint16(vm.instructions[ip+1:])
|
||||
ip += 2
|
||||
globalIndex := code.ReadUint16(ins[ip+1:])
|
||||
vm.currentFrame().ip += 2
|
||||
|
||||
err := vm.push(vm.globals[globalIndex])
|
||||
if err != nil {
|
||||
@@ -134,8 +180,8 @@ func (vm *VM) Run() error {
|
||||
}
|
||||
|
||||
case code.OpArray:
|
||||
numElements := int(code.ReadUint16(vm.instructions[ip+1:]))
|
||||
ip += 2
|
||||
numElements := int(code.ReadUint16(ins[ip+1:]))
|
||||
vm.currentFrame().ip += 2
|
||||
|
||||
array := vm.buildArray(vm.sp-numElements, vm.sp)
|
||||
vm.sp = vm.sp - numElements
|
||||
@@ -146,8 +192,8 @@ func (vm *VM) Run() error {
|
||||
}
|
||||
|
||||
case code.OpHash:
|
||||
numElements := int(code.ReadUint16(vm.instructions[ip+1:]))
|
||||
ip += 2
|
||||
numElements := int(code.ReadUint16(ins[ip+1:]))
|
||||
vm.currentFrame().ip += 2
|
||||
|
||||
hash, err := vm.buildHash(vm.sp-numElements, vm.sp)
|
||||
if err != nil {
|
||||
@@ -169,6 +215,33 @@ func (vm *VM) Run() error {
|
||||
return err
|
||||
}
|
||||
|
||||
case code.OpCall:
|
||||
fn, ok := vm.stack[vm.sp-1].(*object.CompiledFunction)
|
||||
if !ok {
|
||||
return fmt.Errorf("calling non-function")
|
||||
}
|
||||
frame := NewFrame(fn)
|
||||
vm.pushFrame(frame)
|
||||
|
||||
case code.OpReturnValue:
|
||||
returnValue := vm.pop()
|
||||
vm.popFrame()
|
||||
vm.pop()
|
||||
|
||||
err := vm.push(returnValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case code.OpReturn:
|
||||
vm.popFrame()
|
||||
vm.pop()
|
||||
|
||||
err := vm.push(Null)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user