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.
(dot reflect.Value, fieldName string, node expr.Node, args []expr.Node, final, receiver reflect.Value)
| 117 | // The 'final' argument represents the return value from the preceding |
| 118 | // value of the pipeline, if any. |
| 119 | func (s *state) evalField(dot reflect.Value, fieldName string, node expr.Node, args []expr.Node, final, receiver reflect.Value) reflect.Value { |
| 120 | |
| 121 | //u.Debugf("evalField: valid?%v", receiver.IsValid()) |
| 122 | if !receiver.IsValid() { |
| 123 | //u.Warnf("bailing") |
| 124 | return zero |
| 125 | } |
| 126 | typ := receiver.Type() |
| 127 | receiver, _ = findValue(receiver) |
| 128 | // Unless it's an interface, need to get to a value of type *T to guarantee |
| 129 | // we see all methods of T and *T. |
| 130 | ptr := receiver |
| 131 | if ptr.Kind() != reflect.Interface && ptr.CanAddr() { |
| 132 | ptr = ptr.Addr() |
| 133 | } |
| 134 | if method := ptr.MethodByName(fieldName); method.IsValid() { |
| 135 | //u.Warnf("unimplemented method: %v", fieldName) |
| 136 | return s.evalCall(dot, method, node, fieldName, args, final) |
| 137 | } |
| 138 | hasArgs := len(args) > 1 || final.IsValid() |
| 139 | // It's not a method; must be a field of a struct or an element of a map. The receiver must not be nil. |
| 140 | receiver, isNil := findValue(receiver) |
| 141 | //u.Debugf("fld:%s receiver kind():%v val: %v", fieldName, receiver.Kind(), receiver) |
| 142 | if isNil { |
| 143 | return zero |
| 144 | } |
| 145 | switch receiver.Kind() { |
| 146 | case reflect.Struct: |
| 147 | tField, ok := receiver.Type().FieldByName(fieldName) |
| 148 | if !ok { |
| 149 | tField, ok = receiver.Type().FieldByNameFunc(lowerFieldMatch(fieldName)) |
| 150 | if !ok { |
| 151 | tagName := strings.ToLower(fieldName) |
| 152 | // Wow, this is pretty bruttaly expensive |
| 153 | // Iterate over all available fields and read the tag value |
| 154 | for i := 0; i < receiver.NumField(); i++ { |
| 155 | // Get the field, returns https://golang.org/pkg/reflect/#StructField |
| 156 | field := receiver.Type().Field(i) |
| 157 | |
| 158 | // Get the field tag value |
| 159 | tag := field.Tag.Get("json") |
| 160 | if tag == tagName { |
| 161 | tField = field |
| 162 | ok = true |
| 163 | break |
| 164 | } |
| 165 | } |
| 166 | } |
| 167 | } |
| 168 | //u.Infof("got field? %v", fieldName, tField) |
| 169 | if ok { |
| 170 | field := receiver.FieldByIndex(tField.Index) |
| 171 | if tField.PkgPath != "" { // field is unexported |
| 172 | return s.errorf("%s is an unexported field of struct type %s", fieldName, typ) |
| 173 | } |
| 174 | // If it's a function, we must call it. |
| 175 | if hasArgs { |
| 176 | return s.errorf("%s has arguments but cannot be invoked as function", fieldName) |
no test coverage detected