forked from mirror/glob
128 lines
2.4 KiB
Go
128 lines
2.4 KiB
Go
|
package glob
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"github.com/gobwas/glob/match"
|
||
|
)
|
||
|
|
||
|
func parseAll(source, separators string) ([]token, error) {
|
||
|
lexer := newLexer(source)
|
||
|
|
||
|
var tokens []token
|
||
|
for parser := parserMain; parser != nil; {
|
||
|
var err error
|
||
|
tokens, parser, err = parser(lexer, separators)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return tokens, nil
|
||
|
}
|
||
|
|
||
|
type parseFn func(*lexer, string) ([]token, parseFn, error)
|
||
|
|
||
|
func parserMain(lexer *lexer, separators string) ([]token, parseFn, error) {
|
||
|
var (
|
||
|
prev *token
|
||
|
tokens []token
|
||
|
)
|
||
|
|
||
|
for item := lexer.nextItem(); ; {
|
||
|
var t token
|
||
|
|
||
|
if item.t == item_eof {
|
||
|
break
|
||
|
}
|
||
|
|
||
|
switch item.t {
|
||
|
case item_eof:
|
||
|
return tokens, nil, nil
|
||
|
|
||
|
case item_error:
|
||
|
return nil, nil, errors.New(item.s)
|
||
|
|
||
|
case item_text:
|
||
|
t = token{match.Raw{item.s}, item.s}
|
||
|
|
||
|
case item_any:
|
||
|
if prev != nil && prev.matcher.Kind() == match.KindMultipleSeparated {
|
||
|
// remove simple any and replace it with super_any
|
||
|
tokens = tokens[:len(tokens)-1]
|
||
|
t = token{match.Any{""}, item.s}
|
||
|
} else {
|
||
|
t = token{match.Any{separators}, item.s}
|
||
|
}
|
||
|
|
||
|
case item_single:
|
||
|
t = token{match.Single{separators}, item.s}
|
||
|
|
||
|
case item_range_open:
|
||
|
return tokens, parserRange, nil
|
||
|
}
|
||
|
|
||
|
prev = &t
|
||
|
}
|
||
|
|
||
|
return tokens, nil, nil
|
||
|
}
|
||
|
|
||
|
func parserRange(lexer *lexer, separators string) ([]token, parseFn, error) {
|
||
|
var (
|
||
|
not bool
|
||
|
lo rune
|
||
|
hi rune
|
||
|
chars string
|
||
|
)
|
||
|
|
||
|
for item := lexer.nextItem(); ; {
|
||
|
switch item.t {
|
||
|
case item_eof:
|
||
|
return nil, nil, errors.New("unexpected end")
|
||
|
|
||
|
case item_error:
|
||
|
return nil, nil, errors.New(item.s)
|
||
|
|
||
|
case item_range_not:
|
||
|
not = true
|
||
|
|
||
|
case item_range_lo:
|
||
|
r := []rune(item.s)
|
||
|
if len(r) != 1 {
|
||
|
return nil, nil, fmt.Errorf("unexpected length of lo character")
|
||
|
}
|
||
|
|
||
|
lo = r[0]
|
||
|
|
||
|
case item_range_minus:
|
||
|
//
|
||
|
|
||
|
case item_range_hi:
|
||
|
r := []rune(item.s)
|
||
|
if len(r) != 1 {
|
||
|
return nil, nil, fmt.Errorf("unexpected length of hi character")
|
||
|
}
|
||
|
|
||
|
hi = r[0]
|
||
|
|
||
|
case item_range_chars:
|
||
|
chars = item.s
|
||
|
|
||
|
case item_range_close:
|
||
|
isRange := lo != 0 && hi != 0
|
||
|
isChars := chars == ""
|
||
|
|
||
|
if !(isChars != isRange) {
|
||
|
return nil, nil, fmt.Errorf("parse error: unexpected lo, hi, chars in range")
|
||
|
}
|
||
|
|
||
|
if isRange {
|
||
|
return []token{token{match.Between{lo, hi, not}, ""}}, parserMain, nil
|
||
|
} else {
|
||
|
return []token{token{match.RangeList{chars, not}, ""}}, parserMain, nil
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|