Exemple #1
0
func compileMatchers(matchers []match.Matcher) (match.Matcher, error) {
	if len(matchers) == 0 {
		return nil, fmt.Errorf("compile error: need at least one matcher")
	}

	if len(matchers) == 1 {
		return matchers[0], nil
	}

	if m := glueMatchers(matchers); m != nil {
		return m, nil
	}

	idx := -1
	maxLen := -1
	var val match.Matcher
	for i, matcher := range matchers {
		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 {
		right = matchers[idx+1:]
	}

	var l, r match.Matcher
	var err error
	if len(left) > 0 {
		l, err = compileMatchers(left)
		if err != nil {
			return nil, err
		}
	}

	if len(right) > 0 {
		r, err = compileMatchers(right)
		if err != nil {
			return nil, err
		}
	}

	return match.NewBTree(val, l, r), nil
}
Exemple #2
0
func compileMatchers(matchers []match.Matcher) (match.Matcher, error) {
	if len(matchers) == 0 {
		return nil, fmt.Errorf("compile error: need at least one matcher")
	}

	if len(matchers) == 1 {
		return matchers[0], nil
	}

	if m := glueMatchers(matchers); m != nil {
		return m, nil
	}

	var (
		val match.Matcher
		idx int
	)
	maxLen := -1
	for i, matcher := range matchers {
		l := matcher.Len()
		if l >= maxLen {
			maxLen = l
			idx = i
			val = matcher
		}
	}

	left := matchers[:idx]
	var right []match.Matcher
	if len(matchers) > idx+1 {
		right = matchers[idx+1:]
	}

	var l, r match.Matcher
	var err error
	if len(left) > 0 {
		l, err = compileMatchers(left)
		if err != nil {
			return nil, err
		}
	}

	if len(right) > 0 {
		r, err = compileMatchers(right)
		if err != nil {
			return nil, err
		}
	}

	return match.NewBTree(val, l, r), nil
}
func TestCompileMatchers(t *testing.T) {
	for id, test := range []struct {
		in  []match.Matcher
		exp match.Matcher
	}{
		{
			[]match.Matcher{
				match.NewSuper(),
				match.NewSingle(separators),
				match.NewText("c"),
			},
			match.NewBTree(
				match.NewText("c"),
				match.NewBTree(
					match.NewSingle(separators),
					match.NewSuper(),
					nil,
				),
				nil,
			),
		},
		{
			[]match.Matcher{
				match.NewAny(nil),
				match.NewText("c"),
				match.NewAny(nil),
			},
			match.NewBTree(
				match.NewText("c"),
				match.NewAny(nil),
				match.NewAny(nil),
			),
		},
		{
			[]match.Matcher{
				match.NewRange('a', 'c', true),
				match.NewList([]rune{'z', 't', 'e'}, false),
				match.NewText("c"),
				match.NewSingle(nil),
			},
			match.NewRow(
				4,
				match.Matchers{
					match.NewRange('a', 'c', true),
					match.NewList([]rune{'z', 't', 'e'}, false),
					match.NewText("c"),
					match.NewSingle(nil),
				}...,
			),
		},
	} {
		act, err := compileMatchers(test.in)
		if err != nil {
			t.Errorf("#%d convert matchers error: %s", id, err)
			continue
		}

		if !reflect.DeepEqual(act, test.exp) {
			t.Errorf("#%d unexpected convert matchers result:\nact: %#v\nexp: %#v", id, act, test.exp)
			continue
		}
	}
}
func TestCompiler(t *testing.T) {
	for id, test := range []struct {
		ast    *nodePattern
		result Glob
		sep    []rune
	}{
		{
			ast:    pattern(&nodeText{text: "abc"}),
			result: match.NewText("abc"),
		},
		{
			ast:    pattern(&nodeAny{}),
			sep:    separators,
			result: match.NewAny(separators),
		},
		{
			ast:    pattern(&nodeAny{}),
			result: match.NewSuper(),
		},
		{
			ast:    pattern(&nodeSuper{}),
			result: match.NewSuper(),
		},
		{
			ast:    pattern(&nodeSingle{}),
			sep:    separators,
			result: match.NewSingle(separators),
		},
		{
			ast: pattern(&nodeRange{
				lo:  'a',
				hi:  'z',
				not: true,
			}),
			result: match.NewRange('a', 'z', true),
		},
		{
			ast: pattern(&nodeList{
				chars: "abc",
				not:   true,
			}),
			result: match.NewList([]rune{'a', 'b', 'c'}, true),
		},
		{
			ast: pattern(&nodeAny{}, &nodeSingle{}, &nodeSingle{}, &nodeSingle{}),
			sep: separators,
			result: match.EveryOf{Matchers: match.Matchers{
				match.NewMin(3),
				match.NewContains(string(separators), true),
			}},
		},
		{
			ast:    pattern(&nodeAny{}, &nodeSingle{}, &nodeSingle{}, &nodeSingle{}),
			result: match.NewMin(3),
		},
		{
			ast: pattern(&nodeAny{}, &nodeText{text: "abc"}, &nodeSingle{}),
			sep: separators,
			result: match.NewBTree(
				match.NewRow(
					4,
					match.Matchers{
						match.NewText("abc"),
						match.NewSingle(separators),
					}...,
				),
				match.NewAny(separators),
				nil,
			),
		},
		{
			ast: pattern(&nodeSuper{}, &nodeSingle{}, &nodeText{text: "abc"}, &nodeSingle{}),
			sep: separators,
			result: match.NewBTree(
				match.NewRow(
					5,
					match.Matchers{
						match.NewSingle(separators),
						match.NewText("abc"),
						match.NewSingle(separators),
					}...,
				),
				match.NewSuper(),
				nil,
			),
		},
		{
			ast:    pattern(&nodeAny{}, &nodeText{text: "abc"}),
			result: match.NewSuffix("abc"),
		},
		{
			ast:    pattern(&nodeText{text: "abc"}, &nodeAny{}),
			result: match.NewPrefix("abc"),
		},
		{
			ast:    pattern(&nodeText{text: "abc"}, &nodeAny{}, &nodeText{text: "def"}),
			result: match.NewPrefixSuffix("abc", "def"),
		},
		{
			ast:    pattern(&nodeAny{}, &nodeAny{}, &nodeAny{}, &nodeText{text: "abc"}, &nodeAny{}, &nodeAny{}),
			result: match.NewContains("abc", false),
		},
		{
			ast: pattern(&nodeAny{}, &nodeAny{}, &nodeAny{}, &nodeText{text: "abc"}, &nodeAny{}, &nodeAny{}),
			sep: separators,
			result: match.NewBTree(
				match.NewText("abc"),
				match.NewAny(separators),
				match.NewAny(separators),
			),
		},
		{
			ast: pattern(&nodeSuper{}, &nodeSingle{}, &nodeText{text: "abc"}, &nodeSuper{}, &nodeSingle{}),
			result: match.NewBTree(
				match.NewText("abc"),
				match.NewMin(1),
				match.NewMin(1),
			),
		},
		{
			ast:    pattern(anyOf(&nodeText{text: "abc"})),
			result: match.NewText("abc"),
		},
		{
			ast:    pattern(anyOf(pattern(anyOf(pattern(&nodeText{text: "abc"}))))),
			result: match.NewText("abc"),
		},
		{
			ast: pattern(anyOf(
				pattern(
					&nodeText{text: "abc"},
					&nodeSingle{},
				),
				pattern(
					&nodeText{text: "abc"},
					&nodeList{chars: "def"},
				),
				pattern(
					&nodeText{text: "abc"},
				),
				pattern(
					&nodeText{text: "abc"},
				),
			)),
			result: match.NewBTree(
				match.NewText("abc"),
				nil,
				match.AnyOf{Matchers: match.Matchers{
					match.NewSingle(nil),
					match.NewList([]rune{'d', 'e', 'f'}, false),
					match.NewNothing(),
				}},
			),
		},
		{
			ast: pattern(
				&nodeRange{lo: 'a', hi: 'z'},
				&nodeRange{lo: 'a', hi: 'x', not: true},
				&nodeAny{},
			),
			result: match.NewBTree(
				match.NewRow(
					2,
					match.Matchers{
						match.NewRange('a', 'z', false),
						match.NewRange('a', 'x', true),
					}...,
				),
				nil,
				match.NewSuper(),
			),
		},
		{
			ast: pattern(anyOf(
				pattern(
					&nodeText{text: "abc"},
					&nodeList{chars: "abc"},
					&nodeText{text: "ghi"},
				),
				pattern(
					&nodeText{text: "abc"},
					&nodeList{chars: "def"},
					&nodeText{text: "ghi"},
				),
			)),
			result: match.NewRow(
				7,
				match.Matchers{
					match.NewText("abc"),
					match.AnyOf{Matchers: match.Matchers{
						match.NewList([]rune{'a', 'b', 'c'}, false),
						match.NewList([]rune{'d', 'e', 'f'}, false),
					}},
					match.NewText("ghi"),
				}...,
			),
		},
		//				{
		//			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 {
			t.Errorf("compilation error: %s", err)
			continue
		}

		if !reflect.DeepEqual(m, test.result) {
			t.Errorf("#%d results are not equal:\nexp: %#v\nact: %#v", id, test.result, m)
			continue
		}
	}
}
Exemple #5
0
func TestCompiler(t *testing.T) {
	for id, test := range []struct {
		ast    *ast.Node
		result match.Matcher
		sep    []rune
	}{
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindText, ast.Text{"abc"}),
			),
			result: match.NewText("abc"),
		},
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindAny, nil),
			),
			sep:    separators,
			result: match.NewAny(separators),
		},
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindAny, nil),
			),
			result: match.NewSuper(),
		},
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindSuper, nil),
			),
			result: match.NewSuper(),
		},
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindSingle, nil),
			),
			sep:    separators,
			result: match.NewSingle(separators),
		},
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindRange, ast.Range{
					Lo:  'a',
					Hi:  'z',
					Not: true,
				}),
			),
			result: match.NewRange('a', 'z', true),
		},
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindList, ast.List{
					Chars: "abc",
					Not:   true,
				}),
			),
			result: match.NewList([]rune{'a', 'b', 'c'}, true),
		},
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindAny, nil),
				ast.NewNode(ast.KindSingle, nil),
				ast.NewNode(ast.KindSingle, nil),
				ast.NewNode(ast.KindSingle, nil),
			),
			sep: separators,
			result: match.EveryOf{Matchers: match.Matchers{
				match.NewMin(3),
				match.NewContains(string(separators), true),
			}},
		},
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindAny, nil),
				ast.NewNode(ast.KindSingle, nil),
				ast.NewNode(ast.KindSingle, nil),
				ast.NewNode(ast.KindSingle, nil),
			),
			result: match.NewMin(3),
		},
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindAny, nil),
				ast.NewNode(ast.KindText, ast.Text{"abc"}),
				ast.NewNode(ast.KindSingle, nil),
			),
			sep: separators,
			result: match.NewBTree(
				match.NewRow(
					4,
					match.Matchers{
						match.NewText("abc"),
						match.NewSingle(separators),
					}...,
				),
				match.NewAny(separators),
				nil,
			),
		},
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindText, ast.Text{"/"}),
				ast.NewNode(ast.KindAnyOf, nil,
					ast.NewNode(ast.KindText, ast.Text{"z"}),
					ast.NewNode(ast.KindText, ast.Text{"ab"}),
				),
				ast.NewNode(ast.KindSuper, nil),
			),
			sep: separators,
			result: match.NewBTree(
				match.NewText("/"),
				nil,
				match.NewBTree(
					match.NewAnyOf(match.NewText("z"), match.NewText("ab")),
					nil,
					match.NewSuper(),
				),
			),
		},
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindSuper, nil),
				ast.NewNode(ast.KindSingle, nil),
				ast.NewNode(ast.KindText, ast.Text{"abc"}),
				ast.NewNode(ast.KindSingle, nil),
			),
			sep: separators,
			result: match.NewBTree(
				match.NewRow(
					5,
					match.Matchers{
						match.NewSingle(separators),
						match.NewText("abc"),
						match.NewSingle(separators),
					}...,
				),
				match.NewSuper(),
				nil,
			),
		},
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindAny, nil),
				ast.NewNode(ast.KindText, ast.Text{"abc"}),
			),
			result: match.NewSuffix("abc"),
		},
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindText, ast.Text{"abc"}),
				ast.NewNode(ast.KindAny, nil),
			),
			result: match.NewPrefix("abc"),
		},
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindText, ast.Text{"abc"}),
				ast.NewNode(ast.KindAny, nil),
				ast.NewNode(ast.KindText, ast.Text{"def"}),
			),
			result: match.NewPrefixSuffix("abc", "def"),
		},
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindAny, nil),
				ast.NewNode(ast.KindAny, nil),
				ast.NewNode(ast.KindAny, nil),
				ast.NewNode(ast.KindText, ast.Text{"abc"}),
				ast.NewNode(ast.KindAny, nil),
				ast.NewNode(ast.KindAny, nil),
			),
			result: match.NewContains("abc", false),
		},
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindAny, nil),
				ast.NewNode(ast.KindAny, nil),
				ast.NewNode(ast.KindAny, nil),
				ast.NewNode(ast.KindText, ast.Text{"abc"}),
				ast.NewNode(ast.KindAny, nil),
				ast.NewNode(ast.KindAny, nil),
			),
			sep: separators,
			result: match.NewBTree(
				match.NewText("abc"),
				match.NewAny(separators),
				match.NewAny(separators),
			),
		},
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindSuper, nil),
				ast.NewNode(ast.KindSingle, nil),
				ast.NewNode(ast.KindText, ast.Text{"abc"}),
				ast.NewNode(ast.KindSuper, nil),
				ast.NewNode(ast.KindSingle, nil),
			),
			result: match.NewBTree(
				match.NewText("abc"),
				match.NewMin(1),
				match.NewMin(1),
			),
		},
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindText, ast.Text{"abc"}),
			),
			result: match.NewText("abc"),
		},
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindAnyOf, nil,
					ast.NewNode(ast.KindPattern, nil,
						ast.NewNode(ast.KindAnyOf, nil,
							ast.NewNode(ast.KindPattern, nil,
								ast.NewNode(ast.KindText, ast.Text{"abc"}),
							),
						),
					),
				),
			),
			result: match.NewText("abc"),
		},
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindAnyOf, nil,
					ast.NewNode(ast.KindPattern, nil,
						ast.NewNode(ast.KindText, ast.Text{"abc"}),
						ast.NewNode(ast.KindSingle, nil),
					),
					ast.NewNode(ast.KindPattern, nil,
						ast.NewNode(ast.KindText, ast.Text{"abc"}),
						ast.NewNode(ast.KindList, ast.List{Chars: "def"}),
					),
					ast.NewNode(ast.KindPattern, nil,
						ast.NewNode(ast.KindText, ast.Text{"abc"}),
					),
					ast.NewNode(ast.KindPattern, nil,
						ast.NewNode(ast.KindText, ast.Text{"abc"}),
					),
				),
			),
			result: match.NewBTree(
				match.NewText("abc"),
				nil,
				match.AnyOf{Matchers: match.Matchers{
					match.NewSingle(nil),
					match.NewList([]rune{'d', 'e', 'f'}, false),
					match.NewNothing(),
				}},
			),
		},
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindRange, ast.Range{Lo: 'a', Hi: 'z'}),
				ast.NewNode(ast.KindRange, ast.Range{Lo: 'a', Hi: 'x', Not: true}),
				ast.NewNode(ast.KindAny, nil),
			),
			result: match.NewBTree(
				match.NewRow(
					2,
					match.Matchers{
						match.NewRange('a', 'z', false),
						match.NewRange('a', 'x', true),
					}...,
				),
				nil,
				match.NewSuper(),
			),
		},
		{
			ast: ast.NewNode(ast.KindPattern, nil,
				ast.NewNode(ast.KindAnyOf, nil,
					ast.NewNode(ast.KindPattern, nil,
						ast.NewNode(ast.KindText, ast.Text{"abc"}),
						ast.NewNode(ast.KindList, ast.List{Chars: "abc"}),
						ast.NewNode(ast.KindText, ast.Text{"ghi"}),
					),
					ast.NewNode(ast.KindPattern, nil,
						ast.NewNode(ast.KindText, ast.Text{"abc"}),
						ast.NewNode(ast.KindList, ast.List{Chars: "def"}),
						ast.NewNode(ast.KindText, ast.Text{"ghi"}),
					),
				),
			),
			result: match.NewRow(
				7,
				match.Matchers{
					match.NewText("abc"),
					match.AnyOf{Matchers: match.Matchers{
						match.NewList([]rune{'a', 'b', 'c'}, false),
						match.NewList([]rune{'d', 'e', 'f'}, false),
					}},
					match.NewText("ghi"),
				}...,
			),
		},
	} {
		m, err := Compile(test.ast, test.sep)
		if err != nil {
			t.Errorf("compilation error: %s", err)
			continue
		}

		if !reflect.DeepEqual(m, test.result) {
			t.Errorf("[%d] Compile():\nexp: %#v\nact: %#v\n\ngraphviz:\nexp:\n%s\nact:\n%s\n", id, test.result, m, debug.Graphviz("", test.result.(match.Matcher)), debug.Graphviz("", m.(match.Matcher)))
			continue
		}
	}
}
Exemple #6
0
func TestCompileMatchers(t *testing.T) {
	for id, test := range []struct {
		in  []match.Matcher
		exp match.Matcher
	}{
		{
			[]match.Matcher{
				match.Super{},
				match.Single{separators},
				match.NewText("c"),
			},
			match.NewBTree(
				match.NewText("c"),
				match.NewBTree(
					match.Single{separators},
					match.Super{},
					nil,
				),
				nil,
			),
		},
		{
			[]match.Matcher{
				match.Any{},
				match.NewText("c"),
				match.Any{},
			},
			match.NewBTree(
				match.NewText("c"),
				match.Any{},
				match.Any{},
			),
		},
		{
			[]match.Matcher{
				match.Range{'a', 'c', true},
				match.List{"zte", false},
				match.NewText("c"),
				match.Single{},
			},
			match.Row{
				Matchers: match.Matchers{
					match.Range{'a', 'c', true},
					match.List{"zte", false},
					match.NewText("c"),
					match.Single{},
				},
				RunesLength: 4,
			},
		},
	} {
		act, err := compileMatchers(test.in)
		if err != nil {
			t.Errorf("#%d convert matchers error: %s", id, err)
			continue
		}

		if !reflect.DeepEqual(act, test.exp) {
			t.Errorf("#%d unexpected convert matchers result:\nact: %s;\nexp: %s", id, act, test.exp)
			continue
		}
	}
}
Exemple #7
0
func TestCompiler(t *testing.T) {
	for id, test := range []struct {
		ast    *nodePattern
		result Glob
		sep    string
	}{
		{
			ast:    pattern(&nodeText{text: "abc"}),
			result: match.NewText("abc"),
		},
		{
			ast:    pattern(&nodeAny{}),
			sep:    separators,
			result: match.Any{separators},
		},
		{
			ast:    pattern(&nodeAny{}),
			result: match.Super{},
		},
		{
			ast:    pattern(&nodeSuper{}),
			result: match.Super{},
		},
		{
			ast:    pattern(&nodeSingle{}),
			sep:    separators,
			result: match.Single{separators},
		},
		{
			ast: pattern(&nodeRange{
				lo:  'a',
				hi:  'z',
				not: true,
			}),
			result: match.Range{'a', 'z', true},
		},
		{
			ast: pattern(&nodeList{
				chars: "abc",
				not:   true,
			}),
			result: match.List{"abc", true},
		},
		{
			ast: pattern(&nodeAny{}, &nodeSingle{}, &nodeSingle{}, &nodeSingle{}),
			sep: separators,
			result: match.EveryOf{Matchers: match.Matchers{
				match.Min{3},
				match.Contains{separators, true},
			}},
		},
		{
			ast:    pattern(&nodeAny{}, &nodeSingle{}, &nodeSingle{}, &nodeSingle{}),
			result: match.Min{3},
		},
		{
			ast: pattern(&nodeAny{}, &nodeText{text: "abc"}, &nodeSingle{}),
			sep: separators,
			result: match.NewBTree(
				match.Row{
					Matchers: match.Matchers{
						match.NewText("abc"),
						match.Single{separators},
					},
					RunesLength: 4,
				},
				match.Any{separators},
				nil,
			),
		},
		{
			ast: pattern(&nodeSuper{}, &nodeSingle{}, &nodeText{text: "abc"}, &nodeSingle{}),
			sep: separators,
			result: match.NewBTree(
				match.Row{
					Matchers: match.Matchers{
						match.Single{separators},
						match.NewText("abc"),
						match.Single{separators},
					},
					RunesLength: 5,
				},
				match.Super{},
				nil,
			),
		},
		{
			ast:    pattern(&nodeAny{}, &nodeText{text: "abc"}),
			result: match.Suffix{"abc"},
		},
		{
			ast:    pattern(&nodeText{text: "abc"}, &nodeAny{}),
			result: match.Prefix{"abc"},
		},
		{
			ast:    pattern(&nodeText{text: "abc"}, &nodeAny{}, &nodeText{text: "def"}),
			result: match.PrefixSuffix{"abc", "def"},
		},
		{
			ast:    pattern(&nodeAny{}, &nodeAny{}, &nodeAny{}, &nodeText{text: "abc"}, &nodeAny{}, &nodeAny{}),
			result: match.Contains{"abc", false},
		},
		{
			ast: pattern(&nodeAny{}, &nodeAny{}, &nodeAny{}, &nodeText{text: "abc"}, &nodeAny{}, &nodeAny{}),
			sep: separators,
			result: match.NewBTree(
				match.NewText("abc"),
				match.Any{separators},
				match.Any{separators},
			),
		},
		{
			ast: pattern(&nodeSuper{}, &nodeSingle{}, &nodeText{text: "abc"}, &nodeSuper{}, &nodeSingle{}),
			result: match.NewBTree(
				match.NewText("abc"),
				match.Min{1},
				match.Min{1},
			),
		},
		{
			ast:    pattern(anyOf(&nodeText{text: "abc"})),
			result: match.NewText("abc"),
		},
		{
			ast:    pattern(anyOf(pattern(anyOf(pattern(&nodeText{text: "abc"}))))),
			result: match.NewText("abc"),
		},
		{
			ast: pattern(anyOf(
				pattern(
					&nodeText{text: "abc"},
					&nodeSingle{},
				),
				pattern(
					&nodeText{text: "abc"},
					&nodeList{chars: "def"},
				),
				pattern(
					&nodeText{text: "abc"},
				),
				pattern(
					&nodeText{text: "abc"},
				),
			)),
			result: match.NewBTree(
				match.NewText("abc"),
				nil,
				match.AnyOf{Matchers: match.Matchers{
					match.Single{},
					match.List{List: "def"},
					match.Nothing{},
				}},
			),
		},
		{
			ast: pattern(
				&nodeRange{lo: 'a', hi: 'z'},
				&nodeRange{lo: 'a', hi: 'x', not: true},
				&nodeAny{},
			),
			result: match.NewBTree(
				match.Row{
					Matchers: match.Matchers{
						match.Range{Lo: 'a', Hi: 'z'},
						match.Range{Lo: 'a', Hi: 'x', Not: true},
					},
					RunesLength: 2,
				},
				nil,
				match.Super{},
			),
		},
		{
			ast: pattern(anyOf(
				pattern(
					&nodeText{text: "abc"},
					&nodeList{chars: "abc"},
					&nodeText{text: "ghi"},
				),
				pattern(
					&nodeText{text: "abc"},
					&nodeList{chars: "def"},
					&nodeText{text: "ghi"},
				),
			)),
			result: match.Row{
				RunesLength: 7,
				Matchers: match.Matchers{
					match.NewText("abc"),
					match.AnyOf{Matchers: match.Matchers{
						match.List{List: "abc"},
						match.List{List: "def"},
					}},
					match.NewText("ghi"),
				},
			},
		},
		//				{
		//			ast: pattern(
		//				anyOf(&nodeText{text: "a"}, &nodeText{text: "b"}),
		//				anyOf(&nodeText{text: "c"}, &nodeText{text: "d"}),
		//			),
		//			result: match.AnyOf{Matchers: match.Matchers{
		//				match.Row{Matchers: match.Matchers{match.Raw{"a"}, match.Raw{"c", 1}}},
		//				match.Row{Matchers: match.Matchers{match.Raw{"a"}, match.Raw{"d"}}},
		//				match.Row{Matchers: match.Matchers{match.Raw{"b"}, match.Raw{"c", 1}}},
		//				match.Row{Matchers: match.Matchers{match.Raw{"b"}, match.Raw{"d"}}},
		//			}},
		//		},
	} {
		prog, err := compile(test.ast, test.sep)
		if err != nil {
			t.Errorf("compilation error: %s", err)
			continue
		}

		if !reflect.DeepEqual(prog, test.result) {
			t.Errorf("#%d results are not equal:\nexp: %s,\nact: %s", id, test.result, prog)
			continue
		}
	}
}