RuleContext.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  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. # A rule context is a record of a single rule invocation. It knows
  6. # which context invoked it, if any. If there is no parent context, then
  7. # naturally the invoking state is not valid. The parent link
  8. # provides a chain upwards from the current rule invocation to the root
  9. # of the invocation tree, forming a stack. We actually carry no
  10. # information about the rule associated with this context (except
  11. # when parsing). We keep only the state number of the invoking state from
  12. # the ATN submachine that invoked this. Contrast this with the s
  13. # pointer inside ParserRuleContext that tracks the current state
  14. # being "executed" for the current rule.
  15. #
  16. # The parent contexts are useful for computing lookahead sets and
  17. # getting error information.
  18. #
  19. # These objects are used during parsing and prediction.
  20. # For the special case of parsers, we use the subclass
  21. # ParserRuleContext.
  22. #
  23. # @see ParserRuleContext
  24. #/
  25. from io import StringIO
  26. from antlr4.tree.Tree import RuleNode, INVALID_INTERVAL, ParseTreeVisitor
  27. from antlr4.tree.Trees import Trees
  28. # need forward declarations
  29. RuleContext = None
  30. Parser = None
  31. class RuleContext(RuleNode):
  32. __slots__ = ('parentCtx', 'invokingState')
  33. EMPTY = None
  34. def __init__(self, parent:RuleContext=None, invokingState:int=-1):
  35. super().__init__()
  36. # What context invoked this rule?
  37. self.parentCtx = parent
  38. # What state invoked the rule associated with this context?
  39. # The "return address" is the followState of invokingState
  40. # If parent is null, this should be -1.
  41. self.invokingState = invokingState
  42. def depth(self):
  43. n = 0
  44. p = self
  45. while p is not None:
  46. p = p.parentCtx
  47. n += 1
  48. return n
  49. # A context is empty if there is no invoking state; meaning nobody call
  50. # current context.
  51. def isEmpty(self):
  52. return self.invokingState == -1
  53. # satisfy the ParseTree / SyntaxTree interface
  54. def getSourceInterval(self):
  55. return INVALID_INTERVAL
  56. def getRuleContext(self):
  57. return self
  58. def getPayload(self):
  59. return self
  60. # Return the combined text of all child nodes. This method only considers
  61. # tokens which have been added to the parse tree.
  62. # <p>
  63. # Since tokens on hidden channels (e.g. whitespace or comments) are not
  64. # added to the parse trees, they will not appear in the output of this
  65. # method.
  66. #/
  67. def getText(self):
  68. if self.getChildCount() == 0:
  69. return ""
  70. with StringIO() as builder:
  71. for child in self.getChildren():
  72. builder.write(child.getText())
  73. return builder.getvalue()
  74. def getRuleIndex(self):
  75. return -1
  76. # For rule associated with this parse tree internal node, return
  77. # the outer alternative number used to match the input. Default
  78. # implementation does not compute nor store this alt num. Create
  79. # a subclass of ParserRuleContext with backing field and set
  80. # option contextSuperClass.
  81. # to set it.
  82. def getAltNumber(self):
  83. return 0 # should use ATN.INVALID_ALT_NUMBER but won't compile
  84. # Set the outer alternative number for this context node. Default
  85. # implementation does nothing to avoid backing field overhead for
  86. # trees that don't need it. Create
  87. # a subclass of ParserRuleContext with backing field and set
  88. # option contextSuperClass.
  89. def setAltNumber(self, altNumber:int):
  90. pass
  91. def getChild(self, i:int):
  92. return None
  93. def getChildCount(self):
  94. return 0
  95. def getChildren(self):
  96. for c in []:
  97. yield c
  98. def accept(self, visitor:ParseTreeVisitor):
  99. return visitor.visitChildren(self)
  100. # # Call this method to view a parse tree in a dialog box visually.#/
  101. # public Future<JDialog> inspect(@Nullable Parser parser) {
  102. # List<String> ruleNames = parser != null ? Arrays.asList(parser.getRuleNames()) : null;
  103. # return inspect(ruleNames);
  104. # }
  105. #
  106. # public Future<JDialog> inspect(@Nullable List<String> ruleNames) {
  107. # TreeViewer viewer = new TreeViewer(ruleNames, this);
  108. # return viewer.open();
  109. # }
  110. #
  111. # # Save this tree in a postscript file#/
  112. # public void save(@Nullable Parser parser, String fileName)
  113. # throws IOException, PrintException
  114. # {
  115. # List<String> ruleNames = parser != null ? Arrays.asList(parser.getRuleNames()) : null;
  116. # save(ruleNames, fileName);
  117. # }
  118. #
  119. # # Save this tree in a postscript file using a particular font name and size#/
  120. # public void save(@Nullable Parser parser, String fileName,
  121. # String fontName, int fontSize)
  122. # throws IOException
  123. # {
  124. # List<String> ruleNames = parser != null ? Arrays.asList(parser.getRuleNames()) : null;
  125. # save(ruleNames, fileName, fontName, fontSize);
  126. # }
  127. #
  128. # # Save this tree in a postscript file#/
  129. # public void save(@Nullable List<String> ruleNames, String fileName)
  130. # throws IOException, PrintException
  131. # {
  132. # Trees.writePS(this, ruleNames, fileName);
  133. # }
  134. #
  135. # # Save this tree in a postscript file using a particular font name and size#/
  136. # public void save(@Nullable List<String> ruleNames, String fileName,
  137. # String fontName, int fontSize)
  138. # throws IOException
  139. # {
  140. # Trees.writePS(this, ruleNames, fileName, fontName, fontSize);
  141. # }
  142. #
  143. # # Print out a whole tree, not just a node, in LISP format
  144. # # (root child1 .. childN). Print just a node if this is a leaf.
  145. # # We have to know the recognizer so we can get rule names.
  146. # #/
  147. # @Override
  148. # public String toStringTree(@Nullable Parser recog) {
  149. # return Trees.toStringTree(this, recog);
  150. # }
  151. #
  152. # Print out a whole tree, not just a node, in LISP format
  153. # (root child1 .. childN). Print just a node if this is a leaf.
  154. #
  155. def toStringTree(self, ruleNames:list=None, recog:Parser=None):
  156. return Trees.toStringTree(self, ruleNames=ruleNames, recog=recog)
  157. # }
  158. #
  159. # @Override
  160. # public String toStringTree() {
  161. # return toStringTree((List<String>)null);
  162. # }
  163. #
  164. def __str__(self):
  165. return self.toString(None, None)
  166. # @Override
  167. # public String toString() {
  168. # return toString((List<String>)null, (RuleContext)null);
  169. # }
  170. #
  171. # public final String toString(@Nullable Recognizer<?,?> recog) {
  172. # return toString(recog, ParserRuleContext.EMPTY);
  173. # }
  174. #
  175. # public final String toString(@Nullable List<String> ruleNames) {
  176. # return toString(ruleNames, null);
  177. # }
  178. #
  179. # // recog null unless ParserRuleContext, in which case we use subclass toString(...)
  180. # public String toString(@Nullable Recognizer<?,?> recog, @Nullable RuleContext stop) {
  181. # String[] ruleNames = recog != null ? recog.getRuleNames() : null;
  182. # List<String> ruleNamesList = ruleNames != null ? Arrays.asList(ruleNames) : null;
  183. # return toString(ruleNamesList, stop);
  184. # }
  185. def toString(self, ruleNames:list, stop:RuleContext)->str:
  186. with StringIO() as buf:
  187. p = self
  188. buf.write("[")
  189. while p is not None and p is not stop:
  190. if ruleNames is None:
  191. if not p.isEmpty():
  192. buf.write(str(p.invokingState))
  193. else:
  194. ri = p.getRuleIndex()
  195. ruleName = ruleNames[ri] if ri >= 0 and ri < len(ruleNames) else str(ri)
  196. buf.write(ruleName)
  197. if p.parentCtx is not None and (ruleNames is not None or not p.parentCtx.isEmpty()):
  198. buf.write(" ")
  199. p = p.parentCtx
  200. buf.write("]")
  201. return buf.getvalue()