1 /*
2 * Copyright (c) 2012-2020 The ANTLR Project. All rights reserved.
3 * Use of this file is governed by the BSD 3-clause license that
4 * can be found in the LICENSE.txt file in the project root.
5 */6 7 moduleantlr.v4.runtime.ParserRuleContext;
8 9 importantlr.v4.runtime.InterfaceParser;
10 importantlr.v4.runtime.RecognitionException;
11 importantlr.v4.runtime.RuleContext;
12 importantlr.v4.runtime.Token;
13 importantlr.v4.runtime.misc;
14 importantlr.v4.runtime.tree.ErrorNode;
15 importantlr.v4.runtime.tree.ErrorNodeImpl;
16 importantlr.v4.runtime.tree.ParseTree;
17 importantlr.v4.runtime.tree.ParseTreeListener;
18 importantlr.v4.runtime.tree.TerminalNode;
19 importantlr.v4.runtime.tree.TerminalNodeImpl;
20 importstd.algorithm;
21 importstd.conv;
22 importstd.format;
23 importstd.variant;
24 25 /**
26 * A rule invocation record for parsing.
27 *
28 * Contains all of the information about the current rule not stored in the
29 * RuleContext. It handles parse tree children list, Any ATN state
30 * tracing, and the default values available for rule invocations:
31 * start, stop, rule index, current alt number.
32 *
33 * Subclasses made for each rule and grammar track the parameters,
34 * return values, locals, and labels specific to that rule. These
35 * are the objects that are returned from rules.
36 *
37 * Note text is not an actual field of a rule return value; it is computed
38 * from start and stop using the input stream's toString() method. I
39 * could add a ctor to this so that we can pass in and store the input
40 * stream, but I'm not sure we want to do that. It would seem to be undefined
41 * to get the .text property anyway if the rule matches tokens from multiple
42 * input streams.
43 *
44 * I do not use getters for fields of objects that are used simply to
45 * group values such as this aggregate. The getters/setters are there to
46 * satisfy the superclass interface.
47 */48 classParserRuleContext : RuleContext49 {
50 51 /**
52 * @uml
53 * @__gshared
54 */55 publicstatic__gsharedParserRuleContextEMPTY = newParserRuleContext;
56 57 /**
58 * If we are debugging or building a parse tree for a visitor,
59 * we need to track all of the tokens and rule invocations associated
60 * with this rule's context. This is empty for parsing w/o tree constr.
61 * operation because we don't the need to track the details about
62 * how we parse this rule.
63 */64 publicParseTree[] children;
65 66 publicTokenstart;
67 68 publicTokenstop;
69 70 /**
71 * The exception that forced this rule to return. If the rule successfully
72 * completed, this is {@code null}.
73 */74 publicRecognitionExceptionexception;
75 76 publicthis()
77 {
78 }
79 80 publicthis(ParserRuleContextparent, intinvokingStateNumber)
81 {
82 super(parent, invokingStateNumber);
83 }
84 85 /**
86 * COPY a ctx (I'm deliberately not using copy constructor) to avoid
87 * confusion with creating node with parent. Does not copy children
88 * (except error leaves).
89 *
90 * This is used in the generated parser code to flip a generic XContext
91 * node for rule X to a YContext for alt label Y. In that sense, it is
92 * not really a generic copy function.
93 *
94 * If we do an error sync() at start of a rule, we might add error nodes
95 * to the generic XContext so this function must copy those nodes to
96 * the YContext as well else they are lost!
97 */98 publicvoidcopyFrom(ParserRuleContextctx)
99 {
100 this.parent = ctx.parent;
101 this.invokingState = ctx.invokingState;
102 103 this.start = ctx.start;
104 this.stop = ctx.stop;
105 // copy any error nodes to alt label node106 if (ctx.children) {
107 this.children.length = 0;
108 // reset parent pointer for any error nodes109 foreach (ParseTreechild; ctx.children) {
110 if (cast(ErrorNode)child) {
111 addChild(cast(ErrorNode)child);
112 }
113 }
114 }
115 }
116 117 publicvoidenterRule(ParseTreeListenerlistener)
118 {
119 }
120 121 publicvoidexitRule(ParseTreeListenerlistener)
122 {
123 }
124 125 /**
126 * Add a parse tree node to this as a child. Works for
127 * internal and leaf nodes. Does not set parent link;
128 * other add methods must do that. Other addChild methods
129 * call this.
130 *
131 * We cannot set the parent pointer of the incoming node
132 * because the existing interfaces do not have a setParent()
133 * method and I don't want to break backward compatibility for this.
134 *
135 * @since 4.7
136 */137 publicParseTreeaddAnyChild(ParseTreet)
138 {
139 if (childrenisnull) {
140 ParseTree[] newChildren;
141 children = newChildren;
142 }
143 children ~= t;
144 returnt;
145 }
146 147 publicRuleContextaddChild(RuleContextruleInvocation)
148 {
149 returncast(RuleContext)addAnyChild(ruleInvocation);
150 }
151 152 /**
153 * Add a token leaf node child and force its parent to be this node.
154 */155 publicTerminalNodeaddChild(TerminalNodet)
156 {
157 t.setParent(this);
158 returncast(TerminalNode)addAnyChild(t);
159 }
160 161 /**
162 * Used by enterOuterAlt to toss out a RuleContext previously added as
163 * we entered a rule. If we have # label, we will need to remove
164 * generic ruleContext object.
165 */166 publicvoidremoveLastChild()
167 {
168 if (children !isnull) {
169 children.length--;
170 }
171 }
172 173 publicTerminalNodeaddChild(TokenmatchedToken)
174 {
175 TerminalNodeImplt = newTerminalNodeImpl(matchedToken);
176 addChild(t);
177 t.parent = this;
178 returnt;
179 }
180 181 publicErrorNodeaddErrorNode(TokenbadToken)
182 {
183 ErrorNodeImplt = newErrorNodeImpl(badToken);
184 addChild(t);
185 t.parent = this;
186 returnt;
187 }
188 189 /**
190 * Override to make type more specific
191 * @uml
192 * @override
193 */194 publicoverrideParserRuleContextgetParent()
195 {
196 returncast(ParserRuleContext)super.getParent();
197 }
198 199 /**
200 * @uml
201 * @override
202 */203 publicoverrideParseTreegetChild(inti)
204 {
205 returnchildren && i >= 0 &&
206 i < to!int(children.length) ? children[i] : null;
207 }
208 209 publicautogetChild(T)(inti)
210 {
211 if (childrenisnull || i < 0 || i >= children.length) {
212 returnnull;
213 }
214 215 intj = -1; // what element have we found with ctxType?216 foreach (o; children) {
217 if (cast(T)o) {
218 j++;
219 if (j == i) {
220 returncast(T)o;
221 }
222 }
223 }
224 returnnull;
225 }
226 227 publicTerminalNodegetToken(intttype, inti)
228 {
229 if (childrenisnull || i < 0 || i >= children.length) {
230 returnnull;
231 }
232 233 intj = -1; // what token with ttype have we found?234 foreach (o; children) {
235 if (cast(TerminalNode)o) {
236 TerminalNodetnode = cast(TerminalNode)o;
237 Tokensymbol = tnode.getSymbol;
238 if (symbol.getType == ttype) {
239 j++;
240 if ( j == i ) {
241 returntnode;
242 }
243 }
244 }
245 }
246 returnnull;
247 }
248 249 publicTerminalNode[] getTokens(intttype)
250 {
251 TerminalNode[] emptyList;
252 if (childrenisnull) {
253 returnemptyList;
254 }
255 256 TerminalNode[] tokens = null;
257 foreach (o; children) {
258 if (cast(TerminalNode)o) {
259 TerminalNodetnode = cast(TerminalNode)o;
260 Tokensymbol = tnode.getSymbol;
261 if (symbol.getType == ttype) {
262 if (tokensisnull) {
263 tokens.length = 0;
264 }
265 tokens ~= tnode;
266 }
267 }
268 }
269 270 if (tokensisnull) {
271 returnemptyList;
272 }
273 returntokens;
274 }
275 276 publicTgetRuleContext(T)(inti)
277 {
278 returngetChild!T(i);
279 }
280 281 publicT[] getRuleContexts(T)()
282 {
283 if (childrenisnull) {
284 T[] l;
285 returnl;
286 }
287 T[] contexts = null;
288 foreach (o; children) {
289 if (cast(T)o) {
290 contexts ~= cast(T)o;
291 }
292 }
293 294 if (contextsisnull) {
295 T[] l;
296 returnl;
297 }
298 returncontexts;
299 }
300 301 /**
302 * @uml
303 * @override
304 */305 publicoverrideintgetChildCount()
306 {
307 returnchildren ? to!int(children.length) : 0;
308 }
309 310 /**
311 * @uml
312 * @override
313 */314 publicoverrideIntervalgetSourceInterval()
315 {
316 if (startisnull) {
317 returncast(Interval)Interval.INVALID;
318 }
319 if (stopisnull || stop.getTokenIndex()<start.getTokenIndex()) {
320 returnInterval.of(to!int(start.getTokenIndex), to!int(start.getTokenIndex)-1); // empty321 }
322 returnInterval.of(to!int(start.getTokenIndex), to!int(stop.getTokenIndex));
323 }
324 325 /**
326 * Get the initial token in this context.
327 * Note that the range from start to stop is inclusive, so for rules that do not consume anything
328 * (for example, zero length or error productions) this token may exceed stop.
329 */330 publicTokengetStart()
331 {
332 returnstart;
333 }
334 335 /**
336 * Get the final token in this context.
337 * Note that the range from start to stop is inclusive, so for rules that do not consume anything
338 * (for example, zero length or error productions) this token may precede start.
339 */340 publicTokengetStop()
341 {
342 returnstop;
343 }
344 345 /**
346 * Used for rule context info debugging during parse-time, not so much for ATN debugging
347 */348 publicstringtoInfoString(InterfaceParserrecognizer)
349 {
350 string[] rules = recognizer.getRuleInvocationStack(this);
351 rules.reverse();
352 returnformat("ParserRuleContext{ %1$s " ~
353 "start=%2$s, stop=%3$s}", rules,
354 start.getText, stop.getText);
355 }
356 357 }
358 359 version (AntlrUnittest)
360 {
361 importdshould;
362 363 @("emptyInstanceParserRuleContext")
364 unittest365 {
366 autorpc = ParserRuleContext.EMPTY;
367 rpc.should.not.be(null);
368 rpc.getChildCount.should.equal(0);
369 autorpc1 = ParserRuleContext.EMPTY;
370 rpc1.should.not.be(null);
371 rpc1.should.be(rpc);
372 rpc.getStart.should.equal(null);
373 rpc.getStop.should.equal(null);
374 rpc.getSourceInterval.toString.should.equal("-1..-2");
375 rpc.getParent.should.be(null);
376 }
377 }