forked from mirror/glob
145 lines
2.7 KiB
Go
145 lines
2.7 KiB
Go
package parser
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"github.com/gobwas/glob/lexer"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
type Lexer interface {
|
|
Next() lexer.Token
|
|
}
|
|
|
|
type parseFn func(Node, Lexer) (parseFn, Node, error)
|
|
|
|
func Parse(lexer Lexer) (*PatternNode, error) {
|
|
var parser parseFn
|
|
|
|
root := &PatternNode{}
|
|
|
|
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:
|
|
return parserMain, tree.append(&TextNode{Text: token.Raw}), nil
|
|
|
|
case lexer.Any:
|
|
return parserMain, tree.append(&AnyNode{}), nil
|
|
|
|
case lexer.Super:
|
|
return parserMain, tree.append(&SuperNode{}), nil
|
|
|
|
case lexer.Single:
|
|
return parserMain, tree.append(&SingleNode{}), nil
|
|
|
|
case lexer.RangeOpen:
|
|
return parserRange, tree, nil
|
|
|
|
case lexer.TermsOpen:
|
|
return parserMain, tree.append(&AnyOfNode{}).append(&PatternNode{}), nil
|
|
|
|
case lexer.Separator:
|
|
return parserMain, tree.Parent().append(&PatternNode{}), 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 {
|
|
tree = tree.append(&RangeNode{
|
|
Lo: lo,
|
|
Hi: hi,
|
|
Not: not,
|
|
})
|
|
} else {
|
|
tree = tree.append(&ListNode{
|
|
Chars: chars,
|
|
Not: not,
|
|
})
|
|
}
|
|
|
|
return parserMain, tree, nil
|
|
}
|
|
}
|
|
}
|