about summary refs log tree commit diff
path: root/pkg/lang/vm/vm.go
blob: a6e1fb84c1051c49605c4f403f2e300af144dcb7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package vm

import (
	"fmt"
	"jinx/pkg/lang/vm/code"
)

type VM struct {
	code  *code.Code
	pc    int
	stack CallStack
}

func New(code *code.Code) *VM {
	return &VM{
		code:  code,
		pc:    0,
		stack: NewCallStack(),
	}
}

func (vm *VM) Run() {
	for vm.pc < vm.code.Len() {
		op, advance := vm.code.GetOp(vm.pc)
		vm.pc += advance
		vm.step(op)
	}
}

type stepDecision int

const (
	stepDecisionContinue stepDecision = iota
	stepDecisionHalt
)

func (vm *VM) step(op code.Op) stepDecision {
	switch op {
	case code.OpNop:
		// do nothing
	case code.OpHalt:
		return stepDecisionHalt

	case code.OpPushInt:
		x, advance := vm.code.GetInt(vm.pc)
		vm.pc += advance

		vm.execPushInt(x)
	case code.OpPushFloat:
		x, advance := vm.code.GetFloat(vm.pc)
		vm.pc += advance

		vm.execPushFloat(x)
	case code.OpPushString:
		str, advance := vm.code.GetString(vm.pc)
		vm.pc += advance

		vm.execPushString(str)
	case code.OpPushNull:
		vm.execPushNull()
	case code.OpPushTrue:
		vm.execPushBool(true)
	case code.OpPushFalse:
		vm.execPushBool(false)
	case code.OpPushArray:
		vm.execPushArray()
	case code.OpPushFunction:
		panic("not implemented")
	case code.OpPushObject:
		panic("not implemented")

	case code.OpGetGlobal:
		panic("not implemented")
	case code.OpGetLocal:
		offset, advance := vm.code.GetInt(vm.pc)
		vm.pc += advance

		vm.execGetLocal(int(offset))
	case code.OpGetMember:
		panic("not implemented")
	case code.OpGetArg:
		vm.execGetArg()
	case code.OpGetEnv:
		panic("not implemented")

	case code.OpAdd:
		vm.execAdd()
	case code.OpSub:
		vm.execSub()
	case code.OpIndex:
		vm.execIndex()
	case code.OpCall:
		panic("not implemented")

	case code.OpJmp:
		pc, _ := vm.code.GetUint(vm.pc)
		vm.pc = int(pc)
	case code.OpJez:
		panic("not implemented")

	case code.OpRet:
		panic("not implemented")

	default:
		panic(fmt.Errorf("unimplemented op: %v", op))
	}

	return stepDecisionContinue
}