浏览代码

Adding Globals to the VM

simon 3 年之前
父节点
当前提交
afe0734de5
共有 4 个文件被更改,包括 51 次插入2 次删除
  1. 7 0
      compiler/compiler.go
  2. 10 2
      repl/repl.go
  3. 24 0
      vm/vm.go
  4. 10 0
      vm/vm_test.go

+ 7 - 0
compiler/compiler.go

@@ -36,6 +36,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 {
 	switch node := node.(type) {
 	case *ast.Program:

+ 10 - 2
repl/repl.go

@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"github/runnignwater/monkey/compiler"
 	"github/runnignwater/monkey/lexer"
+	"github/runnignwater/monkey/object"
 	"github/runnignwater/monkey/parser"
 	"github/runnignwater/monkey/vm"
 	"io"
@@ -24,6 +25,10 @@ func Start(in io.Reader, out io.Writer) {
 	scanner := bufio.NewScanner(in)
 	// env := object.NewEnvironment()
 
+	var constants []object.Object
+	globals := make([]object.Object, vm.GlobalSize)
+	symbolTable := compiler.NewSymbolTable()
+
 	for {
 		fmt.Printf(PROMPT)
 		scan := scanner.Scan()
@@ -50,7 +55,7 @@ func Start(in io.Reader, out io.Writer) {
 		// 	}
 		// }
 
-		comp := compiler.New()
+		comp := compiler.NewWithState(symbolTable, constants)
 		err := comp.Compile(program)
 		if err != nil {
 			_, err := fmt.Fprintf(out, "Woops! Compilation failed:\n %s\n", err)
@@ -60,7 +65,10 @@ func Start(in io.Reader, out io.Writer) {
 			continue
 		}
 
-		machine := vm.New(comp.ByteCode())
+		code := comp.ByteCode()
+		constants = code.Constants
+
+		machine := vm.NewWithGlobalsStore(code, globals)
 		err = machine.Run()
 		if err != nil {
 			_, err := fmt.Fprintf(out, "Woops! Executing bytecode failed:\n %s\n", err)

+ 24 - 0
vm/vm.go

@@ -13,6 +13,7 @@ import (
 )
 
 const StackSize = 2048
+const GlobalSize = 65535
 
 var True = &object.Boolean{Value: true}
 var False = &object.Boolean{Value: false}
@@ -24,6 +25,8 @@ type VM struct {
 
 	stack []object.Object
 	sp    int // Always points to the next value. Top of stack is stack[sp-1]
+
+	globals []object.Object
 }
 
 func New(byteCode *compiler.ByteCode) *VM {
@@ -33,9 +36,17 @@ func New(byteCode *compiler.ByteCode) *VM {
 
 		stack: make([]object.Object, StackSize),
 		sp:    0,
+
+		globals: make([]object.Object, GlobalSize),
 	}
 }
 
+func NewWithGlobalsStore(byteCode *compiler.ByteCode, s []object.Object) *VM {
+	vm := New(byteCode)
+	vm.globals = s
+	return vm
+}
+
 // func (vm *VM) StackTop() object.Object {
 // 	if vm.sp == 0 {
 // 		return nil
@@ -105,6 +116,19 @@ func (vm *VM) Run() error {
 			if err != nil {
 				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
+			}
 		}
 	}
 

+ 10 - 0
vm/vm_test.go

@@ -76,6 +76,16 @@ func TestBooleanExpression(t *testing.T) {
 
 	runVmTests(t, tests)
 }
+func TestGlobalLetStatement(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)
+}
+
 func runVmTests(t *testing.T, tests []vmTestCase) {
 	t.Helper()