glob/compiler/compiler.go

116 lines
2.4 KiB
Go

package compiler
// TODO use constructor with all matchers, and to their structs private
// TODO glue multiple Text nodes (like after QuoteMeta)
import (
"fmt"
"github.com/gobwas/glob/internal/debug"
"github.com/gobwas/glob/match"
"github.com/gobwas/glob/syntax/ast"
)
func Compile(tree *ast.Node, sep []rune) (match.Matcher, error) {
m, err := compile(tree, sep)
if err != nil {
return nil, err
}
return m, nil
}
func compileNodes(ns []*ast.Node, sep []rune) ([]match.Matcher, error) {
var matchers []match.Matcher
for _, n := range ns {
m, err := compile(n, sep)
if err != nil {
return nil, err
}
matchers = append(matchers, m)
}
return matchers, nil
}
func compile(node *ast.Node, sep []rune) (m match.Matcher, err error) {
if debug.Enabled {
debug.EnterPrefix("compiler: compiling %s", node)
defer func() {
if err != nil {
debug.Logf("->! %v", err)
} else {
debug.Logf("-> %s", m)
}
debug.LeavePrefix()
}()
}
// todo this could be faster on pattern_alternatives_combine_lite (see glob_test.go)
if n := ast.Minimize(node); n != nil {
debug.Logf("minimized tree -> %s", node, n)
r, err := compile(n, sep)
if debug.Enabled {
if err != nil {
debug.Logf("compiler: compile minimized tree failed: %v", err)
} else {
debug.Logf("compiler: minimized tree")
debug.Logf("compiler: \t%s", node)
debug.Logf("compiler: \t%s", n)
}
}
if err == nil {
return r, nil
}
}
switch node.Kind {
case ast.KindAnyOf:
matchers, err := compileNodes(node.Children, sep)
if err != nil {
return nil, err
}
return match.NewAnyOf(matchers...), nil
case ast.KindPattern:
if len(node.Children) == 0 {
return match.NewNothing(), nil
}
matchers, err := compileNodes(node.Children, sep)
if err != nil {
return nil, err
}
m, err = match.Compile(match.Minimize(matchers))
if err != nil {
return nil, err
}
case ast.KindAny:
m = match.NewAny(sep)
case ast.KindSuper:
m = match.NewSuper()
case ast.KindSingle:
m = match.NewSingle(sep)
case ast.KindNothing:
m = match.NewNothing()
case ast.KindList:
l := node.Value.(ast.List)
m = match.NewList([]rune(l.Chars), l.Not)
case ast.KindRange:
r := node.Value.(ast.Range)
m = match.NewRange(r.Lo, r.Hi, r.Not)
case ast.KindText:
t := node.Value.(ast.Text)
m = match.NewText(t.Text)
default:
return nil, fmt.Errorf("could not compile tree: unknown node type")
}
return match.Optimize(m), nil
}