1// Package gintersect provides methods to check whether the intersection of several globs matches a non-empty set of strings. 2package gintersect 3 4import ( 5 "fmt" 6 "strings" 7) 8 9// Glob represents a glob. 10type Glob []Token 11 12// NewGlob constructs a Glob from the given string by tokenizing and then simplifying it, or reports errors if any. 13func NewGlob(input string) (Glob, error) { 14 tokens, err := Tokenize([]rune(input)) 15 if err != nil { 16 return nil, err 17 } 18 19 tokens = Simplify(tokens) 20 21 return Glob(tokens), nil 22} 23 24// TokenType is the type of a Token. 25type TokenType uint 26 27const ( 28 TTCharacter TokenType = iota 29 TTDot 30 TTSet 31) 32 33// Flag applies to a token. 34type Flag uint 35 36func (f Flag) String() (s string) { 37 for r, flag := range flagRunes { 38 if f == flag { 39 s = string(r) 40 break 41 } 42 } 43 return 44} 45 46const ( 47 FlagNone = iota 48 FlagPlus 49 FlagStar 50) 51 52// Token is the element that makes up a Glob. 53type Token interface { 54 Type() TokenType 55 Flag() Flag 56 SetFlag(Flag) 57 // Equal describes whether the given Token is exactly equal to this one, barring differences in flags. 58 Equal(Token) bool 59 String() string 60} 61 62// token is the base for all structs implementing Token. 63type token struct { 64 ttype TokenType 65 flag Flag 66} 67 68func (t token) Type() TokenType { 69 return t.ttype 70} 71 72func (t token) Flag() Flag { 73 return t.flag 74} 75 76func (t *token) SetFlag(f Flag) { 77 t.flag = f 78} 79 80// character is a specific rune. It implements Token. 81type character struct { 82 token 83 r rune 84} 85 86func NewCharacter(r rune) Token { 87 return &character{ 88 token: token{ttype: TTCharacter}, 89 r: r, 90 } 91} 92 93func (c character) Equal(other Token) bool { 94 if c.Type() != other.Type() { 95 return false 96 } 97 98 o := other.(*character) 99 return c.Rune() == o.Rune() 100} 101 102func (c character) String() string { 103 return fmt.Sprintf("{character: %s flag: %s}", string(c.Rune()), c.Flag().String()) 104} 105 106func (c character) Rune() rune { 107 return c.r 108} 109 110// dot is any character. It implements Token. 111type dot struct { 112 token 113} 114 115func NewDot() Token { 116 return &dot{ 117 token: token{ttype: TTDot}, 118 } 119} 120 121func (d dot) Equal(other Token) bool { 122 if d.Type() != other.Type() { 123 return false 124 } 125 126 return true 127} 128 129func (d dot) String() string { 130 return fmt.Sprintf("{dot flag: %s}", d.Flag().String()) 131} 132 133// set is a set of characters (similar to regexp character class). 134// It implements Token. 135type set struct { 136 token 137 runes map[rune]bool 138} 139 140func NewSet(runes []rune) Token { 141 m := map[rune]bool{} 142 for _, r := range runes { 143 m[r] = true 144 } 145 return &set{ 146 token: token{ttype: TTSet}, 147 runes: m, 148 } 149} 150 151func (s set) Equal(other Token) bool { 152 if s.Type() != other.Type() { 153 return false 154 } 155 156 o := other.(*set) 157 r1, r2 := s.Runes(), o.Runes() 158 159 if len(r1) != len(r2) { 160 return false 161 } 162 163 for k, _ := range r1 { 164 if _, ok := r2[k]; !ok { 165 return false 166 } 167 } 168 169 return true 170} 171 172func (s set) String() string { 173 rs := make([]string, 0, 30) 174 for r, _ := range s.Runes() { 175 rs = append(rs, string(r)) 176 } 177 return fmt.Sprintf("{set: %s flag: %s}", strings.Join(rs, ""), s.Flag().String()) 178} 179 180func (s set) Runes() map[rune]bool { 181 return s.runes 182} 183