Skip to content

Commit 7266f1e

Browse files
authored
Merge pull request #545 from boriel/refact/visitor
Refact/visitor
2 parents 3431453 + 6a3d9f2 commit 7266f1e

10 files changed

Lines changed: 113 additions & 121 deletions

File tree

src/api/optimize.py

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
#!/usr/bin/env python
22
# -*- coding: utf-8 -*-
33

4-
import types
5-
64
from typing import NamedTuple
75
from typing import Optional
86
from typing import Set
@@ -32,6 +30,11 @@ class ToVisit(NamedTuple):
3230

3331

3432
class GenericVisitor(NodeVisitor):
33+
""" A slightly different visitor, that just traverses an AST, but does not return
34+
a translation of it. Used to examine the AST or do transformations
35+
"""
36+
node_type = ToVisit
37+
3538
@property
3639
def O_LEVEL(self):
3740
return OPTIONS.optimization_level
@@ -52,34 +55,14 @@ def TYPE(type_):
5255
return gl.SYMBOL_TABLE.basic_types[type_]
5356

5457
def visit(self, node):
55-
stack = [ToVisit(node)]
56-
last_result = None
57-
58-
while stack:
59-
try:
60-
last = stack[-1]
61-
if isinstance(last, types.GeneratorType):
62-
stack.append(last.send(last_result))
63-
last_result = None
64-
elif isinstance(last, ToVisit):
65-
stack.append(self._visit(stack.pop()))
66-
else:
67-
last_result = stack.pop()
68-
except StopIteration:
69-
stack.pop()
70-
71-
return last_result
72-
73-
def _visit(self, node):
58+
return super().visit(ToVisit(node))
59+
60+
def _visit(self, node: ToVisit):
7461
if node.obj is None:
7562
return None
7663

77-
__DEBUG__("Optimizer: Visiting node {}".format(str(node.obj)), 1)
78-
methname = 'visit_' + node.obj.token
79-
meth = getattr(self, methname, None)
80-
if meth is None:
81-
meth = self.generic_visit
82-
64+
__DEBUG__(f"Optimizer: Visiting node {str(node.obj)}", 1)
65+
meth = getattr(self, f"visit_{node.obj.token}", self.generic_visit)
8366
return meth(node.obj)
8467

8568
def generic_visit(self, node: Ast):
@@ -172,28 +155,28 @@ def _set_children_as_accessed(self, node: symbols.SYMBOL):
172155
for symbol in self._get_calls_from_children(node):
173156
symbol.entry.accessed = True
174157

175-
def visit_FUNCCALL(self, node: symbols.SYMBOL):
158+
def visit_FUNCCALL(self, node: symbols.FUNCCALL):
176159
self._set_children_as_accessed(node)
177160
yield node
178161

179-
def visit_CALL(self, node: symbols.SYMBOL):
162+
def visit_CALL(self, node: symbols.CALL):
180163
self._set_children_as_accessed(node)
181164
yield node
182165

183-
def visit_FUNCDECL(self, node: symbols.SYMBOL):
166+
def visit_FUNCDECL(self, node: symbols.FUNCDECL):
184167
if node.entry.accessed:
185168
for symbol in self._get_calls_from_children(node):
186169
symbol.entry.accessed = True
187170

188171
yield node
189172

190-
def visit_GOTO(self, node: symbols.SYMBOL):
173+
def visit_GOTO(self, node: symbols.SENTENCE):
191174
parent = node.get_parent(symbols.FUNCDECL)
192175
if parent is None: # Global scope?
193176
node.args[0].accessed = True
194177
yield node
195178

196-
def visit_GOSUB(self, node: symbols.SYMBOL):
179+
def visit_GOSUB(self, node: symbols.SENTENCE):
197180
return self.visit_GOTO(node)
198181

199182

src/ast/ast.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
# the GNU General License
1010
# ----------------------------------------------------------------------
1111

12-
from typing import Callable, Any
12+
from typing import Any, Callable, Type
13+
1314
import types
1415
from .tree import Tree
1516

@@ -20,10 +21,14 @@
2021
class Ast(Tree):
2122
""" Adds some methods for easier coding...
2223
"""
23-
pass
24+
@property
25+
def token(self):
26+
return self.__class__
2427

2528

2629
class NodeVisitor:
30+
node_type: Type = Ast
31+
2732
def visit(self, node):
2833
stack = [node]
2934
last_result = None
@@ -34,7 +39,7 @@ def visit(self, node):
3439
if isinstance(last, types.GeneratorType):
3540
stack.append(last.send(last_result))
3641
last_result = None
37-
elif isinstance(last, Ast):
42+
elif isinstance(last, self.node_type):
3843
stack.append(self._visit(stack.pop()))
3944
else:
4045
last_result = stack.pop()
@@ -44,15 +49,12 @@ def visit(self, node):
4449
return last_result
4550

4651
def _visit(self, node):
47-
methname = 'visit_' + node.token
48-
meth = getattr(self, methname, None)
49-
if meth is None:
50-
meth = self.generic_visit
52+
meth = getattr(self, f"visit_{node.token}", self.generic_visit)
5153
return meth(node)
5254

5355
@staticmethod
5456
def generic_visit(node: Ast):
55-
raise RuntimeError("No {}() method defined".format('visit_' + node.token))
57+
raise RuntimeError(f"No visit_{node.token}() method defined")
5658

5759
def filter_inorder(self,
5860
node,

src/ast/tree.py

Lines changed: 66 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
#!/usr/bin/python
22
# -*- coding: utf-8 -*-
33

4-
import collections
4+
import collections.abc
55

66
from typing import Iterable
77
from typing import List
88
from typing import Optional
9+
from typing import Union
910

1011
from src.api.errors import Error
1112

@@ -29,65 +30,8 @@ class Tree:
2930
"""
3031
parent: Optional['Tree'] = None
3132

32-
class ChildrenList:
33-
def __init__(self, node: 'Tree'):
34-
assert isinstance(node, Tree)
35-
self.parent = node # Node having this children
36-
self._children: List['Tree'] = []
37-
38-
def __getitem__(self, key):
39-
if isinstance(key, int):
40-
return self._children[key]
41-
42-
result = Tree.ChildrenList(self.parent)
43-
for x in self._children[key]:
44-
result.append(x)
45-
return result
46-
47-
def __setitem__(self, key, value):
48-
assert value is None or isinstance(value, Tree)
49-
if value is not None:
50-
value.parent = self.parent
51-
self._children[key] = value
52-
53-
def __delitem__(self, key):
54-
self._children[key].parent = None
55-
del self._children[key]
56-
57-
def append(self, value):
58-
assert isinstance(value, Tree)
59-
value.parent = self.parent
60-
self._children.append(value)
61-
62-
def insert(self, pos, value):
63-
assert isinstance(value, Tree)
64-
value.parent = self.parent
65-
self._children.insert(pos, value)
66-
67-
def pop(self, pos=-1):
68-
result = self._children.pop(pos)
69-
result.parent = None
70-
return result
71-
72-
def __len__(self):
73-
return len(self._children)
74-
75-
def __add__(self, other):
76-
if not isinstance(other, Tree.ChildrenList):
77-
assert isinstance(other, collections.Container)
78-
79-
result = Tree.ChildrenList(self.parent)
80-
for x in self:
81-
result.append(x)
82-
for x in other:
83-
result.append(x)
84-
return result
85-
86-
def __repr__(self):
87-
return "%s:%s" % (self.parent.__repr__(), str([x.__repr__() for x in self._children]))
88-
8933
def __init__(self):
90-
self._children = Tree.ChildrenList(self)
34+
self._children = ChildrenList(self)
9135

9236
@property
9337
def children(self):
@@ -99,7 +43,7 @@ def children(self, value: Iterable):
9943
while len(self.children):
10044
self.children.pop()
10145

102-
self._children = Tree.ChildrenList(self)
46+
self._children = ChildrenList(self)
10347
for x in value:
10448
self.children.append(x)
10549

@@ -127,12 +71,72 @@ def postorder(self):
12771

12872
yield self
12973

130-
def appendChild(self, node: 'Tree'):
74+
def append_child(self, node: 'Tree'):
13175
""" Appends the given node to the current children list
13276
"""
13377
self.children.append(node)
13478

135-
def prependChild(self, node: 'Tree'):
79+
def prepend_child(self, node: 'Tree'):
13680
""" Inserts the given node at the beginning of the children list
13781
"""
13882
self.children.insert(0, node)
83+
84+
85+
class ChildrenList:
86+
owner: Tree
87+
88+
def __init__(self, node: Tree):
89+
assert isinstance(node, Tree)
90+
self.owner = node # Node having this children
91+
self._children: List[Tree] = []
92+
93+
def __getitem__(self, key: Union[int, slice]):
94+
if isinstance(key, int):
95+
return self._children[key]
96+
97+
result = ChildrenList(self.owner)
98+
for x in self._children[key]:
99+
result.append(x)
100+
return result
101+
102+
def __setitem__(self, key, value: Optional[Tree]):
103+
assert value is None or isinstance(value, Tree)
104+
if value is not None:
105+
value.parent = self.owner
106+
self._children[key] = value
107+
108+
def __delitem__(self, key):
109+
self._children[key].parent = None
110+
del self._children[key]
111+
112+
def append(self, value: Tree):
113+
assert isinstance(value, Tree)
114+
value.parent = self.owner
115+
self._children.append(value)
116+
117+
def insert(self, pos: int, value: Tree):
118+
assert isinstance(value, Tree)
119+
value.parent = self.owner
120+
self._children.insert(pos, value)
121+
122+
def pop(self, pos: int = -1):
123+
result = self._children.pop(pos)
124+
result.parent = None
125+
return result
126+
127+
def __len__(self):
128+
return len(self._children)
129+
130+
def __add__(self, other):
131+
if not isinstance(other, ChildrenList):
132+
assert isinstance(other, collections.abc.Container)
133+
134+
result = ChildrenList(self.owner)
135+
for x in self:
136+
result.append(x)
137+
for x in other:
138+
result.append(x)
139+
return result
140+
141+
def __repr__(self):
142+
return f"{repr(self.owner)}:{str([repr(x) for x in self._children])}"

src/symbols/arglist.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def args(self):
2424
def args(self, value):
2525
for i in value:
2626
assert isinstance(value, SymbolARGUMENT)
27-
self.appendChild(i)
27+
self.append_child(i)
2828

2929
def __getitem__(self, range_):
3030
return self.args[range_]
@@ -56,6 +56,6 @@ def make_node(cls, node, *args):
5656

5757
for arg in args:
5858
assert isinstance(arg, SymbolARGUMENT)
59-
node.appendChild(arg)
59+
node.append_child(arg)
6060

6161
return node

src/symbols/boundlist.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
# the GNU General License
1010
# ----------------------------------------------------------------------
1111

12+
from typing import Optional
13+
1214
from .symbol_ import Symbol
1315
from .bound import SymbolBOUND
1416

@@ -32,7 +34,7 @@ def __str__(self):
3234
return '(%s)' % ', '.join(str(x) for x in self)
3335

3436
@classmethod
35-
def make_node(cls, node, *args):
37+
def make_node(cls, node: Optional[Symbol], *args):
3638
""" Creates an array BOUND LIST.
3739
"""
3840
if node is None:
@@ -44,6 +46,6 @@ def make_node(cls, node, *args):
4446
for arg in args:
4547
if arg is None:
4648
continue
47-
node.appendChild(arg)
49+
node.append_child(arg)
4850

4951
return node

src/symbols/paramlist.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,14 @@ def make_node(cls, node, *params):
4444

4545
for i in params:
4646
if i is not None:
47-
node.appendChild(i)
47+
node.append_child(i)
4848

4949
return node
5050

51-
def appendChild(self, param):
51+
def append_child(self, param):
5252
""" Overrides base class.
5353
"""
54-
Symbol.appendChild(self, param)
54+
Symbol.append_child(self, param)
5555
if param.offset is None:
5656
param.offset = self.size
5757
self.size += param.size

src/symbols/symbol_.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def __init__(self, *children):
2626
self._t = None
2727
for child in children:
2828
assert isinstance(child, Symbol)
29-
self.appendChild(child)
29+
self.append_child(child)
3030

3131
self._required_by: Counter = Counter() # Symbols that depends on this one
3232
self._requires: Counter = Counter() # Symbols this one depends on

src/zxbasm/asmparse.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ def makenode(cls, symbol, *nexts):
322322
continue
323323
if not isinstance(i, cls):
324324
raise NotAnAstError(i)
325-
result.appendChild(i)
325+
result.append_child(i)
326326

327327
return result
328328

0 commit comments

Comments
 (0)