Tree.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. # Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
  2. # Use of this file is governed by the BSD 3-clause license that
  3. # can be found in the LICENSE.txt file in the project root.
  4. #/
  5. # The basic notion of a tree has a parent, a payload, and a list of children.
  6. # It is the most abstract interface for all the trees used by ANTLR.
  7. #/
  8. from antlr4.Token import Token
  9. INVALID_INTERVAL = (-1, -2)
  10. class Tree(object):
  11. pass
  12. class SyntaxTree(Tree):
  13. pass
  14. class ParseTree(SyntaxTree):
  15. pass
  16. class RuleNode(ParseTree):
  17. pass
  18. class TerminalNode(ParseTree):
  19. pass
  20. class ErrorNode(TerminalNode):
  21. pass
  22. class ParseTreeVisitor(object):
  23. def visit(self, tree):
  24. return tree.accept(self)
  25. def visitChildren(self, node):
  26. result = self.defaultResult()
  27. n = node.getChildCount()
  28. for i in range(n):
  29. if not self.shouldVisitNextChild(node, result):
  30. return result
  31. c = node.getChild(i)
  32. childResult = c.accept(self)
  33. result = self.aggregateResult(result, childResult)
  34. return result
  35. def visitTerminal(self, node):
  36. return self.defaultResult()
  37. def visitErrorNode(self, node):
  38. return self.defaultResult()
  39. def defaultResult(self):
  40. return None
  41. def aggregateResult(self, aggregate, nextResult):
  42. return nextResult
  43. def shouldVisitNextChild(self, node, currentResult):
  44. return True
  45. ParserRuleContext = None
  46. class ParseTreeListener(object):
  47. def visitTerminal(self, node:TerminalNode):
  48. pass
  49. def visitErrorNode(self, node:ErrorNode):
  50. pass
  51. def enterEveryRule(self, ctx:ParserRuleContext):
  52. pass
  53. def exitEveryRule(self, ctx:ParserRuleContext):
  54. pass
  55. del ParserRuleContext
  56. class TerminalNodeImpl(TerminalNode):
  57. __slots__ = ('parentCtx', 'symbol')
  58. def __init__(self, symbol:Token):
  59. self.parentCtx = None
  60. self.symbol = symbol
  61. def __setattr__(self, key, value):
  62. super().__setattr__(key, value)
  63. def getChild(self, i:int):
  64. return None
  65. def getSymbol(self):
  66. return self.symbol
  67. def getParent(self):
  68. return self.parentCtx
  69. def getPayload(self):
  70. return self.symbol
  71. def getSourceInterval(self):
  72. if self.symbol is None:
  73. return INVALID_INTERVAL
  74. tokenIndex = self.symbol.tokenIndex
  75. return (tokenIndex, tokenIndex)
  76. def getChildCount(self):
  77. return 0
  78. def accept(self, visitor:ParseTreeVisitor):
  79. return visitor.visitTerminal(self)
  80. def getText(self):
  81. return self.symbol.text
  82. def __str__(self):
  83. if self.symbol.type == Token.EOF:
  84. return "<EOF>"
  85. else:
  86. return self.symbol.text
  87. # Represents a token that was consumed during resynchronization
  88. # rather than during a valid match operation. For example,
  89. # we will create this kind of a node during single token insertion
  90. # and deletion as well as during "consume until error recovery set"
  91. # upon no viable alternative exceptions.
  92. class ErrorNodeImpl(TerminalNodeImpl,ErrorNode):
  93. def __init__(self, token:Token):
  94. super().__init__(token)
  95. def accept(self, visitor:ParseTreeVisitor):
  96. return visitor.visitErrorNode(self)
  97. class ParseTreeWalker(object):
  98. DEFAULT = None
  99. def walk(self, listener:ParseTreeListener, t:ParseTree):
  100. """
  101. Performs a walk on the given parse tree starting at the root and going down recursively
  102. with depth-first search. On each node, {@link ParseTreeWalker#enterRule} is called before
  103. recursively walking down into child nodes, then
  104. {@link ParseTreeWalker#exitRule} is called after the recursive call to wind up.
  105. @param listener The listener used by the walker to process grammar rules
  106. @param t The parse tree to be walked on
  107. """
  108. if isinstance(t, ErrorNode):
  109. listener.visitErrorNode(t)
  110. return
  111. elif isinstance(t, TerminalNode):
  112. listener.visitTerminal(t)
  113. return
  114. self.enterRule(listener, t)
  115. for child in t.getChildren():
  116. self.walk(listener, child)
  117. self.exitRule(listener, t)
  118. #
  119. # The discovery of a rule node, involves sending two events: the generic
  120. # {@link ParseTreeListener#enterEveryRule} and a
  121. # {@link RuleContext}-specific event. First we trigger the generic and then
  122. # the rule specific. We to them in reverse order upon finishing the node.
  123. #
  124. def enterRule(self, listener:ParseTreeListener, r:RuleNode):
  125. """
  126. Enters a grammar rule by first triggering the generic event {@link ParseTreeListener#enterEveryRule}
  127. then by triggering the event specific to the given parse tree node
  128. @param listener The listener responding to the trigger events
  129. @param r The grammar rule containing the rule context
  130. """
  131. ctx = r.getRuleContext()
  132. listener.enterEveryRule(ctx)
  133. ctx.enterRule(listener)
  134. def exitRule(self, listener:ParseTreeListener, r:RuleNode):
  135. """
  136. Exits a grammar rule by first triggering the event specific to the given parse tree node
  137. then by triggering the generic event {@link ParseTreeListener#exitEveryRule}
  138. @param listener The listener responding to the trigger events
  139. @param r The grammar rule containing the rule context
  140. """
  141. ctx = r.getRuleContext()
  142. ctx.exitRule(listener)
  143. listener.exitEveryRule(ctx)
  144. ParseTreeWalker.DEFAULT = ParseTreeWalker()