in matchtree.go [598:716]
func (d *indexData) newMatchTree(q query.Q) (matchTree, error) {
if q == nil {
return nil, fmt.Errorf("got nil (sub)query")
}
switch s := q.(type) {
case *query.Regexp:
// RegexpToMatchTreeRecursive tries to distill a matchTree that matches a
// superset of the regexp. If the returned matchTree is equivalent to the
// original regexp, it returns true. An equivalent matchTree has the same
// behaviour as the original regexp and can be used instead.
//
subMT, isEq, _, err := d.regexpToMatchTreeRecursive(s.Regexp, ngramSize, s.FileName, s.CaseSensitive)
if err != nil {
return nil, err
}
// if the query can be used in place of the regexp
// return the subtree
if isEq {
return subMT, nil
}
prefix := ""
if !s.CaseSensitive {
prefix = "(?i)"
}
tr := ®expMatchTree{
regexp: regexp.MustCompile(prefix + s.Regexp.String()),
fileName: s.FileName,
}
return &andMatchTree{
children: []matchTree{
tr, &noVisitMatchTree{subMT},
},
}, nil
case *query.And:
var r []matchTree
for _, ch := range s.Children {
ct, err := d.newMatchTree(ch)
if err != nil {
return nil, err
}
r = append(r, ct)
}
return &andMatchTree{r}, nil
case *query.Or:
var r []matchTree
for _, ch := range s.Children {
ct, err := d.newMatchTree(ch)
if err != nil {
return nil, err
}
r = append(r, ct)
}
return &orMatchTree{r}, nil
case *query.Not:
ct, err := d.newMatchTree(s.Child)
return ¬MatchTree{
child: ct,
}, err
case *query.Substring:
return d.newSubstringMatchTree(s)
case *query.Branch:
mask := uint64(0)
if s.Pattern == "HEAD" {
mask = 1
} else {
for nm, m := range d.branchIDs {
if strings.Contains(nm, s.Pattern) {
mask |= uint64(m)
}
}
}
return &branchQueryMatchTree{
mask: mask,
fileMasks: d.fileBranchMasks,
}, nil
case *query.Const:
if s.Value {
return &bruteForceMatchTree{}, nil
} else {
return &noMatchTree{"const"}, nil
}
case *query.Language:
code, ok := d.metaData.LanguageMap[s.Language]
if !ok {
return &noMatchTree{"lang"}, nil
}
return &docMatchTree{
reason: "language",
numDocs: uint32(len(d.languages)),
predicate: func(docID uint32) bool {
return d.languages[docID] == code
},
}, nil
case *query.Symbol:
mt, err := d.newSubstringMatchTree(s.Atom)
if err != nil {
return nil, err
}
if _, ok := mt.(*regexpMatchTree); ok {
return nil, fmt.Errorf("regexps and short queries not implemented for symbol search")
}
subMT, ok := mt.(*substrMatchTree)
if !ok {
return nil, fmt.Errorf("found %T inside query.Symbol", mt)
}
subMT.matchIterator = d.newTrimByDocSectionIter(s.Atom, subMT.matchIterator)
return subMT, nil
}
log.Panicf("type %T", q)
return nil, nil
}