|
- package ast
-
- import (
- "errors"
- "fmt"
- "github.com/gobwas/glob/syntax/lexer"
- "unicode/utf8"
- )
-
- type Lexer interface {
- Next() lexer.Token
- }
-
- type parseFn func(*Node, Lexer) (parseFn, *Node, error)
-
- func Parse(lexer Lexer) (*Node, error) {
- var parser parseFn
-
- root := NewNode(KindPattern, nil)
-
- var (
- tree *Node
- err error
- )
- for parser, tree = parserMain, root; parser != nil; {
- parser, tree, err = parser(tree, lexer)
- if err != nil {
- return nil, err
- }
- }
-
- return root, nil
- }
-
- func parserMain(tree *Node, lex Lexer) (parseFn, *Node, error) {
- for {
- token := lex.Next()
- switch token.Type {
- case lexer.EOF:
- return nil, tree, nil
-
- case lexer.Error:
- return nil, tree, errors.New(token.Raw)
-
- case lexer.Text:
- Insert(tree, NewNode(KindText, Text{token.Raw}))
- return parserMain, tree, nil
-
- case lexer.Any:
- Insert(tree, NewNode(KindAny, nil))
- return parserMain, tree, nil
-
- case lexer.Super:
- Insert(tree, NewNode(KindSuper, nil))
- return parserMain, tree, nil
-
- case lexer.Single:
- Insert(tree, NewNode(KindSingle, nil))
- return parserMain, tree, nil
-
- case lexer.RangeOpen:
- return parserRange, tree, nil
-
- case lexer.TermsOpen:
- a := NewNode(KindAnyOf, nil)
- Insert(tree, a)
-
- p := NewNode(KindPattern, nil)
- Insert(a, p)
-
- return parserMain, p, nil
-
- case lexer.Separator:
- p := NewNode(KindPattern, nil)
- Insert(tree.Parent, p)
-
- return parserMain, p, nil
-
- case lexer.TermsClose:
- return parserMain, tree.Parent.Parent, nil
-
- default:
- return nil, tree, fmt.Errorf("unexpected token: %s", token)
- }
- }
- return nil, tree, fmt.Errorf("unknown error")
- }
-
- func parserRange(tree *Node, lex Lexer) (parseFn, *Node, error) {
- var (
- not bool
- lo rune
- hi rune
- chars string
- )
- for {
- token := lex.Next()
- switch token.Type {
- case lexer.EOF:
- return nil, tree, errors.New("unexpected end")
-
- case lexer.Error:
- return nil, tree, errors.New(token.Raw)
-
- case lexer.Not:
- not = true
-
- case lexer.RangeLo:
- r, w := utf8.DecodeRuneInString(token.Raw)
- if len(token.Raw) > w {
- return nil, tree, fmt.Errorf("unexpected length of lo character")
- }
- lo = r
-
- case lexer.RangeBetween:
- //
-
- case lexer.RangeHi:
- r, w := utf8.DecodeRuneInString(token.Raw)
- if len(token.Raw) > w {
- return nil, tree, fmt.Errorf("unexpected length of lo character")
- }
-
- hi = r
-
- if hi < lo {
- return nil, tree, fmt.Errorf("hi character '%s' should be greater than lo '%s'", string(hi), string(lo))
- }
-
- case lexer.Text:
- chars = token.Raw
-
- case lexer.RangeClose:
- isRange := lo != 0 && hi != 0
- isChars := chars != ""
-
- if isChars == isRange {
- return nil, tree, fmt.Errorf("could not parse range")
- }
-
- if isRange {
- Insert(tree, NewNode(KindRange, Range{
- Lo: lo,
- Hi: hi,
- Not: not,
- }))
- } else {
- Insert(tree, NewNode(KindList, List{
- Chars: chars,
- Not: not,
- }))
- }
-
- return parserMain, tree, nil
- }
- }
- }
|