1 /*
2  * Copyright (c) 2012-2019 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     public static immutable int MIN_DFA_EDGE = 0;
48 
49     public static immutable int MAX_DFA_EDGE = 127;
50 
51     protected Lexer recog;
52 
53     /**
54      * @uml
55      * The current token's starting index into the character stream.
56      * Shared across DFA to ATN simulation in case the ATN fails and the
57      * DFA did not have a previous accept state. In this case, we use the
58      * ATN-generated exception object.
59      */
60     protected int startIndex = -1;
61 
62     /**
63      * @uml
64      * line number 1..n within the input
65      */
66     protected int line = 1;
67 
68     /**
69      * @uml
70      * The index of the character relative to the beginning of the line 0..n-1
71      */
72     protected int charPositionInLine = 0;
73 
74     public DFA[] decisionToDFA;
75 
76     protected int mode = Lexer.DEFAULT_MODE;
77 
78     protected SimState prevAccept;
79 
80     public static int match_calls = 0;
81 
82     public this(ATN atn, DFA[] decisionToDFA, PredictionContextCache sharedContextCache)
83     {
84         this(null, atn, decisionToDFA,sharedContextCache);
85     }
86 
87     public this(Lexer recog, ATN atn, DFA[] decisionToDFA, PredictionContextCache sharedContextCache)
88     {
89         super(atn, sharedContextCache);
90         this.decisionToDFA = decisionToDFA;
91         this.recog = recog;
92     }
93 
94     public void copyState(LexerATNSimulator simulator)
95     {
96         this.charPositionInLine = simulator.charPositionInLine;
97         this.line = simulator.line;
98         this.mode = simulator.mode;
99         this.startIndex = simulator.startIndex;
100     }
101 
102     public int match(CharStream input, int mode)
103     {
104         match_calls++;
105         this.mode = mode;
106         int mark = input.mark;
107         try {
108             this.startIndex = input.index;
109             this.prevAccept.reset;
110             DFA dfa = decisionToDFA[mode];
111             if (dfa.s0 is null) {
112                 return matchATN(input);
113             }
114             else {
115                 return execATN(input, dfa.s0);
116             }
117         }
118         finally {
119             input.release(mark);
120         }
121     }
122 
123     /**
124      * @uml
125      * @override
126      */
127     public override void reset()
128     {
129         prevAccept.reset();
130         startIndex = -1;
131         line = 1;
132         charPositionInLine = 0;
133         mode = Lexer.DEFAULT_MODE;
134     }
135 
136     /**
137      * @uml
138      * @override
139      */
140     public override void clearDFA()
141     {
142         for (int d = 0; d < decisionToDFA.length; d++) {
143             decisionToDFA[d] = new DFA(atn.getDecisionState(d), d);
144         }
145     }
146 
147     protected int matchATN(CharStream input)
148     {
149         ATNState startState = atn.modeToStartState[mode];
150         int old_mode = mode;
151         ATNConfigSet s0_closure = computeStartState(input, startState);
152         bool suppressEdge = s0_closure.hasSemanticContext;
153         s0_closure.hasSemanticContext = false;
154         DFAState next = addDFAState(s0_closure);
155         if (!suppressEdge) {
156             decisionToDFA[mode].s0 = next;
157         }
158         int predict = execATN(input, next);
159 
160         debug(LexerATNSimulator)
161             writefln("DFA after matchATN:\n%1$s\n", decisionToDFA[old_mode].toLexerString());
162         return predict;
163     }
164 
165     protected int execATN(CharStream input, DFAState ds0)
166     {
167         debug(LexerATNSimulator) {
168             writefln("enter exec index %s from %s", input.index, ds0.configs);
169         }
170 
171         if (ds0.isAcceptState) {
172             // allow zero-length tokens
173             captureSimState(prevAccept, input, ds0);
174         }
175         int t = input.LA(1);
176         DFAState s = ds0; // s is current/from DFA state
177 
178         while (true) { // while more work
179             debug(LexerATNSimulator) {
180                 writefln("execATN loop starting closure: %s\n", s.configs);
181             }
182             // As we move src->trg, src->trg, we keep track of the previous trg to
183             // avoid looking up the DFA state again, which is expensive.
184             // If the previous target was already part of the DFA, we might
185             // be able to avoid doing a reach operation upon t. If s!=null,
186             // it means that semantic predicates didn't prevent us from
187             // creating a DFA state. Once we know s!=null, we check to see if
188             // the DFA state has an edge already for t. If so, we can just reuse
189             // it's configuration set; there's no point in re-computing it.
190             // This is kind of like doing DFA simulation within the ATN
191             // simulation because DFA simulation is really just a way to avoid
192             // computing reach/closure sets. Technically, once we know that
193             // we have a previously added DFA state, we could jump over to
194             // the DFA simulator. But, that would mean popping back and forth
195             // a lot and making things more complicated algorithmically.
196             // This optimization makes a lot of sense for loops within DFA.
197             // A character will take us back to an existing DFA state
198             // that already has lots of edges out of it. e.g., .* in comments.
199             DFAState target = getExistingTargetState(s, t);
200             if (target is null) {
201                 target = computeTargetState(input, s, t);
202             }
203             if (target == ERROR) {
204                 break;
205             }
206             // If this is a consumable input element, make sure to consume before
207             // capturing the accept state so the input index, line, and char
208             // position accurately reflect the state of the interpreter at the
209             // end of the token.
210             if (t != IntStreamConstant.EOF) {
211                 consume(input);
212             }
213 
214             if (target.isAcceptState) {
215                 captureSimState(prevAccept, input, target);
216                 if (t == IntStreamConstant.EOF) {
217                     break;
218                 }
219             }
220             t = input.LA(1);
221             s = target; // flip; current DFA target becomes new src/from state
222         }
223         return failOrAccept(prevAccept, input, s.configs, t);
224     }
225 
226     /**
227      * @uml
228      * Get an existing target state for an edge in the DFA. If the target state
229      * for the edge has not yet been computed or is otherwise not available,
230      * this method returns {@code null}.
231      *
232      *  @param s The current DFA state
233      *  @param t The next input symbol
234      *  @return The existing target DFA state for the given input symbol
235      * {@code t}, or {@code null} if the target state for this edge is not
236      * already cached
237      */
238     public DFAState getExistingTargetState(DFAState s, int t)
239     {
240 	if (s.edges is null || t < MIN_DFA_EDGE || t > MAX_DFA_EDGE) {
241             return null;
242         }
243 
244         DFAState target = s.edges[t - MIN_DFA_EDGE];
245         if (target !is null)
246             debug(LexerATNSimulator) {
247                 writefln("reuse state %1$s"~
248                          " edge to %2$s", s.stateNumber, target.stateNumber);
249             }
250 
251         return target;
252     }
253 
254     /**
255      * @uml
256      * Compute a target state for an edge in the DFA, and attempt to add the
257      * computed state and corresponding edge to the DFA.
258      *
259      *  @param input The input stream
260      *  @param s The current DFA state
261      *  @param t The next input symbol
262      *
263      *  @return The computed target DFA state for the given input symbol
264      * {@code t}. If {@code t} does not lead to a valid DFA state, this method
265      * returns {@link #ERROR}.
266      */
267     protected DFAState computeTargetState(CharStream input, DFAState s, int t)
268     {
269 	ATNConfigSet reach = new OrderedATNConfigSet();
270 
271         // if we don't find an existing DFA state
272         // Fill reach starting from closure, following t transitions
273         getReachableConfigSet(input, s.configs, reach, t);
274 
275         if (reach.isEmpty()) { // we got nowhere on t from s
276             if (!reach.hasSemanticContext) {
277                 // we got nowhere on t, don't throw out this knowledge; it'd
278                 // cause a failover from DFA later.
279                 addDFAEdge(s, t, ERROR);
280             }
281 
282             // stop when we can't match any more char
283             return ERROR;
284         }
285 
286         // Add an edge from s to target DFA found/created for reach
287         return addDFAEdge(s, t, reach);
288     }
289 
290     protected int failOrAccept(SimState prevAccept, CharStream input, ATNConfigSet reach,
291                                int t)
292     {
293 	if (prevAccept.dfaState !is null) {
294             LexerActionExecutor lexerActionExecutor = prevAccept.dfaState.lexerActionExecutor;
295             accept(input, lexerActionExecutor, startIndex,
296                    prevAccept.index, prevAccept.line, prevAccept.charPos);
297             return prevAccept.dfaState.prediction;
298         }
299         else {
300             // if no accept and EOF is first char, return EOF
301             if (t==IntStreamConstant.EOF && input.index() == startIndex) {
302                 return TokenConstantDefinition.EOF;
303             }
304             throw new LexerNoViableAltException(recog, input, startIndex, reach);
305         }
306     }
307 
308     /**
309      * @uml
310      * Given a starting configuration set, figure out all ATN configurations
311      * we can reach upon input {@code t}. Parameter {@code reach} is a return
312      * parameter.
313      */
314     protected void getReachableConfigSet(CharStream input, ATNConfigSet closureATNConfigSet, ATNConfigSet reach,
315                                          int t)
316     {
317 	// this is used to skip processing for configs which have a lower priority
318         // than a config that already reached an accept state for the same rule
319         int skipAlt = ATN.INVALID_ALT_NUMBER;
320         foreach (ATNConfig c; closureATNConfigSet.configs) {
321             bool currentAltReachedAcceptState = c.alt == skipAlt;
322             if (currentAltReachedAcceptState && (cast(LexerATNConfig)c).hasPassedThroughNonGreedyDecision()) {
323                 continue;
324             }
325 
326             debug(LexerATNSimulator) {
327                 writefln("testing %s at %s\n", getTokenName(t), c.toString(recog, true));
328             }
329 
330             int n = c.state.getNumberOfTransitions();
331             for (int ti=0; ti<n; ti++) {               // for each transition
332                 Transition trans = c.state.transition(ti);
333                 ATNState target = getReachableTarget(trans, t);
334                 if (target !is null) {
335                     LexerActionExecutor lexerActionExecutor = (cast(LexerATNConfig)c).getLexerActionExecutor();
336                     if (lexerActionExecutor !is null) {
337                         lexerActionExecutor = lexerActionExecutor.fixOffsetBeforeMatch(input.index() - startIndex);
338                     }
339 
340                     bool treatEofAsEpsilon = t == IntStreamConstant.EOF;
341                     if (closure(input, new LexerATNConfig(cast(LexerATNConfig)c, target, lexerActionExecutor),
342                                 reach, currentAltReachedAcceptState, true, treatEofAsEpsilon)) {
343                         // any remaining configs for this alt have a lower priority than
344                         // the one that just reached an accept state.
345                         skipAlt = c.alt;
346                         break;
347                     }
348                 }
349             }
350         }
351 
352     }
353 
354     protected void accept(CharStream input, LexerActionExecutor lexerActionExecutor, int startIndex,
355                           int index, int line, int charPos)
356     {
357 	debug(LexerATNSimulator) {
358             writefln("ACTION %s\n", lexerActionExecutor);
359         }
360 
361         // seek to after last char in token
362         input.seek(index);
363         this.line = line;
364         this.charPositionInLine = charPos;
365 
366         if (lexerActionExecutor !is null && recog !is null) {
367             lexerActionExecutor.execute(recog, input, startIndex);
368         }
369     }
370 
371     protected ATNState getReachableTarget(Transition trans, int t)
372     {
373         if (trans.matches(t, 0, 0xfffe)) {
374             return trans.target;
375         }
376 
377         return null;
378     }
379 
380     protected ATNConfigSet computeStartState(CharStream input, ATNState p)
381     {
382         PredictionContext initialContext = cast(PredictionContext)PredictionContext.EMPTY;
383         ATNConfigSet configs = new OrderedATNConfigSet();
384         for (int i=0; i<p.getNumberOfTransitions(); i++) {
385             ATNState target = p.transition(i).target;
386             LexerATNConfig c = new LexerATNConfig(target, i+1, initialContext);
387             closure(input, c, configs, false, false, false);
388         }
389         return configs;
390     }
391 
392     /**
393      * @uml
394      * Since the alternatives within any lexer decision are ordered by
395      * preference, this method stops pursuing the closure as soon as an accept
396      * state is reached. After the first accept state is reached by depth-first
397      * search from {@code config}, all other (potentially reachable) states for
398      * this rule would have a lower priority.
399      *
400      *  @return {@code true} if an accept state is reached, otherwise
401      * {@code false}.
402      */
403     protected bool closure(CharStream input, LexerATNConfig config, ATNConfigSet configs,
404                            bool currentAltReachedAcceptState, bool speculative, bool treatEofAsEpsilon)
405     {
406         debug(LexerATNSimulator)
407             writefln("closure(\"%s\")", config);
408         if (cast(RuleStopState)config.state) {
409             debug(LexerATNSimulator)  {
410                 if (recog !is null) {
411                     writefln("closure at %1$s rule stop %2$s\n", recog.getRuleNames()[config.state.ruleIndex], config);
412                 }
413                 else {
414                     writefln("closure at rule stop %s\n", config);
415                 }
416             }
417 
418             if (config.context is null || config.context.hasEmptyPath()) {
419                 if (config.context is null || config.context.isEmpty()) {
420                     configs.add(config);
421                     return true;
422                 }
423                 else {
424                     configs.add(new LexerATNConfig(config,
425                                                    config.state,
426                                                    cast(PredictionContext)PredictionContext.EMPTY));
427                     currentAltReachedAcceptState = true;
428                 }
429             }
430             if (config.context !is null && !config.context.isEmpty() ) {
431                 for (auto i = 0; i < config.context.size; i++) {
432                     if (config.context.getReturnState(i) != PredictionContext.EMPTY_RETURN_STATE) {
433                         PredictionContext newContext = config.context.getParent(i); // "pop" return state
434                         ATNState returnState = atn.states[config.context.getReturnState(i)];
435                         LexerATNConfig c = new LexerATNConfig(config, returnState, newContext);
436                         currentAltReachedAcceptState = closure(input, c, configs, currentAltReachedAcceptState,
437                                                                speculative, treatEofAsEpsilon);
438                     }
439                 }
440             }
441 
442             return currentAltReachedAcceptState;
443         }
444 
445         // optimization
446         if (!config.state.onlyHasEpsilonTransitions) {
447             if (!currentAltReachedAcceptState || !config.hasPassedThroughNonGreedyDecision()) {
448                 configs.add(config);
449             }
450         }
451 
452         ATNState p = config.state;
453         for (int i=0; i<p.getNumberOfTransitions(); i++) {
454             Transition t = p.transition(i);
455             LexerATNConfig c = getEpsilonTarget(input, config, t, configs, speculative, treatEofAsEpsilon);
456             if (c !is null) {
457                 currentAltReachedAcceptState = closure(input, c, configs, currentAltReachedAcceptState,
458                                                        speculative, treatEofAsEpsilon);
459             }
460         }
461         return currentAltReachedAcceptState;
462     }
463 
464     /**
465      * side-effect: can alter configs.hasSemanticContext
466      */
467     protected LexerATNConfig getEpsilonTarget(CharStream input, LexerATNConfig config, Transition t,
468         ref ATNConfigSet configs, bool speculative, bool treatEofAsEpsilon)
469     {
470         debug(LexerATNSimulator) {
471             import std.stdio;
472             writefln("LexerATNSimulator getEpsilonTarget t = %s, serType = %s", t, t.getSerializationType);
473         }
474 	LexerATNConfig c = null;
475         switch (t.getSerializationType) {
476         case TransitionStates.RULE:
477             RuleTransition ruleTransition = cast(RuleTransition)t;
478             PredictionContext newContext =
479                 SingletonPredictionContext.create(config.context, ruleTransition.followState.stateNumber);
480             c = new LexerATNConfig(config, t.target, newContext);
481             break;
482         case TransitionStates.PRECEDENCE:
483             throw new UnsupportedOperationException("Precedence predicates are not supported in lexers.");
484         case TransitionStates.PREDICATE:
485             /*  Track traversing semantic predicates. If we traverse,
486                 we cannot add a DFA state for this "reach" computation
487                 because the DFA would not test the predicate again in the
488                 future. Rather than creating collections of semantic predicates
489                 like v3 and testing them on prediction, v4 will test them on the
490                 fly all the time using the ATN not the DFA. This is slower but
491                 semantically it's not used that often. One of the key elements to
492                 this predicate mechanism is not adding DFA states that see
493                 predicates immediately afterwards in the ATN. For example,
494 
495                 a : ID {p1}? | ID {p2}? ;
496 
497                 should create the start state for rule 'a' (to save start state
498                 competition), but should not create target of ID state. The
499                 collection of ATN states the following ID references includes
500                 states reached by traversing predicates. Since this is when we
501                 test them, we cannot cash the DFA state target of ID.
502             */
503             PredicateTransition pt = cast(PredicateTransition)t;
504             debug(LexerATNSimulator) {
505                 writefln("EVAL rule %1$s:%2$s", pt.ruleIndex, pt.predIndex);
506             }
507             configs.hasSemanticContext = true;
508             if (evaluatePredicate(input, pt.ruleIndex, pt.predIndex, speculative)) {
509                 c = new LexerATNConfig(config, t.target);
510             }
511             break;
512 
513         case TransitionStates.ACTION:
514             if (config.context is null || config.context.hasEmptyPath()) {
515                 // execute actions anywhere in the start rule for a token.
516                 //
517                 // TODO: if the entry rule is invoked recursively, some
518                 // actions may be executed during the recursive call. The
519                 // problem can appear when hasEmptyPath() is true but
520                 // isEmpty() is false. In this case, the config needs to be
521                 // split into two contexts - one with just the empty path
522                 // and another with everything but the empty path.
523                 // Unfortunately, the current algorithm does not allow
524                 // getEpsilonTarget to return two configurations, so
525                 // additional modifications are needed before we can support
526                 // the split operation.
527                 LexerActionExecutor lexerActionExecutor = LexerActionExecutor.append(config.getLexerActionExecutor(), atn.lexerActions[(cast(ActionTransition)t).actionIndex]);
528                 c = new LexerATNConfig(config, t.target, lexerActionExecutor);
529                 break;
530             }
531             else {
532                 // ignore actions in referenced rules
533                 c = new LexerATNConfig(config, t.target);
534                 break;
535             }
536 
537         case TransitionStates.EPSILON:
538             c = new LexerATNConfig(config, t.target);
539             break;
540 
541         case TransitionStates.ATOM:
542         case TransitionStates.RANGE:
543         case TransitionStates.SET:
544             if (treatEofAsEpsilon) {
545                 if (t.matches(IntStreamConstant.EOF, 0, 0xfffe)) {
546                     c = new LexerATNConfig(config, t.target);
547                     break;
548                 }
549             }
550 
551             break;
552         default: {}
553         }
554 
555         return c;
556     }
557 
558     /**
559      * Evaluate a predicate specified in the lexer.
560      *
561      * 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}).
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 }