1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.jexl3.parser;
18
19 import org.apache.commons.jexl3.JexlArithmetic;
20 import org.apache.commons.jexl3.JexlCache;
21 import org.apache.commons.jexl3.JexlContext.NamespaceFunctor;
22 import org.apache.commons.jexl3.JexlInfo;
23 import org.apache.commons.jexl3.JxltEngine;
24 import org.apache.commons.jexl3.introspection.JexlMethod;
25 import org.apache.commons.jexl3.introspection.JexlPropertyGet;
26 import org.apache.commons.jexl3.introspection.JexlPropertySet;
27
28
29
30
31
32
33 public abstract class JexlNode extends SimpleNode implements JexlCache.Reference {
34
35
36
37
38
39
40 public interface Constant<T> {
41 T getLiteral();
42 }
43
44
45
46
47 public interface Funcall {}
48
49
50
51
52 public interface JxltHandle {
53
54
55 String getExpressionSource();
56
57
58 JxltEngine.Expression getExpression();
59
60
61
62
63
64
65 void setExpression(JxltEngine.Expression expr);
66 }
67
68 @Override
69 public Object getCache() {
70 return jjtGetValue();
71 }
72
73 @Override
74 public void setCache(final Object cache) {
75 jjtSetValue(cache);
76 }
77
78
79
80
81
82 public static class Info extends JexlInfo {
83 JexlNode node;
84
85
86
87
88
89
90 public Info(final JexlNode jnode) {
91 this(jnode, jnode.jexlInfo());
92 }
93
94
95
96
97
98
99
100 public Info(final JexlNode jnode, final JexlInfo info) {
101 this(jnode, info.getName(), info.getLine(), info.getColumn());
102 }
103
104
105
106
107
108
109
110
111
112 private Info(final JexlNode jnode, final String name, final int l, final int c) {
113 super(name, l, c);
114 node = jnode;
115 }
116
117 @Override
118 public JexlInfo at(final int l, final int c) {
119 return new Info(node, getName(), l, c);
120 }
121
122 @Override
123 public JexlInfo detach() {
124 node = null;
125 return this;
126 }
127
128
129
130
131 public JexlNode getNode() {
132 return node;
133 }
134 }
135
136
137
138 private static final long serialVersionUID = 1L;
139
140
141 private int lc = -1;
142
143 public JexlNode(final int id) {
144 super(id);
145 }
146
147
148
149
150
151
152
153
154 @Deprecated
155 public JexlNode(final Parser p, final int id) {
156 super(p, id);
157 }
158
159
160
161
162
163
164
165 public void clearCache() {
166 final Object value = jjtGetValue();
167 if (value instanceof JexlPropertyGet
168 || value instanceof JexlPropertySet
169 || value instanceof JexlMethod
170 || value instanceof Funcall
171 || value instanceof Class
172 || value instanceof NamespaceFunctor) {
173 jjtSetValue(null);
174 }
175 for (int n = 0; n < jjtGetNumChildren(); ++n) {
176 jjtGetChild(n).clearCache();
177 }
178 }
179
180 public int getColumn() {
181 return this.lc & 0xfff;
182 }
183
184 public int getLine() {
185 return this.lc >>> 0xc;
186 }
187
188
189
190
191
192
193
194
195 public boolean isConstant() {
196 return isConstant(this instanceof JexlNode.Constant<?>);
197 }
198
199 protected boolean isConstant(final boolean literal) {
200 if (literal) {
201 for (int n = 0; n < jjtGetNumChildren(); ++n) {
202 final JexlNode child = jjtGetChild(n);
203 if (child instanceof ASTReference || child instanceof ASTMapEntry) {
204 final boolean is = child.isConstant(true);
205 if (!is) {
206 return false;
207 }
208 } else if (!child.isConstant()) {
209 return false;
210 }
211 }
212 return true;
213 }
214 return false;
215 }
216
217
218
219
220 public boolean isGlobalVar() {
221 if (this instanceof ASTVar) {
222 return false;
223 }
224 if (this instanceof ASTIdentifier) {
225 return ((ASTIdentifier) this).getSymbol() < 0;
226 }
227 final int nc = jjtGetNumChildren() - 1;
228 if (nc >= 0) {
229 final JexlNode first = jjtGetChild(0);
230 return first.isGlobalVar();
231 }
232 if (jjtGetParent() instanceof ASTReference) {
233 return true;
234 }
235 return false;
236 }
237
238
239
240
241
242
243 public boolean isLeftValue() {
244 JexlNode walk = this;
245 do {
246 if (walk instanceof ASTIdentifier
247 || walk instanceof ASTIdentifierAccess
248 || walk instanceof ASTArrayAccess) {
249 return true;
250 }
251 final int nc = walk.jjtGetNumChildren() - 1;
252 if (nc < 0) {
253 return walk.jjtGetParent() instanceof ASTReference;
254 }
255 walk = walk.jjtGetChild(nc);
256 } while (walk != null);
257 return false;
258 }
259
260
261
262
263
264
265
266
267 public boolean isSafeLhs(final boolean safe) {
268 if (this instanceof ASTReference) {
269 return jjtGetChild(0).isSafeLhs(safe);
270 }
271 if (this instanceof ASTMethodNode) {
272 if (jjtGetNumChildren() > 1
273 && jjtGetChild(0) instanceof ASTIdentifierAccess
274 && (((ASTIdentifierAccess) jjtGetChild(0)).isSafe() || safe)) {
275 return true;
276 }
277 }
278 final JexlNode parent = jjtGetParent();
279 if (parent == null) {
280 return false;
281 }
282
283 final int nsiblings = parent.jjtGetNumChildren();
284 int rhs = -1;
285 for(int s = 0; s < nsiblings; ++s) {
286 final JexlNode sibling = parent.jjtGetChild(s);
287 if (sibling == this) {
288
289 rhs = s + 1;
290 break;
291 }
292 }
293
294 if (rhs >= 0 && rhs < nsiblings) {
295 JexlNode rsibling = parent.jjtGetChild(rhs);
296 if (rsibling instanceof ASTMethodNode || rsibling instanceof ASTFunctionNode) {
297 rsibling = rsibling.jjtGetChild(0);
298 }
299 if (rsibling instanceof ASTIdentifierAccess
300 && (((ASTIdentifierAccess) rsibling).isSafe() || safe)) {
301 return true;
302 }
303 if (rsibling instanceof ASTArrayAccess) {
304 return safe;
305 }
306 }
307 return false;
308 }
309
310
311
312
313
314
315
316
317
318 public boolean isStrictOperator(final JexlArithmetic arithmetic) {
319 return OperatorController.INSTANCE.isStrict(arithmetic, this);
320 }
321
322
323
324
325
326
327 public JexlInfo jexlInfo() {
328 return jexlInfo(null);
329 }
330
331
332
333
334
335
336
337 public JexlInfo jexlInfo(final String name) {
338 JexlInfo info = null;
339 JexlNode node = this;
340 while (node != null) {
341 if (node.jjtGetValue() instanceof JexlInfo) {
342 info = (JexlInfo) node.jjtGetValue();
343 break;
344 }
345 node = node.jjtGetParent();
346 }
347 if (lc >= 0) {
348 final int c = lc & 0xfff;
349 final int l = lc >> 0xc;
350
351 return info != null ? info.at(info.getLine() + l - 1, c) : new JexlInfo(name, l, c);
352 }
353
354 return info;
355 }
356
357 public void jjtSetFirstToken(final Token t) {
358
359
360 this.lc = t.beginLine << 0xc | 0xfff & t.beginColumn;
361 }
362
363 public void jjtSetLastToken(final Token t) {
364
365 }
366
367 }