Find cycles in fallthru map. Try to break them; not right, yet.
Chris Pressey
7 years ago
58 | 58 | analyzer.analyze_program(program) |
59 | 59 | |
60 | 60 | if options.optimize_fallthru: |
61 | import json | |
61 | 62 | from sixtypical.fallthru import FallthruAnalyzer |
62 | 63 | |
63 | 64 | fa = FallthruAnalyzer(debug=options.debug) |
64 | 65 | fa.analyze_program(program) |
65 | 66 | |
66 | 67 | if options.dump_fallthru_info: |
67 | import json | |
68 | sys.stdout.write(json.dumps(fa.fallthru_map, indent=4, sort_keys=True)) | |
68 | fallthru_map = dict(fa.fallthru_map) | |
69 | sys.stdout.write(json.dumps(fallthru_map, indent=4, sort_keys=True)) | |
69 | 70 | sys.stdout.write("\n") |
71 | ||
72 | fa.find_ancestors() | |
73 | ||
74 | if options.debug and options.dump_fallthru_info: | |
75 | sys.stdout.write("*** ancestors:\n") | |
76 | sys.stdout.write(json.dumps(fa.ancestor_map, indent=4, sort_keys=True)) | |
77 | sys.stdout.write("\n") | |
78 | ||
79 | fa.find_cycles() | |
80 | ||
81 | if fa.cycles_found: | |
82 | if options.dump_fallthru_info: | |
83 | sys.stdout.write("*** cycles found:\n") | |
84 | sys.stdout.write(json.dumps(sorted(fa.cycles_found), indent=4, sort_keys=True)) | |
85 | sys.stdout.write("\n") | |
86 | ||
87 | fa.break_cycles() | |
88 | ||
89 | if options.dump_fallthru_info and fallthru_map != fa.fallthru_map: | |
90 | sys.stdout.write("*** after breaking cycles:\n") | |
91 | sys.stdout.write(json.dumps(fa.fallthru_map, indent=4, sort_keys=True)) | |
92 | sys.stdout.write("\n") | |
70 | 93 | |
71 | 94 | if options.analyze_only: |
72 | 95 | return |
0 | 0 | # encoding: UTF-8 |
1 | 1 | |
2 | 2 | from sixtypical.model import RoutineType |
3 | ||
4 | ||
5 | def make_transitive_closure(d, key, s): | |
6 | for sub in d.get(key, []): | |
7 | if sub not in s: | |
8 | s.add(sub) | |
9 | make_transitive_closure(d, sub, s) | |
3 | 10 | |
4 | 11 | |
5 | 12 | class FallthruAnalyzer(object): |
14 | 21 | if len(encountered_gotos) == 1 and isinstance(encountered_gotos[0].type, RoutineType): |
15 | 22 | fallthru_map.setdefault(encountered_gotos[0].name, set()).add(routine.name) |
16 | 23 | self.fallthru_map = dict([(k, sorted(v)) for k, v in fallthru_map.iteritems()]) |
24 | return self.fallthru_map | |
25 | ||
26 | def find_ancestors(self): | |
27 | self.ancestor_map = {} | |
28 | for key in self.fallthru_map: | |
29 | ancestors = set() | |
30 | make_transitive_closure(self.fallthru_map, key, ancestors) | |
31 | self.ancestor_map[key] = sorted(ancestors) | |
32 | return self.ancestor_map | |
33 | ||
34 | def find_cycles(self): | |
35 | self.cycles_found = set() | |
36 | for key in self.ancestor_map: | |
37 | if key in self.ancestor_map[key]: | |
38 | self.cycles_found.add(key) | |
39 | return self.cycles_found | |
17 | 40 | |
18 | 41 | def break_cycles(self): |
19 | raise NotImplementedError | |
42 | new_fallthru_map = {} | |
43 | for key in self.fallthru_map: | |
44 | values = set(self.fallthru_map[key]) - self.cycles_found | |
45 | if values: | |
46 | new_fallthru_map[key] = sorted(values) | |
47 | self.fallthru_map = new_fallthru_map | |
20 | 48 | |
21 | 49 | def serialize(self): |
22 | 50 | raise NotImplementedError |
133 | 133 | = "bar" |
134 | 134 | = ] |
135 | 135 | = } |
136 | = *** cycles found: | |
137 | = [ | |
138 | = "bar", | |
139 | = "foo" | |
140 | = ] | |
141 | = *** after breaking cycles: | |
142 | = { | |
143 | = "bar": [ | |
144 | = "foo" | |
145 | = ] | |
146 | = } | |
136 | 147 | |
137 | 148 | If a routine does two tail calls (which is possible because they |
138 | 149 | can be in different branches of an `if`) it cannot fall through to another |