Commit bb33c5b7 authored by Chris Jewell's avatar Chris Jewell
Browse files

Fixed bug in ASTWalker -- the tree was being modified in-place, rather than...

Fixed bug in ASTWalker -- the tree was being modified in-place, rather than separately.  Now the ASTWalker works on a copy of the tree to avoid mangling existing tree objects.  Shallow copies of nodes are made to avoid copying any external references (e.g. symbol table).
parent a03dcde5
......@@ -17,6 +17,8 @@
# IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
import copy
from gem.gemlang.ast.ast_base import ASTNode
......@@ -28,18 +30,18 @@ class ASTWalker:
based on Lark's internals. Starting at the root node, each child is visited in turn.
Rules are as follows:
1. On entry to `node` of type `Foo`, if a method OnEntry_Foo(self, node) exists, it is called.
2. On exiting `node` of type `Foo`, if a method OnExit_Foo(self, node) exists, it is called.
3. If an OnEntry_* method returns non-null, the corresponding OnExit_* method is _not_ called.
4. Whatever an OnEntry_* or OnExit_* method returns, it replaces the node in the children list of the
parent node in the AST.
3. If an `OnEntry_*` method returns non-null, the corresponding `OnExit_*` method is _not_ called.
4. Whatever an `OnEntry_*` or `OnExit_*` method returns, it replaces the node in the children list of the
parent node in the AST.
"""
def __call(self, when, ast_node):
attr = "{}_{}".format(when, ast_node.__class__.__name__)
action = getattr(self, attr, None)
if action is None:
return ast_node
action = getattr(self, attr, self.__default__)
return action(ast_node)
def __callOnEntry(self, ast_node):
......@@ -56,12 +58,16 @@ class ASTWalker:
else:
return new_node
def __default__(self, ast_node):
return ast_node
def walk(self, ast_node):
"""Walks an AST, dispatching methods as appropriate.
:param ast_node: an ASTNode instance.
:return an object according to the return values of the OnExit_* and OnEntry_* methods.
"""
ast_node = copy.copy(ast_node)
ast_node = self.__callOnEntry(ast_node)
if isinstance(ast_node,
ASTNode): # Trap to allow re-writing to something other than an AST
......
......@@ -86,8 +86,6 @@ class CodeGenerator(ASTWalker):
args = self.walk(call.children[1])
if isinstance(fsymb, BuiltInFunctionSymbol):
return out.builtin_function[str(fname)](args)
# if isinstance(fsymb, STMSymbol):
# return out.STMInstance(str(fname), args)
return out.Function(str(fname), args)
def onExit_ArgList(self, arglist):
......
......@@ -120,6 +120,6 @@ class TestASTWalkerTransform(unittest.TestCase):
addnode = AddExpr(x, y)
subnode = SubExpr(z, addnode)
self.visitor.walk(subnode)
subnode = self.visitor.walk(subnode)
self.assertEqual('(SubExpr (Number 2.3) (Number 4.5))',
serialize(subnode))
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment