-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy patharray.go
More file actions
142 lines (123 loc) · 3.11 KB
/
array.go
File metadata and controls
142 lines (123 loc) · 3.11 KB
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
141
142
package pkg
import (
"fmt"
"go/token"
"reflect"
)
var _ Expr = ArrayType{}
type ArrayType struct {
lbrackPos token.Pos // position of "["
len Expr
elt Expr
}
// Eval creates and pushes an instance of the array or slice type onto the operand stack.
func (a ArrayType) eval(vm *VM) {
vm.pushOperand(reflect.ValueOf(a))
}
func (a ArrayType) makeValue(vm *VM, size int, elements []reflect.Value) reflect.Value {
if a.len != nil {
len := vm.returnsEval(a.len)
/// override size from Len expression unless Ellipsis
if len.Kind() == reflect.Int {
size = int(len.Int())
}
}
eltType := makeType(vm, a.elt)
if a.len == nil {
// slice
sliceType := reflect.SliceOf(eltType)
return reflect.MakeSlice(sliceType, size, size)
} else {
// array
arrayType := reflect.ArrayOf(size, eltType)
ptrArray := reflect.New(arrayType)
return ptrArray.Elem()
}
}
func (a ArrayType) flow(g *graphBuilder) (head Step) {
g.next(a)
return g.current
}
// composite is (a reflect on) a Go array or slice
func (a ArrayType) literalCompose(vm *VM, composite reflect.Value, values []reflect.Value) reflect.Value {
if len(values) == 0 {
return composite
}
// TODO optimize this
elementType := composite.Type().Elem()
for i, v := range values {
if elementType.Kind() == reflect.Array {
composingElem := a.elt.(CanCompose)
elemValues := v.Interface().([]reflect.Value)
composingElem.literalCompose(vm, composite.Index(i), elemValues)
continue
}
rv := reflect.TypeOf(v)
needConversion := elementType != rv
if needConversion {
if v.CanConvert(elementType) {
composite.Index(i).Set(v.Convert(elementType))
}
} else {
composite.Index(i).Set(v)
}
}
return composite
}
func (a ArrayType) pos() token.Pos { return a.lbrackPos }
func (a ArrayType) String() string {
return fmt.Sprintf("ArrayType(%v,slice=%v)", a.elt, a.len == nil)
}
var _ Expr = SliceExpr{}
// http://golang.org/ref/spec#Slice_expressions
type SliceExpr struct {
x Expr // expression
lbrackPos token.Pos // position of "["
low Expr // begin of slice range; or nil
high Expr // end of slice range; or nil
max Expr // maximum capacity of slice; or nil
// TODO handle this
slice3 bool // true if 3-index slice (2 colons present)
}
func (s SliceExpr) eval(vm *VM) {
// stack has max, high, low, x
var high, low, x reflect.Value
if s.max != nil {
// ignore max
_ = vm.popOperand()
}
if s.high != nil {
high = vm.popOperand()
}
if s.low != nil {
low = vm.popOperand()
}
var result reflect.Value
x = vm.popOperand()
if low.IsValid() {
if high.IsValid() {
result = x.Slice(int(low.Int()), int(high.Int()))
} else {
result = x.Slice(int(low.Int()), x.Len())
}
}
vm.pushOperand(result)
}
func (s SliceExpr) flow(g *graphBuilder) (head Step) {
head = s.x.flow(g)
if s.low != nil {
s.low.flow(g)
}
if s.high != nil {
s.high.flow(g)
}
if s.max != nil {
s.max.flow(g)
}
g.next(s)
return
}
func (s SliceExpr) pos() token.Pos { return s.lbrackPos }
func (s SliceExpr) String() string {
return fmt.Sprintf("SliceExpr(%v,%v:%v:%v)", s.x, s.low, s.high, s.max)
}