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. | |
| #/ | |
| from antlr4.IntervalSet import IntervalSet | |
| from antlr4.RuleContext import RuleContext | |
| from antlr4.Token import Token | |
| from antlr4.atn.ATNType import ATNType | |
| from antlr4.atn.ATNState import ATNState, DecisionState | |
| class ATN(object): | |
| __slots__ = ( | |
| 'grammarType', 'maxTokenType', 'states', 'decisionToState', | |
| 'ruleToStartState', 'ruleToStopState', 'modeNameToStartState', | |
| 'ruleToTokenType', 'lexerActions', 'modeToStartState' | |
| ) | |
| INVALID_ALT_NUMBER = 0 | |
| # Used for runtime deserialization of ATNs from strings#/ | |
| def __init__(self, grammarType:ATNType , maxTokenType:int ): | |
| # The type of the ATN. | |
| self.grammarType = grammarType | |
| # The maximum value for any symbol recognized by a transition in the ATN. | |
| self.maxTokenType = maxTokenType | |
| self.states = [] | |
| # Each subrule/rule is a decision point and we must track them so we | |
| # can go back later and build DFA predictors for them. This includes | |
| # all the rules, subrules, optional blocks, ()+, ()* etc... | |
| self.decisionToState = [] | |
| # Maps from rule index to starting state number. | |
| self.ruleToStartState = [] | |
| # Maps from rule index to stop state number. | |
| self.ruleToStopState = None | |
| self.modeNameToStartState = dict() | |
| # For lexer ATNs, this maps the rule index to the resulting token type. | |
| # For parser ATNs, this maps the rule index to the generated bypass token | |
| # type if the | |
| # {@link ATNDeserializationOptions#isGenerateRuleBypassTransitions} | |
| # deserialization option was specified; otherwise, this is {@code null}. | |
| self.ruleToTokenType = None | |
| # For lexer ATNs, this is an array of {@link LexerAction} objects which may | |
| # be referenced by action transitions in the ATN. | |
| self.lexerActions = None | |
| self.modeToStartState = [] | |
| # Compute the set of valid tokens that can occur starting in state {@code s}. | |
| # If {@code ctx} is null, the set of tokens will not include what can follow | |
| # the rule surrounding {@code s}. In other words, the set will be | |
| # restricted to tokens reachable staying within {@code s}'s rule. | |
| def nextTokensInContext(self, s:ATNState, ctx:RuleContext): | |
| from antlr4.LL1Analyzer import LL1Analyzer | |
| anal = LL1Analyzer(self) | |
| return anal.LOOK(s, ctx=ctx) | |
| # Compute the set of valid tokens that can occur starting in {@code s} and | |
| # staying in same rule. {@link Token#EPSILON} is in set if we reach end of | |
| # rule. | |
| def nextTokensNoContext(self, s:ATNState): | |
| if s.nextTokenWithinRule is not None: | |
| return s.nextTokenWithinRule | |
| s.nextTokenWithinRule = self.nextTokensInContext(s, None) | |
| s.nextTokenWithinRule.readonly = True | |
| return s.nextTokenWithinRule | |
| def nextTokens(self, s:ATNState, ctx:RuleContext = None): | |
| if ctx==None: | |
| return self.nextTokensNoContext(s) | |
| else: | |
| return self.nextTokensInContext(s, ctx) | |
| def addState(self, state:ATNState): | |
| if state is not None: | |
| state.atn = self | |
| state.stateNumber = len(self.states) | |
| self.states.append(state) | |
| def removeState(self, state:ATNState): | |
| self.states[state.stateNumber] = None # just free mem, don't shift states in list | |
| def defineDecisionState(self, s:DecisionState): | |
| self.decisionToState.append(s) | |
| s.decision = len(self.decisionToState)-1 | |
| return s.decision | |
| def getDecisionState(self, decision:int): | |
| if len(self.decisionToState)==0: | |
| return None | |
| else: | |
| return self.decisionToState[decision] | |
| # Computes the set of input symbols which could follow ATN state number | |
| # {@code stateNumber} in the specified full {@code context}. This method | |
| # considers the complete parser context, but does not evaluate semantic | |
| # predicates (i.e. all predicates encountered during the calculation are | |
| # assumed true). If a path in the ATN exists from the starting state to the | |
| # {@link RuleStopState} of the outermost context without matching any | |
| # symbols, {@link Token#EOF} is added to the returned set. | |
| # | |
| # <p>If {@code context} is {@code null}, it is treated as | |
| # {@link ParserRuleContext#EMPTY}.</p> | |
| # | |
| # @param stateNumber the ATN state number | |
| # @param context the full parse context | |
| # @return The set of potentially valid input symbols which could follow the | |
| # specified state in the specified context. | |
| # @throws IllegalArgumentException if the ATN does not contain a state with | |
| # number {@code stateNumber} | |
| #/ | |
| def getExpectedTokens(self, stateNumber:int, ctx:RuleContext ): | |
| if stateNumber < 0 or stateNumber >= len(self.states): | |
| raise Exception("Invalid state number.") | |
| s = self.states[stateNumber] | |
| following = self.nextTokens(s) | |
| if Token.EPSILON not in following: | |
| return following | |
| expected = IntervalSet() | |
| expected.addSet(following) | |
| expected.removeOne(Token.EPSILON) | |
| while (ctx != None and ctx.invokingState >= 0 and Token.EPSILON in following): | |
| invokingState = self.states[ctx.invokingState] | |
| rt = invokingState.transitions[0] | |
| following = self.nextTokens(rt.followState) | |
| expected.addSet(following) | |
| expected.removeOne(Token.EPSILON) | |
| ctx = ctx.parentCtx | |
| if Token.EPSILON in following: | |
| expected.addOne(Token.EOF) | |
| return expected | |