1package ast 2 3import ( 4 "errors" 5 "fmt" 6 "github.com/gobwas/glob/syntax/lexer" 7 "unicode/utf8" 8) 9 10type Lexer interface { 11 Next() lexer.Token 12} 13 14type parseFn func(*Node, Lexer) (parseFn, *Node, error) 15 16func Parse(lexer Lexer) (*Node, error) { 17 var parser parseFn 18 19 root := NewNode(KindPattern, nil) 20 21 var ( 22 tree *Node 23 err error 24 ) 25 for parser, tree = parserMain, root; parser != nil; { 26 parser, tree, err = parser(tree, lexer) 27 if err != nil { 28 return nil, err 29 } 30 } 31 32 return root, nil 33} 34 35func parserMain(tree *Node, lex Lexer) (parseFn, *Node, error) { 36 for { 37 token := lex.Next() 38 switch token.Type { 39 case lexer.EOF: 40 return nil, tree, nil 41 42 case lexer.Error: 43 return nil, tree, errors.New(token.Raw) 44 45 case lexer.Text: 46 Insert(tree, NewNode(KindText, Text{token.Raw})) 47 return parserMain, tree, nil 48 49 case lexer.Any: 50 Insert(tree, NewNode(KindAny, nil)) 51 return parserMain, tree, nil 52 53 case lexer.Super: 54 Insert(tree, NewNode(KindSuper, nil)) 55 return parserMain, tree, nil 56 57 case lexer.Single: 58 Insert(tree, NewNode(KindSingle, nil)) 59 return parserMain, tree, nil 60 61 case lexer.RangeOpen: 62 return parserRange, tree, nil 63 64 case lexer.TermsOpen: 65 a := NewNode(KindAnyOf, nil) 66 Insert(tree, a) 67 68 p := NewNode(KindPattern, nil) 69 Insert(a, p) 70 71 return parserMain, p, nil 72 73 case lexer.Separator: 74 p := NewNode(KindPattern, nil) 75 Insert(tree.Parent, p) 76 77 return parserMain, p, nil 78 79 case lexer.TermsClose: 80 return parserMain, tree.Parent.Parent, nil 81 82 default: 83 return nil, tree, fmt.Errorf("unexpected token: %s", token) 84 } 85 } 86 return nil, tree, fmt.Errorf("unknown error") 87} 88 89func parserRange(tree *Node, lex Lexer) (parseFn, *Node, error) { 90 var ( 91 not bool 92 lo rune 93 hi rune 94 chars string 95 ) 96 for { 97 token := lex.Next() 98 switch token.Type { 99 case lexer.EOF: 100 return nil, tree, errors.New("unexpected end") 101 102 case lexer.Error: 103 return nil, tree, errors.New(token.Raw) 104 105 case lexer.Not: 106 not = true 107 108 case lexer.RangeLo: 109 r, w := utf8.DecodeRuneInString(token.Raw) 110 if len(token.Raw) > w { 111 return nil, tree, fmt.Errorf("unexpected length of lo character") 112 } 113 lo = r 114 115 case lexer.RangeBetween: 116 // 117 118 case lexer.RangeHi: 119 r, w := utf8.DecodeRuneInString(token.Raw) 120 if len(token.Raw) > w { 121 return nil, tree, fmt.Errorf("unexpected length of lo character") 122 } 123 124 hi = r 125 126 if hi < lo { 127 return nil, tree, fmt.Errorf("hi character '%s' should be greater than lo '%s'", string(hi), string(lo)) 128 } 129 130 case lexer.Text: 131 chars = token.Raw 132 133 case lexer.RangeClose: 134 isRange := lo != 0 && hi != 0 135 isChars := chars != "" 136 137 if isChars == isRange { 138 return nil, tree, fmt.Errorf("could not parse range") 139 } 140 141 if isRange { 142 Insert(tree, NewNode(KindRange, Range{ 143 Lo: lo, 144 Hi: hi, 145 Not: not, 146 })) 147 } else { 148 Insert(tree, NewNode(KindList, List{ 149 Chars: chars, 150 Not: not, 151 })) 152 } 153 154 return parserMain, tree, nil 155 } 156 } 157} 158