@@ -54,7 +54,7 @@ func (n unaryNode) Type(table typesTable) (Type, error) {
54
54
55
55
switch n .operator {
56
56
case "!" , "not" :
57
- if isBoolType (ntype ) {
57
+ if isBoolType (ntype ) || isInterfaceType ( ntype ) {
58
58
return boolType , nil
59
59
}
60
60
return nil , fmt .Errorf (`invalid operation: %v (mismatched type %v)` , n , ntype )
@@ -80,8 +80,15 @@ func (n binaryNode) Type(table typesTable) (Type, error) {
80
80
return boolType , nil
81
81
}
82
82
return nil , fmt .Errorf (`invalid operation: %v (mismatched types %v and %v)` , n , ltype , rtype )
83
+
83
84
case "or" , "||" , "and" , "&&" :
84
- if isBoolType (ltype ) && isBoolType (rtype ) {
85
+ if (isBoolType (ltype ) || isInterfaceType (ltype )) && (isBoolType (rtype ) || isInterfaceType (rtype )) {
86
+ return boolType , nil
87
+ }
88
+ return nil , fmt .Errorf (`invalid operation: %v (mismatched types %v and %v)` , n , ltype , rtype )
89
+
90
+ case "|" , "^" , "&" , "<" , ">" , ">=" , "<=" , "+" , "-" , "*" , "/" , "%" , "**" , ".." :
91
+ if (isNumberType (ltype ) || isInterfaceType (ltype )) && (isNumberType (rtype ) || isInterfaceType (rtype )) {
85
92
return boolType , nil
86
93
}
87
94
return nil , fmt .Errorf (`invalid operation: %v (mismatched types %v and %v)` , n , ltype , rtype )
@@ -91,7 +98,19 @@ func (n binaryNode) Type(table typesTable) (Type, error) {
91
98
}
92
99
93
100
func (n matchesNode ) Type (table typesTable ) (Type , error ) {
94
- return boolType , nil
101
+ var err error
102
+ ltype , err := n .left .Type (table )
103
+ if err != nil {
104
+ return nil , err
105
+ }
106
+ rtype , err := n .right .Type (table )
107
+ if err != nil {
108
+ return nil , err
109
+ }
110
+ if (isStringType (ltype ) || isInterfaceType (ltype )) && (isStringType (rtype ) || isInterfaceType (rtype )) {
111
+ return boolType , nil
112
+ }
113
+ return nil , fmt .Errorf (`invalid operation: %v (mismatched types %v and %v)` , n , ltype , rtype )
95
114
}
96
115
97
116
func (n propertyNode ) Type (table typesTable ) (Type , error ) {
@@ -141,8 +160,14 @@ func (n methodNode) Type(table typesTable) (Type, error) {
141
160
}
142
161
143
162
func (n builtinNode ) Type (table typesTable ) (Type , error ) {
163
+ for _ , node := range n .arguments {
164
+ _ , err := node .Type (table )
165
+ if err != nil {
166
+ return nil , err
167
+ }
168
+ }
144
169
if _ , ok := builtins [n .name ]; ok {
145
- return nil , nil
170
+ return interfaceType , nil
146
171
}
147
172
return nil , fmt .Errorf ("%v undefined" , n )
148
173
}
@@ -167,7 +192,7 @@ func (n conditionalNode) Type(table typesTable) (Type, error) {
167
192
if err != nil {
168
193
return nil , err
169
194
}
170
- if ! isBoolType (ctype ) {
195
+ if ! isBoolType (ctype ) && ! isInterfaceType ( ctype ) {
171
196
return nil , fmt .Errorf ("non-bool %v (type %v) used as condition" , n .cond , ctype )
172
197
}
173
198
_ , err = n .exp1 .Type (table )
@@ -216,60 +241,88 @@ func (n pairNode) Type(table typesTable) (Type, error) {
216
241
217
242
// helper funcs for reflect
218
243
219
- func isComparable (ltype Type , rtype Type ) bool {
220
- ltype = dereference (ltype )
221
- if ltype == nil {
222
- return true
223
- }
224
- rtype = dereference (rtype )
225
- if rtype == nil {
226
- return true
244
+ func isComparable (l Type , r Type ) bool {
245
+ l = dereference (l )
246
+ r = dereference (r )
247
+
248
+ if l == nil || r == nil {
249
+ return true // It is possible to compare with nil.
227
250
}
228
251
229
- if canBeNumberType ( ltype ) && canBeNumberType ( rtype ) {
252
+ if isNumberType ( l ) && isNumberType ( r ) {
230
253
return true
231
- } else if ltype .Kind () == reflect .Interface {
254
+ } else if l .Kind () == reflect .Interface {
232
255
return true
233
- } else if rtype .Kind () == reflect .Interface {
256
+ } else if r .Kind () == reflect .Interface {
234
257
return true
235
- } else if ltype == rtype {
258
+ } else if l == r {
236
259
return true
237
260
}
238
261
return false
239
262
}
240
263
241
- func isBoolType (ntype Type ) bool {
242
- ntype = dereference (ntype )
243
- if ntype == nil {
244
- return false
264
+ func isInterfaceType (t Type ) bool {
265
+ t = dereference (t )
266
+ if t != nil {
267
+ switch t .Kind () {
268
+ case reflect .Interface :
269
+ return true
270
+ }
245
271
}
272
+ return false
273
+ }
246
274
247
- switch ntype .Kind () {
248
- case reflect .Interface :
249
- return true
250
- case reflect .Bool :
251
- return true
275
+ func isNumberType (t Type ) bool {
276
+ t = dereference (t )
277
+ if t != nil {
278
+ switch t .Kind () {
279
+ case reflect .Float32 , reflect .Float64 :
280
+ fallthrough
281
+ case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
282
+ fallthrough
283
+ case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 :
284
+ return true
285
+ }
252
286
}
253
287
return false
254
288
}
255
289
256
- func fieldType (ntype Type , name string ) (Type , bool ) {
257
- ntype = dereference (ntype )
258
- if ntype == nil {
259
- return nil , false
290
+ func isBoolType (t Type ) bool {
291
+ t = dereference (t )
292
+ if t != nil {
293
+ switch t .Kind () {
294
+ case reflect .Bool :
295
+ return true
296
+ }
260
297
}
298
+ return false
299
+ }
261
300
262
- switch ntype . Kind () {
263
- case reflect . Interface :
264
- return interfaceType , true
265
- case reflect . Struct :
266
- if t , ok := ntype . FieldByName ( name ); ok {
267
- return t . Type , true
301
+ func isStringType ( t Type ) bool {
302
+ t = dereference ( t )
303
+ if t != nil {
304
+ switch t . Kind () {
305
+ case reflect . String :
306
+ return true
268
307
}
269
- case reflect .Map :
270
- return ntype .Elem (), true
271
308
}
309
+ return false
310
+ }
272
311
312
+ func fieldType (ntype Type , name string ) (Type , bool ) {
313
+ ntype = dereference (ntype )
314
+ if ntype != nil {
315
+ switch ntype .Kind () {
316
+ case reflect .Interface :
317
+ return interfaceType , true
318
+ case reflect .Struct :
319
+ if t , ok := ntype .FieldByName (name ); ok {
320
+ return t .Type , true
321
+ }
322
+ case reflect .Map :
323
+ return ntype .Elem (), true
324
+ }
325
+ }
273
326
return nil , false
274
327
}
275
328
0 commit comments