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