github.com/Rookout/GoSDK@v0.1.48/pkg/processor/paths/nodes.go (about) 1 package paths 2 3 import ( 4 "fmt" 5 "go/constant" 6 "go/token" 7 "go/types" 8 "math/big" 9 "reflect" 10 "strconv" 11 "strings" 12 13 "github.com/Rookout/GoSDK/pkg/processor/namespaces" 14 "github.com/Rookout/GoSDK/pkg/rookoutErrors" 15 ) 16 17 type Kind = reflect.Kind 18 19 const ( 20 None = iota + reflect.UnsafePointer + 1 21 List 22 NamespaceResult 23 ) 24 25 type node interface { 26 } 27 28 type executableNode interface { 29 node 30 Execute(namespace namespaces.Namespace) (valueNode, rookoutErrors.RookoutError) 31 } 32 33 type valueNode interface { 34 node 35 Kind() Kind 36 Interface() interface{} 37 } 38 39 type optNode struct { 40 optStr string 41 level optLevel 42 token token.Token 43 } 44 45 func newOpt(optStr string) (node, rookoutErrors.RookoutError) { 46 o := &optNode{} 47 o.optStr = optStr 48 49 optUpper := strings.ToUpper(o.optStr) 50 for key, value := range ArithmeticExpressions { 51 if key == optUpper { 52 o.optStr = value 53 break 54 } 55 } 56 57 found := false 58 for i := optLevel(0); i < NUM_OF_LEVELS; i++ { 59 for j := 0; j < len(optLevelToStr[i]); j++ { 60 if o.optStr == optLevelToStr[i][j] { 61 o.level = i 62 found = true 63 break 64 } 65 } 66 } 67 if !found { 68 return nil, rookoutErrors.NewRookInvalidArithmeticPathException("condition could not be resolved: "+optStr, nil) 69 } 70 71 o.token, _ = strToToken[o.optStr] 72 73 return o, nil 74 } 75 76 func newValueNode(val interface{}) valueNode { 77 switch val.(type) { 78 case nil: 79 return newNoneNode() 80 case *big.Rat: 81 val, _ = val.(*big.Rat).Float64() 82 return reflect.ValueOf(val) 83 case int64: 84 return reflect.ValueOf(int(val.(int64))) 85 default: 86 return reflect.ValueOf(val) 87 } 88 } 89 90 func valueNodeToConstantValue(val valueNode) (constant.Value, bool) { 91 switch val.Kind() { 92 case NamespaceResult: 93 return valueNodeToConstantValue(newValueNode(val.Interface())) 94 case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8: 95 return constant.MakeInt64(val.(reflect.Value).Int()), true 96 case reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8: 97 return constant.MakeUint64(val.(reflect.Value).Uint()), true 98 case reflect.String: 99 return constant.MakeString(val.(reflect.Value).String()), true 100 case reflect.Float64, reflect.Float32: 101 return constant.MakeFloat64(val.(reflect.Value).Float()), true 102 case reflect.Bool: 103 return constant.MakeBool(val.(reflect.Value).Bool()), true 104 default: 105 return nil, false 106 } 107 } 108 109 func isOperable(a valueNode, b valueNode) (res bool) { 110 defer func() { 111 if v := recover(); v != nil { 112 res = false 113 } 114 }() 115 116 aValue := reflect.ValueOf(a.Interface()) 117 bValue := reflect.ValueOf(b.Interface()) 118 aValue.Convert(bValue.Type()) 119 bValue.Convert(aValue.Type()) 120 return true 121 } 122 123 func (o *optNode) evalExpression(a valueNode, b valueNode) (v valueNode, err rookoutErrors.RookoutError) { 124 defer func() { 125 r := recover() 126 if r != nil { 127 msg := fmt.Sprintf("unable to evaluate %v %s %v (%v)", a, o.optStr, b, r) 128 v = nil 129 err = rookoutErrors.NewRookInvalidArithmeticPathException(msg, nil) 130 } 131 }() 132 133 aValue, aIsPrimitive := valueNodeToConstantValue(a) 134 bValue, bIsPrimitive := valueNodeToConstantValue(b) 135 136 if !aIsPrimitive || !bIsPrimitive || !isOperable(a, b) { 137 aObj := a.Interface() 138 bObj := b.Interface() 139 140 if (aObj == namespaces.ReferenceTypeInstance && bObj != nil) || (bObj == namespaces.ReferenceTypeInstance && aObj != nil) { 141 msg := "Comparison of reference types to something other than nil is not supported" 142 return nil, rookoutErrors.NewRookInvalidArithmeticPathException(msg, nil) 143 } 144 145 if aObj == namespaces.StructTypeInstance || bObj == namespaces.StructTypeInstance { 146 msg := "Comparison of structs is not supported" 147 return nil, rookoutErrors.NewRookInvalidArithmeticPathException(msg, nil) 148 } 149 150 eq := reflect.DeepEqual(aObj, bObj) 151 if (o.optStr == "==" && eq) || 152 (o.optStr == "!=" && !eq) { 153 return newValueNode(true), nil 154 } else if (o.optStr == "!=" && eq) || 155 (o.optStr == "==" && !eq) { 156 return newValueNode(false), nil 157 } 158 159 evaluation := fmt.Sprintf("%v%s%v", a.Interface(), o.optStr, b.Interface()) 160 res, evalErr := types.Eval(token.NewFileSet(), nil, token.NoPos, evaluation) 161 if evalErr != nil { 162 msg := fmt.Sprintf("unable to evaluate %s", evaluation) 163 return nil, rookoutErrors.NewRookInvalidArithmeticPathException(msg, evalErr) 164 } 165 return newValueNode(constant.Val(res.Value)), nil 166 } 167 168 if o.level == COMP { 169 res := constant.Compare(aValue, o.token, bValue) 170 return newValueNode(res), nil 171 } else { 172 resVal := constant.BinaryOp(aValue, o.token, bValue) 173 return newValueNode(constant.Val(resVal)), nil 174 } 175 } 176 177 func (o *optNode) inExpression(a valueNode, b valueNode) (valueNode, rookoutErrors.RookoutError) { 178 switch b.Interface().(type) { 179 case []interface{}: 180 list := b.Interface().([]interface{}) 181 for _, v := range list { 182 if a.Interface() == v { 183 return newValueNode(true), nil 184 } 185 } 186 return newValueNode(false), nil 187 case string: 188 aStr, ok := a.Interface().(string) 189 if !ok { 190 return newValueNode(false), nil 191 } 192 193 unquoted, err := strconv.Unquote(aStr) 194 if err == nil { 195 aStr = unquoted 196 } 197 198 if strings.Contains(b.Interface().(string), aStr) { 199 return newValueNode(true), nil 200 } 201 return newValueNode(false), nil 202 default: 203 msg := fmt.Sprintf("can't use `in` expression on %v of type %#v", b, b) 204 return nil, rookoutErrors.NewRookInvalidArithmeticPathException(msg, nil) 205 } 206 } 207 208 func (o *optNode) Execute(a valueNode, b valueNode) (valueNode, rookoutErrors.RookoutError) { 209 switch o.level { 210 case MULDIV, ADDSUB, COMP, AND, OR: 211 return o.evalExpression(a, b) 212 case IN: 213 return o.inExpression(a, b) 214 } 215 msg := fmt.Sprintf("invalid opt level: %d (%s)", o.level, o.optStr) 216 return nil, rookoutErrors.NewRookInvalidArithmeticPathException(msg, nil) 217 } 218 219 type listNode struct { 220 nodes []node 221 } 222 223 func newListNode(nodes []node) *listNode { 224 l := &listNode{} 225 l.nodes = nodes 226 return l 227 } 228 229 func (l *listNode) Execute(namespace namespaces.Namespace) (valueNode, rookoutErrors.RookoutError) { 230 var err rookoutErrors.RookoutError 231 for i, n := range l.nodes { 232 if executable, ok := n.(executableNode); ok { 233 l.nodes[i], err = executable.Execute(namespace) 234 if err != nil { 235 return nil, err 236 } 237 } 238 } 239 return l, nil 240 } 241 242 func (l *listNode) Interface() interface{} { 243 values := make([]interface{}, 0, len(l.nodes)) 244 for _, n := range l.nodes { 245 if val, ok := n.(valueNode); ok { 246 values = append(values, val.Interface()) 247 } 248 } 249 return values 250 } 251 252 func (l *listNode) Kind() Kind { 253 return List 254 } 255 256 type comparisonNode struct { 257 left node 258 opt *optNode 259 right node 260 } 261 262 func newComparisonNode(left node, opt *optNode, right node) node { 263 return &comparisonNode{ 264 left: left, 265 opt: opt, 266 right: right, 267 } 268 } 269 270 func (c *comparisonNode) Execute(namespace namespaces.Namespace) (n valueNode, err rookoutErrors.RookoutError) { 271 left := c.left 272 right := c.right 273 if executable, ok := left.(executableNode); ok { 274 left, err = executable.Execute(namespace) 275 if err != nil { 276 return nil, err 277 } 278 } 279 if executable, ok := right.(executableNode); ok { 280 right, err = executable.Execute(namespace) 281 if err != nil { 282 return nil, err 283 } 284 } 285 return c.opt.Execute(left.(valueNode), right.(valueNode)) 286 } 287 288 type namespaceNode struct { 289 operations []pathOperation 290 } 291 292 func newNamespaceNode(operations []pathOperation) *namespaceNode { 293 n := &namespaceNode{} 294 n.operations = operations 295 return n 296 } 297 298 func (n *namespaceNode) Execute(namespace namespaces.Namespace) (valueNode, rookoutErrors.RookoutError) { 299 if namespace == nil { 300 return nil, rookoutErrors.NewRookInvalidArithmeticPathException("unable to Execute namespace operations on nil", nil) 301 } 302 303 var err rookoutErrors.RookoutError 304 res := namespace 305 for _, path := range n.operations { 306 res, err = path.Read(res, false) 307 if err != nil { 308 return nil, err 309 } 310 } 311 312 return newNamespaceResultNode(res), nil 313 } 314 315 type namespaceResultNode struct { 316 namespace namespaces.Namespace 317 } 318 319 func newNamespaceResultNode(namespace namespaces.Namespace) *namespaceResultNode { 320 n := &namespaceResultNode{} 321 n.namespace = namespace 322 return n 323 } 324 325 func (n *namespaceResultNode) Kind() Kind { 326 return NamespaceResult 327 } 328 329 func (n *namespaceResultNode) Interface() interface{} { 330 return n.namespace.GetObject() 331 } 332 333 type noneNode struct { 334 } 335 336 func newNoneNode() *noneNode { 337 return &noneNode{} 338 } 339 340 func (n *noneNode) Kind() Kind { 341 return None 342 } 343 344 func (n *noneNode) Interface() interface{} { 345 return nil 346 }