-
Notifications
You must be signed in to change notification settings - Fork 11
/
reflect.go
262 lines (225 loc) · 8.18 KB
/
reflect.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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
package rbxmk
import (
lua "github.com/anaminus/gopher-lua"
"github.com/anaminus/rbxmk/dump"
"github.com/anaminus/rbxmk/rtypes"
"github.com/robloxapi/types"
)
// Pusher converts a types.Value to a Lua value. If err is nil, then lv must not
// be nil.
type Pusher func(c Context, v types.Value) (lv lua.LValue, err error)
// Puller converts a Lua value to a types.Value. lv must be non-nil.
type Puller func(c Context, lv lua.LValue) (v types.Value, err error)
// Setter sets known type v to p. p must be a pointer to a known type. Returns
// an error if v cannot be set to p.
type Setter func(p interface{}, v types.Value) (err error)
// Reflector defines reflection behavior for a type. It defines how to convert a
// types.Value between a Lua value, and behaviors when the type is a userdata.
// It also defines functions for constructing values of the type. A Reflector
// can be registered with a World.
type Reflector struct {
// Name is the name of the type.
Name string
Flags ReflectorFlags
// PushTo converts v to a Lua value. l must be used only for the conversion
// of values as needed. If err is nil, then lv must not be nil.
PushTo Pusher
// PullFrom converts a Lua value to v. l must be used only for the
// conversion of values as needed. lv must be non-nil.
PullFrom Puller
// SetTo sets reflector type v to the value pointed to by p. p must be a
// pointer to a value that v can be set to. Returns an error if p is not a
// known type.
SetTo Setter
// Metatable defines the metamethods of a custom type. If Metatable is
// non-nil, then a metatable is constructed and registered as a type
// metatable under Name.
Metatable Metatable
// Properties defines the properties of a custom type. If the __index and
// __newindex metamethods are not defined by Metatable, then Properties
// defines them according to the given properties. In case of name
// conflicts, methods are prioritized over properties.
Properties Properties
// Symbols defines the symbols of a custom type. If the __index and
// __newindex metamethods are not defined by Metatable, then Symbols defines
// them according to the given properties.
Symbols Symbols
// Methods defines the methods of a custom type. If the __index and
// __newindex metamethods are not defined by Metatable, then Methods defines
// them according to the given members. In case of name conflicts, methods
// are prioritized over properties.
Methods Methods
// Constructors defines functions that construct the type. If non-nil, a
// table containing each constructor is created and set as a global
// referenced by Name.
Constructors Constructors
// Environment is called after the type is registered to provide additional
// setup.
Environment func(s State)
// ConvertFrom receives an arbitrary value and attempts to convert it to the
// reflector's type. Returns nil if the value could not be converted.
ConvertFrom func(v types.Value) types.Value
// Enums defines enums that related to the type. These are registered along
// with the reflector.
Enums Enums
// Types is a list of additional type reflectors that this reflector depends
// on.
Types []func() Reflector
// Dump returns an additional description of the API of the reflector's
// type. Member and constructor APIs should be described by their respective
// fields.
Dump func() dump.TypeDef
}
type ReflectorFlags uint8
const (
_ ReflectorFlags = (1 << iota) / 2
Exprim // Whether the type is an explicit primitive.
)
// DumpAll returns a full description of the API of the reflector's type by
// merging the result of Dump, Members, and Constructors.
func (r Reflector) DumpAll() dump.TypeDef {
var def dump.TypeDef
if r.Dump != nil {
def = r.Dump()
}
for name, property := range r.Properties {
if property.Dump == nil {
continue
}
if _, ok := def.Properties[name]; !ok {
if def.Properties == nil {
def.Properties = dump.Properties{}
}
def.Properties[name] = property.Dump()
}
}
for symbol, property := range r.Symbols {
if property.Dump == nil {
continue
}
if _, ok := def.Symbols[symbol.Name]; !ok {
if def.Symbols == nil {
def.Symbols = dump.Properties{}
}
def.Symbols[symbol.Name] = property.Dump()
}
}
for name, method := range r.Methods {
if method.Dump == nil {
continue
}
if _, ok := def.Methods[name]; !ok {
if def.Methods == nil {
def.Methods = dump.Methods{}
}
def.Methods[name] = method.Dump()
}
}
for name, ctor := range r.Constructors {
if ctor.Dump == nil {
continue
}
funcs := append(def.Constructors[name], ctor.Dump()...)
if len(funcs) > 0 {
if def.Constructors == nil {
def.Constructors = dump.Constructors{}
}
def.Constructors[name] = funcs
}
}
for _, r := range r.Types {
def.Requires = append(def.Requires, r().Name)
}
return def
}
// Metatable defines the metamethods of a custom type.
type Metatable map[string]Metamethod
// Metamethod is called when a metamethod is invoked.
type Metamethod func(s State) int
// Properties is a set of properties keyed by name.
type Properties map[string]Property
// Symbols is a set of properties keyed by symbol.
type Symbols map[rtypes.Symbol]Property
// Property defines a property of a custom type.
type Property struct {
// Get gets the value of a member from v and pushes it onto s. The index is
// the 2nd argument in s.
Get func(s State, v types.Value) int
// Set gets a value from s and sets it to a member of v. The index and value
// are the 2nd and 3rd arguments in s. Set is optional, if nil, the property
// will be treated as read-only.
Set func(s State, v types.Value)
// Dump returns a description of the member's API.
Dump func() dump.Property
}
// Methods is a set of methods keyed by name.
type Methods map[string]Method
// Method defines a member of a custom type.
type Method struct {
// Cond returns whether the method exists based on some condition involving
// the value. The method always exists if Cond is nil.
Cond func(v types.Value) bool
// Func is the body of the method. The first argument will be the same value
// as v.
Func func(s State, v types.Value) int
// Dump returns a description of the member's API.
Dump func() dump.Function
}
// Constructors is a set of constructor functions keyed by name.
type Constructors map[string]Constructor
// Constructor creates a new value of a Reflector. The function can receive
// arguments from s.L, and must push a new value to s.L.
type Constructor struct {
Func func(s State) int
// Dump returns a description of constructor's API. Each function describes
// one possible signature of the constructor.
Dump func() dump.MultiFunction
}
// Enums is a set of enums keyed by name.
type Enums map[string]func() dump.Enum
// PushTypeTo returns a Pusher that converts v to a userdata set with a type
// metatable registered as type t. Each push always produces a new userdata.
// This results in better performance, but makes the value unsuitable as a table
// key.
func PushTypeTo(t string) Pusher {
return func(c Context, v types.Value) (lv lua.LValue, err error) {
u := c.NewUserData(v)
c.SetMetatable(u, c.GetTypeMetatable(t))
return u, nil
}
}
// PushPtrTypeTo returns a Pusher that converts v to a userdata set with a type
// metatable registered as type t. The same value will push the same userdata,
// making the value usable as a table key.
func PushPtrTypeTo(t string) Pusher {
return func(c Context, v types.Value) (lv lua.LValue, err error) {
u := c.UserDataOf(v, t)
return u, nil
}
}
// PullTypeFrom returns a Puller that converts v from a userdata set with a type
// metatable registered as type t.
func PullTypeFrom(t string) Puller {
return func(c Context, lv lua.LValue) (v types.Value, err error) {
if u, ok := lv.(*lua.LUserData); ok {
if u.Metatable == c.GetTypeMetatable(t) {
if v, ok = u.Value().(types.Value); ok {
return v, nil
}
}
}
return nil, TypeError{Want: t, Got: lv.Type().String()}
}
}
// typeError is an error where a type was received where another was expected.
type TypeError struct {
Want string
Got string
}
// Error implements the error interface.
func (err TypeError) Error() string {
if err.Got == "" {
return err.Want + " expected"
}
return err.Want + " expected, got " + err.Got
}