about summary refs log tree commit diff
path: root/pkg/lang/vm/vm.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/lang/vm/vm.go')
-rw-r--r--pkg/lang/vm/vm.go163
1 files changed, 114 insertions, 49 deletions
diff --git a/pkg/lang/vm/vm.go b/pkg/lang/vm/vm.go
index 8b47915..4a4aa68 100644
--- a/pkg/lang/vm/vm.go
+++ b/pkg/lang/vm/vm.go
@@ -7,18 +7,28 @@ import (
 )
 
 type VM struct {
-	code   *code.Code
-	pc     int
+	pos code.Pos
+
+	modules []*code.Code
+
 	stack  stack.Stack
 	memory mem.Mem
+
+	canAddGlobals bool
+	globals       map[string]mem.Ptr
 }
 
-func New(code *code.Code) *VM {
+func New(main *code.Code, deps []*code.Code) *VM {
 	vm := &VM{
-		code:   code,
-		pc:     0,
+		pos: code.NewPos(0, 0),
+
+		modules: append([]*code.Code{main}, deps...),
+
 		stack:  stack.New(),
 		memory: mem.New(),
+
+		canAddGlobals: false,
+		globals:       make(map[string]mem.Ptr),
 	}
 
 	if err := vm.setup(); err != nil {
@@ -46,14 +56,56 @@ func (vm *VM) GetResult() (string, error) {
 }
 
 func (vm *VM) Run() error {
-	for vm.pc < vm.code.Len() {
-		op, advance := vm.code.GetOp(vm.pc)
-		vm.pc += advance
+	vm.canAddGlobals = true
+	for i := 1; i < len(vm.modules); i++ {
+		if err := vm.executeModule(i); err != nil {
+			return err
+		}
+
+		// Drop all calls from the stack after the module has finished
+		for vm.stack.CallDepth() > 1 {
+			if _, err := vm.popCallAndDrop(); err != nil {
+				return err
+			}
+		}
+
+		// Drop the root stack values
+		for !vm.stack.IsEmpty() {
+			if _, err := vm.popAndDrop(); err != nil {
+				return err
+			}
+		}
+	}
+
+	vm.canAddGlobals = false
+	if err := vm.executeModule(0); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (vm *VM) executeModule(moduleID int) error {
+	vm.pos = code.NewPos(moduleID, 0)
+
+	if err := vm.stack.PutRootCall(vm.pos); err != nil {
+		return err
+	}
+
+	for {
+		module := vm.modules[vm.module()]
 
-		if decision, err := vm.step(op); err != nil {
+		if vm.pc() >= module.Len() {
+			return nil
+		}
+
+		op, advance := module.GetOp(vm.pc())
+		vm.advancePC(advance)
+
+		if decision, err := vm.step(module, op); err != nil {
 			return Error{
-				Pc:   vm.pc,
-				Line: vm.code.Debug().PCToLine(vm.pc),
+				Pos:  vm.pos,
+				Line: module.Debug().PCToLine(vm.pc()),
 				Err:  err,
 			}
 		} else if decision == stepDecisionHalt {
@@ -71,7 +123,7 @@ const (
 	stepDecisionHalt
 )
 
-func (vm *VM) step(op code.Op) (stepDecision, error) {
+func (vm *VM) step(module *code.Code, op code.Op) (stepDecision, error) {
 	var err error
 	switch op {
 	case code.OpNop:
@@ -80,18 +132,18 @@ func (vm *VM) step(op code.Op) (stepDecision, error) {
 		return stepDecisionHalt, nil
 
 	case code.OpPushInt:
-		x, advance := vm.code.GetInt(vm.pc)
-		vm.pc += advance
+		x, advance := module.GetInt(vm.pc())
+		vm.advancePC(advance)
 
 		vm.execPushInt(x)
 	case code.OpPushFloat:
-		x, advance := vm.code.GetFloat(vm.pc)
-		vm.pc += advance
+		x, advance := module.GetFloat(vm.pc())
+		vm.advancePC(advance)
 
 		vm.execPushFloat(x)
 	case code.OpPushString:
-		str, advance := vm.code.GetString(vm.pc)
-		vm.pc += advance
+		str, advance := module.GetString(vm.pc())
+		vm.advancePC(advance)
 
 		err = vm.execPushString(str)
 	case code.OpPushNull:
@@ -103,60 +155,73 @@ func (vm *VM) step(op code.Op) (stepDecision, error) {
 	case code.OpPushArray:
 		vm.execPushArray()
 	case code.OpPushFunction:
-		x, advance := vm.code.GetUint(vm.pc)
-		vm.pc += advance
+		x, advance := module.GetUint(vm.pc())
+		vm.advancePC(advance)
 
 		vm.execPushFunction(int(x))
 	case code.OpPushObject:
 		err = vm.execPushObject()
 	case code.OpPushType:
-		name, advance := vm.code.GetString(vm.pc)
-		vm.pc += advance
+		name, advance := module.GetString(vm.pc())
+		vm.advancePC(advance)
 
 		err = vm.execPushType(name)
 
 	case code.OpDrop:
-		dropAmount, advance := vm.code.GetUint(vm.pc)
-		vm.pc += advance
+		dropAmount, advance := module.GetUint(vm.pc())
+		vm.advancePC(advance)
 
 		err = vm.execDrop(uint(dropAmount))
 
+	case code.OpAddGlobal:
+		globalName, advance := module.GetString(vm.pc())
+		vm.advancePC(advance)
+
+		err = vm.execAddGlobal(globalName)
 	case code.OpGetGlobal:
-		panic("not implemented")
+		globalName, advance := module.GetString(vm.pc())
+		vm.advancePC(advance)
+
+		err = vm.execGetGlobal(globalName)
+	case code.OpSetGlobal:
+		globalName, advance := module.GetString(vm.pc())
+		vm.advancePC(advance)
+
+		err = vm.execSetGlobal(globalName)
 	case code.OpGetLocal:
-		offset, advance := vm.code.GetInt(vm.pc)
-		vm.pc += advance
+		offset, advance := module.GetInt(vm.pc())
+		vm.advancePC(advance)
 
 		err = vm.execGetLocal(int(offset))
 	case code.OpSetLocal:
-		offset, advance := vm.code.GetInt(vm.pc)
-		vm.pc += advance
+		offset, advance := module.GetInt(vm.pc())
+		vm.advancePC(advance)
 
 		err = vm.execSetLocal(int(offset))
 	case code.OpGetMember:
-		name, advance := vm.code.GetString(vm.pc)
-		vm.pc += advance
+		name, advance := module.GetString(vm.pc())
+		vm.advancePC(advance)
 
 		err = vm.execGetMember(name)
 	case code.OpSetMember:
-		name, advance := vm.code.GetString(vm.pc)
-		vm.pc += advance
+		name, advance := module.GetString(vm.pc())
+		vm.advancePC(advance)
 
 		err = vm.execSetMember(name)
 
 	case code.OpGetEnv:
-		envIndex, advance := vm.code.GetUint(vm.pc)
-		vm.pc += advance
+		envIndex, advance := module.GetUint(vm.pc())
+		vm.advancePC(advance)
 
 		err = vm.execGetEnv(int(envIndex))
 	case code.OpSetEnv:
-		envIndex, advance := vm.code.GetUint(vm.pc)
-		vm.pc += advance
+		envIndex, advance := module.GetUint(vm.pc())
+		vm.advancePC(advance)
 
 		err = vm.execSetEnv(int(envIndex))
 	case code.OpAddToEnv:
-		local, advance := vm.code.GetUint(vm.pc)
-		vm.pc += advance
+		local, advance := module.GetUint(vm.pc())
+		vm.advancePC(advance)
 
 		err = vm.execAddToEnv(int(local))
 
@@ -164,8 +229,8 @@ func (vm *VM) step(op code.Op) (stepDecision, error) {
 		err = vm.execAnchorType()
 
 	case code.OpSetArgCount:
-		argCount, advance := vm.code.GetUint(vm.pc)
-		vm.pc += advance
+		argCount, advance := module.GetUint(vm.pc())
+		vm.advancePC(advance)
 
 		err = vm.execSetArgCount(uint(argCount))
 
@@ -193,21 +258,21 @@ func (vm *VM) step(op code.Op) (stepDecision, error) {
 	case code.OpIndex:
 		err = vm.execIndex()
 	case code.OpCall:
-		argCount, advance := vm.code.GetUint(vm.pc)
-		vm.pc += advance
+		argCount, advance := module.GetUint(vm.pc())
+		vm.advancePC(advance)
 
 		err = vm.execCall(uint(argCount))
 
 	case code.OpJmp:
-		pc, _ := vm.code.GetUint(vm.pc)
-		vm.pc = int(pc)
+		pc, _ := module.GetUint(vm.pc())
+		vm.setPC(int(pc))
 	case code.OpJt:
-		pc, advance := vm.code.GetUint(vm.pc)
-		vm.pc += advance
+		pc, advance := module.GetUint(vm.pc())
+		vm.advancePC(advance)
 		err = vm.execJumpIf(int(pc), true)
 	case code.OpJf:
-		pc, advance := vm.code.GetUint(vm.pc)
-		vm.pc += advance
+		pc, advance := module.GetUint(vm.pc())
+		vm.advancePC(advance)
 		err = vm.execJumpIf(int(pc), false)
 	case code.OpRet:
 		err = vm.execRet()