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  }