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