This repository has been archived by the owner on Jul 4, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
find_pattern.py
97 lines (71 loc) · 2.81 KB
/
find_pattern.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#!/usr/bin/env python
"""Script that makes determining PATTERN for a new fix much easier.
Figuring out exactly what PATTERN I want for a given fixer class is
getting tedious. This script will step through each possible subtree
for a given string, allowing you to select which one you want. It will
then try to figure out an appropriate pattern to match that tree. This
pattern will require some editing (it will be overly restrictive) but
should provide a solid base to work with and handle the tricky parts.
Usage:
python find_pattern.py "g.throw(E, V, T)"
This will step through each subtree in the parse. To reject a
candidate subtree, hit enter; to accept a candidate, hit "y" and
enter. The pattern will be spit out to stdout.
For example, the above will yield a succession of possible snippets,
skipping all leaf-only trees. I accept
'g.throw(E, V, T)'
This causes find_pattern to spit out
power< 'g' trailer< '.' 'throw' >
trailer< '(' arglist< 'E' ',' 'V' ',' 'T' > ')' > >
Some minor tweaks later, I'm left with
power< any trailer< '.' 'throw' >
trailer< '(' args=arglist< exc=any ',' val=any [',' tb=any] > ')' > >
which is exactly what I was after.
Larger snippets can be placed in a file (as opposed to a command-line
arg) and processed with the -f option.
"""
__author__ = "Collin Winter <[email protected]>"
# Python imports
import optparse
import sys
from io import StringIO
# Local imports
from lib2to3 import pytree
from lib2to3.pgen2 import driver
from lib2to3.pygram import python_symbols, python_grammar
driver = driver.Driver(python_grammar, convert=pytree.convert)
def main(args):
parser = optparse.OptionParser(usage="find_pattern.py [options] [string]")
parser.add_option("-f", "--file", action="store",
help="Read a code snippet from the specified file")
# Parse command line arguments
options, args = parser.parse_args(args)
if options.file:
tree = driver.parse_file(options.file)
elif len(args) > 1:
tree = driver.parse_stream(StringIO(args[1] + "\n"))
else:
print("You must specify an input file or an input string", file=sys.stderr)
return 1
examine_tree(tree)
return 0
def examine_tree(tree):
for node in tree.post_order():
if isinstance(node, pytree.Leaf):
continue
print(repr(str(node)))
verdict = input()
if verdict.strip():
print(find_pattern(node))
return
def find_pattern(node):
if isinstance(node, pytree.Leaf):
return repr(node.value)
return find_symbol(node.type) + \
"< " + " ".join(find_pattern(n) for n in node.children) + " >"
def find_symbol(sym):
for n, v in list(python_symbols.__dict__.items()):
if v == sym:
return n
if __name__ == "__main__":
sys.exit(main(sys.argv))