github.com/Axway/agent-sdk@v1.1.101/pkg/filter/conditionparser.go (about) 1 package filter 2 3 import ( 4 "go/ast" 5 "go/parser" 6 "go/token" 7 "regexp" 8 "strings" 9 10 utilerrors "github.com/Axway/agent-sdk/pkg/util/errors" 11 ) 12 13 var ( 14 dashMatchReg = regexp.MustCompile(`tag\.MatchRegEx\("([\w+\.\*]+-)+[\w+\.\*]+"\)`) 15 dashTagNameReg = regexp.MustCompile(`tag\.(\w+-)+\w+`) 16 ) 17 18 // ConditionParser - Represents the filter condition parser 19 type ConditionParser struct { 20 err error 21 newConditions []Condition 22 } 23 24 // NewConditionParser - Create a new instance of condition parser 25 func NewConditionParser() *ConditionParser { 26 return &ConditionParser{ 27 newConditions: make([]Condition, 0), 28 } 29 } 30 31 // Parse - parses the AST tree to filter condition 32 func (f *ConditionParser) Parse(filterConfig string) ([]Condition, error) { 33 parsedConditions, err := f.parseCondition(strings.TrimSpace(f.preProcessCondition(filterConfig))) 34 if err != nil { 35 return nil, err 36 } 37 38 return parsedConditions, nil 39 } 40 41 func (f *ConditionParser) preProcessCondition(filterCondition string) string { 42 filterCondition = applyDashPlaceholder(dashMatchReg, filterCondition) 43 return applyDashPlaceholder(dashTagNameReg, filterCondition) 44 } 45 46 func applyDashPlaceholder(re *regexp.Regexp, filterCondition string) string { 47 return re.ReplaceAllStringFunc(filterCondition, func(s string) string { 48 return strings.ReplaceAll(s, Dash, DashPlaceHolder) 49 }) 50 } 51 52 func (f *ConditionParser) parseCondition(filterCodition string) ([]Condition, error) { 53 if filterCodition == "" { 54 return nil, nil 55 } 56 src := "package main\nvar b bool = " + filterCodition 57 fset := token.NewFileSet() 58 node, err := parser.ParseFile(fset, "filter_config", []byte(src), parser.AllErrors) 59 // ast.Fprint(os.Stdout, fset, node, nil) 60 if err != nil { 61 errSegments := strings.Split(err.Error(), ":") 62 errMsg := errSegments[len(errSegments)-1] 63 return nil, ErrFilterConfiguration.FormatError(errMsg) 64 } 65 66 ast.Inspect(node, f.parseConditionExpr) 67 if f.err != nil { 68 return nil, f.err 69 } 70 return f.newConditions, f.err 71 } 72 73 func (f *ConditionParser) parseConditionExpr(node ast.Node) bool { 74 valueSpec, ok := node.(*ast.ValueSpec) 75 if !ok { 76 return true 77 } 78 for _, valueEx := range valueSpec.Values { 79 newCondition, err := f.parseExpr(valueEx) 80 f.newConditions = append(f.newConditions, newCondition) 81 f.err = err 82 if f.err != nil { 83 return false 84 } 85 } 86 return true 87 } 88 89 func (f *ConditionParser) isConditionalExpr(expr *ast.BinaryExpr) bool { 90 op := expr.Op 91 opPrecendence := op.Precedence() 92 return (opPrecendence <= 3) 93 } 94 95 func (f *ConditionParser) isSimpleExpr(expr *ast.BinaryExpr) bool { 96 op := expr.Op 97 opPrecendence := op.Precedence() 98 return (opPrecendence == 3) 99 } 100 101 func (f *ConditionParser) parseExpr(expr ast.Expr) (Condition, error) { 102 bexpr, ok := expr.(*ast.BinaryExpr) 103 if ok { 104 return f.parseBinaryExpr(bexpr) 105 } else if callExpr, ok := expr.(*ast.CallExpr); ok { 106 ce, err := f.parseCallExpr(callExpr) 107 if err != nil { 108 return nil, err 109 } 110 return &SimpleCondition{ 111 LHSExpr: ce, 112 }, nil 113 } 114 return nil, ErrFilterExpression 115 } 116 117 func (f *ConditionParser) parseCallExpr(expr *ast.CallExpr) (CallExpr, error) { 118 funcSelectorExprt, ok := expr.Fun.(*ast.SelectorExpr) 119 if !ok { 120 return nil, ErrFilterExpression 121 } 122 funcSelector, err := f.parseSelectorExpr(funcSelectorExprt) 123 if err != nil { 124 return nil, err 125 } 126 selectorType, selector, err := f.parseSelector(funcSelector) 127 if err != nil { 128 return nil, err 129 } 130 funcName := selector[strings.LastIndex(selector, ".")+1:] 131 132 callType, err := GetCallType(funcName) 133 if err != nil { 134 return nil, utilerrors.Wrap(ErrFilterGeneralParse, err.Error()) 135 } 136 137 var callArguments []interface{} 138 if expr.Args != nil { 139 callArguments, err = f.parseCallArguments(expr.Args) 140 if err != nil { 141 return nil, err 142 } 143 } 144 145 name := "" 146 lastSelectorIndex := strings.LastIndex(selector, ".") 147 if lastSelectorIndex != -1 { 148 name = selector[:lastSelectorIndex] 149 } 150 callExpr, err := newCallExpr(callType, selectorType, name, callArguments) 151 if err != nil { 152 return nil, utilerrors.Wrap(ErrFilterGeneralParse, err.Error()) 153 } 154 return callExpr, nil 155 } 156 157 func (f *ConditionParser) parseCallArguments(args []ast.Expr) ([]interface{}, error) { 158 argsList := make([]interface{}, 0) 159 for _, argExpr := range args { 160 literal, ok := argExpr.(*ast.BasicLit) 161 if !ok { 162 return nil, ErrFilterArgument 163 } 164 arg := strings.Trim(literal.Value, `"`) 165 argsList = append(argsList, arg) 166 } 167 return argsList, nil 168 } 169 170 func (f *ConditionParser) parseSelector(selector string) (selectorType, selectorPath string, err error) { 171 selectorType = selector[0:strings.Index(selector, ".")] 172 selectorPath = selector[strings.Index(selector, ".")+1:] 173 if selectorType != filterTypeTag && selectorType != filterTypeAttr { 174 err = ErrFilterSelectorType 175 } 176 return 177 } 178 179 func (f *ConditionParser) parseSelectorExpr(expr *ast.SelectorExpr) (string, error) { 180 var xName string 181 var err error 182 x, ok := expr.X.(*ast.Ident) 183 if ok { 184 xName = x.Name 185 } else if x, ok := expr.X.(*ast.SelectorExpr); ok { 186 xName, err = f.parseSelectorExpr(x) 187 } else { 188 err = ErrFilterSelectorExpr 189 } 190 if err != nil { 191 return "", err 192 } 193 194 return xName + "." + expr.Sel.Name, nil 195 } 196 197 func (f *ConditionParser) parseBinaryExpr(expr *ast.BinaryExpr) (Condition, error) { 198 if !f.isConditionalExpr(expr) { 199 return nil, ErrFilterOperator 200 } 201 202 if f.isSimpleExpr(expr) { 203 return f.parseSimpleBinaryExpr(expr) 204 } 205 return f.parseCompoundBinaryExpr(expr) 206 } 207 208 func (f *ConditionParser) parseSimpleLHS(expr *ast.BinaryExpr) (CallExpr, error) { 209 lhs, ok := expr.X.(*ast.SelectorExpr) 210 if ok { 211 return f.parseSelectorLHS(lhs) 212 } else if lhs, ok := expr.X.(*ast.CallExpr); ok { 213 return f.parseCallLHS(lhs) 214 } 215 return nil, ErrFilterCondition 216 } 217 218 func (f *ConditionParser) parseSelectorLHS(lhs *ast.SelectorExpr) (CallExpr, error) { 219 s, err := f.parseSelectorExpr(lhs) 220 if err != nil { 221 return nil, err 222 } 223 filterType, filterName, err := f.parseSelector(s) 224 if err != nil { 225 return nil, err 226 } 227 return newCallExpr(GETVALUE, filterType, filterName, nil) 228 } 229 230 func (f *ConditionParser) parseCallLHS(lhs *ast.CallExpr) (CallExpr, error) { 231 ce, err := f.parseCallExpr(lhs) 232 if err != nil { 233 return nil, err 234 } 235 return ce, nil 236 } 237 238 func (f *ConditionParser) parseSimpleRHS(expr *ast.BinaryExpr) (filterValue ComparableValue) { 239 literal, ok := expr.Y.(*ast.BasicLit) 240 if ok { 241 filterValue = newStringRHSValue(strings.Trim(literal.Value, `"`)) 242 } else if identVal, ok := expr.Y.(*ast.Ident); ok { 243 filterValue = newStringRHSValue(identVal.Name) 244 } 245 return 246 } 247 248 func (f *ConditionParser) parseSimpleBinaryExpr(expr *ast.BinaryExpr) (Condition, error) { 249 filterNode := &SimpleCondition{ 250 Operator: expr.Op.String(), 251 } 252 var err error 253 254 filterNode.LHSExpr, err = f.parseSimpleLHS(expr) 255 if err != nil { 256 return nil, err 257 } 258 filterNode.Value = f.parseSimpleRHS(expr) 259 return filterNode, nil 260 } 261 262 func (f *ConditionParser) parseCompoundBinaryExpr(expr *ast.BinaryExpr) (Condition, error) { 263 filterNode := &CompoundCondition{ 264 Operator: expr.Op.String(), 265 } 266 267 var err error 268 filterNode.LHSCondition, err = f.parseExpr(expr.X) 269 if err != nil { 270 return nil, err 271 } 272 filterNode.RHSCondition, err = f.parseExpr(expr.Y) 273 if err != nil { 274 return nil, err 275 } 276 return filterNode, nil 277 }