github.com/jgbaldwinbrown/perf@v0.1.1/benchproc/internal/parse/tree.go (about)

     1  // Copyright 2022 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package parse
     6  
     7  import (
     8  	"fmt"
     9  	"regexp"
    10  	"strings"
    11  )
    12  
    13  // A Filter is a node in the boolean filter. It can either be a
    14  // FilterOp or a FilterMatch.
    15  type Filter interface {
    16  	isFilter()
    17  	String() string
    18  }
    19  
    20  // A FilterMatch is a leaf in a Filter tree that tests a specific key
    21  // for a match.
    22  type FilterMatch struct {
    23  	Key string
    24  
    25  	// Regexp is the regular expression to match against the
    26  	// value. This may be nil, in which case this is a literal
    27  	// match against Lit.
    28  	Regexp *regexp.Regexp
    29  	// Lit is the literal value to match against the value if Regexp
    30  	// is nil.
    31  	Lit string
    32  
    33  	// Off is the byte offset of the key in the original query,
    34  	// for error reporting.
    35  	Off int
    36  }
    37  
    38  func (q *FilterMatch) isFilter() {}
    39  func (q *FilterMatch) String() string {
    40  	if q.Regexp != nil {
    41  		return quoteWord(q.Key) + ":/" + q.Regexp.String() + "/"
    42  	}
    43  	return quoteWord(q.Key) + ":" + quoteWord(q.Lit)
    44  }
    45  
    46  // Match returns whether q matches the given value of q.Key.
    47  func (q *FilterMatch) Match(value []byte) bool {
    48  	if q.Regexp != nil {
    49  		return q.Regexp.Match(value)
    50  	}
    51  	return q.Lit == string(value)
    52  }
    53  
    54  // MatchString returns whether q matches the given value of q.Key.
    55  func (q *FilterMatch) MatchString(value string) bool {
    56  	if q.Regexp != nil {
    57  		return q.Regexp.MatchString(value)
    58  	}
    59  	return q.Lit == value
    60  }
    61  
    62  // A FilterOp is a boolean operator in the Filter tree. OpNot must have
    63  // exactly one child node. OpAnd and OpOr may have zero or more child nodes.
    64  type FilterOp struct {
    65  	Op    Op
    66  	Exprs []Filter
    67  }
    68  
    69  func (q *FilterOp) isFilter() {}
    70  func (q *FilterOp) String() string {
    71  	var op string
    72  	switch q.Op {
    73  	case OpNot:
    74  		return fmt.Sprintf("-%s", q.Exprs[0])
    75  	case OpAnd:
    76  		if len(q.Exprs) == 0 {
    77  			return "*"
    78  		}
    79  		op = " AND "
    80  	case OpOr:
    81  		if len(q.Exprs) == 0 {
    82  			return "-*"
    83  		}
    84  		op = " OR "
    85  	}
    86  	var buf strings.Builder
    87  	buf.WriteByte('(')
    88  	for i, e := range q.Exprs {
    89  		if i > 0 {
    90  			buf.WriteString(op)
    91  		}
    92  		buf.WriteString(e.String())
    93  	}
    94  	buf.WriteByte(')')
    95  	return buf.String()
    96  }
    97  
    98  // Op specifies a type of boolean operator.
    99  type Op int
   100  
   101  const (
   102  	OpAnd Op = 1 + iota
   103  	OpOr
   104  	OpNot
   105  )