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