github.com/Rookout/GoSDK@v0.1.48/pkg/processor/paths/arithmetic_path.go (about) 1 package paths 2 3 import ( 4 "fmt" 5 "github.com/Rookout/GoSDK/pkg/processor/namespaces" 6 "github.com/Rookout/GoSDK/pkg/rookoutErrors" 7 "go/token" 8 "strings" 9 ) 10 11 type Path interface { 12 ReadFrom(rootNamespace namespaces.Namespace) (namespaces.Namespace, rookoutErrors.RookoutError) 13 WriteTo(rootNamespace namespaces.Namespace, value namespaces.Namespace) rookoutErrors.RookoutError 14 } 15 16 type ArithmeticPath struct { 17 operations node 18 writeOperations []pathOperation 19 negation bool 20 } 21 22 func NewArithmeticPath(configuration interface{}) (*ArithmeticPath, rookoutErrors.RookoutError) { 23 var configStr string 24 switch configuration.(type) { 25 case string: 26 configStr = configuration.(string) 27 case map[string]interface{}: 28 configMap := configuration.(map[string]interface{}) 29 path, ok := configMap["path"] 30 if !ok || path == nil { 31 return nil, rookoutErrors.NewRookInvalidArithmeticPathException(configuration, nil) 32 } 33 34 configStr, ok = path.(string) 35 if !ok { 36 return nil, rookoutErrors.NewRookInvalidArithmeticPathException(configuration, nil) 37 } 38 default: 39 return nil, rookoutErrors.NewRookInvalidArithmeticPathException(configuration, nil) 40 } 41 42 arithmeticPath := &ArithmeticPath{ 43 negation: false, 44 } 45 46 if strings.HasPrefix(configStr, "NOT(") && strings.HasSuffix(configStr, ")") { 47 arithmeticPath.negation = true 48 configStr = configStr[len("NOT(") : len(configStr)-len(")")] 49 } 50 51 mapsActions, err := newMapsActions() 52 if err != nil { 53 return nil, err 54 } 55 arithmeticPath.operations, err = mapsActions.Parse(configStr) 56 if err != nil { 57 return nil, err 58 } 59 arithmeticPath.writeOperations = mapsActions.GetWriteOperations() 60 61 return arithmeticPath, nil 62 } 63 64 func (a ArithmeticPath) ReadFrom(rootNamespace namespaces.Namespace) (namespaces.Namespace, rookoutErrors.RookoutError) { 65 var res valueNode 66 var err rookoutErrors.RookoutError 67 if operations, ok := a.operations.(executableNode); ok { 68 res, err = operations.Execute(rootNamespace) 69 if err != nil { 70 return nil, err 71 } 72 } else { 73 res = a.operations.(valueNode) 74 } 75 76 switch res.(type) { 77 case *namespaceResultNode: 78 return res.(*namespaceResultNode).namespace, nil 79 default: 80 val := res.Interface() 81 if _, ok := val.(bool); ok && a.negation { 82 val = !val.(bool) 83 } 84 return namespaces.NewGoObjectNamespace(val), nil 85 } 86 } 87 88 func (a ArithmeticPath) WriteTo(namespace namespaces.Namespace, value namespaces.Namespace) rookoutErrors.RookoutError { 89 if operations, ok := a.operations.(executableNode); ok { 90 _, _ = operations.Execute(namespace) 91 } 92 93 var rookErr rookoutErrors.RookoutError 94 for _, op := range a.writeOperations[:len(a.writeOperations)-1] { 95 namespace, rookErr = op.Read(namespace, true) 96 if rookErr != nil { 97 return rookErr 98 } 99 } 100 101 lastOp := a.writeOperations[len(a.writeOperations)-1] 102 lastWriteOp, ok := lastOp.(writeOperation) 103 if !ok { 104 msg := fmt.Sprintf("last operation is not writable: %v (%#v)", lastOp, lastOp) 105 return rookoutErrors.NewRookInvalidArithmeticPathException(msg, nil) 106 } 107 rookErr = lastWriteOp.Write(namespace, value) 108 if rookErr != nil { 109 return rookErr 110 } 111 112 return nil 113 } 114 115 type optLevel uint32 116 117 118 const ( 119 MULDIV optLevel = 0 120 ADDSUB optLevel = 1 121 COMP optLevel = 2 122 IN optLevel = 3 123 AND optLevel = 4 124 OR optLevel = 5 125 NUM_OF_LEVELS optLevel = 6 126 ) 127 128 var optLevelToStr = map[optLevel][]string{ 129 MULDIV: {"*", "/"}, 130 ADDSUB: {"+", "-"}, 131 COMP: {"<=", ">=", "!=", "=", "==", ">", "<", "LT", "GT", "LE", "GE", "EQ", "NE", "lt", "gt", "le", "ge", "eq", "ne"}, 132 IN: {"IN", "in"}, 133 AND: {"&&"}, 134 OR: {"||"}, 135 } 136 137 var ArithmeticExpressions = map[string]string{ 138 "NE": "!=", 139 "=": "==", 140 "EQ": "==", 141 "LT": "<", 142 "GT": ">", 143 "GE": ">=", 144 "LE": "<=", 145 "IN": "in", 146 147 "AND": "&&", 148 "OR": "||", 149 } 150 151 var strToToken = map[string]token.Token{ 152 "+": token.ADD, 153 "-": token.SUB, 154 "*": token.MUL, 155 "/": token.QUO, 156 "&&": token.LAND, 157 "||": token.LOR, 158 "<=": token.LEQ, 159 ">=": token.GEQ, 160 "!=": token.NEQ, 161 "=": token.EQL, 162 "==": token.EQL, 163 ">": token.GTR, 164 "<": token.LSS, 165 }