1 /*
2  * Copyright (c) 2012-2017 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 package org.antlr.v4.runtime;
7 
8 import org.antlr.v4.runtime.atn.ATN;
9 import org.antlr.v4.runtime.misc.Interval;
10 import org.antlr.v4.runtime.tree.ParseTree;
11 import org.antlr.v4.runtime.tree.ParseTreeVisitor;
12 import org.antlr.v4.runtime.tree.RuleNode;
13 import org.antlr.v4.runtime.tree.Trees;
14 
15 import java.util.Arrays;
16 import java.util.List;
17 
18 /** A rule context is a record of a single rule invocation.
19  *
20  *  We form a stack of these context objects using the parent
21  *  pointer. A parent pointer of null indicates that the current
22  *  context is the bottom of the stack. The ParserRuleContext subclass
23  *  as a children list so that we can turn this data structure into a
24  *  tree.
25  *
26  *  The root node always has a null pointer and invokingState of -1.
27  *
28  *  Upon entry to parsing, the first invoked rule function creates a
29  *  context object (a subclass specialized for that rule such as
30  *  SContext) and makes it the root of a parse tree, recorded by field
31  *  Parser._ctx.
32  *
33  *  public final SContext s() throws RecognitionException {
34  *      SContext _localctx = new SContext(_ctx, getState()); <-- create new node
35  *      enterRule(_localctx, 0, RULE_s);                     <-- push it
36  *      ...
37  *      exitRule();                                          <-- pop back to _localctx
38  *      return _localctx;
39  *  }
40  *
41  *  A subsequent rule invocation of r from the start rule s pushes a
42  *  new context object for r whose parent points at s and use invoking
43  *  state is the state with r emanating as edge label.
44  *
45  *  The invokingState fields from a context object to the root
46  *  together form a stack of rule indication states where the root
47  *  (bottom of the stack) has a -1 sentinel value. If we invoke start
48  *  symbol s then call r1, which calls r2, the  would look like
49  *  this:
50  *
51  *     SContext[-1]   <- root node (bottom of the stack)
52  *     R1Context[p]   <- p in rule s called r1
53  *     R2Context[q]   <- q in rule r1 called r2
54  *
55  *  So the top of the stack, _ctx, represents a call to the current
56  *  rule and it holds the return address from another rule that invoke
57  *  to this rule. To invoke a rule, we must always have a current context.
58  *
59  *  The parent contexts are useful for computing lookahead sets and
60  *  getting error information.
61  *
62  *  These objects are used during parsing and prediction.
63  *  For the special case of parsers, we use the subclass
64  *  ParserRuleContext.
65  *
66  *  @see ParserRuleContext
67  */
68 public class RuleContext implements RuleNode {
69 	public static final ParserRuleContext EMPTY = new ParserRuleContext();
70 
71 	/** What context invoked this rule? */
72 	public RuleContext parent;
73 
74 	/** What state invoked the rule associated with this context?
75 	 *  The "return address" is the followState of invokingState
76 	 *  If parent is null, this should be -1 this context object represents
77 	 *  the start rule.
78 	 */
79 	public int invokingState = -1;
80 
RuleContext()81 	public RuleContext() {}
82 
RuleContext(RuleContext parent, int invokingState)83 	public RuleContext(RuleContext parent, int invokingState) {
84 		this.parent = parent;
85 		//if ( parent!=null ) System.out.println("invoke "+stateNumber+" from "+parent);
86 		this.invokingState = invokingState;
87 	}
88 
depth()89 	public int depth() {
90 		int n = 0;
91 		RuleContext p = this;
92 		while ( p!=null ) {
93 			p = p.parent;
94 			n++;
95 		}
96 		return n;
97 	}
98 
99 	/** A context is empty if there is no invoking state; meaning nobody called
100 	 *  current context.
101 	 */
isEmpty()102 	public boolean isEmpty() {
103 		return invokingState == -1;
104 	}
105 
106 	// satisfy the ParseTree / SyntaxTree interface
107 
108 	@Override
getSourceInterval()109 	public Interval getSourceInterval() {
110 		return Interval.INVALID;
111 	}
112 
113 	@Override
getRuleContext()114 	public RuleContext getRuleContext() { return this; }
115 
116 	@Override
getParent()117 	public RuleContext getParent() { return parent; }
118 
119 	@Override
getPayload()120 	public RuleContext getPayload() { return this; }
121 
122 	/** Return the combined text of all child nodes. This method only considers
123 	 *  tokens which have been added to the parse tree.
124 	 *  <p>
125 	 *  Since tokens on hidden channels (e.g. whitespace or comments) are not
126 	 *  added to the parse trees, they will not appear in the output of this
127 	 *  method.
128 	 */
129 	@Override
getText()130 	public String getText() {
131 		if (getChildCount() == 0) {
132 			return "";
133 		}
134 
135 		StringBuilder builder = new StringBuilder();
136 		for (int i = 0; i < getChildCount(); i++) {
137 			builder.append(getChild(i).getText());
138 		}
139 
140 		return builder.toString();
141 	}
142 
getRuleIndex()143 	public int getRuleIndex() { return -1; }
144 
145 	/** For rule associated with this parse tree internal node, return
146 	 *  the outer alternative number used to match the input. Default
147 	 *  implementation does not compute nor store this alt num. Create
148 	 *  a subclass of ParserRuleContext with backing field and set
149 	 *  option contextSuperClass.
150 	 *  to set it.
151 	 *
152 	 *  @since 4.5.3
153 	 */
getAltNumber()154 	public int getAltNumber() { return ATN.INVALID_ALT_NUMBER; }
155 
156 	/** Set the outer alternative number for this context node. Default
157 	 *  implementation does nothing to avoid backing field overhead for
158 	 *  trees that don't need it.  Create
159      *  a subclass of ParserRuleContext with backing field and set
160      *  option contextSuperClass.
161 	 *
162 	 *  @since 4.5.3
163 	 */
setAltNumber(int altNumber)164 	public void setAltNumber(int altNumber) { }
165 
166 	/** @since 4.7. {@see ParseTree#setParent} comment */
167 	@Override
setParent(RuleContext parent)168 	public void setParent(RuleContext parent) {
169 		this.parent = parent;
170 	}
171 
172 	@Override
getChild(int i)173 	public ParseTree getChild(int i) {
174 		return null;
175 	}
176 
177 	@Override
getChildCount()178 	public int getChildCount() {
179 		return 0;
180 	}
181 
182 	@Override
accept(ParseTreeVisitor<? extends T> visitor)183 	public <T> T accept(ParseTreeVisitor<? extends T> visitor) { return visitor.visitChildren(this); }
184 
185 	/** Print out a whole tree, not just a node, in LISP format
186 	 *  (root child1 .. childN). Print just a node if this is a leaf.
187 	 *  We have to know the recognizer so we can get rule names.
188 	 */
189 	@Override
toStringTree(Parser recog)190 	public String toStringTree(Parser recog) {
191 		return Trees.toStringTree(this, recog);
192 	}
193 
194 	/** Print out a whole tree, not just a node, in LISP format
195 	 *  (root child1 .. childN). Print just a node if this is a leaf.
196 	 */
toStringTree(List<String> ruleNames)197 	public String toStringTree(List<String> ruleNames) {
198 		return Trees.toStringTree(this, ruleNames);
199 	}
200 
201 	@Override
toStringTree()202 	public String toStringTree() {
203 		return toStringTree((List<String>)null);
204 	}
205 
206 	@Override
toString()207 	public String toString() {
208 		return toString((List<String>)null, (RuleContext)null);
209 	}
210 
toString(Recognizer<?,?> recog)211 	public final String toString(Recognizer<?,?> recog) {
212 		return toString(recog, ParserRuleContext.EMPTY);
213 	}
214 
toString(List<String> ruleNames)215 	public final String toString(List<String> ruleNames) {
216 		return toString(ruleNames, null);
217 	}
218 
219 	// recog null unless ParserRuleContext, in which case we use subclass toString(...)
toString(Recognizer<?,?> recog, RuleContext stop)220 	public String toString(Recognizer<?,?> recog, RuleContext stop) {
221 		String[] ruleNames = recog != null ? recog.getRuleNames() : null;
222 		List<String> ruleNamesList = ruleNames != null ? Arrays.asList(ruleNames) : null;
223 		return toString(ruleNamesList, stop);
224 	}
225 
toString(List<String> ruleNames, RuleContext stop)226 	public String toString(List<String> ruleNames, RuleContext stop) {
227 		StringBuilder buf = new StringBuilder();
228 		RuleContext p = this;
229 		buf.append("[");
230 		while (p != null && p != stop) {
231 			if (ruleNames == null) {
232 				if (!p.isEmpty()) {
233 					buf.append(p.invokingState);
234 				}
235 			}
236 			else {
237 				int ruleIndex = p.getRuleIndex();
238 				String ruleName = ruleIndex >= 0 && ruleIndex < ruleNames.size() ? ruleNames.get(ruleIndex) : Integer.toString(ruleIndex);
239 				buf.append(ruleName);
240 			}
241 
242 			if (p.parent != null && (ruleNames != null || !p.parent.isEmpty())) {
243 				buf.append(" ");
244 			}
245 
246 			p = p.parent;
247 		}
248 
249 		buf.append("]");
250 		return buf.toString();
251 	}
252 }
253