Spaces:
Paused
Paused
| # 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. | |
| #* A rule invocation record for parsing. | |
| # | |
| # Contains all of the information about the current rule not stored in the | |
| # RuleContext. It handles parse tree children list, Any ATN state | |
| # tracing, and the default values available for rule indications: | |
| # start, stop, rule index, current alt number, current | |
| # ATN state. | |
| # | |
| # Subclasses made for each rule and grammar track the parameters, | |
| # return values, locals, and labels specific to that rule. These | |
| # are the objects that are returned from rules. | |
| # | |
| # Note text is not an actual field of a rule return value; it is computed | |
| # from start and stop using the input stream's toString() method. I | |
| # could add a ctor to this so that we can pass in and store the input | |
| # stream, but I'm not sure we want to do that. It would seem to be undefined | |
| # to get the .text property anyway if the rule matches tokens from multiple | |
| # input streams. | |
| # | |
| # I do not use getters for fields of objects that are used simply to | |
| # group values such as this aggregate. The getters/setters are there to | |
| # satisfy the superclass interface. | |
| from antlr4.RuleContext import RuleContext | |
| from antlr4.Token import Token | |
| from antlr4.tree.Tree import ParseTreeListener, ParseTree, TerminalNodeImpl, ErrorNodeImpl, TerminalNode, \ | |
| INVALID_INTERVAL | |
| # need forward declaration | |
| ParserRuleContext = None | |
| class ParserRuleContext(RuleContext): | |
| __slots__ = ('children', 'start', 'stop', 'exception') | |
| def __init__(self, parent:ParserRuleContext = None, invokingStateNumber:int = None ): | |
| super().__init__(parent, invokingStateNumber) | |
| #* If we are debugging or building a parse tree for a visitor, | |
| # we need to track all of the tokens and rule invocations associated | |
| # with this rule's context. This is empty for parsing w/o tree constr. | |
| # operation because we don't the need to track the details about | |
| # how we parse this rule. | |
| #/ | |
| self.children = None | |
| self.start = None | |
| self.stop = None | |
| # The exception that forced this rule to return. If the rule successfully | |
| # completed, this is {@code null}. | |
| self.exception = None | |
| #* COPY a ctx (I'm deliberately not using copy constructor)#/ | |
| # | |
| # This is used in the generated parser code to flip a generic XContext | |
| # node for rule X to a YContext for alt label Y. In that sense, it is | |
| # not really a generic copy function. | |
| # | |
| # If we do an error sync() at start of a rule, we might add error nodes | |
| # to the generic XContext so this function must copy those nodes to | |
| # the YContext as well else they are lost! | |
| #/ | |
| def copyFrom(self, ctx:ParserRuleContext): | |
| # from RuleContext | |
| self.parentCtx = ctx.parentCtx | |
| self.invokingState = ctx.invokingState | |
| self.children = None | |
| self.start = ctx.start | |
| self.stop = ctx.stop | |
| # copy any error nodes to alt label node | |
| if ctx.children is not None: | |
| self.children = [] | |
| # reset parent pointer for any error nodes | |
| for child in ctx.children: | |
| if isinstance(child, ErrorNodeImpl): | |
| self.children.append(child) | |
| child.parentCtx = self | |
| # Double dispatch methods for listeners | |
| def enterRule(self, listener:ParseTreeListener): | |
| pass | |
| def exitRule(self, listener:ParseTreeListener): | |
| pass | |
| #* Does not set parent link; other add methods do that#/ | |
| def addChild(self, child:ParseTree): | |
| if self.children is None: | |
| self.children = [] | |
| self.children.append(child) | |
| return child | |
| #* Used by enterOuterAlt to toss out a RuleContext previously added as | |
| # we entered a rule. If we have # label, we will need to remove | |
| # generic ruleContext object. | |
| #/ | |
| def removeLastChild(self): | |
| if self.children is not None: | |
| del self.children[len(self.children)-1] | |
| def addTokenNode(self, token:Token): | |
| node = TerminalNodeImpl(token) | |
| self.addChild(node) | |
| node.parentCtx = self | |
| return node | |
| def addErrorNode(self, badToken:Token): | |
| node = ErrorNodeImpl(badToken) | |
| self.addChild(node) | |
| node.parentCtx = self | |
| return node | |
| def getChild(self, i:int, ttype:type = None): | |
| if ttype is None: | |
| return self.children[i] if len(self.children)>i else None | |
| else: | |
| for child in self.getChildren(): | |
| if not isinstance(child, ttype): | |
| continue | |
| if i==0: | |
| return child | |
| i -= 1 | |
| return None | |
| def getChildren(self, predicate = None): | |
| if self.children is not None: | |
| for child in self.children: | |
| if predicate is not None and not predicate(child): | |
| continue | |
| yield child | |
| def getToken(self, ttype:int, i:int): | |
| for child in self.getChildren(): | |
| if not isinstance(child, TerminalNode): | |
| continue | |
| if child.symbol.type != ttype: | |
| continue | |
| if i==0: | |
| return child | |
| i -= 1 | |
| return None | |
| def getTokens(self, ttype:int ): | |
| if self.getChildren() is None: | |
| return [] | |
| tokens = [] | |
| for child in self.getChildren(): | |
| if not isinstance(child, TerminalNode): | |
| continue | |
| if child.symbol.type != ttype: | |
| continue | |
| tokens.append(child) | |
| return tokens | |
| def getTypedRuleContext(self, ctxType:type, i:int): | |
| return self.getChild(i, ctxType) | |
| def getTypedRuleContexts(self, ctxType:type): | |
| children = self.getChildren() | |
| if children is None: | |
| return [] | |
| contexts = [] | |
| for child in children: | |
| if not isinstance(child, ctxType): | |
| continue | |
| contexts.append(child) | |
| return contexts | |
| def getChildCount(self): | |
| return len(self.children) if self.children else 0 | |
| def getSourceInterval(self): | |
| if self.start is None or self.stop is None: | |
| return INVALID_INTERVAL | |
| else: | |
| return (self.start.tokenIndex, self.stop.tokenIndex) | |
| RuleContext.EMPTY = ParserRuleContext() | |
| class InterpreterRuleContext(ParserRuleContext): | |
| def __init__(self, parent:ParserRuleContext, invokingStateNumber:int, ruleIndex:int): | |
| super().__init__(parent, invokingStateNumber) | |
| self.ruleIndex = ruleIndex | |