forked from layeh/gopher-luar
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathslice.go
128 lines (107 loc) · 2.58 KB
/
slice.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
package luar // import "layeh.com/gopher-luar"
import (
"reflect"
"github.com/yuin/gopher-lua"
)
func sliceIndex(L *lua.LState) int {
ref, mt, isPtr := check(L, 1, reflect.Slice)
key := L.CheckAny(2)
switch converted := key.(type) {
case lua.LNumber:
index := int(converted)
if index < 1 || index > ref.Len() {
L.ArgError(2, "index out of range")
}
val := ref.Index(index - 1)
if (val.Kind() == reflect.Struct || val.Kind() == reflect.Array) && val.CanAddr() {
val = val.Addr()
}
L.Push(New(L, val.Interface()))
case lua.LString:
if !isPtr {
if fn := mt.method(string(converted)); fn != nil {
L.Push(fn)
return 1
}
}
if fn := mt.ptrMethod(string(converted)); fn != nil {
L.Push(fn)
return 1
}
return 0
default:
L.ArgError(2, "must be a number or string")
}
return 1
}
func sliceNewIndex(L *lua.LState) int {
ref, _, isPtr := check(L, 1, reflect.Slice)
index := L.CheckInt(2)
value := L.CheckAny(3)
if isPtr {
L.RaiseError("invalid operation on slice pointer")
}
if index < 1 || index > ref.Len() {
L.ArgError(2, "index out of range")
}
ref.Index(index - 1).Set(lValueToReflect(L, value, ref.Type().Elem(), nil))
return 0
}
func sliceLen(L *lua.LState) int {
ref, _, isPtr := check(L, 1, reflect.Slice)
if isPtr {
L.RaiseError("invalid operation on slice pointer")
}
L.Push(lua.LNumber(ref.Len()))
return 1
}
func sliceCall(L *lua.LState) int {
ref, _, isPtr := check(L, 1, reflect.Slice)
if isPtr {
L.RaiseError("invalid operation on slice pointer")
}
i := 0
fn := func(L *lua.LState) int {
if i >= ref.Len() {
return 0
}
item := ref.Index(i).Interface()
L.Push(lua.LNumber(i + 1))
L.Push(New(L, item))
i++
return 2
}
L.Push(L.NewFunction(fn))
return 1
}
func sliceEq(L *lua.LState) int {
ref1, _, isPtr1 := check(L, 1, reflect.Slice)
ref2, _, isPtr2 := check(L, 2, reflect.Slice)
if isPtr1 && isPtr2 {
L.Push(lua.LBool(ref1.Pointer() == ref2.Pointer()))
return 1
}
L.RaiseError("invalid operation == on slice")
return 0 // never reaches
}
// slice methods
func sliceCapacity(L *lua.LState) int {
ref, _, _ := check(L, 1, reflect.Slice)
L.Push(lua.LNumber(ref.Cap()))
return 1
}
func sliceAppend(L *lua.LState) int {
ref, _, _ := check(L, 1, reflect.Slice)
hint := ref.Type().Elem()
values := make([]reflect.Value, L.GetTop()-1)
for i := 2; i <= L.GetTop(); i++ {
value := lValueToReflect(L, L.Get(i), hint, nil)
if value.Type() != hint {
L.ArgError(i, "invalid type")
}
values[i-2] = value
}
newSlice := reflect.Append(ref, values...)
L.Push(New(L, newSlice.Interface()))
return 1
}