@@ -2,16 +2,9 @@ package nature
2
2
3
3
import (
4
4
"reflect"
5
- )
6
5
7
- func derefTypeKind (t reflect.Type , k reflect.Kind ) (_ reflect.Type , _ reflect.Kind , changed bool ) {
8
- for k == reflect .Pointer {
9
- changed = true
10
- t = t .Elem ()
11
- k = t .Kind ()
12
- }
13
- return t , k , changed
14
- }
6
+ "github.com/expr-lang/expr/internal/deref"
7
+ )
15
8
16
9
func fieldName (fieldName string , tag reflect.StructTag ) (string , bool ) {
17
10
switch taggedName := tag .Get ("expr" ); taggedName {
@@ -27,7 +20,7 @@ func fieldName(fieldName string, tag reflect.StructTag) (string, bool) {
27
20
type structData struct {
28
21
cache * Cache
29
22
rType reflect.Type
30
- fields map [string ]structField
23
+ fields map [string ]* structField
31
24
numField , ownIdx , anonIdx int
32
25
33
26
curParent , curChild * structData
@@ -39,22 +32,29 @@ type structField struct {
39
32
Index []int
40
33
}
41
34
35
+ func (s * structData ) setCache (c * Cache ) {
36
+ s .cache = c
37
+ for _ , sf := range s .fields {
38
+ sf .SetCache (c )
39
+ }
40
+ }
41
+
42
42
func (s * structData ) finished () bool {
43
43
return s .ownIdx >= s .numField && // no own fields left to visit
44
44
s .anonIdx >= s .numField && // no embedded fields to visit
45
45
s .curChild == nil // no child in process of visiting
46
46
}
47
47
48
- func (s * structData ) structField (parentEmbed * structData , name string ) ( structField , bool ) {
48
+ func (s * structData ) structField (parentEmbed * structData , name string ) * structField {
49
49
if s .fields == nil {
50
50
if s .numField > 0 {
51
- s .fields = make (map [string ]structField , s .numField )
51
+ s .fields = make (map [string ]* structField , s .numField )
52
52
}
53
- } else if f , ok := s .fields [name ]; ok {
54
- return f , true
53
+ } else if f := s .fields [name ]; f != nil {
54
+ return f
55
55
}
56
56
if s .finished () {
57
- return structField {}, false
57
+ return nil
58
58
}
59
59
60
60
// Lookup own fields first.
@@ -73,7 +73,7 @@ func (s *structData) structField(parentEmbed *structData, name string) (structFi
73
73
continue
74
74
}
75
75
nt := s .cache .FromType (field .Type )
76
- sf := structField {
76
+ sf := & structField {
77
77
Nature : nt ,
78
78
Index : field .Index ,
79
79
}
@@ -82,14 +82,14 @@ func (s *structData) structField(parentEmbed *structData, name string) (structFi
82
82
parentEmbed .trySet (fName , sf )
83
83
}
84
84
if fName == name {
85
- return sf , true
85
+ return sf
86
86
}
87
87
}
88
88
89
89
if s .curChild != nil {
90
- sf , ok := s .findInEmbedded (parentEmbed , s .curChild , s .curChildIndex , name )
91
- if ok {
92
- return sf , true
90
+ sf := s .findInEmbedded (parentEmbed , s .curChild , s .curChildIndex , name )
91
+ if sf != nil {
92
+ return sf
93
93
}
94
94
}
95
95
@@ -101,26 +101,26 @@ func (s *structData) structField(parentEmbed *structData, name string) (structFi
101
101
if ! field .Anonymous {
102
102
continue
103
103
}
104
- t , k , _ := derefTypeKind (field .Type , field .Type .Kind ())
104
+ t , k , _ := deref . TypeKind (field .Type , field .Type .Kind ())
105
105
if k != reflect .Struct {
106
106
continue
107
107
}
108
108
109
109
childEmbed := s .cache .getStruct (t ).structData
110
- sf , ok := s .findInEmbedded (parentEmbed , childEmbed , field .Index , name )
111
- if ok {
112
- return sf , true
110
+ sf := s .findInEmbedded (parentEmbed , childEmbed , field .Index , name )
111
+ if sf != nil {
112
+ return sf
113
113
}
114
114
}
115
115
116
- return structField {}, false
116
+ return nil
117
117
}
118
118
119
119
func (s * structData ) findInEmbedded (
120
120
parentEmbed , childEmbed * structData ,
121
121
childIndex []int ,
122
122
name string ,
123
- ) ( structField , bool ) {
123
+ ) * structField {
124
124
// Set current parent/child data. This allows trySet to handle child fields
125
125
// and add them to our struct and to the parent as well if needed
126
126
s .curParent = parentEmbed
@@ -145,29 +145,29 @@ func (s *structData) findInEmbedded(
145
145
}
146
146
147
147
// Recheck if we have what we needed from the above sync
148
- if sf , ok := s .fields [name ]; ok {
149
- return sf , true
148
+ if sf := s .fields [name ]; sf != nil {
149
+ return sf
150
150
}
151
151
152
152
// Try finding in the child again in case it hasn't finished
153
153
if ! childEmbed .finished () {
154
- if _ , ok := childEmbed .structField (s , name ); ok {
155
- return s .fields [name ], true
154
+ if childEmbed .structField (s , name ) != nil {
155
+ return s .fields [name ]
156
156
}
157
157
}
158
158
159
- return structField {}, false
159
+ return nil
160
160
}
161
161
162
- func (s * structData ) trySet (name string , sf structField ) {
162
+ func (s * structData ) trySet (name string , sf * structField ) {
163
163
if _ , ok := s .fields [name ]; ok {
164
164
return
165
165
}
166
- sf .Index = append (s .curChildIndex , sf .Index ... )
167
- s .fields [name ] = structField {
166
+ sf = & structField {
168
167
Nature : sf .Nature ,
169
- Index : sf .Index ,
168
+ Index : append ( s . curChildIndex , sf .Index ... ) ,
170
169
}
170
+ s .fields [name ] = sf
171
171
if s .curParent != nil {
172
172
s .curParent .trySet (name , sf )
173
173
}
@@ -178,7 +178,7 @@ func StructFields(c *Cache, t reflect.Type) map[string]Nature {
178
178
if t == nil {
179
179
return table
180
180
}
181
- t , k , _ := derefTypeKind (t , t .Kind ())
181
+ t , k , _ := deref . TypeKind (t , t .Kind ())
182
182
if k == reflect .Struct {
183
183
// lookup for a field with an empty name, which will cause to never find a
184
184
// match, meaning everything will have been cached.
@@ -195,7 +195,7 @@ type methodset struct {
195
195
cache * Cache
196
196
rType reflect.Type
197
197
kind reflect.Kind
198
- methods map [string ]method
198
+ methods map [string ]* method
199
199
numMethod , idx int
200
200
}
201
201
@@ -204,11 +204,18 @@ type method struct {
204
204
nature Nature
205
205
}
206
206
207
- func (s * methodset ) method (name string ) (method , bool ) {
207
+ func (s * methodset ) setCache (c * Cache ) {
208
+ s .cache = c
209
+ for _ , m := range s .methods {
210
+ m .nature .SetCache (c )
211
+ }
212
+ }
213
+
214
+ func (s * methodset ) method (name string ) * method {
208
215
if s .methods == nil {
209
- s .methods = make (map [string ]method , s .numMethod )
210
- } else if m , ok := s .methods [name ]; ok {
211
- return m , true
216
+ s .methods = make (map [string ]* method , s .numMethod )
217
+ } else if m := s .methods [name ]; m != nil {
218
+ return m
212
219
}
213
220
for ; s .idx < s .numMethod ; s .idx ++ {
214
221
rm := s .rType .Method (s .idx )
@@ -227,14 +234,14 @@ func (s *methodset) method(name string) (method, bool) {
227
234
// different indexes for different types which implement
228
235
// the same interface.
229
236
}
230
- m := method {
237
+ m := & method {
231
238
Method : rm ,
232
239
nature : nt ,
233
240
}
234
241
s .methods [rm .Name ] = m
235
242
if rm .Name == name {
236
- return m , true
243
+ return m
237
244
}
238
245
}
239
- return method {}, false
246
+ return nil
240
247
}
0 commit comments