1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
|
package bexpr
import (
"fmt"
"reflect"
"regexp"
"strings"
)
var byteSliceTyp reflect.Type = reflect.TypeOf([]byte{})
var primitiveEqualityFns = map[reflect.Kind]func(first interface{}, second reflect.Value) bool{
reflect.Bool: doEqualBool,
reflect.Int: doEqualInt,
reflect.Int8: doEqualInt8,
reflect.Int16: doEqualInt16,
reflect.Int32: doEqualInt32,
reflect.Int64: doEqualInt64,
reflect.Uint: doEqualUint,
reflect.Uint8: doEqualUint8,
reflect.Uint16: doEqualUint16,
reflect.Uint32: doEqualUint32,
reflect.Uint64: doEqualUint64,
reflect.Float32: doEqualFloat32,
reflect.Float64: doEqualFloat64,
reflect.String: doEqualString,
}
func doEqualBool(first interface{}, second reflect.Value) bool {
return first.(bool) == second.Bool()
}
func doEqualInt(first interface{}, second reflect.Value) bool {
return first.(int) == int(second.Int())
}
func doEqualInt8(first interface{}, second reflect.Value) bool {
return first.(int8) == int8(second.Int())
}
func doEqualInt16(first interface{}, second reflect.Value) bool {
return first.(int16) == int16(second.Int())
}
func doEqualInt32(first interface{}, second reflect.Value) bool {
return first.(int32) == int32(second.Int())
}
func doEqualInt64(first interface{}, second reflect.Value) bool {
return first.(int64) == second.Int()
}
func doEqualUint(first interface{}, second reflect.Value) bool {
return first.(uint) == uint(second.Uint())
}
func doEqualUint8(first interface{}, second reflect.Value) bool {
return first.(uint8) == uint8(second.Uint())
}
func doEqualUint16(first interface{}, second reflect.Value) bool {
return first.(uint16) == uint16(second.Uint())
}
func doEqualUint32(first interface{}, second reflect.Value) bool {
return first.(uint32) == uint32(second.Uint())
}
func doEqualUint64(first interface{}, second reflect.Value) bool {
return first.(uint64) == second.Uint()
}
func doEqualFloat32(first interface{}, second reflect.Value) bool {
return first.(float32) == float32(second.Float())
}
func doEqualFloat64(first interface{}, second reflect.Value) bool {
return first.(float64) == second.Float()
}
func doEqualString(first interface{}, second reflect.Value) bool {
return first.(string) == second.String()
}
// Get rid of 0 to many levels of pointers to get at the real type
func derefType(rtype reflect.Type) reflect.Type {
for rtype.Kind() == reflect.Ptr {
rtype = rtype.Elem()
}
return rtype
}
func doMatchMatches(expression *MatchExpression, value reflect.Value) (bool, error) {
if !value.Type().ConvertibleTo(byteSliceTyp) {
return false, fmt.Errorf("Value of type %s is not convertible to []byte", value.Type())
}
re := expression.Value.Converted.(*regexp.Regexp)
return re.Match(value.Convert(byteSliceTyp).Interface().([]byte)), nil
}
func doMatchEqual(expression *MatchExpression, value reflect.Value) (bool, error) {
// NOTE: see preconditions in evaluateMatchExpressionRecurse
eqFn := primitiveEqualityFns[value.Kind()]
matchValue := getMatchExprValue(expression)
return eqFn(matchValue, value), nil
}
func doMatchIn(expression *MatchExpression, value reflect.Value) (bool, error) {
// NOTE: see preconditions in evaluateMatchExpressionRecurse
matchValue := getMatchExprValue(expression)
switch kind := value.Kind(); kind {
case reflect.Map:
found := value.MapIndex(reflect.ValueOf(matchValue))
return found.IsValid(), nil
case reflect.Slice, reflect.Array:
itemType := derefType(value.Type().Elem())
eqFn := primitiveEqualityFns[itemType.Kind()]
for i := 0; i < value.Len(); i++ {
item := value.Index(i)
// the value will be the correct type as we verified the itemType
if eqFn(matchValue, reflect.Indirect(item)) {
return true, nil
}
}
return false, nil
case reflect.String:
return strings.Contains(value.String(), matchValue.(string)), nil
default:
// this shouldn't be possible but we have to have something to return to keep the compiler happy
return false, fmt.Errorf("Cannot perform in/contains operations on type %s for selector: %q", kind, expression.Selector)
}
}
func doMatchIsEmpty(matcher *MatchExpression, value reflect.Value) (bool, error) {
// NOTE: see preconditions in evaluateMatchExpressionRecurse
return value.Len() == 0, nil
}
func getMatchExprValue(expression *MatchExpression) interface{} {
// NOTE: see preconditions in evaluateMatchExpressionRecurse
if expression.Value == nil {
return nil
}
if expression.Value.Converted != nil {
return expression.Value.Converted
}
return expression.Value.Raw
}
func evaluateMatchExpressionRecurse(expression *MatchExpression, depth int, rvalue reflect.Value, fields FieldConfigurations) (bool, error) {
// NOTE: Some information about preconditions is probably good to have here. Parsing
// as well as the extra validation pass that MUST occur before executing the
// expression evaluation allow us to make some assumptions here.
//
// 1. Selectors MUST be valid. Therefore we don't need to test if they should
// be valid. This means that we can index in the FieldConfigurations map
// and a configuration MUST be present.
// 2. If expression.Value could be converted it will already have been. No need to try
// and convert again. There is also no need to check that the types match as they MUST
// in order to have passed validation.
// 3. If we are presented with a map and we have more selectors to go through then its key
// type MUST be a string
// 4. We already have validated that the operations can be performed on the target data.
// So calls to the doMatch* functions don't need to do any checking to ensure that
// calling various fns on them will work and not panic - because they wont.
if depth >= len(expression.Selector) {
// we have reached the end of the selector - execute the match operations
switch expression.Operator {
case MatchEqual:
return doMatchEqual(expression, rvalue)
case MatchNotEqual:
result, err := doMatchEqual(expression, rvalue)
if err == nil {
return !result, nil
}
return false, err
case MatchIn:
return doMatchIn(expression, rvalue)
case MatchNotIn:
result, err := doMatchIn(expression, rvalue)
if err == nil {
return !result, nil
}
return false, err
case MatchIsEmpty:
return doMatchIsEmpty(expression, rvalue)
case MatchIsNotEmpty:
result, err := doMatchIsEmpty(expression, rvalue)
if err == nil {
return !result, nil
}
return false, err
case MatchMatches:
return doMatchMatches(expression, rvalue)
case MatchNotMatches:
result, err := doMatchMatches(expression, rvalue)
if err == nil {
return !result, nil
}
return false, err
default:
return false, fmt.Errorf("Invalid match operation: %d", expression.Operator)
}
}
switch rvalue.Kind() {
case reflect.Struct:
fieldName := expression.Selector[depth]
fieldConfig := fields[FieldName(fieldName)]
if fieldConfig.StructFieldName != "" {
fieldName = fieldConfig.StructFieldName
}
value := reflect.Indirect(rvalue.FieldByName(fieldName))
if matcher, ok := value.Interface().(MatchExpressionEvaluator); ok {
return matcher.EvaluateMatch(expression.Selector[depth+1:], expression.Operator, getMatchExprValue(expression))
}
return evaluateMatchExpressionRecurse(expression, depth+1, value, fieldConfig.SubFields)
case reflect.Slice, reflect.Array:
// TODO (mkeeler) - Should we support implementing the MatchExpressionEvaluator interface for slice/array types?
// Punting on that for now.
for i := 0; i < rvalue.Len(); i++ {
item := reflect.Indirect(rvalue.Index(i))
// we use the same depth because right now we are not allowing
// selection of individual slice/array elements
result, err := evaluateMatchExpressionRecurse(expression, depth, item, fields)
if err != nil {
return false, err
}
// operations on slices are implicity ANY operations currently so the first truthy evaluation we find we can stop
if result {
return true, nil
}
}
return false, nil
case reflect.Map:
// TODO (mkeeler) - Should we support implementing the MatchExpressionEvaluator interface for map types
// such as the FieldConfigurations type? Maybe later
//
value := reflect.Indirect(rvalue.MapIndex(reflect.ValueOf(expression.Selector[depth])))
if !value.IsValid() {
// when the key doesn't exist in the map
switch expression.Operator {
case MatchEqual, MatchIsNotEmpty, MatchIn:
return false, nil
default:
// MatchNotEqual, MatchIsEmpty, MatchNotIn
// Whatever you were looking for cannot be equal because it doesn't exist
// Similarly it cannot be in some other container and every other container
// is always empty.
return true, nil
}
}
if matcher, ok := value.Interface().(MatchExpressionEvaluator); ok {
return matcher.EvaluateMatch(expression.Selector[depth+1:], expression.Operator, getMatchExprValue(expression))
}
return evaluateMatchExpressionRecurse(expression, depth+1, value, fields[FieldNameAny].SubFields)
default:
return false, fmt.Errorf("Value at selector %q with type %s does not support nested field selection", expression.Selector[:depth], rvalue.Kind())
}
}
func evaluateMatchExpression(expression *MatchExpression, datum interface{}, fields FieldConfigurations) (bool, error) {
if matcher, ok := datum.(MatchExpressionEvaluator); ok {
return matcher.EvaluateMatch(expression.Selector, expression.Operator, getMatchExprValue(expression))
}
rvalue := reflect.Indirect(reflect.ValueOf(datum))
return evaluateMatchExpressionRecurse(expression, 0, rvalue, fields)
}
func evaluate(ast Expression, datum interface{}, fields FieldConfigurations) (bool, error) {
switch node := ast.(type) {
case *UnaryExpression:
switch node.Operator {
case UnaryOpNot:
result, err := evaluate(node.Operand, datum, fields)
return !result, err
}
case *BinaryExpression:
switch node.Operator {
case BinaryOpAnd:
result, err := evaluate(node.Left, datum, fields)
if err != nil || result == false {
return result, err
}
return evaluate(node.Right, datum, fields)
case BinaryOpOr:
result, err := evaluate(node.Left, datum, fields)
if err != nil || result == true {
return result, err
}
return evaluate(node.Right, datum, fields)
}
case *MatchExpression:
return evaluateMatchExpression(node, datum, fields)
}
return false, fmt.Errorf("Invalid AST node")
}
|