VM globals
Some checks failed
Build / build (push) Failing after 1m50s
Test / build (push) Failing after 1m25s

This commit is contained in:
Chuck Smith
2024-02-20 16:24:59 -05:00
parent e8254fc996
commit 8caeaca559
4 changed files with 54 additions and 2 deletions

View File

@@ -32,6 +32,13 @@ func New() *Compiler {
} }
} }
func NewWithState(s *SymbolTable, constants []object.Object) *Compiler {
compiler := New()
compiler.symbolTable = s
compiler.constants = constants
return compiler
}
func (c *Compiler) Compile(node ast.Node) error { func (c *Compiler) Compile(node ast.Node) error {
switch node := node.(type) { switch node := node.(type) {
case *ast.Program: case *ast.Program:

View File

@@ -6,6 +6,7 @@ import (
"io" "io"
"monkey/compiler" "monkey/compiler"
"monkey/lexer" "monkey/lexer"
"monkey/object"
"monkey/parser" "monkey/parser"
"monkey/vm" "monkey/vm"
) )
@@ -15,6 +16,10 @@ const PROMPT = ">> "
func Start(in io.Reader, out io.Writer) { func Start(in io.Reader, out io.Writer) {
scanner := bufio.NewScanner(in) scanner := bufio.NewScanner(in)
constants := []object.Object{}
globals := make([]object.Object, vm.GlobalsSize)
symbolTable := compiler.NewSymbolTable()
for { for {
fmt.Fprintf(out, PROMPT) fmt.Fprintf(out, PROMPT)
scanned := scanner.Scan() scanned := scanner.Scan()
@@ -32,14 +37,17 @@ func Start(in io.Reader, out io.Writer) {
continue continue
} }
comp := compiler.New() comp := compiler.NewWithState(symbolTable, constants)
err := comp.Compile(program) err := comp.Compile(program)
if err != nil { if err != nil {
fmt.Fprintf(out, "Woops! Compilation failed:\n %s\n", err) fmt.Fprintf(out, "Woops! Compilation failed:\n %s\n", err)
continue continue
} }
machine := vm.New(comp.Bytecode()) code := comp.Bytecode()
constants = code.Constants
machine := vm.NewWithGlobalState(comp.Bytecode(), globals)
err = machine.Run() err = machine.Run()
if err != nil { if err != nil {
fmt.Fprintf(out, "Woops! Executing bytecode failed:\n %s\n", err) fmt.Fprintf(out, "Woops! Executing bytecode failed:\n %s\n", err)

View File

@@ -8,6 +8,7 @@ import (
) )
const StackSize = 2048 const StackSize = 2048
const GlobalsSize = 65536
var Null = &object.Null{} var Null = &object.Null{}
var True = &object.Boolean{Value: true} var True = &object.Boolean{Value: true}
@@ -19,6 +20,8 @@ type VM struct {
stack []object.Object stack []object.Object
sp int // Always points to the next value. Top of stack is stack[sp-1] sp int // Always points to the next value. Top of stack is stack[sp-1]
globals []object.Object
} }
func New(bytecode *compiler.Bytecode) *VM { func New(bytecode *compiler.Bytecode) *VM {
@@ -28,9 +31,17 @@ func New(bytecode *compiler.Bytecode) *VM {
stack: make([]object.Object, StackSize), stack: make([]object.Object, StackSize),
sp: 0, sp: 0,
globals: make([]object.Object, GlobalsSize),
} }
} }
func NewWithGlobalState(bytecode *compiler.Bytecode, s []object.Object) *VM {
vm := New(bytecode)
vm.globals = s
return vm
}
func (vm *VM) LastPoppedStackElem() object.Object { func (vm *VM) LastPoppedStackElem() object.Object {
return vm.stack[vm.sp] return vm.stack[vm.sp]
} }
@@ -106,6 +117,22 @@ func (vm *VM) Run() error {
if err != nil { if err != nil {
return err return err
} }
case code.OpSetGlobal:
globalIndex := code.ReadUint16(vm.instructions[ip+1:])
ip += 2
vm.globals[globalIndex] = vm.pop()
case code.OpGetGlobal:
globalIndex := code.ReadUint16(vm.instructions[ip+1:])
ip += 2
err := vm.push(vm.globals[globalIndex])
if err != nil {
return err
}
} }
} }

View File

@@ -165,3 +165,13 @@ func TestConditionals(t *testing.T) {
runVmTests(t, tests) runVmTests(t, tests)
} }
func TestGlobalLetStatements(t *testing.T) {
tests := []vmTestCase{
{"let one = 1; one", 1},
{"let one = 1; let two = 2; one + two", 3},
{"let one = 1; let two = one + one; one + two", 3},
}
runVmTests(t, tests)
}