go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/common/data/text/sequence/matcher.go (about) 1 // Copyright 2022 The LUCI Authors. 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 sequence 16 17 import ( 18 "regexp" 19 "strings" 20 21 "go.chromium.org/luci/common/errors" 22 ) 23 24 // Matcher is a single element of a Pattern and can match a single element in 25 // a sequence. 26 // 27 // There are also two 'special' Matchers: 28 // - Ellipsis - Unconditionally matches zero or more elements in a sequence. 29 // - Edge - Matches the beginning or end of a sequence with zero-width. 30 type Matcher interface { 31 Matches(tok string) bool 32 } 33 34 type ellipsis struct{} 35 36 func (ellipsis) Matches(tok string) bool { panic("don't call Ellipsis.Matches") } 37 38 type edge struct{} 39 40 func (edge) Matches(tok string) bool { panic("don't call Edge.Matches") } 41 42 // LiteralMatcher matches a sequence element with exactly this content. 43 type LiteralMatcher string 44 45 // Matches implements Matcher. 46 func (l LiteralMatcher) Matches(tok string) bool { 47 return (string)(l) == tok 48 } 49 50 // RegexpMatcher matches a sequence element with this Regexp. 51 type RegexpMatcher struct{ R *regexp.Regexp } 52 53 // Matches implements Matcher. 54 func (r RegexpMatcher) Matches(tok string) bool { 55 return r.R.MatchString(tok) 56 } 57 58 var ( 59 // Ellipsis is a special Pattern Matcher which matches any number of tokens of 60 // arbitrary length. 61 Ellipsis = ellipsis{} 62 63 // Edge is a special 0-width Pattern Matcher which only matches at the 64 // beginning or the end of a command. 65 Edge = edge{} 66 ) 67 68 // ParseRegLiteral parses `token` as either a regex or literal matcher. 69 // 70 // If `token` starts and ends with `/` it's contents is parsed as 71 // a RegexpMatcher, otherwise `token` is returned as a LiteralMatcher. 72 func ParseRegLiteral(token string) (Matcher, error) { 73 if strings.HasPrefix(token, "/") && strings.HasSuffix(token, "/") { 74 pat, err := regexp.Compile(token[1 : len(token)-1]) 75 if err != nil { 76 return nil, errors.Annotate(err, "invalid regexp").Err() 77 } 78 return RegexpMatcher{pat}, nil 79 } 80 return LiteralMatcher(token), nil 81 }