158 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
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
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |