github.com/bytedance/go-tagexpr/v2@v2.9.8/spec_selector.go (about)

     1  // Copyright 2019 Bytedance Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package tagexpr
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"regexp"
    21  	"strings"
    22  )
    23  
    24  type selectorExprNode struct {
    25  	exprBackground
    26  	field, name  string
    27  	subExprs     []ExprNode
    28  	boolOpposite *bool
    29  	signOpposite *bool
    30  }
    31  
    32  func (se *selectorExprNode) String() string {
    33  	return fmt.Sprintf("(%s)%s", se.field, se.name)
    34  }
    35  
    36  func (p *Expr) readSelectorExprNode(expr *string) ExprNode {
    37  	field, name, subSelector, boolOpposite, signOpposite, found := findSelector(expr)
    38  	if !found {
    39  		return nil
    40  	}
    41  	operand := &selectorExprNode{
    42  		field:        field,
    43  		name:         name,
    44  		boolOpposite: boolOpposite,
    45  		signOpposite: signOpposite,
    46  	}
    47  	operand.subExprs = make([]ExprNode, 0, len(subSelector))
    48  	for _, s := range subSelector {
    49  		grp := newGroupExprNode()
    50  		err := p.parseExprNode(&s, grp)
    51  		if err != nil {
    52  			return nil
    53  		}
    54  		sortPriority(grp)
    55  		operand.subExprs = append(operand.subExprs, grp)
    56  	}
    57  	return operand
    58  }
    59  
    60  var selectorRegexp = regexp.MustCompile(`^([\!\+\-]*)(\([ \t]*[A-Za-z_]+[A-Za-z0-9_\.]*[ \t]*\))?(\$)([\)\[\],\+\-\*\/%><\|&!=\^ \t\\]|$)`)
    61  
    62  func findSelector(expr *string) (field string, name string, subSelector []string, boolOpposite, signOpposite *bool, found bool) {
    63  	raw := *expr
    64  	a := selectorRegexp.FindAllStringSubmatch(raw, -1)
    65  	if len(a) != 1 {
    66  		return
    67  	}
    68  	r := a[0]
    69  	if s0 := r[2]; len(s0) > 0 {
    70  		field = strings.TrimSpace(s0[1 : len(s0)-1])
    71  	}
    72  	name = r[3]
    73  	*expr = (*expr)[len(a[0][0])-len(r[4]):]
    74  	for {
    75  		sub := readPairedSymbol(expr, '[', ']')
    76  		if sub == nil {
    77  			break
    78  		}
    79  		if *sub == "" || (*sub)[0] == '[' {
    80  			*expr = raw
    81  			return "", "", nil, nil, nil, false
    82  		}
    83  		subSelector = append(subSelector, strings.TrimSpace(*sub))
    84  	}
    85  	prefix := r[1]
    86  	if len(prefix) == 0 {
    87  		found = true
    88  		return
    89  	}
    90  	_, boolOpposite, signOpposite = getBoolAndSignOpposite(&prefix)
    91  	found = true
    92  	return
    93  }
    94  
    95  func (se *selectorExprNode) Run(ctx context.Context, currField string, tagExpr *TagExpr) interface{} {
    96  	var subFields []interface{}
    97  	if n := len(se.subExprs); n > 0 {
    98  		subFields = make([]interface{}, n)
    99  		for i, e := range se.subExprs {
   100  			subFields[i] = e.Run(ctx, currField, tagExpr)
   101  		}
   102  	}
   103  	field := se.field
   104  	if field == "" {
   105  		field = currField
   106  	}
   107  	v := tagExpr.getValue(field, subFields)
   108  	return realValue(v, se.boolOpposite, se.signOpposite)
   109  }