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