# 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): 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