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.LexerATNSimulator;
8 
9 import std.conv;
10 import std.format;
11 import std.stdio;
12 import antlr.v4.runtime.atn.ATNSimulator;
13 import antlr.v4.runtime.IntStreamConstant;
14 import antlr.v4.runtime.Lexer;
15 import antlr.v4.runtime.UnsupportedOperationException;
16 import antlr.v4.runtime.dfa.DFA;
17 import antlr.v4.runtime.dfa.DFAState;
18 import antlr.v4.runtime.atn.ATN;
19 import antlr.v4.runtime.atn.ATNState;
20 import antlr.v4.runtime.atn.ATNConfigSet;
21 import antlr.v4.runtime.atn.ATNConfig;
22 import antlr.v4.runtime.atn.LexerActionExecutor;
23 import antlr.v4.runtime.atn.LexerATNConfig;
24 import antlr.v4.runtime.atn.PredictionContext;
25 import antlr.v4.runtime.atn.RuleTransition;
26 import antlr.v4.runtime.atn.RuleStopState;
27 import antlr.v4.runtime.atn.PredictionContextCache;
28 import antlr.v4.runtime.atn.SimState;
29 import antlr.v4.runtime.atn.SingletonPredictionContext;
30 import antlr.v4.runtime.atn.PredicateTransition;
31 import antlr.v4.runtime.atn.Transition;
32 import antlr.v4.runtime.atn.TransitionStates;
33 import antlr.v4.runtime.atn.ActionTransition;
34 import antlr.v4.runtime.atn.OrderedATNConfigSet;
35 import antlr.v4.runtime.CharStream;
36 import antlr.v4.runtime.LexerNoViableAltException;
37 import antlr.v4.runtime.Token;
38 import antlr.v4.runtime.TokenConstantDefinition;
39 import antlr.v4.runtime.misc;
40 
41 // Class LexerATNSimulator
42 /**
43  * "dup" of ParserInterpreter
44  */
45 class LexerATNSimulator : ATNSimulator
46 {
47 
48     public static immutable int MIN_DFA_EDGE = 0;
49 
50     public static immutable int MAX_DFA_EDGE = 127;
51 
52     protected Lexer recog;
53 
54     /**
55      * @uml
56      * The current token's starting index into the character stream.
57      * Shared across DFA to ATN simulation in case the ATN fails and the
58      * DFA did not have a previous accept state. In this case, we use the
59      * ATN-generated exception object.
60      */
61     protected int startIndex = -1;
62 
63     /**
64      * @uml
65      * line number 1..n within the input
66      */
67     protected int line = 1;
68 
69     /**
70      * @uml
71      * The index of the character relative to the beginning of the line 0..n-1
72      */
73     protected int charPositionInLine = 0;
74 
75     public DFA[] decisionToDFA;
76 
77     protected int mode = Lexer.DEFAULT_MODE;
78 
79     protected SimState prevAccept;
80 
81     public static int match_calls = 0;
82 
83     public this(ATN atn, DFA[] decisionToDFA, PredictionContextCache sharedContextCache)
84     {
85         this(null, atn, decisionToDFA,sharedContextCache);
86     }
87 
88     public this(Lexer recog, ATN atn, DFA[] decisionToDFA, PredictionContextCache sharedContextCache)
89     {
90         super(atn, sharedContextCache);
91         this.decisionToDFA = decisionToDFA;
92         this.recog = recog;
93     }
94 
95     public void copyState(LexerATNSimulator simulator)
96     {
97         this.charPositionInLine = simulator.charPositionInLine;
98         this.line = simulator.line;
99         this.mode = simulator.mode;
100         this.startIndex = simulator.startIndex;
101     }
102 
103     public int match(CharStream input, int mode)
104     {
105         match_calls++;
106         this.mode = mode;
107         int mark = input.mark;
108         try {
109             this.startIndex = input.index;
110             this.prevAccept.reset;
111             DFA dfa = decisionToDFA[mode];
112             if (dfa.s0 is null) {
113                 return matchATN(input);
114             }
115             else {
116                 return execATN(input, dfa.s0);
117             }
118         }
119         finally {
120             input.release(mark);
121         }
122     }
123 
124     /**
125      * @uml
126      * @override
127      */
128     public override void reset()
129     {
130         prevAccept.reset();
131         startIndex = -1;
132         line = 1;
133         charPositionInLine = 0;
134         mode = Lexer.DEFAULT_MODE;
135     }
136 
137     /**
138      * @uml
139      * @override
140      */
141     public override void clearDFA()
142     {
143         for (int d = 0; d < decisionToDFA.length; d++) {
144             decisionToDFA[d] = new DFA(atn.getDecisionState(d), d);
145         }
146     }
147 
148     protected int matchATN(CharStream input)
149     {
150         ATNState startState = atn.modeToStartState[mode];
151         int old_mode = mode;
152         ATNConfigSet s0_closure = computeStartState(input, startState);
153         bool suppressEdge = s0_closure.hasSemanticContext;
154         s0_closure.hasSemanticContext = false;
155         DFAState next = addDFAState(s0_closure);
156         if (!suppressEdge) {
157             decisionToDFA[mode].s0 = next;
158         }
159         int predict = execATN(input, next);
160 
161         debug(LexerATNSimulator)
162             writefln("DFA after matchATN:\n%1$s\n", decisionToDFA[old_mode].toLexerString());
163         return predict;
164     }
165 
166     protected int execATN(CharStream input, DFAState ds0)
167     {
168         debug(LexerATNSimulator) {
169             writefln("enter exec index %s from %s", input.index, ds0.configs);
170         }
171 
172         if (ds0.isAcceptState) {
173             // allow zero-length tokens
174             captureSimState(prevAccept, input, ds0);
175         }
176         int t = input.LA(1);
177         DFAState s = ds0; // s is current/from DFA state
178 
179         while (true) { // while more work
180             debug(LexerATNSimulator) {
181                 writefln("execATN loop starting closure: %s\n", s.configs);
182             }
183             // As we move src->trg, src->trg, we keep track of the previous trg to
184             // avoid looking up the DFA state again, which is expensive.
185             // If the previous target was already part of the DFA, we might
186             // be able to avoid doing a reach operation upon t. If s!=null,
187             // it means that semantic predicates didn't prevent us from
188             // creating a DFA state. Once we know s!=null, we check to see if
189             // the DFA state has an edge already for t. If so, we can just reuse
190             // it's configuration set; there's no point in re-computing it.
191             // This is kind of like doing DFA simulation within the ATN
192             // simulation because DFA simulation is really just a way to avoid
193             // computing reach/closure sets. Technically, once we know that
194             // we have a previously added DFA state, we could jump over to
195             // the DFA simulator. But, that would mean popping back and forth
196             // a lot and making things more complicated algorithmically.
197             // This optimization makes a lot of sense for loops within DFA.
198             // A character will take us back to an existing DFA state
199             // that already has lots of edges out of it. e.g., .* in comments.
200             DFAState target = getExistingTargetState(s, t);
201             if (target is null) {
202                 target = computeTargetState(input, s, t);
203             }
204             if (target == ERROR) {
205                 break;
206             }
207             // If this is a consumable input element, make sure to consume before
208             // capturing the accept state so the input index, line, and char
209             // position accurately reflect the state of the interpreter at the
210             // end of the token.
211             if (t != IntStreamConstant.EOF) {
212                 consume(input);
213             }
214 
215             if (target.isAcceptState) {
216                 captureSimState(prevAccept, input, target);
217                 if (t == IntStreamConstant.EOF) {
218                     break;
219                 }
220             }
221             t = input.LA(1);
222             s = target; // flip; current DFA target becomes new src/from state
223         }
224         return failOrAccept(prevAccept, input, s.configs, t);
225     }
226 
227     /**
228      * @uml
229      * Get an existing target state for an edge in the DFA. If the target state
230      * for the edge has not yet been computed or is otherwise not available,
231      * this method returns {@code null}.
232      *
233      *  @param s The current DFA state
234      *  @param t The next input symbol
235      *  @return The existing target DFA state for the given input symbol
236      * {@code t}, or {@code null} if the target state for this edge is not
237      * already cached
238      */
239     public DFAState getExistingTargetState(DFAState s, int t)
240     {
241 	if (s.edges is null || t < MIN_DFA_EDGE || t > MAX_DFA_EDGE) {
242             return null;
243         }
244 
245         DFAState target = s.edges[t - MIN_DFA_EDGE];
246         if (target !is null)
247             debug(LexerATNSimulator) {
248                 writefln("reuse state %1$s"~
249                          " edge to %2$s", s.stateNumber, target.stateNumber);
250             }
251 
252         return target;
253     }
254 
255     /**
256      * @uml
257      * Compute a target state for an edge in the DFA, and attempt to add the
258      * computed state and corresponding edge to the DFA.
259      *
260      *  @param input The input stream
261      *  @param s The current DFA state
262      *  @param t The next input symbol
263      *
264      *  @return The computed target DFA state for the given input symbol
265      * {@code t}. If {@code t} does not lead to a valid DFA state, this method
266      * returns {@link #ERROR}.
267      */
268     protected DFAState computeTargetState(CharStream input, DFAState s, int t)
269     {
270 	ATNConfigSet reach = new OrderedATNConfigSet();
271 
272         // if we don't find an existing DFA state
273         // Fill reach starting from closure, following t transitions
274         getReachableConfigSet(input, s.configs, reach, t);
275 
276         if (reach.isEmpty()) { // we got nowhere on t from s
277             if (!reach.hasSemanticContext) {
278                 // we got nowhere on t, don't throw out this knowledge; it'd
279                 // cause a failover from DFA later.
280                 addDFAEdge(s, t, ERROR);
281             }
282 
283             // stop when we can't match any more char
284             return ERROR;
285         }
286 
287         // Add an edge from s to target DFA found/created for reach
288         return addDFAEdge(s, t, reach);
289     }
290 
291     protected int failOrAccept(SimState prevAccept, CharStream input, ATNConfigSet reach,
292                                int t)
293     {
294 	if (prevAccept.dfaState !is null) {
295             LexerActionExecutor lexerActionExecutor = prevAccept.dfaState.lexerActionExecutor;
296             accept(input, lexerActionExecutor, startIndex,
297                    prevAccept.index, prevAccept.line, prevAccept.charPos);
298             return prevAccept.dfaState.prediction;
299         }
300         else {
301             // if no accept and EOF is first char, return EOF
302             if (t==IntStreamConstant.EOF && input.index() == startIndex) {
303                 return TokenConstantDefinition.EOF;
304             }
305             throw new LexerNoViableAltException(recog, input, startIndex, reach);
306         }
307     }
308 
309     /**
310      * @uml
311      * Given a starting configuration set, figure out all ATN configurations
312      * we can reach upon input {@code t}. Parameter {@code reach} is a return
313      * parameter.
314      */
315     protected void getReachableConfigSet(CharStream input, ATNConfigSet closureATNConfigSet, ATNConfigSet reach,
316                                          int t)
317     {
318 	// this is used to skip processing for configs which have a lower priority
319         // than a config that already reached an accept state for the same rule
320         int skipAlt = ATN.INVALID_ALT_NUMBER;
321         foreach (ATNConfig c; closureATNConfigSet.configs) {
322             bool currentAltReachedAcceptState = c.alt == skipAlt;
323             if (currentAltReachedAcceptState && (cast(LexerATNConfig)c).hasPassedThroughNonGreedyDecision()) {
324                 continue;
325             }
326 
327             debug(LexerATNSimulator) {
328                 writefln("testing %s at %s\n", getTokenName(t), c.toString(recog, true));
329             }
330 
331             int n = c.state.getNumberOfTransitions();
332             for (int ti=0; ti<n; ti++) {               // for each transition
333                 Transition trans = c.state.transition(ti);
334                 ATNState target = getReachableTarget(trans, t);
335                 if (target !is null) {
336                     LexerActionExecutor lexerActionExecutor = (cast(LexerATNConfig)c).getLexerActionExecutor();
337                     if (lexerActionExecutor !is null) {
338                         lexerActionExecutor = lexerActionExecutor.fixOffsetBeforeMatch(input.index() - startIndex);
339                     }
340 
341                     bool treatEofAsEpsilon = t == IntStreamConstant.EOF;
342                     if (closure(input, new LexerATNConfig(cast(LexerATNConfig)c, target, lexerActionExecutor),
343                                 reach, currentAltReachedAcceptState, true, treatEofAsEpsilon)) {
344                         // any remaining configs for this alt have a lower priority than
345                         // the one that just reached an accept state.
346                         skipAlt = c.alt;
347                         break;
348                     }
349                 }
350             }
351         }
352 
353     }
354 
355     protected void accept(CharStream input, LexerActionExecutor lexerActionExecutor, int startIndex,
356                           int index, int line, int charPos)
357     {
358 	debug(LexerATNSimulator) {
359             writefln("ACTION %s\n", lexerActionExecutor);
360         }
361 
362         // seek to after last char in token
363         input.seek(index);
364         this.line = line;
365         this.charPositionInLine = charPos;
366 
367         if (lexerActionExecutor !is null && recog !is null) {
368             lexerActionExecutor.execute(recog, input, startIndex);
369         }
370     }
371 
372     protected ATNState getReachableTarget(Transition trans, int t)
373     {
374         if (trans.matches(t, 0, 0xfffe)) {
375             return trans.target;
376         }
377 
378         return null;
379     }
380 
381     protected ATNConfigSet computeStartState(CharStream input, ATNState p)
382     {
383         PredictionContext initialContext = cast(PredictionContext)PredictionContext.EMPTY;
384         ATNConfigSet configs = new OrderedATNConfigSet();
385         for (int i=0; i<p.getNumberOfTransitions(); i++) {
386             ATNState target = p.transition(i).target;
387             LexerATNConfig c = new LexerATNConfig(target, i+1, initialContext);
388             closure(input, c, configs, false, false, false);
389         }
390         return configs;
391     }
392 
393     /**
394      * @uml
395      * Since the alternatives within any lexer decision are ordered by
396      * preference, this method stops pursuing the closure as soon as an accept
397      * state is reached. After the first accept state is reached by depth-first
398      * search from {@code config}, all other (potentially reachable) states for
399      * this rule would have a lower priority.
400      *
401      *  @return {@code true} if an accept state is reached, otherwise
402      * {@code false}.
403      */
404     protected bool closure(CharStream input, LexerATNConfig config, ATNConfigSet configs,
405                            bool currentAltReachedAcceptState, bool speculative, bool treatEofAsEpsilon)
406     {
407         if (cast(RuleStopState)config.state) {
408             debug(LexerATNSimulator)  {
409                 if (recog !is null) {
410                     writefln("closure at %1$s rule stop %2$s\n", recog.getRuleNames()[config.state.ruleIndex], config);
411                 }
412                 else {
413                     writefln("closure at rule stop %s\n", config);
414                 }
415             }
416 
417             if (config.context is null || config.context.hasEmptyPath()) {
418                 if (config.context is null || config.context.isEmpty()) {
419                     configs.add(config);
420                     return true;
421                 }
422                 else {
423                     configs.add(new LexerATNConfig(config,
424                                                    config.state,
425                                                    cast(PredictionContext)PredictionContext.EMPTY));
426                     currentAltReachedAcceptState = true;
427                 }
428             }
429             if (config.context !is null && !config.context.isEmpty() ) {
430                 for (auto i = 0; i < config.context.size; i++) {
431                     if (config.context.getReturnState(i) != PredictionContext.EMPTY_RETURN_STATE) {
432                         PredictionContext newContext = config.context.getParent(i); // "pop" return state
433                         ATNState returnState = atn.states[config.context.getReturnState(i)];
434                         LexerATNConfig c = new LexerATNConfig(config, returnState, newContext);
435                         currentAltReachedAcceptState = closure(input, c, configs, currentAltReachedAcceptState,
436                                                                speculative, treatEofAsEpsilon);
437                     }
438                 }
439             }
440 
441             return currentAltReachedAcceptState;
442         }
443 
444         // optimization
445         if (!config.state.onlyHasEpsilonTransitions) {
446             if (!currentAltReachedAcceptState || !config.hasPassedThroughNonGreedyDecision()) {
447                 configs.add(config);
448             }
449         }
450 
451         ATNState p = config.state;
452         for (int i=0; i<p.getNumberOfTransitions(); i++) {
453             Transition t = p.transition(i);
454             LexerATNConfig c = getEpsilonTarget(input, config, t, configs, speculative, treatEofAsEpsilon);
455             if (c !is null) {
456                 currentAltReachedAcceptState = closure(input, c, configs, currentAltReachedAcceptState,
457                                                        speculative, treatEofAsEpsilon);
458             }
459         }
460         return currentAltReachedAcceptState;
461     }
462 
463     /**
464      * side-effect: can alter configs.hasSemanticContext
465      */
466     protected LexerATNConfig getEpsilonTarget(CharStream input, LexerATNConfig config, Transition t,
467         ref ATNConfigSet configs, bool speculative, bool treatEofAsEpsilon)
468     {
469         debug(LexerATNSimulator) {
470             import std.stdio;
471             writefln("LexerATNSimulator getEpsilonTarget t = %s, serType = %s", t, t.getSerializationType);
472         }
473 	LexerATNConfig c = null;
474         switch (t.getSerializationType) {
475         case TransitionStates.RULE:
476             RuleTransition ruleTransition = cast(RuleTransition)t;
477             PredictionContext newContext =
478                 SingletonPredictionContext.create(config.context, ruleTransition.followState.stateNumber);
479             c = new LexerATNConfig(config, t.target, newContext);
480             break;
481         case TransitionStates.PRECEDENCE:
482             throw new UnsupportedOperationException("Precedence predicates are not supported in lexers.");
483         case TransitionStates.PREDICATE:
484             /*  Track traversing semantic predicates. If we traverse,
485                 we cannot add a DFA state for this "reach" computation
486                 because the DFA would not test the predicate again in the
487                 future. Rather than creating collections of semantic predicates
488                 like v3 and testing them on prediction, v4 will test them on the
489                 fly all the time using the ATN not the DFA. This is slower but
490                 semantically it's not used that often. One of the key elements to
491                 this predicate mechanism is not adding DFA states that see
492                 predicates immediately afterwards in the ATN. For example,
493 
494                 a : ID {p1}? | ID {p2}? ;
495 
496                 should create the start state for rule 'a' (to save start state
497                 competition), but should not create target of ID state. The
498                 collection of ATN states the following ID references includes
499                 states reached by traversing predicates. Since this is when we
500                 test them, we cannot cash the DFA state target of ID.
501             */
502             PredicateTransition pt = cast(PredicateTransition)t;
503             debug(LexerATNSimulator) {
504                 writefln("EVAL rule %1$s:%2$s", pt.ruleIndex, pt.predIndex);
505             }
506             configs.hasSemanticContext = true;
507             if (evaluatePredicate(input, pt.ruleIndex, pt.predIndex, speculative)) {
508                 c = new LexerATNConfig(config, t.target);
509             }
510             break;
511 
512         case TransitionStates.ACTION:
513             if (config.context is null || config.context.hasEmptyPath()) {
514                 // execute actions anywhere in the start rule for a token.
515                 //
516                 // TODO: if the entry rule is invoked recursively, some
517                 // actions may be executed during the recursive call. The
518                 // problem can appear when hasEmptyPath() is true but
519                 // isEmpty() is false. In this case, the config needs to be
520                 // split into two contexts - one with just the empty path
521                 // and another with everything but the empty path.
522                 // Unfortunately, the current algorithm does not allow
523                 // getEpsilonTarget to return two configurations, so
524                 // additional modifications are needed before we can support
525                 // the split operation.
526                 LexerActionExecutor lexerActionExecutor = LexerActionExecutor.append(config.getLexerActionExecutor(), atn.lexerActions[(cast(ActionTransition)t).actionIndex]);
527                 c = new LexerATNConfig(config, t.target, lexerActionExecutor);
528                 break;
529             }
530             else {
531                 // ignore actions in referenced rules
532                 c = new LexerATNConfig(config, t.target);
533                 break;
534             }
535 
536         case TransitionStates.EPSILON:
537             c = new LexerATNConfig(config, t.target);
538             break;
539 
540         case TransitionStates.ATOM:
541         case TransitionStates.RANGE:
542         case TransitionStates.SET:
543             if (treatEofAsEpsilon) {
544                 if (t.matches(IntStreamConstant.EOF, 0, 0xfffe)) {
545                     c = new LexerATNConfig(config, t.target);
546                     break;
547                 }
548             }
549 
550             break;
551         default: {}
552         }
553 
554         return c;
555     }
556 
557     /**
558      * @uml
559      * Evaluate a predicate specified in the lexer.
560      *
561      * <p>If {@code speculative} is {@code true}, this method was called before
562      * {@link #consume} for the matched character. This method should call
563      * {@link #consume} before evaluating the predicate to ensure position
564      * sensitive values, including {@link Lexer#getText}, {@link Lexer#getLine},
565      * and {@link Lexer#getCharPositionInLine}, properly reflect the current
566      * lexer state. This method should restore {@code input} and the simulator
567      * to the original state before returning (i.e. undo the actions made by the
568      * call to {@link #consume}.</p>
569      *
570      *  @param input The input stream.
571      *  @param ruleIndex The rule containing the predicate.
572      *  @param predIndex The index of the predicate within the rule.
573      *  @param speculative {@code true} if the current index in {@code input} is
574      *  one character before the predicate's location.
575      *
576      *  @return {@code true} if the specified predicate evaluates to
577      * {@code true}.
578      */
579     protected bool evaluatePredicate(CharStream input, int ruleIndex, int predIndex, bool speculative)
580     {
581 	// assume true if no recognizer was provided
582         if (recog is null) {
583             return true;
584         }
585 
586         if (!speculative) {
587             return recog.sempred(null, ruleIndex, predIndex);
588         }
589 
590         int savedCharPositionInLine = charPositionInLine;
591         int savedLine = line;
592         int index = input.index();
593         int marker = input.mark();
594         try {
595             consume(input);
596             return recog.sempred(null, ruleIndex, predIndex);
597         }
598         finally {
599             charPositionInLine = savedCharPositionInLine;
600             line = savedLine;
601             input.seek(index);
602             input.release(marker);
603         }
604     }
605 
606     public void captureSimState(ref SimState settings, CharStream input, DFAState dfaState)
607     {
608         settings.index = input.index;
609         settings.line = line;
610         settings.charPos = charPositionInLine;
611         settings.dfaState = dfaState;
612     }
613 
614     protected DFAState addDFAEdge(DFAState from, int t, ATNConfigSet q)
615     {
616 	/* leading to this call, ATNConfigSet.hasSemanticContext is used as a
617          * marker indicating dynamic predicate evaluation makes this edge
618          * dependent on the specific input sequence, so the static edge in the
619          * DFA should be omitted. The target DFAState is still created since
620          * execATN has the ability to resynchronize with the DFA state cache
621          * following the predicate evaluation step.
622          *
623          * TJP notes: next time through the DFA, we see a pred again and eval.
624          * If that gets us to a previously created (but dangling) DFA
625          * state, we can continue in pure DFA mode from there.
626          */
627         bool suppressEdge = q.hasSemanticContext;
628         q.hasSemanticContext = false;
629 
630         DFAState to = addDFAState(q);
631 
632         if (suppressEdge) {
633             return to;
634         }
635 
636         addDFAEdge(from, t, to);
637         return to;
638     }
639 
640     protected void addDFAEdge(DFAState p, int t, DFAState q)
641     {
642 	if (t < MIN_DFA_EDGE || t > MAX_DFA_EDGE) {
643             // Only track edges within the DFA bounds
644             return;
645         }
646 
647         debug(LexerATNSimulator) {
648             writefln("EDGE %1$s -> %2$s upon %3$s", p, q, t);
649         }
650 
651         synchronized (p) {
652             if (p.edges is null) {
653                 //  make room for tokens 1..n and -1 masquerading as index 0
654                 p.edges = new DFAState[MAX_DFA_EDGE-MIN_DFA_EDGE+1];
655             }
656             p.edges[t - MIN_DFA_EDGE] = q; // connect
657         }
658     }
659 
660     /**
661      * Add a new DFA state if there isn't one with this set of
662      * configurations already. This method also detects the first
663      * configuration containing an ATN rule stop state. Later, when
664      * traversing the DFA, we will know which rule to accept.
665      */
666     protected DFAState addDFAState(ATNConfigSet configs)
667     {
668         /* the lexer evaluates predicates on-the-fly; by this point configs
669          * should not contain any configurations with unevaluated predicates.
670          */
671         assert(!configs.hasSemanticContext);
672         DFAState proposed = new DFAState(configs);
673         ATNConfig firstConfigWithRuleStopState;
674         foreach (ATNConfig c; configs.configs) {
675             if (cast(RuleStopState)c.state)	{
676                 firstConfigWithRuleStopState = c;
677                 break;
678             }
679         }
680         if (firstConfigWithRuleStopState) {
681             proposed.isAcceptState = true;
682             proposed.lexerActionExecutor = (cast(LexerATNConfig)firstConfigWithRuleStopState).getLexerActionExecutor();
683             proposed.prediction = atn.ruleToTokenType[firstConfigWithRuleStopState.state.ruleIndex];
684         }
685         DFA dfa = decisionToDFA[mode];
686         //DFAState existing = dfa.states[proposed];
687         if (proposed in dfa.states)
688             return dfa.states[proposed];
689         DFAState newState = proposed;
690         newState.stateNumber = to!int(dfa.states.length);
691         configs.readonly(true);
692         newState.configs = configs;
693         dfa.states[newState] =  newState;
694         return newState;
695     }
696 
697     public DFA getDFA(int mode)
698     {
699         return decisionToDFA[mode];
700     }
701 
702     public string getText(CharStream input)
703     {
704         // index is first lookahead char, don't include.
705         return input.getText(Interval.of(startIndex, input.index()-1));
706     }
707 
708     public int getLine()
709     {
710         return line;
711     }
712 
713     public void setLine(int line)
714     {
715         this.line = line;
716     }
717 
718     public int getCharPositionInLine()
719     {
720 	return charPositionInLine;
721     }
722 
723     public void setCharPositionInLine(int charPositionInLine)
724     {
725         this.charPositionInLine = charPositionInLine;
726     }
727 
728     public void consume(CharStream input)
729     {
730 	int curChar = input.LA(1);
731         if (curChar == '\n') {
732             line++;
733             charPositionInLine=0;
734         } else {
735             charPositionInLine++;
736         }
737         input.consume();
738     }
739 
740     public string getTokenName(int t)
741     {
742         if (t == -1) return "EOF";
743         //if ( atn.g!=null ) return atn.g.getTokenDisplayName(t);
744         return format("'%s'", t);
745     }
746 
747 }