mirror of https://github.com/gobwas/glob.git
commit
1a9b5d0057
196
compiler.go
196
compiler.go
|
@ -385,20 +385,25 @@ func compileMatchers(matchers []match.Matcher) (match.Matcher, error) {
|
|||
return m, nil
|
||||
}
|
||||
|
||||
var (
|
||||
val match.Matcher
|
||||
idx int
|
||||
)
|
||||
idx := -1
|
||||
maxLen := -1
|
||||
var val match.Matcher
|
||||
for i, matcher := range matchers {
|
||||
l := matcher.Len()
|
||||
if l >= maxLen {
|
||||
if l := matcher.Len(); l != -1 && l >= maxLen {
|
||||
maxLen = l
|
||||
idx = i
|
||||
val = matcher
|
||||
}
|
||||
}
|
||||
|
||||
if val == nil { // not found matcher with static length
|
||||
r, err := compileMatchers(matchers[1:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return match.NewBTree(matchers[0], nil, r), nil
|
||||
}
|
||||
|
||||
left := matchers[:idx]
|
||||
var right []match.Matcher
|
||||
if len(matchers) > idx+1 {
|
||||
|
@ -424,74 +429,8 @@ func compileMatchers(matchers []match.Matcher) (match.Matcher, error) {
|
|||
return match.NewBTree(val, l, r), nil
|
||||
}
|
||||
|
||||
//func complexity(m match.Matcher) int {
|
||||
// var matchers []match.Matcher
|
||||
// var k int
|
||||
//
|
||||
// switch matcher := m.(type) {
|
||||
//
|
||||
// case match.Nothing:
|
||||
// return 0
|
||||
//
|
||||
// case match.Max, match.Range, match.Suffix, match.Text:
|
||||
// return 1
|
||||
//
|
||||
// case match.PrefixSuffix, match.Single, match.Row:
|
||||
// return 2
|
||||
//
|
||||
// case match.Any, match.Contains, match.List, match.Min, match.Prefix, match.Super:
|
||||
// return 4
|
||||
//
|
||||
// case match.BTree:
|
||||
// matchers = append(matchers, matcher.Value)
|
||||
// if matcher.Left != nil {
|
||||
// matchers = append(matchers, matcher.Left)
|
||||
// }
|
||||
// if matcher.Right != nil {
|
||||
// matchers = append(matchers, matcher.Right)
|
||||
// }
|
||||
// k = 1
|
||||
//
|
||||
// case match.AnyOf:
|
||||
// matchers = matcher.Matchers
|
||||
// k = 1
|
||||
// case match.EveryOf:
|
||||
// matchers = matcher.Matchers
|
||||
// k = 1
|
||||
//
|
||||
// default:
|
||||
// return 0
|
||||
// }
|
||||
//
|
||||
// var sum int
|
||||
// for _, m := range matchers {
|
||||
// sum += complexity(m)
|
||||
// }
|
||||
//
|
||||
// return sum * k
|
||||
//}
|
||||
|
||||
func doAnyOf(n *nodeAnyOf, s []rune) (match.Matcher, error) {
|
||||
var matchers []match.Matcher
|
||||
for _, desc := range n.children() {
|
||||
if desc == nil {
|
||||
matchers = append(matchers, match.NewNothing())
|
||||
continue
|
||||
}
|
||||
|
||||
m, err := do(desc, s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
matchers = append(matchers, optimize(m))
|
||||
}
|
||||
|
||||
return match.NewAnyOf(matchers...), nil
|
||||
}
|
||||
|
||||
func do(leaf node, s []rune) (m match.Matcher, err error) {
|
||||
switch n := leaf.(type) {
|
||||
|
||||
case *nodeAnyOf:
|
||||
// todo this could be faster on pattern_alternatives_combine_lite
|
||||
if n := minimizeAnyOf(n.children()); n != nil {
|
||||
|
@ -559,120 +498,7 @@ func do(leaf node, s []rune) (m match.Matcher, err error) {
|
|||
return optimize(m), nil
|
||||
}
|
||||
|
||||
func do2(node node, s []rune) ([]match.Matcher, error) {
|
||||
var result []match.Matcher
|
||||
|
||||
switch n := node.(type) {
|
||||
|
||||
case *nodePattern:
|
||||
ways := [][]match.Matcher{[]match.Matcher{}}
|
||||
|
||||
for _, desc := range node.children() {
|
||||
variants, err := do2(desc, s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fmt.Println("variants pat", variants)
|
||||
|
||||
for i, l := 0, len(ways); i < l; i++ {
|
||||
for i := 0; i < len(variants); i++ {
|
||||
o := optimize(variants[i])
|
||||
if i == len(variants)-1 {
|
||||
ways[i] = append(ways[i], o)
|
||||
} else {
|
||||
var w []match.Matcher
|
||||
copy(w, ways[i])
|
||||
ways = append(ways, append(w, o))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("ways pat", ways)
|
||||
}
|
||||
|
||||
for _, matchers := range ways {
|
||||
c, err := compileMatchers(minimizeMatchers(matchers))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, c)
|
||||
}
|
||||
|
||||
case *nodeAnyOf:
|
||||
ways := make([][]match.Matcher, len(node.children()))
|
||||
for _, desc := range node.children() {
|
||||
variants, err := do2(desc, s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fmt.Println("variants any", variants)
|
||||
|
||||
for x, l := 0, len(ways); x < l; x++ {
|
||||
for i := 0; i < len(variants); i++ {
|
||||
o := optimize(variants[i])
|
||||
if i == len(variants)-1 {
|
||||
ways[x] = append(ways[x], o)
|
||||
} else {
|
||||
var w []match.Matcher
|
||||
copy(w, ways[x])
|
||||
ways = append(ways, append(w, o))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("ways any", ways)
|
||||
}
|
||||
|
||||
for _, matchers := range ways {
|
||||
c, err := compileMatchers(minimizeMatchers(matchers))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, c)
|
||||
}
|
||||
|
||||
case *nodeList:
|
||||
result = append(result, match.NewList([]rune(n.chars), n.not))
|
||||
|
||||
case *nodeRange:
|
||||
result = append(result, match.NewRange(n.lo, n.hi, n.not))
|
||||
|
||||
case *nodeAny:
|
||||
result = append(result, match.NewAny(s))
|
||||
|
||||
case *nodeSuper:
|
||||
result = append(result, match.NewSuper())
|
||||
|
||||
case *nodeSingle:
|
||||
result = append(result, match.NewSingle(s))
|
||||
|
||||
case *nodeText:
|
||||
result = append(result, match.NewText(n.text))
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("could not compile tree: unknown node type")
|
||||
}
|
||||
|
||||
for i, m := range result {
|
||||
result[i] = optimize(m)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func compile(ast *nodePattern, s []rune) (Glob, error) {
|
||||
// ms, err := do2(ast, s)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// if len(ms) == 1 {
|
||||
// return ms[0], nil
|
||||
// } else {
|
||||
// return match.NewAnyOf(ms), nil
|
||||
// }
|
||||
|
||||
g, err := do(ast, s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -2,6 +2,7 @@ package glob
|
|||
|
||||
import (
|
||||
"github.com/gobwas/glob/match"
|
||||
"github.com/gobwas/glob/match/debug"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
@ -270,6 +271,19 @@ func TestCompiler(t *testing.T) {
|
|||
nil,
|
||||
),
|
||||
},
|
||||
{
|
||||
ast: pattern(&nodeText{text: "/"}, anyOf(&nodeText{text: "z"}, &nodeText{text: "ab"}), &nodeSuper{}),
|
||||
sep: separators,
|
||||
result: match.NewBTree(
|
||||
match.NewText("/"),
|
||||
nil,
|
||||
match.NewBTree(
|
||||
match.NewAnyOf(match.NewText("z"), match.NewText("ab")),
|
||||
nil,
|
||||
match.NewSuper(),
|
||||
),
|
||||
),
|
||||
},
|
||||
{
|
||||
ast: pattern(&nodeSuper{}, &nodeSingle{}, &nodeText{text: "abc"}, &nodeSingle{}),
|
||||
sep: separators,
|
||||
|
@ -397,18 +411,6 @@ func TestCompiler(t *testing.T) {
|
|||
}...,
|
||||
),
|
||||
},
|
||||
// {
|
||||
// ast: pattern(
|
||||
// anyOf(&nodeText{text: "a"}, &nodeText{text: "b"}),
|
||||
// anyOf(&nodeText{text: "c"}, &nodeText{text: "d"}),
|
||||
// ),
|
||||
// result: match.AnyOf{Matchers: match.Matchers{
|
||||
// match.NewRow(Matchers: match.Matchers{match.Raw{"a"}, match.Raw{"c", 1}}),
|
||||
// match.NewRow(Matchers: match.Matchers{match.Raw{"a"}, match.Raw{"d"}}),
|
||||
// match.NewRow(Matchers: match.Matchers{match.Raw{"b"}, match.Raw{"c", 1}}),
|
||||
// match.NewRow(Matchers: match.Matchers{match.Raw{"b"}, match.Raw{"d"}}),
|
||||
// }},
|
||||
// },
|
||||
} {
|
||||
m, err := compile(test.ast, test.sep)
|
||||
if err != nil {
|
||||
|
@ -417,7 +419,7 @@ func TestCompiler(t *testing.T) {
|
|||
}
|
||||
|
||||
if !reflect.DeepEqual(m, test.result) {
|
||||
t.Errorf("#%d results are not equal:\nexp: %#v\nact: %#v", id, test.result, m)
|
||||
t.Errorf("#%d results are not equal:\nexp: %#v\nact: %#v\nexp:\n%s\nact:\n%s\n", id, test.result, m, debug.Graphviz("", test.result.(match.Matcher)), debug.Graphviz("", m.(match.Matcher)))
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
|
10
glob_test.go
10
glob_test.go
|
@ -108,6 +108,10 @@ func TestGlob(t *testing.T) {
|
|||
glob(true, "{*,**}{a,b}", "ab"),
|
||||
glob(false, "{*,**}{a,b}", "ac"),
|
||||
|
||||
glob(true, "/{rate,[a-z][a-z][a-z]}*", "/rate"),
|
||||
glob(true, "/{rate,[0-9][0-9][0-9]}*", "/rate"),
|
||||
glob(true, "/{rate,[a-z][a-z][a-z]}*", "/usd"),
|
||||
|
||||
glob(true, pattern_all, fixture_all_match),
|
||||
glob(false, pattern_all, fixture_all_mismatch),
|
||||
|
||||
|
@ -162,7 +166,11 @@ func TestQuoteMeta(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
in: `[foo*]`,
|
||||
out: `\[foo\*\]`,
|
||||
out: `\[foo\*]`,
|
||||
},
|
||||
{
|
||||
in: `{foo*}`,
|
||||
out: `\{foo\*\}`,
|
||||
},
|
||||
{
|
||||
in: string(specials),
|
||||
|
|
36
lexer.go
36
lexer.go
|
@ -25,7 +25,6 @@ var specials = []byte{
|
|||
char_single,
|
||||
char_escape,
|
||||
char_range_open,
|
||||
char_range_close,
|
||||
char_terms_open,
|
||||
char_terms_close,
|
||||
}
|
||||
|
@ -123,6 +122,20 @@ func (i item) String() string {
|
|||
return fmt.Sprintf("%v<%s>", i.t, i.s)
|
||||
}
|
||||
|
||||
type stubLexer struct {
|
||||
Items []item
|
||||
pos int
|
||||
}
|
||||
|
||||
func (s *stubLexer) nextItem() (ret item) {
|
||||
if s.pos == len(s.Items) {
|
||||
return item{item_eof, ""}
|
||||
}
|
||||
ret = s.Items[s.pos]
|
||||
s.pos++
|
||||
return
|
||||
}
|
||||
|
||||
type lexer struct {
|
||||
input string
|
||||
start int
|
||||
|
@ -269,20 +282,20 @@ func lexRaw(l *lexer) stateFn {
|
|||
return lexTermsOpen
|
||||
|
||||
case char_terms_close:
|
||||
l.unread()
|
||||
return lexTermsClose
|
||||
if l.inTerms() { // if we are in terms
|
||||
l.unread()
|
||||
return lexTermsClose
|
||||
}
|
||||
|
||||
case char_comma:
|
||||
if l.inTerms() { // if we are not in terms
|
||||
if l.inTerms() { // if we are in terms
|
||||
l.unread()
|
||||
return lexSeparator
|
||||
}
|
||||
fallthrough
|
||||
|
||||
default:
|
||||
l.unread()
|
||||
return lexText
|
||||
}
|
||||
|
||||
l.unread()
|
||||
return lexText
|
||||
}
|
||||
|
||||
if l.pos > l.start {
|
||||
|
@ -325,7 +338,10 @@ scan:
|
|||
escaped = false
|
||||
}
|
||||
|
||||
l.emit(item_text, string(data))
|
||||
if len(data) > 0 {
|
||||
l.emit(item_text, string(data))
|
||||
}
|
||||
|
||||
return lexRaw
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,24 @@ func TestLexGood(t *testing.T) {
|
|||
item{item_eof, ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
pattern: "/{rate,[0-9]]}*",
|
||||
items: []item{
|
||||
item{item_text, "/"},
|
||||
item{item_terms_open, "{"},
|
||||
item{item_text, "rate"},
|
||||
item{item_separator, ","},
|
||||
item{item_range_open, "["},
|
||||
item{item_range_lo, "0"},
|
||||
item{item_range_between, "-"},
|
||||
item{item_range_hi, "9"},
|
||||
item{item_range_close, "]"},
|
||||
item{item_text, "]"},
|
||||
item{item_terms_close, "}"},
|
||||
item{item_any, "*"},
|
||||
item{item_eof, ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
pattern: "hello,world",
|
||||
items: []item{
|
||||
|
@ -114,6 +132,19 @@ func TestLexGood(t *testing.T) {
|
|||
item{item_eof, ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
pattern: "/{z,ab}*",
|
||||
items: []item{
|
||||
item{item_text, "/"},
|
||||
item{item_terms_open, "{"},
|
||||
item{item_text, "z"},
|
||||
item{item_separator, ","},
|
||||
item{item_text, "ab"},
|
||||
item{item_terms_close, "}"},
|
||||
item{item_any, "*"},
|
||||
item{item_eof, ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
pattern: "{[!日-語],*,?,{a,b,\\c}}",
|
||||
items: []item{
|
||||
|
|
|
@ -63,16 +63,15 @@ func (self AnyOf) Len() (l int) {
|
|||
l = -1
|
||||
for _, m := range self.Matchers {
|
||||
ml := m.Len()
|
||||
if ml == -1 {
|
||||
return -1
|
||||
}
|
||||
|
||||
if l == -1 {
|
||||
switch {
|
||||
case l == -1:
|
||||
l = ml
|
||||
continue
|
||||
}
|
||||
|
||||
if l != ml {
|
||||
case ml == -1:
|
||||
return -1
|
||||
|
||||
case l != ml:
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
|
13
parser.go
13
parser.go
|
@ -11,6 +11,11 @@ type node interface {
|
|||
append(node)
|
||||
}
|
||||
|
||||
// todo may be split it into another package
|
||||
type lexerIface interface {
|
||||
nextItem() item
|
||||
}
|
||||
|
||||
type nodeImpl struct {
|
||||
desc []node
|
||||
}
|
||||
|
@ -72,9 +77,9 @@ func (t *tree) leave() {
|
|||
t.current = t.path[len(t.path)-1]
|
||||
}
|
||||
|
||||
type parseFn func(*tree, *lexer) (parseFn, error)
|
||||
type parseFn func(*tree, lexerIface) (parseFn, error)
|
||||
|
||||
func parse(lexer *lexer) (*nodePattern, error) {
|
||||
func parse(lexer lexerIface) (*nodePattern, error) {
|
||||
var parser parseFn
|
||||
|
||||
root := &nodePattern{}
|
||||
|
@ -97,7 +102,7 @@ func parse(lexer *lexer) (*nodePattern, error) {
|
|||
return root, nil
|
||||
}
|
||||
|
||||
func parserMain(tree *tree, lexer *lexer) (parseFn, error) {
|
||||
func parserMain(tree *tree, lexer lexerIface) (parseFn, error) {
|
||||
for stop := false; !stop; {
|
||||
item := lexer.nextItem()
|
||||
|
||||
|
@ -151,7 +156,7 @@ func parserMain(tree *tree, lexer *lexer) (parseFn, error) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func parserRange(tree *tree, lexer *lexer) (parseFn, error) {
|
||||
func parserRange(tree *tree, lexer lexerIface) (parseFn, error) {
|
||||
var (
|
||||
not bool
|
||||
lo rune
|
||||
|
|
127
parser_test.go
127
parser_test.go
|
@ -8,11 +8,15 @@ import (
|
|||
|
||||
func TestParseString(t *testing.T) {
|
||||
for id, test := range []struct {
|
||||
pattern string
|
||||
tree node
|
||||
items []item
|
||||
tree node
|
||||
}{
|
||||
{
|
||||
pattern: "abc",
|
||||
//pattern: "abc",
|
||||
items: []item{
|
||||
item{item_text, "abc"},
|
||||
item{item_eof, ""},
|
||||
},
|
||||
tree: &nodePattern{
|
||||
nodeImpl: nodeImpl{
|
||||
desc: []node{
|
||||
|
@ -22,7 +26,13 @@ func TestParseString(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
pattern: "a*c",
|
||||
//pattern: "a*c",
|
||||
items: []item{
|
||||
item{item_text, "a"},
|
||||
item{item_any, "*"},
|
||||
item{item_text, "c"},
|
||||
item{item_eof, ""},
|
||||
},
|
||||
tree: &nodePattern{
|
||||
nodeImpl: nodeImpl{
|
||||
desc: []node{
|
||||
|
@ -34,7 +44,13 @@ func TestParseString(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
pattern: "a**c",
|
||||
//pattern: "a**c",
|
||||
items: []item{
|
||||
item{item_text, "a"},
|
||||
item{item_super, "**"},
|
||||
item{item_text, "c"},
|
||||
item{item_eof, ""},
|
||||
},
|
||||
tree: &nodePattern{
|
||||
nodeImpl: nodeImpl{
|
||||
desc: []node{
|
||||
|
@ -46,7 +62,13 @@ func TestParseString(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
pattern: "a?c",
|
||||
//pattern: "a?c",
|
||||
items: []item{
|
||||
item{item_text, "a"},
|
||||
item{item_single, "?"},
|
||||
item{item_text, "c"},
|
||||
item{item_eof, ""},
|
||||
},
|
||||
tree: &nodePattern{
|
||||
nodeImpl: nodeImpl{
|
||||
desc: []node{
|
||||
|
@ -58,7 +80,16 @@ func TestParseString(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
pattern: "[!a-z]",
|
||||
//pattern: "[!a-z]",
|
||||
items: []item{
|
||||
item{item_range_open, "["},
|
||||
item{item_not, "!"},
|
||||
item{item_range_lo, "a"},
|
||||
item{item_range_between, "-"},
|
||||
item{item_range_hi, "z"},
|
||||
item{item_range_close, "]"},
|
||||
item{item_eof, ""},
|
||||
},
|
||||
tree: &nodePattern{
|
||||
nodeImpl: nodeImpl{
|
||||
desc: []node{
|
||||
|
@ -68,7 +99,13 @@ func TestParseString(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
pattern: "[az]",
|
||||
//pattern: "[az]",
|
||||
items: []item{
|
||||
item{item_range_open, "["},
|
||||
item{item_text, "az"},
|
||||
item{item_range_close, "]"},
|
||||
item{item_eof, ""},
|
||||
},
|
||||
tree: &nodePattern{
|
||||
nodeImpl: nodeImpl{
|
||||
desc: []node{
|
||||
|
@ -78,7 +115,15 @@ func TestParseString(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
pattern: "{a,z}",
|
||||
//pattern: "{a,z}",
|
||||
items: []item{
|
||||
item{item_terms_open, "{"},
|
||||
item{item_text, "a"},
|
||||
item{item_separator, ","},
|
||||
item{item_text, "z"},
|
||||
item{item_terms_close, "}"},
|
||||
item{item_eof, ""},
|
||||
},
|
||||
tree: &nodePattern{
|
||||
nodeImpl: nodeImpl{
|
||||
desc: []node{
|
||||
|
@ -99,7 +144,65 @@ func TestParseString(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
pattern: "{a,{x,y},?,[a-z],[!qwe]}",
|
||||
//pattern: "/{z,ab}*",
|
||||
items: []item{
|
||||
item{item_text, "/"},
|
||||
item{item_terms_open, "{"},
|
||||
item{item_text, "z"},
|
||||
item{item_separator, ","},
|
||||
item{item_text, "ab"},
|
||||
item{item_terms_close, "}"},
|
||||
item{item_any, "*"},
|
||||
item{item_eof, ""},
|
||||
},
|
||||
tree: &nodePattern{
|
||||
nodeImpl: nodeImpl{
|
||||
desc: []node{
|
||||
&nodeText{text: "/"},
|
||||
&nodeAnyOf{nodeImpl: nodeImpl{desc: []node{
|
||||
&nodePattern{
|
||||
nodeImpl: nodeImpl{desc: []node{
|
||||
&nodeText{text: "z"},
|
||||
}},
|
||||
},
|
||||
&nodePattern{
|
||||
nodeImpl: nodeImpl{desc: []node{
|
||||
&nodeText{text: "ab"},
|
||||
}},
|
||||
},
|
||||
}}},
|
||||
&nodeAny{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
//pattern: "{a,{x,y},?,[a-z],[!qwe]}",
|
||||
items: []item{
|
||||
item{item_terms_open, "{"},
|
||||
item{item_text, "a"},
|
||||
item{item_separator, ","},
|
||||
item{item_terms_open, "{"},
|
||||
item{item_text, "x"},
|
||||
item{item_separator, ","},
|
||||
item{item_text, "y"},
|
||||
item{item_terms_close, "}"},
|
||||
item{item_separator, ","},
|
||||
item{item_single, "?"},
|
||||
item{item_separator, ","},
|
||||
item{item_range_open, "["},
|
||||
item{item_range_lo, "a"},
|
||||
item{item_range_between, "-"},
|
||||
item{item_range_hi, "z"},
|
||||
item{item_range_close, "]"},
|
||||
item{item_separator, ","},
|
||||
item{item_range_open, "["},
|
||||
item{item_not, "!"},
|
||||
item{item_text, "qwe"},
|
||||
item{item_range_close, "]"},
|
||||
item{item_terms_close, "}"},
|
||||
item{item_eof, ""},
|
||||
},
|
||||
tree: &nodePattern{
|
||||
nodeImpl: nodeImpl{
|
||||
desc: []node{
|
||||
|
@ -150,7 +253,9 @@ func TestParseString(t *testing.T) {
|
|||
},
|
||||
},
|
||||
} {
|
||||
pattern, err := parse(newLexer(test.pattern))
|
||||
lexer := &stubLexer{Items: test.items}
|
||||
pattern, err := parse(lexer)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("#%d %s", id, err)
|
||||
continue
|
||||
|
|
Loading…
Reference in New Issue