func (s *state) evalField(dot reflect.Value, fieldName string, node expr.Node, args []expr.Node, final, receiver reflect.Value) reflect.Value {

	//u.Debugf("evalField: valid?%v", receiver.IsValid())
	if !receiver.IsValid() {
		//u.Warnf("bailing")
		return zero
	}
	typ := receiver.Type()
	receiver, _ = findValue(receiver)
	// Unless it's an interface, need to get to a value of type *T to guarantee
	// we see all methods of T and *T.
	ptr := receiver
	if ptr.Kind() != reflect.Interface && ptr.CanAddr() {
		ptr = ptr.Addr()
	}
	if method := ptr.MethodByName(fieldName); method.IsValid() {
		//u.Warnf("unimplemented method: %v", fieldName)
		return s.evalCall(dot, method, node, fieldName, args, final)
	}
	hasArgs := len(args) > 1 || final.IsValid()
	// It's not a method; must be a field of a struct or an element of a map. The receiver must not be nil.
	receiver, isNil := findValue(receiver)
	//u.Debugf("fld:%s  receiver kind():%v  val: %v", fieldName, receiver.Kind(), receiver)
	if isNil {
		return zero
	}
	switch receiver.Kind() {
	case reflect.Struct:
		tField, ok := receiver.Type().FieldByName(fieldName)
		if !ok {
			tField, ok = receiver.Type().FieldByNameFunc(lowerFieldMatch(fieldName))
			if !ok {
				tagName := strings.ToLower(fieldName)
				// Wow, this is pretty bruttaly expensive
				// Iterate over all available fields and read the tag value
				for i := 0; i < receiver.NumField(); i++ {
					// Get the field, returns https://golang.org/pkg/reflect/#StructField
					field := receiver.Type().Field(i)

					// Get the field tag value
					tag := field.Tag.Get("json")
					if tag == tagName {
						tField = field
						ok = true
						break
					}
				}
			}
		}
		//u.Infof("got field? %v", fieldName, tField)
		if ok {
			field := receiver.FieldByIndex(tField.Index)
			if tField.PkgPath != "" { // field is unexported
				return s.errorf("%s is an unexported field of struct type %s", fieldName, typ)
			}
			// If it's a function, we must call it.
			if hasArgs {
				return s.errorf("%s has arguments but cannot be invoked as function", fieldName)
			}
			return field
		}
		//context reader doesn't care about empty values
		return zero
	case reflect.Map:
		// If it's a map, attempt to use the field name as a key.
		nameVal := reflect.ValueOf(fieldName)
		if nameVal.Type().AssignableTo(receiver.Type().Key()) {
			if hasArgs {
				return s.errorf("%s is not a method but has arguments", fieldName)
			}
			result := receiver.MapIndex(nameVal)
			if !result.IsValid() {
				u.Errorf("could not evaluate %v", nameVal)
				// switch s.tmpl.option.missingKey {
				// case mapInvalid:
				// 	// Just use the invalid value.
				// case mapZeroValue:
				// 	result = reflect.Zero(receiver.Type().Elem())
				// case mapError:
				// 	s.errorf("map has no entry for key %q", fieldName)
				// }
			}
			return result
		}
	}
	s.errorf("can't evaluate field %s in type %s", fieldName, typ)
	panic("not reached")
}
// evalField evaluates an expression like (.Field) or (.Field arg1 arg2).
// The 'final' argument represents the return value from the preceding
// value of the pipeline, if any.
evalField evaluates an expression like (.Field) or (.Field arg1 arg2).
The 'final' argument represents the return value from the preceding
value of the pipeline, if any.
// evalField evaluates an expression like ( . Field ) or ( . Field arg1 arg2 ) . // The ' final ' argument represents the return value from the preceding // value of the pipeline if any .
func (s *state) evalField(dot reflect.Value, fieldName string, node expr.Node, args []expr.Node, final, receiver reflect.Value) reflect.Value {
	if !receiver.IsValid() {
		return zero
	}
	typ := receiver.Type()
	receiver, _ = findValue(receiver)
	ptr := receiver
	if ptr.Kind() != reflect.Interface && ptr.CanAddr() {
		ptr = ptr.Addr()
	}
	if method := ptr.MethodByName(fieldName); method.IsValid() {
		return s.evalCall(dot, method, node, fieldName, args, final)
	}
	hasArgs := len(args) > 1 || final.IsValid()
	receiver, isNil := findValue(receiver)
	if isNil {
		return zero
	}
	switch receiver.Kind() {
	case reflect.Struct:
		tField, ok := receiver.Type().FieldByName(fieldName)
		if !ok {
			tField, ok = receiver.Type().FieldByNameFunc(lowerFieldMatch(fieldName))
			if !ok {
				tagName := strings.ToLower(fieldName)
				for i := 0; i < receiver.NumField(); i++ {
					field := receiver.Type().Field(i)
					tag := field.Tag.Get("json")
					if tag == tagName {
						tField = field
						ok = true
						break
					}
				}
			}
		}
		if ok {
			field := receiver.FieldByIndex(tField.Index)
			if tField.PkgPath != "" { 
				return s.errorf("%s is an unexported field of struct type %s", fieldName, typ)
			}
			if hasArgs {
				return s.errorf("%s has arguments but cannot be invoked as function", fieldName)
			}
			return field
		}
		return zero
	case reflect.Map:
		nameVal := reflect.ValueOf(fieldName)
		if nameVal.Type().AssignableTo(receiver.Type().Key()) {
			if hasArgs {
				return s.errorf("%s is not a method but has arguments", fieldName)
			}
			result := receiver.MapIndex(nameVal)
			if !result.IsValid() {
				u.Errorf("could not evaluate %v", nameVal)
			}
			return result
		}
	}
	s.errorf("can't evaluate field %s in type %s", fieldName, typ)
	panic("not reached")
}
func ( s * state ) evalField ( dot reflect . Value , fieldName string , node expr . Node , args [ ] expr . Node , final , receiver reflect . Value ) reflect . Value { if ! receiver . IsValid ( ) { return zero } typ := receiver . Type ( ) receiver , _ = findValue ( receiver ) ptr := receiver if ptr . Kind ( ) != reflect . Interface && ptr . CanAddr ( ) { ptr = ptr . Addr ( ) } if method := ptr . MethodByName ( fieldName ) ; method . IsValid ( ) { return s . evalCall ( dot , method , node , fieldName , args , final ) } hasArgs := len ( args ) > 1 || final . IsValid ( ) receiver , isNil := findValue ( receiver ) if isNil { return zero } switch receiver . Kind ( ) { case reflect . Struct : tField , ok := receiver . Type ( ) . FieldByName ( fieldName ) if ! ok { tField , ok = receiver . Type ( ) . FieldByNameFunc ( lowerFieldMatch ( fieldName ) ) if ! ok { tagName := strings . ToLower ( fieldName ) for i := 0 ; i < receiver . NumField ( ) ; i ++ { field := receiver . Type ( ) . Field ( i ) tag := field . Tag . Get ( " " ) if tag == tagName { tField = field ok = true break } } } } if ok { field := receiver . FieldByIndex ( tField . Index ) if tField . PkgPath != " " { return s . errorf ( " " , fieldName , typ ) } if hasArgs { return s . errorf ( " " , fieldName ) } return field } return zero case reflect . Map : nameVal := reflect . ValueOf ( fieldName ) if nameVal . Type ( ) . AssignableTo ( receiver . Type ( ) . Key ( ) ) { if hasArgs { return s . errorf ( " " , fieldName ) } result := receiver . MapIndex ( nameVal ) if ! result . IsValid ( ) { u . Errorf ( " " , nameVal ) } return result } } s . errorf ( " " , fieldName , typ ) panic ( " " ) }
evalField evaluates an expression like (.Field) or (.Field arg1 arg2).
evalField evaluates an expression like ( . Field ) or ( . Field arg1 arg2 ) .
//u.Debugf("evalField: valid?%v", receiver.IsValid()) //u.Warnf("bailing") // Unless it's an interface, need to get to a value of type *T to guarantee // we see all methods of T and *T. //u.Warnf("unimplemented method: %v", fieldName) // It's not a method; must be a field of a struct or an element of a map. The receiver must not be nil. //u.Debugf("fld:%s  receiver kind():%v  val: %v", fieldName, receiver.Kind(), receiver) // Wow, this is pretty bruttaly expensive // Iterate over all available fields and read the tag value // Get the field, returns https://golang.org/pkg/reflect/#StructField // Get the field tag value //u.Infof("got field? %v", fieldName, tField) // field is unexported // If it's a function, we must call it. //context reader doesn't care about empty values // If it's a map, attempt to use the field name as a key. // switch s.tmpl.option.missingKey { // case mapInvalid: // 	// Just use the invalid value. // case mapZeroValue: // 	result = reflect.Zero(receiver.Type().Elem()) // case mapError: // 	s.errorf("map has no entry for key %q", fieldName) // }