forked from goplus/gop
/
var.go
140 lines (101 loc) · 2.64 KB
/
var.go
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package exec
import (
"errors"
qlang "qlang.io/spec"
)
var (
// ErrAssignWithoutVal is returned when variable assign without value
ErrAssignWithoutVal = errors.New("variable assign without value")
// ErrMultiAssignExprMustBeSlice is returned when expression of multi assignment must be a slice
ErrMultiAssignExprMustBeSlice = errors.New("expression of multi assignment must be a slice")
)
// -----------------------------------------------------------------------------
type iRef struct {
name int
}
func (p *iRef) Exec(stk *Stack, ctx *Context) {
stk.Push(ctx.getRef(p.name))
}
func (p *iRef) ToVar() Instr {
return &iVar{p.name}
}
func (p *Context) getRef(name int) interface{} {
if name < symbolIndexMax {
return p.FastGetVar(name)
}
scope := name >> symbolNameBits
for scope > 0 {
p = p.parent
scope--
}
return p.FastGetVar(name & (symbolIndexMax - 1))
}
// SymbolIndex returns symbol index value.
//
func SymbolIndex(id, scope int) int {
return id | (scope << symbolNameBits)
}
// Ref returns an instruction that refers a variable.
//
func Ref(name int) Instr {
return &iRef{name}
}
// -----------------------------------------------------------------------------
// Var
type iVar struct {
name int
}
func (p *iVar) Exec(stk *Stack, ctx *Context) {
stk.Push(&variable{Name: p.name})
}
// Var returns a Var instruction.
//
func Var(name int) Instr {
return &iVar{name}
}
// -----------------------------------------------------------------------------
type iGet int
func (p iGet) Exec(stk *Stack, ctx *Context) {
k, ok1 := stk.Pop()
o, ok2 := stk.Pop()
if !ok1 || !ok2 {
panic("unexpected to call `Get` instruction")
}
stk.Push(qlang.Get(o, k))
}
func (p iGet) ToVar() Instr {
return GetVar
}
// Get is the Get instruction.
//
var Get Instr = iGet(0)
// -----------------------------------------------------------------------------
type iGetVar int
func (p iGetVar) Exec(stk *Stack, ctx *Context) {
k, ok1 := stk.Pop()
o, ok2 := stk.Pop()
if !ok1 || !ok2 {
panic("unexpected to call `GetVar` instruction")
}
stk.Push(&qlang.DataIndex{Data: o, Index: k})
}
// GetVar is the Get instruction.
//
var GetVar Instr = iGetVar(0)
// -----------------------------------------------------------------------------
type iGfnRef struct {
val interface{}
toVar func() Instr
}
func (p *iGfnRef) Exec(stk *Stack, ctx *Context) {
stk.Push(p.val)
}
func (p *iGfnRef) ToVar() Instr {
return p.toVar()
}
// GfnRef returns an instruction that refers a fntable item.
//
func GfnRef(v interface{}, toVar func() Instr) Instr {
return &iGfnRef{v, toVar}
}
// -----------------------------------------------------------------------------