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