@@ -157,23 +157,34 @@ func (v *checker) IdentifierNode(node *ast.IdentifierNode) (reflect.Type, info)
157
157
if node .Value == "$env" {
158
158
return mapType , info {}
159
159
}
160
- if fn , ok := v .config .Builtins [node .Value ]; ok {
160
+ return v .env (node , node .Value , true )
161
+ }
162
+
163
+ type NodeWithIndexes interface {
164
+ ast.Node
165
+ SetFieldIndex (field []int )
166
+ SetMethodIndex (methodIndex int )
167
+ }
168
+
169
+ func (v * checker ) env (node NodeWithIndexes , name string , strict bool ) (reflect.Type , info ) {
170
+ if fn , ok := v .config .Builtins [name ]; ok {
161
171
return functionType , info {fn : fn }
162
172
}
163
- if fn , ok := v .config .Functions [node . Value ]; ok {
173
+ if fn , ok := v .config .Functions [name ]; ok {
164
174
return functionType , info {fn : fn }
165
175
}
166
- if t , ok := v .config .Types [node . Value ]; ok {
176
+ if t , ok := v .config .Types [name ]; ok {
167
177
if t .Ambiguous {
168
- return v .error (node , "ambiguous identifier %v" , node .Value )
178
+ return v .error (node , "ambiguous identifier %v" , name )
179
+ }
180
+ node .SetFieldIndex (t .FieldIndex )
181
+ if t .Method {
182
+ node .SetMethodIndex (t .MethodIndex )
169
183
}
170
- node .Method = t .Method
171
- node .MethodIndex = t .MethodIndex
172
- node .FieldIndex = t .FieldIndex
173
184
return t .Type , info {method : t .Method }
174
185
}
175
- if v .config .Strict {
176
- return v .error (node , "unknown name %v" , node . Value )
186
+ if v .config .Strict && strict {
187
+ return v .error (node , "unknown name %v" , name )
177
188
}
178
189
if v .config .DefaultType != nil {
179
190
return v .config .DefaultType , info {}
@@ -433,12 +444,16 @@ func (v *checker) MemberNode(node *ast.MemberNode) (reflect.Type, info) {
433
444
prop , _ := v .visit (node .Property )
434
445
435
446
if an , ok := node .Node .(* ast.IdentifierNode ); ok && an .Value == "$env" {
436
- // If the index is a constant string, can save some
437
- // cycles later by finding the type of its referent
438
447
if name , ok := node .Property .(* ast.StringNode ); ok {
439
- if t , ok := v .config .Types [name .Value ]; ok {
440
- return t .Type , info {method : t .Method }
441
- } // No error if no type found; it may be added to env between compile and run
448
+ strict := v .config .Strict
449
+ if node .Optional {
450
+ // If user explicitly set optional flag, then we should not
451
+ // throw error if field is not found (as user trying to handle
452
+ // this case). But if user did not set optional flag, then we
453
+ // should throw error if field is not found & v.config.Strict.
454
+ strict = false
455
+ }
456
+ return v .env (node , name .Value , strict )
442
457
}
443
458
return anyType , info {}
444
459
}
@@ -460,8 +475,7 @@ func (v *checker) MemberNode(node *ast.MemberNode) (reflect.Type, info) {
460
475
// the same interface.
461
476
return m .Type , info {}
462
477
} else {
463
- node .Method = true
464
- node .MethodIndex = m .Index
478
+ node .SetMethodIndex (m .Index )
465
479
node .Name = name .Value
466
480
return m .Type , info {method : true }
467
481
}
0 commit comments