func (vm *VM) Set(register Register, val *ast.Literal) {
	vm.set(register, val, 1)
}
Set will set a register.
package vm
import (
	"fmt"
	"io"
	"math/rand"
	"os"
	"regexp"
	"runtime/debug"
	"sort"
	"strings"
	"time"
	"github.com/elliotchance/ok/ast"
	"github.com/elliotchance/ok/ast/asttest"
	"github.com/elliotchance/ok/types"
)
const (
	StateRegister = "0"
	StackRegister = "__stack"
)
type CompiledTest struct {
	*CompiledFunc
	TestName string
}
type VM struct {
	fns map[string]*CompiledFunc
	Return []Register
	Stack  []map[Register]*ast.Literal
	tests  []*CompiledTest
	pkg    string
	Stdout io.Writer
	TestsPass, TestsFailed int
	TotalAssertions        int
	CurrentTestName        string
	CurrentTestPassed      bool
	ErrType  *types.Type
	ErrValue *ast.Literal
	ErrStack []string
	FinallyBlocks [][]*FinallyBlock
	rand *rand.Rand
	Types map[TypeRegister]*types.Type
	Symbols map[SymbolRegister]*ast.Literal
	Globals       map[string]*ast.Literal
	GlobalsToLoad map[string]string
}
func NewVM(pkg string) *VM {
	return &VM{
		fns:     make(map[string]*CompiledFunc),
		pkg:     pkg,
		Stdout:  os.Stdout,
		rand:    rand.New(rand.NewSource(int64(time.Now().Nanosecond()))),
		Types:   map[TypeRegister]*types.Type{},
		Symbols: map[SymbolRegister]*ast.Literal{},
		Globals: map[string]*ast.Literal{},
	}
}
func (vm *VM) prepareGlobals() error {
	for name, uniqueName := range vm.GlobalsToLoad {
		registers, err := vm.call(uniqueName, nil,
			map[string]*ast.Literal{}, types.Any, "unknown")
		if err != nil {
			return err
		}
		vm.catchUnhandledError()
		vm.Return = nil
		vm.Set(Register(name), vm.Get(registers[0]))
	}
	return nil
}
func (vm *VM) Run(mainPackage string) error {
	if err := vm.prepareGlobals(); err != nil {
		return err
	}
	mainFunction := vm.Globals[mainPackage].Map["main"].Value
	_, err := vm.call(mainFunction, nil, map[string]*ast.Literal{},
		types.Any, "")
	if err != nil {
		return err
	}
	vm.catchUnhandledError()
	return nil
}
func (vm *VM) RunTests(verbose bool, filter *regexp.Regexp, packageName string) error {
	if err := vm.prepareGlobals(); err != nil {
		return err
	}
	for _, t := range vm.tests {
		if !filter.MatchString(t.TestName) {
			continue
		}
		if verbose {
			fmt.Println("#", t.TestName)
		}
		vm.CurrentTestPassed = true
		err := vm.runTest(t, map[string]*ast.Literal{}, packageName)
		if err != nil {
			return err
		}
		if vm.CurrentTestPassed {
			vm.TestsPass++
		} else {
			vm.TestsFailed++
		}
	}
	return nil
}
func (vm *VM) appendStack(stackDescription string, parentScope map[string]*ast.Literal, returnType *types.Type) {
	registers := map[Register]*ast.Literal{
		Register(StackRegister): asttest.NewLiteralString(stackDescription),
	}
	vm.Stack = append(vm.Stack, registers)
	vm.Set(StateRegister, &ast.Literal{
		Kind: returnType,
		Map: map[string]*ast.Literal{
			StateRegister: {
				Kind: types.Any,
				Map:  parentScope,
			},
		},
	})
}
func (vm *VM) call(
	uniqueName string,
	arguments []Register,
	parentScope map[string]*ast.Literal,
	returnType *types.Type,
	pos string,
) ([]Register, error) {
	fn := vm.fns[uniqueName]
	if fn == nil {
		panic("no such function: " + uniqueName)
	}
	if pos == "" {
		pos = fn.Pos
	}
	stackDesc := stackDescription(pos, fn.Name)
	vm.appendStack(stackDesc, parentScope, returnType)
	var finallyBlocks []*FinallyBlock
	for _, ins := range fn.Finally {
		finallyBlocks = append(finallyBlocks, &FinallyBlock{
			Run:          false,
			Instructions: ins,
		})
	}
	vm.FinallyBlocks = append(vm.FinallyBlocks, finallyBlocks)
	for i, arg := range arguments {
		vm.Set(Register(fn.Arguments[i]), vm.get(arg, 2))
	}
	fnName := fmt.Sprintf("%s (%s)", fn.Name, fn.UniqueName)
	returns, err := vm.runInstructions(fnName, fn.Instructions, false)
	if err != nil {
		return nil, err
	}
	for _, fb := range finallyBlocks {
		if fb.Run {
			_, err := vm.runInstructions(fnName, fb.Instructions, true)
			if err != nil {
				return nil, err
			}
		}
	}
	vm.FinallyBlocks = vm.FinallyBlocks[:len(vm.FinallyBlocks)-1]
	return returns, nil
}
func (vm *VM) dumpMemory() {
	fmt.Printf("Registers:\n")
	var keys []string
	for key := range vm.Stack[len(vm.Stack)-1] {
		keys = append(keys, string(key))
	}
	sort.Strings(keys)
	for _, n := range keys {
		if n == StateRegister {
			fmt.Printf("  %s: <State>\n", n)
		} else {
			fmt.Printf("  %s: %v\n", n, vm.Stack[len(vm.Stack)-1][Register(n)])
		}
	}
	fmt.Printf("\nState:\n")
	keys = nil
	for key := range vm.Stack[len(vm.Stack)-1][StateRegister].Map {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	for _, n := range keys {
		fmt.Printf("  %s: %v\n", n, vm.Stack[len(vm.Stack)-1][StateRegister].Map[n])
	}
	fmt.Printf("\nStack:\n")
	for _, v := range vm.Stack {
		fmt.Printf("  %s\n", v[StackRegister].Value)
	}
}
func (vm *VM) recoverPanic(funcName string, ins *Instructions, i *int) func() {
	return func() {
		if r := recover(); r != nil {
			fmt.Printf("VM panicked in function %s at instruction #%d: %s\n\n",
				funcName, *i+1, ins.Instructions[*i].String())
			vm.dumpMemory()
			fmt.Println()
			fmt.Println(r)
			fmt.Println(string(debug.Stack()))
			os.Exit(1)
		}
	}
}
func (vm *VM) runInstructions(
	funcName string,
	ins *Instructions,
	inFinally bool,
) ([]Register, error) {
	i := 0
	defer vm.recoverPanic(funcName, ins, &i)()
	totalInstructions := len(ins.Instructions)
	for ; i < totalInstructions; i++ {
		ins := ins.Instructions[i]
		if vm.ErrType != nil && !inFinally {
			if on, ok := ins.(*On); ok {
				if on.Finished {
					return nil, nil
				}
				switch vm.Types[on.Type].Name {
				case vm.ErrType.Name,
					"error.Error", "Error":
					vm.Set("err", vm.ErrValue)
					vm.ErrType = nil
				}
			}
			continue
		}
		err := ins.Execute(&i, vm)
		if err != nil {
			return nil, err
		}
		if vm.Return != nil && !inFinally {
			return vm.Return, nil
		}
	}
	return nil, nil
}
func (vm *VM) printStack() {
	wd, _ := os.Getwd()
	reverse(vm.ErrStack)
	fmt.Printf("%s: %v\n", vm.ErrType, vm.ErrValue.Map["Error"])
	stackLen := len(vm.ErrStack[:len(vm.ErrStack)-2])
	for i, s := range vm.ErrStack[:len(vm.ErrStack)-2] {
		parts := strings.Split(strings.TrimPrefix(s, wd), "|")
		fmt.Println("", "", stackLen-i, parts[1]+"()", "at", parts[0])
	}
}
func (vm *VM) catchUnhandledError() {
	if vm.ErrType != nil {
		vm.printStack()
		os.Exit(1)
	}
}
func stackDescription(pos, funcName string) string {
	return fmt.Sprintf("%s|%s", pos, funcName)
}
func (vm *VM) runTest(
	test *CompiledTest,
	parentScope map[string]*ast.Literal,
	packageName string,
) error {
	vm.CurrentTestName = test.TestName
	stackDesc := stackDescription(test.Pos,
		fmt.Sprintf("test \"%s\"", test.TestName))
	vm.appendStack(stackDesc, parentScope, types.Any)
	_, err := vm.runInstructions(test.TestName, test.Instructions, false)
	if err != nil {
		return err
	}
	if vm.ErrType != nil {
		wd, _ := os.Getwd()
		fmt.Printf("%s: %s: %s: unhandled error\n",
			packageName, strings.TrimPrefix(test.Pos, wd), vm.CurrentTestName)
		vm.printStack()
		vm.ErrType = nil
		vm.CurrentTestPassed = false
	}
	vm.catchUnhandledError()
	vm.Stack = vm.Stack[:len(vm.Stack)-1]
	return err
}
func (vm *VM) assert(pass bool, left, op, right, pos string) {
	if !pass {
		wd, _ := os.Getwd()
		fmt.Printf("%s: %s: %s: assert(%s %s %s) failed\n",
			vm.pkg, strings.TrimPrefix(pos, wd), vm.CurrentTestName,
			left, op, right)
		vm.CurrentTestPassed = false
	}
	vm.TotalAssertions++
}
func isRegister(register Register) bool {
	r := register[0]
	return r >= '0' && r <= '9'
}