VM globals
This commit is contained in:
@@ -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:
|
||||||
|
|||||||
12
repl/repl.go
12
repl/repl.go
@@ -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)
|
||||||
|
|||||||
27
vm/vm.go
27
vm/vm.go
@@ -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
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user