run functions
Some checks failed
Build / build (push) Failing after 1m36s
Test / build (push) Successful in 1m37s

This commit is contained in:
Chuck Smith
2024-03-04 16:11:25 -05:00
parent e56fb40f83
commit 9d06c90e41
2 changed files with 184 additions and 21 deletions

115
vm/vm.go
View File

@@ -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
}
}
}