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 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, size_t 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<String> 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 auto 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)
963 writeln();
964 writefln!"Decision %1$s:"(dfa.decision);
965 write(dfa.toString(getVocabulary));
966 seenOne = true;
967 }
968 }
969 }
970
971 public string getSourceName()
972 {
973 return _input.getSourceName();
974 }
975
976 /**
977 * @uml
978 * @override
979 */
980 public override ParseInfo getParseInfo()
981 {
982 ParserATNSimulator interp = getInterpreter;
983 if (interp.classinfo == ProfilingATNSimulator.classinfo) {
984 return new ParseInfo(cast(ProfilingATNSimulator)interp);
985 }
986 return null;
987 }
988
989 public void setProfile(bool profile)
990 {
991 ParserATNSimulator interp = getInterpreter();
992 auto saveMode = interp.getPredictionMode();
993 if (profile) {
994 if (interp.classinfo != ProfilingATNSimulator.classinfo) {
995 setInterpreter(new ProfilingATNSimulator(this));
996 }
997 }
998 else if (interp.classinfo == ProfilingATNSimulator.classinfo) {
999 ParserATNSimulator sim =
1000 new ParserATNSimulator(this, getATN(), interp.decisionToDFA, interp.getSharedContextCache());
1001 setInterpreter(sim);
1002 }
1003 getInterpreter.setPredictionMode(saveMode);
1004 }
1005
1006 public void setTrace(bool trace)
1007 {
1008 if (!trace) {
1009 removeParseListener(_tracer);
1010 _tracer = null;
1011 }
1012 else {
1013 if (_tracer !is null ) removeParseListener(_tracer);
1014 else _tracer = new TraceListener();
1015 addParseListener(_tracer);
1016 }
1017 }
1018
1019 /**
1020 * @uml
1021 * Gets whether a {@link TraceListener} is registered as a parse listener
1022 * for the parser.
1023 *
1024 * @see #setTrace(boolean)
1025 */
1026 public bool isTrace()
1027 {
1028 return _tracer !is null;
1029 }
1030
1031 public final ParserRuleContext ctx()
1032 {
1033 return this.ctx_;
1034 }
1035
1036 public final void ctx(ParserRuleContext ctx)
1037 {
1038 this.ctx_ = ctx;
1039 }
1040
1041 public final int numberOfSyntaxErrors()
1042 {
1043 return this.numberOfSyntaxErrors_;
1044 }
1045
1046 }