Skip to content

Commit e4b0780

Browse files
committed
pattern: use map to represent relevant types
Some nodes mark all types as relevant, and multiple such nodes may occur in a single pattern (e.g. via '(Or _ _ _ ...)'). Use a map to only store each type once. This doesn't really matter for real use cases, but fuzzing can produce absurd patterns.
1 parent fa19c88 commit e4b0780

File tree

2 files changed

+25
-23
lines changed

2 files changed

+25
-23
lines changed

internal/cmd/gogrep/gogrep.go

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,17 @@ func match(fset *token.FileSet, pat pattern.Pattern, f *ast.File) {
2121
return true
2222
}
2323

24-
for _, rel := range pat.Relevant {
25-
if rel == reflect.TypeOf(node) {
26-
m := &pattern.Matcher{}
27-
if m.Match(pat, node) {
28-
fmt.Printf("%s: ", fset.Position(node.Pos()))
29-
format.Node(os.Stdout, fset, node)
30-
fmt.Println()
31-
}
32-
33-
// OPT(dh): we could further speed this up by not
34-
// chasing down impossible subtrees. For example,
35-
// we'll never find an ImportSpec beneath a FuncLit.
36-
return true
24+
if _, ok := pat.Relevant[reflect.TypeOf(node)]; ok {
25+
m := &pattern.Matcher{}
26+
if m.Match(pat, node) {
27+
fmt.Printf("%s: ", fset.Position(node.Pos()))
28+
format.Node(os.Stdout, fset, node)
29+
fmt.Println()
3730
}
31+
32+
// OPT(dh): we could further speed this up by not
33+
// chasing down impossible subtrees. For example,
34+
// we'll never find an ImportSpec beneath a FuncLit.
3835
}
3936
return true
4037
})

pattern/parser.go

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type Pattern struct {
1212
Root Node
1313
// Relevant contains instances of ast.Node that could potentially
1414
// initiate a successful match of the pattern.
15-
Relevant []reflect.Type
15+
Relevant map[reflect.Type]struct{}
1616

1717
// Mapping from binding index to binding name
1818
Bindings []string
@@ -27,27 +27,29 @@ func MustParse(s string) Pattern {
2727
return pat
2828
}
2929

30-
func roots(node Node) []reflect.Type {
30+
func roots(node Node, m map[reflect.Type]struct{}) {
3131
switch node := node.(type) {
3232
case Or:
33-
var out []reflect.Type
3433
for _, el := range node.Nodes {
35-
out = append(out, roots(el)...)
34+
roots(el, m)
3635
}
37-
return out
3836
case Not:
39-
return roots(node.Node)
37+
roots(node.Node, m)
4038
case Binding:
41-
return roots(node.Node)
39+
roots(node.Node, m)
4240
case Nil, nil:
4341
// this branch is reached via bindings
44-
return allTypes
42+
for _, T := range allTypes {
43+
m[T] = struct{}{}
44+
}
4545
default:
4646
Ts, ok := nodeToASTTypes[reflect.TypeOf(node)]
4747
if !ok {
4848
panic(fmt.Sprintf("internal error: unhandled type %T", node))
4949
}
50-
return Ts
50+
for _, T := range Ts {
51+
m[T] = struct{}{}
52+
}
5153
}
5254
}
5355

@@ -212,9 +214,12 @@ func (p *Parser) Parse(s string) (Pattern, error) {
212214
for name, idx := range p.bindings {
213215
bindings[idx] = name
214216
}
217+
218+
relevant := map[reflect.Type]struct{}{}
219+
roots(root, relevant)
215220
return Pattern{
216221
Root: root,
217-
Relevant: roots(root),
222+
Relevant: relevant,
218223
Bindings: bindings,
219224
}, nil
220225
}

0 commit comments

Comments
 (0)