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 )