Spaces:
Build error
Build error
# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. | |
# Use of this file is governed by the BSD 3-clause license that | |
# can be found in the LICENSE.txt file in the project root. | |
#/ | |
# The basic notion of a tree has a parent, a payload, and a list of children. | |
# It is the most abstract interface for all the trees used by ANTLR. | |
#/ | |
from antlr4.Token import Token | |
INVALID_INTERVAL = (-1, -2) | |
class Tree(object): | |
pass | |
class SyntaxTree(Tree): | |
pass | |
class ParseTree(SyntaxTree): | |
pass | |
class RuleNode(ParseTree): | |
pass | |
class TerminalNode(ParseTree): | |
pass | |
class ErrorNode(TerminalNode): | |
pass | |
class ParseTreeVisitor(object): | |
def visit(self, tree): | |
return tree.accept(self) | |
def visitChildren(self, node): | |
result = self.defaultResult() | |
n = node.getChildCount() | |
for i in range(n): | |
if not self.shouldVisitNextChild(node, result): | |
return result | |
c = node.getChild(i) | |
childResult = c.accept(self) | |
result = self.aggregateResult(result, childResult) | |
return result | |
def visitTerminal(self, node): | |
return self.defaultResult() | |
def visitErrorNode(self, node): | |
return self.defaultResult() | |
def defaultResult(self): | |
return None | |
def aggregateResult(self, aggregate, nextResult): | |
return nextResult | |
def shouldVisitNextChild(self, node, currentResult): | |
return True | |
ParserRuleContext = None | |
class ParseTreeListener(object): | |
def visitTerminal(self, node:TerminalNode): | |
pass | |
def visitErrorNode(self, node:ErrorNode): | |
pass | |
def enterEveryRule(self, ctx:ParserRuleContext): | |
pass | |
def exitEveryRule(self, ctx:ParserRuleContext): | |
pass | |
del ParserRuleContext | |
class TerminalNodeImpl(TerminalNode): | |
__slots__ = ('parentCtx', 'symbol') | |
def __init__(self, symbol:Token): | |
self.parentCtx = None | |
self.symbol = symbol | |
def __setattr__(self, key, value): | |
super().__setattr__(key, value) | |
def getChild(self, i:int): | |
return None | |
def getSymbol(self): | |
return self.symbol | |
def getParent(self): | |
return self.parentCtx | |
def getPayload(self): | |
return self.symbol | |
def getSourceInterval(self): | |
if self.symbol is None: | |
return INVALID_INTERVAL | |
tokenIndex = self.symbol.tokenIndex | |
return (tokenIndex, tokenIndex) | |
def getChildCount(self): | |
return 0 | |
def accept(self, visitor:ParseTreeVisitor): | |
return visitor.visitTerminal(self) | |
def getText(self): | |
return self.symbol.text | |
def __str__(self): | |
if self.symbol.type == Token.EOF: | |
return "<EOF>" | |
else: | |
return self.symbol.text | |
# Represents a token that was consumed during resynchronization | |
# rather than during a valid match operation. For example, | |
# we will create this kind of a node during single token insertion | |
# and deletion as well as during "consume until error recovery set" | |
# upon no viable alternative exceptions. | |
class ErrorNodeImpl(TerminalNodeImpl,ErrorNode): | |
def __init__(self, token:Token): | |
super().__init__(token) | |
def accept(self, visitor:ParseTreeVisitor): | |
return visitor.visitErrorNode(self) | |
class ParseTreeWalker(object): | |
DEFAULT = None | |
def walk(self, listener:ParseTreeListener, t:ParseTree): | |
""" | |
Performs a walk on the given parse tree starting at the root and going down recursively | |
with depth-first search. On each node, {@link ParseTreeWalker#enterRule} is called before | |
recursively walking down into child nodes, then | |
{@link ParseTreeWalker#exitRule} is called after the recursive call to wind up. | |
@param listener The listener used by the walker to process grammar rules | |
@param t The parse tree to be walked on | |
""" | |
if isinstance(t, ErrorNode): | |
listener.visitErrorNode(t) | |
return | |
elif isinstance(t, TerminalNode): | |
listener.visitTerminal(t) | |
return | |
self.enterRule(listener, t) | |
for child in t.getChildren(): | |
self.walk(listener, child) | |
self.exitRule(listener, t) | |
# | |
# The discovery of a rule node, involves sending two events: the generic | |
# {@link ParseTreeListener#enterEveryRule} and a | |
# {@link RuleContext}-specific event. First we trigger the generic and then | |
# the rule specific. We to them in reverse order upon finishing the node. | |
# | |
def enterRule(self, listener:ParseTreeListener, r:RuleNode): | |
""" | |
Enters a grammar rule by first triggering the generic event {@link ParseTreeListener#enterEveryRule} | |
then by triggering the event specific to the given parse tree node | |
@param listener The listener responding to the trigger events | |
@param r The grammar rule containing the rule context | |
""" | |
ctx = r.getRuleContext() | |
listener.enterEveryRule(ctx) | |
ctx.enterRule(listener) | |
def exitRule(self, listener:ParseTreeListener, r:RuleNode): | |
""" | |
Exits a grammar rule by first triggering the event specific to the given parse tree node | |
then by triggering the generic event {@link ParseTreeListener#exitEveryRule} | |
@param listener The listener responding to the trigger events | |
@param r The grammar rule containing the rule context | |
""" | |
ctx = r.getRuleContext() | |
ctx.exitRule(listener) | |
listener.exitEveryRule(ctx) | |
ParseTreeWalker.DEFAULT = ParseTreeWalker() | |