1 /*
2  * Copyright (c) 2012-2018 The ANTLR Project. All rights reserved.
3  * Use of this file is governed by the BSD 3-clause license that
4  * can be found in the LICENSE.txt file in the project root.
5  */
6 
7 module antlr.v4.runtime.atn.ATN;
8 
9 import std.conv;
10 import antlr.v4.runtime.IllegalArgumentException;
11 import antlr.v4.runtime.RuleContext;
12 import antlr.v4.runtime.atn.ATNState;
13 import antlr.v4.runtime.atn.ATNType;
14 import antlr.v4.runtime.atn.DecisionState;
15 import antlr.v4.runtime.atn.RuleStartState;
16 import antlr.v4.runtime.atn.RuleStopState;
17 import antlr.v4.runtime.atn.LL1Analyzer;
18 import antlr.v4.runtime.atn.RuleTransition;
19 import antlr.v4.runtime.Token;
20 import antlr.v4.runtime.TokenConstantDefinition;
21 import antlr.v4.runtime.atn.TokensStartState;
22 import antlr.v4.runtime.atn.LexerAction;
23 import antlr.v4.runtime.misc.IntervalSet;
24 
25 // Class ATN
26 /**
27  * Class implementation adapted from Java code
28  */
29 class ATN
30 {
31 
32     public static immutable int INVALID_ALT_NUMBER = 0;
33 
34     public ATNState[] states;
35 
36     /**
37      * @uml
38      * Each subrule/rule is a decision point and we must track them so we
39      * can go back later and build DFA predictors for them.  This includes
40      * all the rules, subrules, optional blocks, ()+, ()* etc...
41      */
42     public DecisionState[] decisionToState;
43 
44     /**
45      * @uml
46      * Maps from rule index to starting state number.
47      */
48     public RuleStartState[] ruleToStartState;
49 
50     /**
51      * @uml
52      * Maps from rule index to stop state number.
53      */
54     public RuleStopState[] ruleToStopState;
55 
56     public TokensStartState[string] modeNameToStartState;
57 
58     /**
59      * @uml
60      * The type of the ATN.
61      */
62     public ATNType grammarType;
63 
64     /**
65      * @uml
66      * The maximum value for any symbol recognized by a transition in the ATN.
67      */
68     public int maxTokenType;
69 
70     /**
71      * @uml
72      * For lexer ATNs, this maps the rule index to the resulting token type.
73      * For parser ATNs, this maps the rule index to the generated bypass token
74      * type if the
75      * {@link ATNDeserializationOptions#isGenerateRuleBypassTransitions}
76      * deserialization option was specified; otherwise, this is {@code null}.
77      */
78     public int[] ruleToTokenType;
79 
80     /**
81      * @uml
82      * For lexer ATNs, this is an array of {@link LexerAction} objects which may
83      * be referenced by action transitions in the ATN.
84      */
85     public LexerAction[] lexerActions;
86 
87     public TokensStartState[] modeToStartState;
88 
89     /**
90      * @uml
91      * Used for runtime deserialization of ATNs from strings
92      */
93     public this(ATNType grammarType, int maxTokenType)
94     {
95         this.grammarType = grammarType;
96         this.maxTokenType = maxTokenType;
97     }
98 
99     /**
100      * @uml
101      * Compute the set of valid tokens that can occur starting in state {@code s}.
102      * If {@code ctx} is null, the set of tokens will not include what can follow
103      * the rule surrounding {@code s}. In other words, the set will be
104      * restricted to tokens reachable staying within {@code s}'s rule.
105      */
106     public IntervalSet nextTokens(ATNState s, RuleContext ctx)
107     {
108         LL1Analyzer anal = new LL1Analyzer(this);
109         IntervalSet next = anal.LOOK(s, ctx);
110         return next;
111     }
112 
113     /**
114      * @uml
115      * Compute the set of valid tokens that can occur starting in {@code s} and
116      * staying in same rule. {@link Token#EPSILON} is in set if we reach end of
117      * rule.
118      */
119     public IntervalSet nextTokens(ATNState s)
120     {
121         debug {
122             import std.stdio;
123             writefln("ATN: nextTokens(ATNState s) %s", s);
124         }
125         if (s.nextTokenWithinRule !is null ) {
126             return s.nextTokenWithinRule;
127         }
128         s.nextTokenWithinRule = nextTokens(s, null);
129         s.nextTokenWithinRule.setReadonly(true);
130         return s.nextTokenWithinRule;
131     }
132 
133     public void addState(ATNState state)
134     {
135         if (state !is null) {
136             state.atn = this;
137             state.stateNumber = to!int(states.length);
138         }
139         states ~= state;
140     }
141 
142     public void removeState(ATNState state)
143     {
144         states[state.stateNumber] = null; // just free mem, don't shift states in list
145     }
146 
147     public int defineDecisionState(DecisionState s)
148     {
149         decisionToState ~= s;
150         s.decision = to!int(decisionToState.length)-1;
151         return s.decision;
152     }
153 
154     public DecisionState getDecisionState(int decision)
155     {
156         if (decisionToState.length > 0) {
157             return decisionToState[decision];
158         }
159         return null;
160     }
161 
162     public int getNumberOfDecisions()
163     {
164         return to!int(decisionToState.length);
165     }
166 
167     /**
168      * @uml
169      * Computes the set of input symbols which could follow ATN state number
170      * {@code stateNumber} in the specified full {@code context}. This method
171      * considers the complete parser context, but does not evaluate semantic
172      * predicates (i.e. all predicates encountered during the calculation are
173      * assumed true). If a path in the ATN exists from the starting state to the
174      * {@link RuleStopState} of the outermost context without matching any
175      * symbols, {@link Token#EOF} is added to the returned set.
176      *
177      * <p>If {@code context} is {@code null}, it is treated as
178      * {@link ParserRuleContext#EMPTY}.</p>
179      *
180      *  @param stateNumber the ATN state number
181      *  @param context the full parse context
182      *  @return The set of potentially valid input symbols which could follow the
183      *  specified state in the specified context.
184      *  @throws IllegalArgumentException if the ATN does not contain a state with
185      *  number {@code stateNumber}
186      */
187     public IntervalSet getExpectedTokens(int stateNumber, RuleContext context)
188     {
189         if (stateNumber < 0 || stateNumber >= states.length) {
190             throw new IllegalArgumentException("Invalid state number.");
191         }
192 
193         RuleContext ctx = context;
194         ATNState s = states[stateNumber];
195         IntervalSet following = nextTokens(s);
196         if (!following.contains(TokenConstantDefinition.EPSILON)) {
197             return following;
198         }
199 
200         IntervalSet expected = new IntervalSet();
201         expected.addAll(following);
202         expected.remove(TokenConstantDefinition.EPSILON);
203         while (ctx !is null && ctx.invokingState >= 0 && following.contains(TokenConstantDefinition.EPSILON)) {
204             ATNState invokingState = states[ctx.invokingState];
205             RuleTransition rt = cast(RuleTransition)invokingState.transition(0);
206             following = nextTokens(rt.followState);
207             expected.addAll(following);
208             expected.remove(TokenConstantDefinition.EPSILON);
209             ctx = ctx.parent;
210         }
211 
212         if (following.contains(TokenConstantDefinition.EPSILON)) {
213             expected.add(TokenConstantDefinition.EOF);
214         }
215 
216         return expected;
217     }
218 
219 }