def addDFAEdge(self, from_: DFAState, tk: int, to: DFAState = None, cfgs: ATNConfigSet = None) -> DFAState: if to is None and cfgs is not None: # leading to this call, ATNConfigSet.hasSemanticContext is used as a # marker indicating dynamic predicate evaluation makes this edge # dependent on the specific input sequence, so the static edge in the # DFA should be omitted. The target DFAState is still created since # execATN has the ability to resynchronize with the DFA state cache # following the predicate evaluation step. # # TJP notes: next time through the DFA, we see a pred again and eval. # If that gets us to a previously created (but dangling) DFA # state, we can continue in pure DFA mode from there. #/ suppressEdge = cfgs.hasSemanticContext cfgs.hasSemanticContext = False to = self.addDFAState(cfgs) if suppressEdge: return to # add the edge if tk < self.MIN_DFA_EDGE or tk > self.MAX_DFA_EDGE: # Only track edges within the DFA bounds return to if self.debug: print("EDGE " + str(from_) + " -> " + str(to) + " upon " + chr(tk)) if from_.edges is None: # make room for tokens 1..n and -1 masquerading as index 0 from_.edges = [None] * (self.MAX_DFA_EDGE - self.MIN_DFA_EDGE + 1) from_.edges[tk - self.MIN_DFA_EDGE] = to # connect return to
def addDFAEdge(self, from_:DFAState, tk:int, to:DFAState=None, cfgs:ATNConfigSet=None) -> DFAState: if to is None and cfgs is not None: # leading to this call, ATNConfigSet.hasSemanticContext is used as a # marker indicating dynamic predicate evaluation makes this edge # dependent on the specific input sequence, so the static edge in the # DFA should be omitted. The target DFAState is still created since # execATN has the ability to resynchronize with the DFA state cache # following the predicate evaluation step. # # TJP notes: next time through the DFA, we see a pred again and eval. # If that gets us to a previously created (but dangling) DFA # state, we can continue in pure DFA mode from there. #/ suppressEdge = cfgs.hasSemanticContext cfgs.hasSemanticContext = False to = self.addDFAState(cfgs) if suppressEdge: return to # add the edge if tk < self.MIN_DFA_EDGE or tk > self.MAX_DFA_EDGE: # Only track edges within the DFA bounds return to if LexerATNSimulator.debug: print("EDGE " + str(from_) + " -> " + str(to) + " upon "+ chr(tk)) if from_.edges is None: # make room for tokens 1..n and -1 masquerading as index 0 from_.edges = [ None ] * (self.MAX_DFA_EDGE - self.MIN_DFA_EDGE + 1) from_.edges[tk - self.MIN_DFA_EDGE] = to # connect return to
def getEpsilonTarget(self, input: InputStream, config: LexerATNConfig, t: Transition, configs: ATNConfigSet, speculative: bool, treatEofAsEpsilon: bool): c = None if t.serializationType == Transition.RULE: newContext = SingletonPredictionContext.create( config.context, t.followState.stateNumber) c = LexerATNConfig(state=t.target, config=config, context=newContext) elif t.serializationType == Transition.PRECEDENCE: raise UnsupportedOperationException( "Precedence predicates are not supported in lexers.") elif t.serializationType == Transition.PREDICATE: # Track traversing semantic predicates. If we traverse, # we cannot add a DFA state for this "reach" computation # because the DFA would not test the predicate again in the # future. Rather than creating collections of semantic predicates # like v3 and testing them on prediction, v4 will test them on the # fly all the time using the ATN not the DFA. This is slower but # semantically it's not used that often. One of the key elements to # this predicate mechanism is not adding DFA states that see # predicates immediately afterwards in the ATN. For example, # a : ID {p1}? | ID {p2}? ; # should create the start state for rule 'a' (to save start state # competition), but should not create target of ID state. The # collection of ATN states the following ID references includes # states reached by traversing predicates. Since this is when we # test them, we cannot cash the DFA state target of ID. if self.debug: print("EVAL rule " + str(t.ruleIndex) + ":" + str(t.predIndex)) configs.hasSemanticContext = True if self.evaluatePredicate(input, t.ruleIndex, t.predIndex, speculative): c = LexerATNConfig(state=t.target, config=config) elif t.serializationType == Transition.ACTION: if config.context is None or config.context.hasEmptyPath(): # execute actions anywhere in the start rule for a token. # # TODO: if the entry rule is invoked recursively, some # actions may be executed during the recursive call. The # problem can appear when hasEmptyPath() is true but # isEmpty() is false. In this case, the config needs to be # split into two contexts - one with just the empty path # and another with everything but the empty path. # Unfortunately, the current algorithm does not allow # getEpsilonTarget to return two configurations, so # additional modifications are needed before we can support # the split operation. lexerActionExecutor = LexerActionExecutor.append( config.lexerActionExecutor, self.atn.lexerActions[t.actionIndex]) c = LexerATNConfig(state=t.target, config=config, lexerActionExecutor=lexerActionExecutor) else: # ignore actions in referenced rules c = LexerATNConfig(state=t.target, config=config) elif t.serializationType == Transition.EPSILON: c = LexerATNConfig(state=t.target, config=config) elif t.serializationType in [ Transition.ATOM, Transition.RANGE, Transition.SET ]: if treatEofAsEpsilon: if t.matches(Token.EOF, 0, 0xFFFF): c = LexerATNConfig(state=t.target, config=config) return c
def getEpsilonTarget(self, input:InputStream, config:LexerATNConfig, t:Transition, configs:ATNConfigSet, speculative:bool, treatEofAsEpsilon:bool): c = None if t.serializationType==Transition.RULE: newContext = SingletonPredictionContext.create(config.context, t.followState.stateNumber) c = LexerATNConfig(state=t.target, config=config, context=newContext) elif t.serializationType==Transition.PRECEDENCE: raise UnsupportedOperationException("Precedence predicates are not supported in lexers.") elif t.serializationType==Transition.PREDICATE: # Track traversing semantic predicates. If we traverse, # we cannot add a DFA state for this "reach" computation # because the DFA would not test the predicate again in the # future. Rather than creating collections of semantic predicates # like v3 and testing them on prediction, v4 will test them on the # fly all the time using the ATN not the DFA. This is slower but # semantically it's not used that often. One of the key elements to # this predicate mechanism is not adding DFA states that see # predicates immediately afterwards in the ATN. For example, # a : ID {p1}? | ID {p2}? ; # should create the start state for rule 'a' (to save start state # competition), but should not create target of ID state. The # collection of ATN states the following ID references includes # states reached by traversing predicates. Since this is when we # test them, we cannot cash the DFA state target of ID. if LexerATNSimulator.debug: print("EVAL rule "+ str(t.ruleIndex) + ":" + str(t.predIndex)) configs.hasSemanticContext = True if self.evaluatePredicate(input, t.ruleIndex, t.predIndex, speculative): c = LexerATNConfig(state=t.target, config=config) elif t.serializationType==Transition.ACTION: if config.context is None or config.context.hasEmptyPath(): # execute actions anywhere in the start rule for a token. # # TODO: if the entry rule is invoked recursively, some # actions may be executed during the recursive call. The # problem can appear when hasEmptyPath() is true but # isEmpty() is false. In this case, the config needs to be # split into two contexts - one with just the empty path # and another with everything but the empty path. # Unfortunately, the current algorithm does not allow # getEpsilonTarget to return two configurations, so # additional modifications are needed before we can support # the split operation. lexerActionExecutor = LexerActionExecutor.append(config.lexerActionExecutor, self.atn.lexerActions[t.actionIndex]) c = LexerATNConfig(state=t.target, config=config, lexerActionExecutor=lexerActionExecutor) else: # ignore actions in referenced rules c = LexerATNConfig(state=t.target, config=config) elif t.serializationType==Transition.EPSILON: c = LexerATNConfig(state=t.target, config=config) elif t.serializationType in [ Transition.ATOM, Transition.RANGE, Transition.SET ]: if treatEofAsEpsilon: if t.matches(Token.EOF, 0, 0xFFFF): c = LexerATNConfig(state=t.target, config=config) return c