github.com/Rookout/GoSDK@v0.1.48/pkg/processor/paths/maps_actions.go (about) 1 package paths 2 3 import ( 4 "fmt" 5 "github.com/Rookout/GoSDK/pkg/rookoutErrors" 6 "github.com/Rookout/GoSDK/pkg/utils" 7 "github.com/yhirose/go-peg" 8 "strconv" 9 "strings" 10 ) 11 12 type mapsActions struct { 13 operations []pathOperation 14 parser *peg.Parser 15 } 16 17 func newMapsActions() (m *mapsActions, err rookoutErrors.RookoutError) { 18 m = &mapsActions{} 19 m.parser, err = m.buildParser() 20 if err != nil { 21 return nil, err 22 } 23 return m, nil 24 } 25 26 func (m *mapsActions) buildParser() (*peg.Parser, rookoutErrors.RookoutError) { 27 28 parser, err := peg.NewParser(` 29 COMPARISON_EXPRESSION <- EXPRESSION (COMPARISON EXPRESSION)* 30 EXPRESSION <- ATOM (COMPARISON ATOM)* 31 32 #For some reason the whitespaces are ignored - causing parsing errors 33 LIST <- [ "["] ([ \t]*ATOM ([ \t]*[,][ \t]* ATOM)*)? ["\]" ][ \t]* 34 ATOM <- NULL / FLOAT / NUMBER / '(' EXPRESSION ')' / '(' COMPARISON_EXPRESSION ')' / CHAR / STRING / APOSTROPHE_STRING / BOOL / LIST / NAMESPACE 35 COMPARISON <- <'+'/'-'/'/'/'*'/'<='/'>='/'!='/'=='/"="/'>'/'<'/"LT"/"GT"/"LE"/"GE"/"EQ"/"NE"/"lt"/"gt"/"le"/"ge"/"eq"/"ne"/"in"/"IN"/"or"/"OR"/"||"/"and"/"AND"/"&&"> 36 NUMBER <- < [-]?[0-9]+ > 37 FLOAT <- < [-]?[0-9]+([.][0-9]+)+ > 38 #The only value we are not capturing here is '"' (") 39 STRING <- < [\"] [ !#-~]* [\"] > 40 APOSTROPHE_STRING <- < ['] [ !-&(-~]* ['] > 41 BOOL <- 'True' / 'False' / 'true' / 'false' 42 CHAR <- < ['] [ !-~] ['] > 43 NULL <- 'None' / 'nil' / 'null' / 'undefined' 44 45 METHOD_ACCESS <- < ([a-zA-Z0-9_]+) > '(' < (ATOM ([,] ATOM)*)? > ')' 46 VARIABLE_ACCESS <- < ([a-zA-Z0-9_]+) > 47 MAP_ACCESS <- '[' < (ATOM) > ']' 48 NAMESPACE <- (METHOD_ACCESS / VARIABLE_ACCESS) (MAP_ACCESS / '.' METHOD_ACCESS / '.' VARIABLE_ACCESS)* 49 50 %whitespace <- [ \t]* 51 --- 52 # Expression parsing 1 is the least important 53 %expr = EXPRESSION 54 %comparison = L + - # level 1 55 %comparison = L * / # level 2 56 %comparison = L > < # level 3 57 `) 58 if nil != err { 59 return nil, rookoutErrors.NewArithmeticPathException(err) 60 } 61 grammar := parser.Grammar 62 63 grammar["COMPARISON_EXPRESSION"].Action = m.makeComparisonExpression 64 grammar["EXPRESSION"].Action = m.makeComparisonExpression 65 grammar["COMPARISON"].Action = m.makeComparison 66 grammar["LIST"].Action = m.makeList 67 grammar["BOOL"].Action = m.makeBoolean 68 grammar["NAMESPACE"].Action = m.makeNamespace 69 grammar["VARIABLE_ACCESS"].Action = m.makeAttributeOperation 70 grammar["METHOD_ACCESS"].Action = m.makeMethodOperation 71 grammar["MAP_ACCESS"].Action = m.makeLookupOperation 72 grammar["FLOAT"].Action = m.makeFloat 73 grammar["NUMBER"].Action = m.makeNumber 74 grammar["STRING"].Action = m.makeString 75 grammar["APOSTROPHE_STRING"].Action = m.makeString 76 grammar["CHAR"].Action = m.makeString 77 grammar["NULL"].Action = m.makeNull 78 79 return parser, nil 80 } 81 82 func (m *mapsActions) Parse(path string) (node, rookoutErrors.RookoutError) { 83 operations, err := m.parser.ParseAndGetValue(path, nil) 84 if err != nil { 85 return nil, rookoutErrors.NewRookInvalidArithmeticPathException(path, err) 86 } 87 return operations.(node), nil 88 } 89 90 func (m *mapsActions) GetWriteOperations() []pathOperation { 91 return m.operations 92 } 93 94 func (m *mapsActions) makeComparisonExpression(values *peg.Values, _ peg.Any) (peg.Any, error) { 95 if values.Len() == 2 { 96 return nil, rookoutErrors.NewRookInvalidArithmeticPathException(values.SS, nil) 97 } 98 99 elements := make([]node, 0, len(values.Vs)) 100 for _, n := range values.Vs { 101 element, ok := n.(node) 102 if !ok { 103 return nil, rookoutErrors.NewRookInvalidArithmeticPathException(values.SS, nil) 104 } 105 elements = append(elements, element) 106 } 107 108 for len(elements) > 1 { 109 elementsChanged := false 110 111 for level := optLevel(0); level < NUM_OF_LEVELS && !elementsChanged; level++ { 112 for i := 1; i < len(elements); i += 2 { 113 left := elements[i-1] 114 opt, ok := elements[i].(*optNode) 115 if !ok { 116 return nil, rookoutErrors.NewRookInvalidArithmeticPathException(values.SS, nil) 117 } 118 right := elements[i+1] 119 120 if opt.level != level { 121 continue 122 } 123 124 compNode := newComparisonNode(left, opt, right) 125 elements[i-1] = compNode 126 elements = append(elements[:i], elements[i+2:]...) 127 128 elementsChanged = true 129 } 130 } 131 } 132 133 return elements[0], nil 134 } 135 136 func (m *mapsActions) makeNamespace(values *peg.Values, _ peg.Any) (peg.Any, error) { 137 var operations []pathOperation 138 for _, rawOperation := range values.Vs { 139 if operation, ok := rawOperation.(pathOperation); ok { 140 operations = append(operations, operation) 141 } else { 142 msg := fmt.Sprintf("parsing %v in (%s)", rawOperation, values.SS) 143 return nil, rookoutErrors.NewRookInvalidArithmeticPathException(msg, nil) 144 } 145 } 146 147 m.operations = append(m.operations, operations...) 148 return newNamespaceNode(operations), nil 149 } 150 151 func (m *mapsActions) makeList(values *peg.Values, _ peg.Any) (peg.Any, error) { 152 a := make([]node, 0, len(values.Vs)) 153 for _, s := range values.Vs { 154 a = append(a, s.(node)) 155 } 156 157 return newListNode(a), nil 158 } 159 160 func (m *mapsActions) makeComparison(values *peg.Values, _ peg.Any) (peg.Any, error) { 161 opt := strings.Replace(values.Token(), " ", "", -1) 162 return newOpt(opt) 163 } 164 165 func (m *mapsActions) makeBoolean(values *peg.Values, _ peg.Any) (peg.Any, error) { 166 val := strings.ToLower(utils.ReplaceAll(values.Token(), " ", "")) 167 if val == "true" { 168 return newValueNode(true), nil 169 } 170 return newValueNode(false), nil 171 } 172 173 func (m *mapsActions) makeString(values *peg.Values, _ peg.Any) (peg.Any, error) { 174 return newValueNode(values.Token()[1 : len(values.Token())-1]), nil 175 } 176 177 func (m *mapsActions) makeNumber(values *peg.Values, _ peg.Any) (peg.Any, error) { 178 i, err := strconv.Atoi(values.Token()) 179 if err != nil { 180 msg := "unable to parse int: " + values.Token() 181 return nil, rookoutErrors.NewRookInvalidArithmeticPathException(msg, err) 182 } 183 return newValueNode(i), nil 184 } 185 186 func (m *mapsActions) makeFloat(values *peg.Values, _ peg.Any) (peg.Any, error) { 187 f, err := strconv.ParseFloat(values.Token(), 64) 188 if err != nil { 189 msg := "unable to parse float: " + values.Token() 190 return nil, rookoutErrors.NewRookInvalidArithmeticPathException(msg, err) 191 } 192 return newValueNode(f), nil 193 } 194 195 func (m *mapsActions) makeLookupOperation(values *peg.Values, _ peg.Any) (peg.Any, error) { 196 return newLookupOperation(values.Token()) 197 } 198 199 func (m *mapsActions) makeMethodOperation(values *peg.Values, _ peg.Any) (peg.Any, error) { 200 args := "" 201 if len(values.Ts) >= 2 { 202 args = values.Ts[1].S 203 if (strings.HasSuffix(args, "'") && strings.HasPrefix(args, "'")) || 204 (strings.HasSuffix(args, "\"") && strings.HasPrefix(args, "\"")) { 205 args = args[1 : len(args)-1] 206 } 207 } 208 return newMethodOperation(values.Token(), args), nil 209 } 210 211 func (m *mapsActions) makeAttributeOperation(values *peg.Values, _ peg.Any) (peg.Any, error) { 212 return newAttributeOperation(values.Token()), nil 213 } 214 215 func (m *mapsActions) makeNull(_ *peg.Values, _ peg.Any) (peg.Any, error) { 216 return newNoneNode(), nil 217 }