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.Parser;
8 
9 import std.stdio;
10 import std.algorithm;
11 import std.conv;
12 import antlr.v4.runtime.ANTLRErrorStrategy;
13 import antlr.v4.runtime.ANTLRErrorListener;
14 import antlr.v4.runtime.DefaultErrorStrategy;
15 import antlr.v4.runtime.Lexer;
16 import antlr.v4.runtime.IntStream;
17 import antlr.v4.runtime.InterfaceRuleContext;
18 import antlr.v4.runtime.RuleContext;
19 import antlr.v4.runtime.ParserRuleContext;
20 import antlr.v4.runtime.Recognizer;
21 import antlr.v4.runtime.RecognitionException;
22 import antlr.v4.runtime.UnsupportedOperationException;
23 import antlr.v4.runtime.Token;
24 import antlr.v4.runtime.CommonToken;
25 import antlr.v4.runtime.TokenFactory;
26 import antlr.v4.runtime.TokenConstantDefinition;
27 import antlr.v4.runtime.TokenStream;
28 import antlr.v4.runtime.TokenSource;
29 import antlr.v4.runtime.InterfaceParser;
30 import antlr.v4.runtime.atn.ATN;
31 import antlr.v4.runtime.atn.ATNSimulator;
32 import antlr.v4.runtime.atn.ParserATNSimulator;
33 import antlr.v4.runtime.atn.ParseInfo;
34 import antlr.v4.runtime.atn.PredictionMode;
35 import antlr.v4.runtime.atn.RuleTransition;
36 import antlr.v4.runtime.atn.ATNDeserializer;
37 import antlr.v4.runtime.atn.ATNDeserializationOptions;
38 import antlr.v4.runtime.atn.ATNState;
39 import antlr.v4.runtime.atn.ProfilingATNSimulator;
40 import antlr.v4.runtime.dfa.DFA;
41 import antlr.v4.runtime.tree.pattern.ParseTreePattern;
42 import antlr.v4.runtime.tree.pattern.ParseTreePatternMatcher;
43 import antlr.v4.runtime.tree.ParseTreeListener;
44 import antlr.v4.runtime.tree.ErrorNode;
45 import antlr.v4.runtime.tree.TerminalNode;
46 import antlr.v4.runtime.misc.IntegerStack;
47 import antlr.v4.runtime.misc.IntervalSet;
48 
49 // Class Parser
50 /**
51  * TODO add class description
52  */
53 abstract class Parser : Recognizer!(Token, ParserATNSimulator), InterfaceParser
54 {
55     // Class TraceListener
56     /**
57      * TODO add class description
58      */
59     class TraceListener : ParseTreeListener
60     {
61 
62         public void enterEveryRule(ParserRuleContext ctx)
63         {
64             writeln("enter   " ~ getRuleNames()[ctx.getRuleIndex()] ~
65                     ", LT(1)=" ~ _input.LT(1).getText());
66         }
67 
68         public void visitTerminal(TerminalNode node)
69         {
70             writeln("consume " ~ node.getSymbol().getText ~ " rule " ~
71                     getRuleNames()[ctx_.getRuleIndex()]);
72         }
73 
74         public void visitErrorNode(ErrorNode node)
75         {
76         }
77 
78         /**
79          * @uml
80          * @override
81          */
82         public override void exitEveryRule(ParserRuleContext ctx)
83         {
84             writeln("exit   " ~ getRuleNames()[ctx.getRuleIndex()] ~
85                     ", LT(1)=" ~ _input.LT(1).getText());
86         }
87 
88     }
89 
90     // Singleton TrimToSizeListener
91     /**
92      * TODO add class description
93      */
94     static class TrimToSizeListener : ParseTreeListener
95     {
96 
97         /**
98          * The single instance of TrimToSizeListener.
99          */
100         private static __gshared Parser.TrimToSizeListener instance_;
101 
102         public void enterEveryRule(ParserRuleContext ctx)
103         {
104         }
105 
106         public void visitTerminal(TerminalNode node)
107         {
108         }
109 
110         public void visitErrorNode(ErrorNode node)
111         {
112         }
113 
114         public void exitEveryRule(ParserRuleContext ctx)
115         {
116             // if (ctx.children.classinfo == ArrayList.classinfo) {
117             //     ((ArrayList<?>)ctx.children).trimToSize();
118             // }
119         }
120 
121         /**
122          * Creates the single instance of TrimToSizeListener.
123          */
124         private shared static this()
125         {
126             instance_ = new TrimToSizeListener;
127         }
128 
129         /**
130          * Returns: A single instance of TrimToSizeListener.
131          */
132         public static TrimToSizeListener instance()
133         {
134             return instance_;
135         }
136 
137     }
138 
139     /**
140      * @uml
141      * This field maps from the serialized ATN string to the deserialized {@link ATN} with
142      * bypass alternatives.
143      *
144      * @see ATNDeserializationOptions#isGenerateRuleBypassTransitions()
145      */
146     private ATN[wstring] bypassAltsAtnCache;
147 
148     protected ANTLRErrorStrategy _errHandler;
149 
150     protected TokenStream _input;
151 
152     public IntegerStack _precedenceStack;
153 
154     /**
155      * @uml
156      * The {@link ParserRuleContext} object for the currently executing rule.
157      * This is always non-null during the parsing process.
158      * @read
159      * @write
160      */
161     public ParserRuleContext ctx_;
162 
163     /**
164      * @uml
165      * Specifies whether or not the parser should construct a parse tree during
166      * the parsing process. The default value is {@code true}.
167      *
168      * @see #getBuildParseTree
169      * @see #setBuildParseTree
170      */
171     protected bool _buildParseTrees = true;
172 
173     public TraceListener _tracer;
174 
175     /**
176      * @uml
177      * The list of {@link ParseTreeListener} listeners registered to receive
178      * events during the parse.
179      *
180      *  @see #addParseListener
181      */
182     public ParseTreeListener[] _parseListeners;
183 
184     /**
185      * @uml
186      * The number of syntax errors reported during parsing. This value is
187      * incremented each time {@link #notifyErrorListeners} is called.
188      */
189     public int _syntaxErrors;
190 
191     /**
192      * @uml
193      * Indicates parser has match()ed EOF token. See {@link #exitRule()}.
194      */
195     public bool matchedEOF;
196 
197     public this()
198     {
199     }
200 
201     public this(TokenStream input)
202     {
203         setInputStream(input);
204     }
205 
206     /**
207      * @uml
208      * reset the parser's state
209      */
210     public void reset()
211     {
212         if (getInputStream() !is null)
213             getInputStream().seek(0);
214         _errHandler = new DefaultErrorStrategy;
215         _errHandler.reset(this);
216         ctx_ = null;
217         _syntaxErrors = 0;
218         matchedEOF = false;
219         _precedenceStack = new IntegerStack();
220         _precedenceStack.clear;
221         _precedenceStack.push(0);
222         ATNSimulator interpreter = getInterpreter();
223         if (interpreter !is null) {
224             interpreter.reset();
225         }
226     }
227 
228     /**
229      * @uml
230      * Match current input symbol against {@code ttype}. If the symbol type
231      * matches, {@link ANTLRErrorStrategy#reportMatch} and {@link #consume} are
232      * called to complete the match process.
233      *
234      * <p>If the symbol type does not match,
235      * {@link ANTLRErrorStrategy#recoverInline} is called on the current error
236      * strategy to attempt recovery. If {@link #getBuildParseTree} is
237      * {@code true} and the token index of the symbol returned by
238      * {@link ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to
239      * the parse tree by calling {@link ParserRuleContext#addErrorNode}.</p>
240      *
241      *  @param ttype the token type to match
242      *  @return the matched symbol
243      *  @throws RecognitionException if the current input symbol did not match
244      *  {@code ttype} and the error strategy could not recover from the
245      *  mismatched symbol
246      */
247     public Token match(int ttype)
248     {
249 	Token t = getCurrentToken;
250 
251         debug(Parser) {
252             import std.stdio;
253             writefln("Parser: match  %s, currentToken = %s", ttype, t);
254         }
255 
256         if (t.getType == ttype) {
257             if (ttype == TokenConstantDefinition.EOF)
258                 {
259                     matchedEOF = true;
260                 }
261             _errHandler.reportMatch(this);
262             consume();
263         }
264         else {
265             t = _errHandler.recoverInline(this);
266             if (_buildParseTrees && t.getTokenIndex == -1) {
267                 // we must have conjured up a new token during single token insertion
268                 // if it's not the current symbol
269                 ctx_.addErrorNode(t);
270             }
271         }
272         return t;
273     }
274 
275     /**
276      * @uml
277      * Match current input symbol as a wildcard. If the symbol type matches
278      * (i.e. has a value greater than 0), {@link ANTLRErrorStrategy#reportMatch}
279      * and {@link #consume} are called to complete the match process.
280      *
281      * <p>If the symbol type does not match,
282      * {@link ANTLRErrorStrategy#recoverInline} is called on the current error
283      * strategy to attempt recovery. If {@link #getBuildParseTree} is
284      * {@code true} and the token index of the symbol returned by
285      * {@link ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to
286      * the parse tree by calling {@link ParserRuleContext#addErrorNode}.</p>
287      *
288      *  @return the matched symbol
289      *  @throws RecognitionException if the current input symbol did not match
290      *  a wildcard and the error strategy could not recover from the mismatched
291      *  symbol
292      */
293     public Token matchWildcard()
294     {
295 	Token t = getCurrentToken();
296         if (t.getType() > 0) {
297             _errHandler.reportMatch(this);
298             consume();
299         }
300         else {
301             t = _errHandler.recoverInline(this);
302             if (_buildParseTrees && t.getTokenIndex() == -1) {
303                 // we must have conjured up a new token during single token insertion
304                 // if it's not the current symbol
305                 ctx_.addErrorNode(t);
306             }
307         }
308         return t;
309     }
310 
311     /**
312      * @uml
313      * Track the {@link ParserRuleContext} objects during the parse and hook
314      * them up using the {@link ParserRuleContext#children} list so that it
315      * forms a parse tree. The {@link ParserRuleContext} returned from the start
316      * rule represents the root of the parse tree.
317      *
318      * <p>Note that if we are not building parse trees, rule contexts only point
319      * upwards. When a rule exits, it returns the context but that gets garbage
320      * collected if nobody holds a reference. It points upwards but nobody
321      * points at it.</p>
322      *
323      * <p>When we build parse trees, we are adding all of these contexts to
324      * {@link ParserRuleContext#children} list. Contexts are then not candidates
325      * for garbage collection.</p>
326      */
327     public void setBuildParseTree(bool buildParseTrees)
328     {
329         this._buildParseTrees = buildParseTrees;
330     }
331 
332     /**
333      * @uml
334      * Gets whether or not a complete parse tree will be constructed while
335      * parsing. This property is {@code true} for a newly constructed parser.
336      *
337      *  @return {@code true} if a complete parse tree will be constructed while
338      *  parsing, otherwise {@code false}
339      */
340     public bool getBuildParseTree()
341     {
342         return _buildParseTrees;
343     }
344 
345     /**
346      * @uml
347      * Trim the internal lists of the parse tree during parsing to conserve memory.
348      * This property is set to {@code false} by default for a newly constructed parser.
349      *
350      *  @param trimParseTrees {@code true} to trim the capacity of the {@link ParserRuleContext#children}
351      *  list to its size after a rule is parsed.
352      */
353     public void setTrimParseTree(bool trimParseTrees)
354     {
355         if (trimParseTrees) {
356             if (getTrimParseTree()) return;
357             addParseListener(TrimToSizeListener.instance);
358         }
359         else {
360             removeParseListener(TrimToSizeListener.instance);
361         }
362     }
363 
364     /**
365      * @uml
366      * The @return {@code true} if the {@link ParserRuleContext#children} list is trimed
367      *  using the default {@link Parser.TrimToSizeListener} during the parse process.
368      */
369     public bool getTrimParseTree()
370     {
371         return canFind(getParseListeners(), TrimToSizeListener.instance);
372     }
373 
374     public ParseTreeListener[] getParseListeners()
375     {
376         ParseTreeListener[] listeners = _parseListeners;
377         if (listeners is null) {
378             return [];
379         }
380 
381         return listeners;
382     }
383 
384     /**
385      * @uml
386      * Registers {@code listener} to receive events during the parsing process.
387      *
388      * <p>To support output-preserving grammar transformations (including but not
389      * limited to left-recursion removal, automated left-factoring, and
390      * optimized code generation), calls to listener methods during the parse
391      * may differ substantially from calls made by
392      * {@link ParseTreeWalker#DEFAULT} used after the parse is complete. In
393      * particular, rule entry and exit events may occur in a different order
394      * during the parse than after the parser. In addition, calls to certain
395      * rule entry methods may be omitted.</p>
396      *
397      * <p>With the following specific exceptions, calls to listener events are
398      * <em>deterministic</em>, i.e. for identical input the calls to listener
399      * methods will be the same.</p>
400      *
401      * <ul>
402      * <li>Alterations to the grammar used to generate code may change the
403      * behavior of the listener calls.</li>
404      * <li>Alterations to the command line options passed to ANTLR 4 when
405      * generating the parser may change the behavior of the listener calls.</li>
406      * <li>Changing the version of the ANTLR Tool used to generate the parser
407      * may change the behavior of the listener calls.</li>
408      * </ul>
409      *
410      *  @param listener the listener to add
411      *
412      *  @throws NullPointerException if {@code} listener is {@code null}
413      */
414     public void addParseListener(ParseTreeListener listener)
415     {
416         assert (listener !is null, "NullPointerException(listener)");
417         _parseListeners ~= listener;
418     }
419 
420     public void removeParseListener(ParseTreeListener listener)
421     {
422         ParseTreeListener[] new_parseListeners;
423         foreach (li; _parseListeners) {
424             if ( li != listener) new_parseListeners ~= li;
425         }
426         _parseListeners = new_parseListeners;
427     }
428 
429     /**
430      * @uml
431      * Remove all parse listeners.
432      *
433      *  @see #addParseListener
434      */
435     public void removeParseListeners()
436     {
437         _parseListeners.length = 0;
438     }
439 
440     /**
441      * @uml
442      * Notify any parse listeners of an enter rule event.
443      *
444      *  @see #addParseListener
445      */
446     protected void triggerEnterRuleEvent()
447     {
448         foreach (listener; _parseListeners) {
449             listener.enterEveryRule(ctx_);
450             ctx_.enterRule(listener);
451         }
452     }
453 
454     /**
455      * @uml
456      * Notify any parse listeners of an exit rule event.
457      *
458      *  @see #addParseListener
459      */
460     protected void triggerExitRuleEvent()
461     {
462         // reverse order walk of listeners
463         for (auto i = _parseListeners.length-1; i >= 0; i--) {
464             ParseTreeListener listener = _parseListeners[i];
465             ctx_.exitRule(listener);
466             listener.exitEveryRule(ctx_);
467         }
468     }
469 
470     /**
471      * @uml
472      * Gets the number of syntax errors reported during parsing. This value is
473      * incremented each time {@link #notifyErrorListeners} is called.
474      *
475      *  @see #notifyErrorListeners
476      */
477     public int getNumberOfSyntaxErrors()
478     {
479         return _syntaxErrors;
480     }
481 
482     /**
483      * @uml
484      * @override
485      */
486     public override TokenFactory!CommonToken tokenFactory()
487     {
488         return _input.getTokenSource().tokenFactory();
489     }
490 
491     /**
492      * Tell our token source and error strategy about a new way to create tokens.
493      * @uml
494      * @override
495      */
496     public override void tokenFactory(TokenFactory!CommonToken factory)
497     {
498         _input.getTokenSource().tokenFactory(factory);
499     }
500 
501     /**
502      * @uml
503      * The ATN with bypass alternatives is expensive to create so we create it
504      * lazily.
505      *
506      *  @throws UnsupportedOperationException if the current parser does not
507      * implement the {@link #getSerializedATN()} method.
508      */
509     public ATN getATNWithBypassAlts()
510     {
511         wstring serializedAtn = getSerializedATN();
512         if (serializedAtn is null) {
513             throw new UnsupportedOperationException("The current parser does not support an ATN with bypass alternatives.");
514         }
515         if (serializedAtn in bypassAltsAtnCache) {
516             return bypassAltsAtnCache[serializedAtn];
517         }
518         ATN result;
519         ATNDeserializationOptions deserializationOptions = new ATNDeserializationOptions();
520         deserializationOptions.generateRuleBypassTransitions(true);
521         result = new ATNDeserializer(deserializationOptions).deserialize(serializedAtn);
522         bypassAltsAtnCache[serializedAtn] = result;
523         return result;
524     }
525 
526     public ParseTreePattern compileParseTreePattern(string pattern, int patternRuleIndex)
527     {
528         if (getTokenStream() !is null) {
529             TokenSource tokenSource = getTokenStream().getTokenSource();
530             if (tokenSource.classinfo == Lexer.classinfo) {
531                 Lexer lexer = cast(Lexer)tokenSource;
532                 return compileParseTreePattern(pattern, patternRuleIndex, lexer);
533             }
534         }
535         throw new UnsupportedOperationException("Parser can't discover a lexer to use");
536     }
537 
538     /**
539      * @uml
540      * The same as {@link #compileParseTreePattern(String, int)} but specify a
541      * {@link Lexer} rather than trying to deduce it from this parser.
542      */
543     public ParseTreePattern compileParseTreePattern(string pattern, int patternRuleIndex,
544                                                     Lexer lexer)
545     {
546         ParseTreePatternMatcher m = new ParseTreePatternMatcher(lexer, this);
547         return m.compile(pattern, patternRuleIndex);
548     }
549 
550     public auto getErrorHandler()
551     {
552         return _errHandler;
553     }
554 
555     public void setErrorHandler(ANTLRErrorStrategy handler)
556     {
557     }
558 
559     /**
560      * @uml
561      * @override
562      */
563     public override TokenStream getInputStream()
564     {
565         return getTokenStream();
566     }
567 
568     /**
569      * @uml
570      * @override
571      */
572     public override void setInputStream(IntStream input)
573     {
574         setTokenStream(cast(TokenStream)input);
575     }
576 
577     public TokenStream getTokenStream()
578     {
579         return _input;
580     }
581 
582     /**
583      * @uml
584      * Set the token stream and reset the parser.
585      */
586     public void setTokenStream(TokenStream input)
587     {
588         this._input = null;
589         reset();
590         this._input = input;
591     }
592 
593     /**
594      * @uml
595      * Match needs to return the current input symbol, which gets put
596      * into the label for the associated token ref; e.g., x=ID.
597      */
598     public Token getCurrentToken()
599     {
600 	return _input.LT(1);
601     }
602 
603     /**
604      * @uml
605      * @final
606      */
607     public final void notifyErrorListeners(string msg)
608     {
609         notifyErrorListeners(getCurrentToken(), msg, null);
610     }
611 
612     public void notifyErrorListeners(Token offendingToken, string msg, RecognitionException e)
613     {
614         _syntaxErrors++;
615         int line = -1;
616         int charPositionInLine = -1;
617         line = offendingToken.getLine();
618         charPositionInLine = offendingToken.getCharPositionInLine();
619         ANTLRErrorListener!(Token, ParserATNSimulator) listener = getErrorListenerDispatch();
620         listener.syntaxError(this, cast(Object)offendingToken, line, charPositionInLine, msg, e);
621     }
622 
623     /**
624      * @uml
625      * Consume and return the {@linkplain #getCurrentToken current symbol}.
626      *
627      * <p>E.g., given the following input with {@code A} being the current
628      * lookahead symbol, this function moves the cursor to {@code B} and returns
629      * {@code A}.</p>
630      *
631      * <pre>
632      *  A B
633      *  ^
634      * </pre>
635      *
636      * If the parser is not in error recovery mode, the consumed symbol is added
637      * to the parse tree using {@link ParserRuleContext#addChild(Token)}, and
638      * {@link ParseTreeListener#visitTerminal} is called on any parse listeners.
639      * If the parser <em>is</em> in error recovery mode, the consumed symbol is
640      * added to the parse tree using
641      * {@link ParserRuleContext#addErrorNode(Token)}, and
642      * {@link ParseTreeListener#visitErrorNode} is called on any parse
643      * listeners.
644      */
645     public Token consume()
646     {
647         Token o = getCurrentToken();
648         if (o.getType() != EOF) {
649             getInputStream().consume();
650         }
651 
652         bool hasListener = _parseListeners !is null && _parseListeners.length;
653         if (_buildParseTrees || hasListener) {
654             if (_errHandler.inErrorRecoveryMode(this)) {
655                 ErrorNode node = ctx_.addErrorNode(o);
656                 if (_parseListeners !is null) {
657                     foreach (ParseTreeListener listener; _parseListeners) {
658                         listener.visitErrorNode(node);
659                     }
660                 }
661             }
662             else {
663                 TerminalNode node = ctx_.addChild(o);
664                 if (_parseListeners !is null) {
665                     foreach (ParseTreeListener listener; _parseListeners) {
666                         listener.visitTerminal(node);
667                     }
668                 }
669             }
670         }
671         return o;
672     }
673 
674     protected void addContextToParseTree()
675     {
676         ParserRuleContext parent = cast(ParserRuleContext)ctx_.parent;
677         // add current context to parent if we have a parent
678         if (parent !is null) {
679             parent.addChild(ctx_);
680         }
681     }
682 
683     public void enterRule(ParserRuleContext localctx, int state, int ruleIndex)
684     {
685         setState(state);
686         ctx_ = localctx;
687         ctx_.start = _input.LT(1);
688         if (_buildParseTrees) addContextToParseTree();
689         if (_parseListeners !is null)
690             triggerEnterRuleEvent();
691     }
692 
693     public void exitRule()
694     {
695         if (matchedEOF) {
696             // if we have matched EOF, it cannot consume past EOF so we use LT(1) here
697             ctx_.stop = _input.LT(1); // LT(1) will be end of file
698         }
699         else {
700             ctx_.stop = _input.LT(-1); // stop node is what we just matched
701         }
702         // trigger event on ctx_, before it reverts to parent
703         if (_parseListeners !is null)
704             triggerExitRuleEvent();
705         setState(ctx_.invokingState);
706         ctx_ = cast(ParserRuleContext)ctx_.parent;
707     }
708 
709     public void enterOuterAlt(ParserRuleContext localctx, int altNum)
710     {
711 	localctx.setAltNumber(altNum);
712         // if we have new localctx, make sure we replace existing ctx
713         // that is previous child of parse tree
714         if (_buildParseTrees && ctx_ != localctx) {
715             ParserRuleContext parent = cast(ParserRuleContext)ctx_.parent;
716             if (parent !is null)
717                 {
718                     parent.removeLastChild();
719                     parent.addChild(localctx);
720                 }
721         }
722         ctx_ = localctx;
723     }
724 
725     /**
726      * @uml
727      * Get the precedence level for the top-most precedence rule.
728      *
729      *  @return The precedence level for the top-most precedence rule, or -1 if
730      * the parser context is not nested within a precedence rule.
731      * @final
732      */
733     public final int getPrecedence()
734     {
735         if (_precedenceStack.isEmpty) {
736             return -1;
737         }
738         return _precedenceStack.peek();
739     }
740 
741     /**
742      * @uml
743      * . @deprecated Use
744      * {@link #enterRecursionRule(ParserRuleContext, int, int, int)} instead.
745      */
746     public void enterRecursionRule(ParserRuleContext localctx, int ruleIndex)
747     {
748 	enterRecursionRule(localctx, getATN().ruleToStartState[ruleIndex].stateNumber, ruleIndex, 0);
749     }
750 
751     public void enterRecursionRule(ParserRuleContext localctx, int state, int ruleIndex,
752                                    int precedence)
753     {
754         setState(state);
755         _precedenceStack.push(precedence);
756         ctx_ = localctx;
757         ctx_.start = _input.LT(1);
758         if(_parseListeners !is null) {
759             triggerEnterRuleEvent(); // simulates rule entry for left-recursive rules
760         }
761     }
762 
763     /**
764      * @uml
765      * Like {@link #enterRule} but for recursive rules.
766      * Make the current context the child of the incoming localctx.
767      */
768     public void pushNewRecursionContext(ParserRuleContext localctx, int state, int ruleIndex)
769     {
770 	ParserRuleContext previous = ctx_;
771         previous.parent = localctx;
772         previous.invokingState = state;
773         previous.stop = _input.LT(-1);
774 
775         ctx_ = localctx;
776         ctx_.start = previous.start;
777         if (_buildParseTrees) {
778             ctx_.addChild(previous);
779         }
780 
781         if (_parseListeners !is null) {
782             triggerEnterRuleEvent(); // simulates rule entry for left-recursive rules
783         }
784     }
785 
786     public void unrollRecursionContexts(ParserRuleContext _parentctx)
787     {
788 	_precedenceStack.pop();
789         ctx_.stop = _input.LT(-1);
790         ParserRuleContext retctx = ctx_; // save current ctx (return value)
791 
792         // unroll so ctx_ is as it was before call to recursive method
793         if (_parseListeners !is null) {
794             while (ctx_ !is _parentctx) {
795                 triggerExitRuleEvent();
796                 ctx_ = cast(ParserRuleContext)ctx_.parent;
797             }
798         }
799         else {
800             ctx_ = _parentctx;
801         }
802 
803         // hook into tree
804         retctx.parent = _parentctx;
805 
806         if (_buildParseTrees && _parentctx !is null) {
807             // add return ctx into invoking rule's tree
808             _parentctx.addChild(retctx);
809         }
810     }
811 
812     public ParserRuleContext getInvokingContext(int ruleIndex)
813     {
814         ParserRuleContext p = ctx_;
815         while (p !is null ) {
816             if ( p.getRuleIndex() == ruleIndex ) return p;
817             p = cast(ParserRuleContext)p.parent;
818         }
819         return null;
820     }
821 
822     /**
823      * @uml
824      * @override
825      */
826     public override bool precpred(InterfaceRuleContext localctx, int precedence)
827     {
828         return precedence >= _precedenceStack.peek();
829     }
830 
831     public bool inContext(string context)
832     {
833 	// TODO: useful in parser?
834         return false;
835     }
836 
837     /**
838      * @uml
839      * Checks whether or not {@code symbol} can follow the current state in the
840      * ATN. The behavior of this method is equivalent to the following, but is
841      * implemented such that the complete context-sensitive follow set does not
842      * need to be explicitly constructed.
843      *
844      * <pre>
845      * return getExpectedTokens().contains(symbol);
846      * </pre>
847      *
848      *  @param symbol the symbol type to check
849      *  @return {@code true} if {@code symbol} can follow the current state in
850      * the ATN, otherwise {@code false}.
851      */
852     public bool isExpectedToken(int symbol)
853     {
854         ATN atn = getInterpreter().atn;
855         ParserRuleContext ctx = ctx_;
856         ATNState s = atn.states[getState];
857         IntervalSet following = atn.nextTokens(s);
858         if (following.contains(symbol)) {
859             return true;
860         }
861         //        System.out.println("following "+s+"="+following);
862         if (!following.contains(TokenConstantDefinition.EPSILON))
863             return false;
864 
865         while (ctx !is null && ctx.invokingState>=0 && following.contains(TokenConstantDefinition.EPSILON) ) {
866             ATNState invokingState = atn.states[ctx.invokingState];
867             RuleTransition rt = cast(RuleTransition)invokingState.transition(0);
868             following = atn.nextTokens(rt.followState);
869             if (following.contains(symbol)) {
870                 return true;
871             }
872 
873             ctx = cast(ParserRuleContext)ctx.parent;
874         }
875         if (following.contains(TokenConstantDefinition.EPSILON) && symbol == TokenConstantDefinition.EOF) {
876             return true;
877         }
878 
879         return false;
880     }
881 
882     public bool isMatchedEOF()
883     {
884 	return matchedEOF;
885     }
886 
887     /**
888      * @uml
889      * Computes the set of input symbols which could follow the current parser
890      * state and context, as given by {@link #getState} and {@link #getContext},
891      * espectively.
892      *
893      *  @see ATN#getExpectedTokens(int, RuleContext)
894      */
895     public IntervalSet getExpectedTokens()
896     {
897         return getATN().getExpectedTokens(getState(), ctx_);
898     }
899 
900     public IntervalSet getExpectedTokensWithinCurrentRule()
901     {
902         ATN atn = getInterpreter().atn;
903         ATNState s = atn.states[getState];
904         return atn.nextTokens(s);
905     }
906 
907     /**
908      * @uml
909      * Get a rule's index (i.e., {@code RULE_ruleName} field) or -1 if not found.
910      */
911     public int getRuleIndex(string ruleName)
912     {
913         if (ruleName in getRuleIndexMap)
914             return getRuleIndexMap[ruleName];
915         return -1;
916     }
917 
918     public ParserRuleContext getRuleContext()
919     {
920         return ctx_;
921     }
922 
923     /**
924      * @uml
925      * Return List&lt;String&gt; of the rule names in your parser instance
926      * leading up to a call to the current rule.  You could override if
927      * you want more details such as the file/line info of where
928      * in the ATN a rule is invoked.
929      *
930      * This is very useful for error messages.
931      */
932     public string[] getRuleInvocationStack()
933     {
934 	return getRuleInvocationStack(ctx_);
935     }
936 
937     public string[] getRuleInvocationStack(RuleContext p)
938     {
939 	string[] ruleNames = getRuleNames();
940         string[] stack;
941         while (p) {
942             // compute what follows who invoked us
943             int ruleIndex = p.getRuleIndex();
944             if (ruleIndex < 0)
945                 stack ~= "n/a";
946             else
947                 stack ~= ruleNames[ruleIndex];
948             p = p.getParent;
949         }
950         return stack;
951     }
952 
953     /**
954      * @uml
955      * For debugging and other purposes.
956      */
957     public string[] getDFAStrings()
958     {
959         string[] s;
960         for (int d = 0; d < _interp.decisionToDFA.length; d++) {
961             DFA dfa = _interp.decisionToDFA[d];
962             s ~= dfa.toString(getVocabulary());
963         }
964         return s;
965     }
966 
967     /**
968      * @uml
969      * For debugging and other purposes.
970      */
971     public void dumpDFA()
972     {
973         bool seenOne = false;
974         for (int d = 0; d < _interp.decisionToDFA.length; d++) {
975             DFA dfa = _interp.decisionToDFA[d];
976             if (dfa.states.length) {
977                 if (seenOne) writeln();
978                 writefln("Decision %1$s:", dfa.decision);
979                 writefln(dfa.toString(getVocabulary()));
980                 seenOne = true;
981             }
982         }
983     }
984 
985     public string getSourceName()
986     {
987         return _input.getSourceName();
988     }
989 
990     /**
991      * @uml
992      * @override
993      */
994     public override ParseInfo getParseInfo()
995     {
996 	ParserATNSimulator interp = getInterpreter();
997         if (interp.classinfo == ProfilingATNSimulator.classinfo) {
998             return new ParseInfo(cast(ProfilingATNSimulator)interp);
999         }
1000         return null;
1001     }
1002 
1003     public void setProfile(bool profile)
1004     {
1005         ParserATNSimulator interp = getInterpreter();
1006         auto saveMode = interp.getPredictionMode();
1007         if (profile) {
1008             if (interp.classinfo != ProfilingATNSimulator.classinfo) {
1009                 setInterpreter(new ProfilingATNSimulator(this));
1010             }
1011         }
1012         else if (interp.classinfo == ProfilingATNSimulator.classinfo) {
1013             ParserATNSimulator sim =
1014                 new ParserATNSimulator(this, getATN(), interp.decisionToDFA, interp.getSharedContextCache());
1015             setInterpreter(sim);
1016         }
1017         getInterpreter().setPredictionMode(saveMode);
1018     }
1019 
1020     public void setTrace(bool trace)
1021     {
1022 	if (!trace) {
1023             removeParseListener(_tracer);
1024             _tracer = null;
1025         }
1026         else {
1027             if (_tracer !is null ) removeParseListener(_tracer);
1028             else _tracer = new TraceListener();
1029             addParseListener(_tracer);
1030         }
1031     }
1032 
1033     /**
1034      * @uml
1035      * Gets whether a {@link TraceListener} is registered as a parse listener
1036      * for the parser.
1037      *
1038      *  @see #setTrace(boolean)
1039      */
1040     public bool isTrace()
1041     {
1042         return _tracer !is null;
1043     }
1044 
1045     public final ParserRuleContext ctx()
1046     {
1047         return this.ctx_;
1048     }
1049 
1050     public final void ctx(ParserRuleContext ctx)
1051     {
1052         this.ctx_ = ctx;
1053     }
1054 
1055 }