1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.jexl3.internal;
19
20 import java.util.Iterator;
21 import java.util.concurrent.Callable;
22 import java.util.function.Consumer;
23
24 import org.apache.commons.jexl3.JexlArithmetic;
25 import org.apache.commons.jexl3.JexlContext;
26 import org.apache.commons.jexl3.JexlEngine;
27 import org.apache.commons.jexl3.JexlException;
28 import org.apache.commons.jexl3.JexlInfo;
29 import org.apache.commons.jexl3.JexlOperator;
30 import org.apache.commons.jexl3.JexlOptions;
31 import org.apache.commons.jexl3.JexlScript;
32 import org.apache.commons.jexl3.JxltEngine;
33
34 import org.apache.commons.jexl3.introspection.JexlMethod;
35 import org.apache.commons.jexl3.introspection.JexlPropertyGet;
36
37 import org.apache.commons.jexl3.parser.*;
38
39
40
41
42
43
44 public class Interpreter extends InterpreterBase {
45
46 protected int fp = 0;
47
48 protected final Frame frame;
49
50 protected LexicalFrame block = null;
51
52
53
54
55 protected static final java.lang.ThreadLocal<Interpreter> INTER =
56 new java.lang.ThreadLocal<>();
57
58
59
60
61
62
63
64
65 protected Interpreter(final Engine engine, final JexlOptions opts, final JexlContext aContext, final Frame eFrame) {
66 super(engine, opts, aContext);
67 this.frame = eFrame;
68 }
69
70
71
72
73
74
75 protected Interpreter(final Interpreter ii, final JexlArithmetic jexla) {
76 super(ii, jexla);
77 frame = ii.frame;
78 block = ii.block != null? new LexicalFrame(ii.block) : null;
79 }
80
81
82
83
84
85
86 protected Interpreter putThreadInterpreter(final Interpreter inter) {
87 final Interpreter pinter = INTER.get();
88 INTER.set(inter);
89 return pinter;
90 }
91
92
93
94
95
96
97
98
99
100
101 public Object interpret(final JexlNode node) {
102 JexlContext.ThreadLocal tcontext = null;
103 JexlEngine tjexl = null;
104 Interpreter tinter = null;
105 try {
106 tinter = putThreadInterpreter(this);
107 if (tinter != null) {
108 fp = tinter.fp + 1;
109 }
110 if (context instanceof JexlContext.ThreadLocal) {
111 tcontext = jexl.putThreadLocal((JexlContext.ThreadLocal) context);
112 }
113 tjexl = jexl.putThreadEngine(jexl);
114 if (fp > jexl.stackOverflow) {
115 throw new JexlException.StackOverflow(node.jexlInfo(), "jexl (" + jexl.stackOverflow + ")", null);
116 }
117 cancelCheck(node);
118 return arithmetic.controlReturn(node.jjtAccept(this, null));
119 } catch(final StackOverflowError xstack) {
120 final JexlException xjexl = new JexlException.StackOverflow(node.jexlInfo(), "jvm", xstack);
121 if (!isSilent()) {
122 throw xjexl.clean();
123 }
124 if (logger.isWarnEnabled()) {
125 logger.warn(xjexl.getMessage(), xjexl.getCause());
126 }
127 } catch (final JexlException.Return xreturn) {
128 return xreturn.getValue();
129 } catch (final JexlException.Cancel xcancel) {
130
131 cancelled.weakCompareAndSet(false, Thread.interrupted());
132 if (isCancellable()) {
133 throw xcancel.clean();
134 }
135 } catch (final JexlException xjexl) {
136 if (!isSilent()) {
137 throw xjexl.clean();
138 }
139 if (logger.isWarnEnabled()) {
140 logger.warn(xjexl.getMessage(), xjexl.getCause());
141 }
142 } finally {
143
144 if (fp == 0) {
145 synchronized (this) {
146 if (functors != null) {
147 for (final Object functor : functors.values()) {
148 closeIfSupported(functor);
149 }
150 functors.clear();
151 functors = null;
152 }
153 }
154 }
155 jexl.putThreadEngine(tjexl);
156 if (context instanceof JexlContext.ThreadLocal) {
157 jexl.putThreadLocal(tcontext);
158 }
159 if (tinter != null) {
160 fp = tinter.fp - 1;
161 }
162 putThreadInterpreter(tinter);
163 }
164 return null;
165 }
166
167
168
169
170
171
172
173
174 public Object getAttribute(final Object object, final Object attribute) {
175 return getAttribute(object, attribute, null);
176 }
177
178
179
180
181
182
183
184
185 public void setAttribute(final Object object, final Object attribute, final Object value) {
186 setAttribute(object, attribute, value, null);
187 }
188
189 @Override
190 protected Object visit(final ASTAddNode node, final Object data) {
191 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
192 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
193 try {
194 final Object result = operators.tryOverload(node, JexlOperator.ADD, left, right);
195 return result != JexlEngine.TRY_FAILED ? result : arithmetic.add(left, right);
196 } catch (final ArithmeticException xrt) {
197 throw new JexlException(findNullOperand(node, left, right), "+ error", xrt);
198 }
199 }
200
201 @Override
202 protected Object visit(final ASTSubNode node, final Object data) {
203 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
204 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
205 try {
206 final Object result = operators.tryOverload(node, JexlOperator.SUBTRACT, left, right);
207 return result != JexlEngine.TRY_FAILED ? result : arithmetic.subtract(left, right);
208 } catch (final ArithmeticException xrt) {
209 throw new JexlException(findNullOperand(node, left, right), "- error", xrt);
210 }
211 }
212
213 @Override
214 protected Object visit(final ASTMulNode node, final Object data) {
215 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
216 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
217 try {
218 final Object result = operators.tryOverload(node, JexlOperator.MULTIPLY, left, right);
219 return result != JexlEngine.TRY_FAILED ? result : arithmetic.multiply(left, right);
220 } catch (final ArithmeticException xrt) {
221 throw new JexlException(findNullOperand(node, left, right), "* error", xrt);
222 }
223 }
224
225 @Override
226 protected Object visit(final ASTDivNode node, final Object data) {
227 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
228 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
229 try {
230 final Object result = operators.tryOverload(node, JexlOperator.DIVIDE, left, right);
231 return result != JexlEngine.TRY_FAILED ? result : arithmetic.divide(left, right);
232 } catch (final ArithmeticException xrt) {
233 if (!arithmetic.isStrict()) {
234 return 0.0d;
235 }
236 throw new JexlException(findNullOperand(node, left, right), "/ error", xrt);
237 }
238 }
239
240 @Override
241 protected Object visit(final ASTModNode node, final Object data) {
242 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
243 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
244 try {
245 final Object result = operators.tryOverload(node, JexlOperator.MOD, left, right);
246 return result != JexlEngine.TRY_FAILED ? result : arithmetic.mod(left, right);
247 } catch (final ArithmeticException xrt) {
248 if (!arithmetic.isStrict()) {
249 return 0.0d;
250 }
251 throw new JexlException(findNullOperand(node, left, right), "% error", xrt);
252 }
253 }
254
255 @Override
256 protected Object visit(final ASTBitwiseAndNode node, final Object data) {
257 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
258 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
259 try {
260 final Object result = operators.tryOverload(node, JexlOperator.AND, left, right);
261 return result != JexlEngine.TRY_FAILED ? result : arithmetic.and(left, right);
262 } catch (final ArithmeticException xrt) {
263 throw new JexlException(findNullOperand(node, left, right), "& error", xrt);
264 }
265 }
266
267 @Override
268 protected Object visit(final ASTBitwiseOrNode node, final Object data) {
269 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
270 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
271 try {
272 final Object result = operators.tryOverload(node, JexlOperator.OR, left, right);
273 return result != JexlEngine.TRY_FAILED ? result : arithmetic.or(left, right);
274 } catch (final ArithmeticException xrt) {
275 throw new JexlException(findNullOperand(node, left, right), "| error", xrt);
276 }
277 }
278
279 @Override
280 protected Object visit(final ASTBitwiseXorNode node, final Object data) {
281 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
282 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
283 try {
284 final Object result = operators.tryOverload(node, JexlOperator.XOR, left, right);
285 return result != JexlEngine.TRY_FAILED ? result : arithmetic.xor(left, right);
286 } catch (final ArithmeticException xrt) {
287 throw new JexlException(findNullOperand(node, left, right), "^ error", xrt);
288 }
289 }
290
291 @Override
292 protected Object visit(final ASTShiftLeftNode node, final Object data) {
293 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
294 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
295 try {
296 final Object result = operators.tryOverload(node, JexlOperator.SHIFTLEFT, left, right);
297 return result != JexlEngine.TRY_FAILED ? result : arithmetic.shiftLeft(left, right);
298 } catch (final ArithmeticException xrt) {
299 throw new JexlException(findNullOperand(node, left, right), "<< error", xrt);
300 }
301 }
302
303 @Override
304 protected Object visit(final ASTShiftRightNode node, final Object data) {
305 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
306 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
307 try {
308 final Object result = operators.tryOverload(node, JexlOperator.SHIFTRIGHT, left, right);
309 return result != JexlEngine.TRY_FAILED ? result : arithmetic.shiftRight(left, right);
310 } catch (final ArithmeticException xrt) {
311 throw new JexlException(findNullOperand(node, left, right), ">> error", xrt);
312 }
313 }
314
315 @Override
316 protected Object visit(final ASTShiftRightUnsignedNode node, final Object data) {
317 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
318 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
319 try {
320 final Object result = operators.tryOverload(node, JexlOperator.SHIFTRIGHTU, left, right);
321 return result != JexlEngine.TRY_FAILED ? result : arithmetic.shiftRightUnsigned(left, right);
322 } catch (final ArithmeticException xrt) {
323 throw new JexlException(findNullOperand(node, left, right), ">> error", xrt);
324 }
325 }
326
327 @Override
328 protected Object visit(final ASTEQNode node, final Object data) {
329 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
330 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
331 try {
332 final Object result = operators.tryOverload(node, JexlOperator.EQ, left, right);
333 return result != JexlEngine.TRY_FAILED ? result : arithmetic.equals(left, right);
334 } catch (final ArithmeticException xrt) {
335 throw new JexlException(findNullOperand(node, left, right), "== error", xrt);
336 }
337 }
338
339 @Override
340 protected Object visit(final ASTNENode node, final Object data) {
341 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
342 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
343 try {
344 final Object result = operators.tryOverload(node, JexlOperator.EQ, left, right);
345 return result != JexlEngine.TRY_FAILED
346 ? !arithmetic.toBoolean(result)
347 : !arithmetic.equals(left, right);
348 } catch (final ArithmeticException xrt) {
349 throw new JexlException(findNullOperand(node, left, right), "!= error", xrt);
350 }
351 }
352
353 @Override
354 protected Object visit(final ASTGENode node, final Object data) {
355 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
356 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
357 try {
358 final Object result = operators.tryOverload(node, JexlOperator.GTE, left, right);
359 return result != JexlEngine.TRY_FAILED
360 ? result
361 : arithmetic.greaterThanOrEqual(left, right);
362 } catch (final ArithmeticException xrt) {
363 throw new JexlException(findNullOperand(node, left, right), ">= error", xrt);
364 }
365 }
366
367 @Override
368 protected Object visit(final ASTGTNode node, final Object data) {
369 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
370 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
371 try {
372 final Object result = operators.tryOverload(node, JexlOperator.GT, left, right);
373 return result != JexlEngine.TRY_FAILED
374 ? result
375 : arithmetic.greaterThan(left, right);
376 } catch (final ArithmeticException xrt) {
377 throw new JexlException(findNullOperand(node, left, right), "> error", xrt);
378 }
379 }
380
381 @Override
382 protected Object visit(final ASTLENode node, final Object data) {
383 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
384 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
385 try {
386 final Object result = operators.tryOverload(node, JexlOperator.LTE, left, right);
387 return result != JexlEngine.TRY_FAILED
388 ? result
389 : arithmetic.lessThanOrEqual(left, right);
390 } catch (final ArithmeticException xrt) {
391 throw new JexlException(findNullOperand(node, left, right), "<= error", xrt);
392 }
393 }
394
395 @Override
396 protected Object visit(final ASTLTNode node, final Object data) {
397 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
398 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
399 try {
400 final Object result = operators.tryOverload(node, JexlOperator.LT, left, right);
401 return result != JexlEngine.TRY_FAILED
402 ? result
403 : arithmetic.lessThan(left, right);
404 } catch (final ArithmeticException xrt) {
405 throw new JexlException(findNullOperand(node, left, right), "< error", xrt);
406 }
407 }
408
409 @Override
410 protected Object visit(final ASTSWNode node, final Object data) {
411 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
412 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
413 return operators.startsWith(node, "^=", left, right);
414 }
415
416 @Override
417 protected Object visit(final ASTNSWNode node, final Object data) {
418 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
419 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
420 return !operators.startsWith(node, "^!", left, right);
421 }
422
423 @Override
424 protected Object visit(final ASTEWNode node, final Object data) {
425 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
426 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
427 return operators.endsWith(node, "$=", left, right);
428 }
429
430 @Override
431 protected Object visit(final ASTNEWNode node, final Object data) {
432 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
433 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
434 return !operators.endsWith(node, "$!", left, right);
435 }
436
437 @Override
438 protected Object visit(final ASTERNode node, final Object data) {
439 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
440 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
441
442
443 return operators.contains(node, "=~", right, left);
444 }
445
446 @Override
447 protected Object visit(final ASTNRNode node, final Object data) {
448 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
449 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
450
451
452 return !operators.contains(node, "!~", right, left);
453 }
454
455 @Override
456 protected Object visit(final ASTRangeNode node, final Object data) {
457 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
458 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
459 try {
460 return arithmetic.createRange(left, right);
461 } catch (final ArithmeticException xrt) {
462 throw new JexlException(findNullOperand(node, left, right), ".. error", xrt);
463 }
464 }
465
466 @Override
467 protected Object visit(final ASTUnaryMinusNode node, final Object data) {
468
469 final Object value = node.jjtGetValue();
470 if (value != null && !(value instanceof JexlMethod)) {
471 return value;
472 }
473 final JexlNode valNode = node.jjtGetChild(0);
474 final Object val = valNode.jjtAccept(this, data);
475 try {
476 final Object result = operators.tryOverload(node, JexlOperator.NEGATE, val);
477 if (result != JexlEngine.TRY_FAILED) {
478 return result;
479 }
480 Object number = arithmetic.negate(val);
481
482
483 if (number instanceof Number && valNode instanceof ASTNumberLiteral) {
484 number = arithmetic.narrowNumber((Number) number, ((ASTNumberLiteral) valNode).getLiteralClass());
485 if (arithmetic.isNegateStable()) {
486 node.jjtSetValue(number);
487 }
488 }
489 return number;
490 } catch (final ArithmeticException xrt) {
491 throw new JexlException(valNode, "- error", xrt);
492 }
493 }
494
495 @Override
496 protected Object visit(final ASTUnaryPlusNode node, final Object data) {
497
498 final Object value = node.jjtGetValue();
499 if (value != null && !(value instanceof JexlMethod)) {
500 return value;
501 }
502 final JexlNode valNode = node.jjtGetChild(0);
503 final Object val = valNode.jjtAccept(this, data);
504 try {
505 final Object result = operators.tryOverload(node, JexlOperator.POSITIVIZE, val);
506 if (result != JexlEngine.TRY_FAILED) {
507 return result;
508 }
509 final Object number = arithmetic.positivize(val);
510 if (valNode instanceof ASTNumberLiteral
511 && number instanceof Number
512 && arithmetic.isPositivizeStable()) {
513 node.jjtSetValue(number);
514 }
515 return number;
516 } catch (final ArithmeticException xrt) {
517 throw new JexlException(valNode, "- error", xrt);
518 }
519 }
520
521 @Override
522 protected Object visit(final ASTBitwiseComplNode node, final Object data) {
523 final Object arg = node.jjtGetChild(0).jjtAccept(this, data);
524 try {
525 final Object result = operators.tryOverload(node, JexlOperator.COMPLEMENT, arg);
526 return result != JexlEngine.TRY_FAILED ? result : arithmetic.complement(arg);
527 } catch (final ArithmeticException xrt) {
528 throw new JexlException(node, "~ error", xrt);
529 }
530 }
531
532 @Override
533 protected Object visit(final ASTNotNode node, final Object data) {
534 final Object val = node.jjtGetChild(0).jjtAccept(this, data);
535 try {
536 final Object result = operators.tryOverload(node, JexlOperator.NOT, val);
537 return result != JexlEngine.TRY_FAILED ? result : arithmetic.not(val);
538 } catch (final ArithmeticException xrt) {
539 throw new JexlException(node, "! error", xrt);
540 }
541 }
542
543 private boolean testPredicate(final JexlNode node, final Object condition) {
544 final Object predicate = operators.tryOverload(node, JexlOperator.CONDITION, condition);
545 return arithmetic.testPredicate(predicate != JexlEngine.TRY_FAILED? predicate : condition);
546 }
547
548 @Override
549 protected Object visit(final ASTIfStatement node, final Object data) {
550 final int n = 0;
551 final int numChildren = node.jjtGetNumChildren();
552 try {
553 Object result = null;
554
555 for(int ifElse = 0; ifElse < (numChildren - 1); ifElse += 2) {
556 final JexlNode testNode = node.jjtGetChild(ifElse);
557 final Object condition = testNode.jjtAccept(this, null);
558 if (testPredicate(testNode, condition)) {
559
560 return node.jjtGetChild(ifElse + 1).jjtAccept(this, null);
561 }
562 }
563
564 if ((numChildren & 1) == 1) {
565
566
567 result = node.jjtGetChild(numChildren - 1).jjtAccept(this, null);
568 }
569 return result;
570 } catch (final ArithmeticException xrt) {
571 throw new JexlException(node.jjtGetChild(n), "if error", xrt);
572 }
573 }
574
575 @Override
576 protected Object visit(final ASTVar node, final Object data) {
577 final int symbol = node.getSymbol();
578
579 if (!options.isLexical() && !node.isLexical()) {
580 if (frame.has(symbol)) {
581 return frame.get(symbol);
582 }
583 } else if (!defineVariable(node, block)) {
584 return redefinedVariable(node, node.getName());
585 }
586 frame.set(symbol, null);
587 return null;
588 }
589
590 @Override
591 protected Object visit(final ASTBlock node, final Object data) {
592 final int cnt = node.getSymbolCount();
593 if (cnt <= 0) {
594 return visitBlock(node, data);
595 }
596 try {
597 block = new LexicalFrame(frame, block);
598 return visitBlock(node, data);
599 } finally {
600 block = block.pop();
601 }
602 }
603
604
605
606
607
608
609
610 private Object visitBlock(final ASTBlock node, final Object data) {
611 final int numChildren = node.jjtGetNumChildren();
612 Object result = null;
613 for (int i = 0; i < numChildren; i++) {
614 cancelCheck(node);
615 result = node.jjtGetChild(i).jjtAccept(this, data);
616 }
617 return result;
618 }
619
620 @Override
621 protected Object visit(final ASTReturnStatement node, final Object data) {
622 final Object val = node.jjtGetChild(0).jjtAccept(this, data);
623 cancelCheck(node);
624 throw new JexlException.Return(node, null, val);
625 }
626
627 @Override
628 protected Object visit(final ASTContinue node, final Object data) {
629 throw new JexlException.Continue(node);
630 }
631
632 @Override
633 protected Object visit(final ASTBreak node, final Object data) {
634 throw new JexlException.Break(node);
635 }
636
637 @Override
638 protected Object visit(final ASTForeachStatement node, final Object data) {
639 return node.getLoopForm() == 0 ? forIterator(node, data) : forLoop(node, data);
640 }
641
642 private Object forIterator(final ASTForeachStatement node, final Object data) {
643 Object result = null;
644
645 final ASTReference loopReference = (ASTReference) node.jjtGetChild(0);
646 final ASTIdentifier loopVariable = (ASTIdentifier) loopReference.jjtGetChild(0);
647 final int symbol = loopVariable.getSymbol();
648 final boolean lexical = loopVariable.isLexical() || options.isLexical() ;
649 final LexicalFrame locals = lexical? new LexicalFrame(frame, block) : null;
650 final boolean loopSymbol = symbol >= 0 && loopVariable instanceof ASTVar;
651 if (lexical) {
652
653
654 if (loopSymbol && !defineVariable((ASTVar) loopVariable, locals)) {
655 return redefinedVariable(node, loopVariable.getName());
656 }
657 block = locals;
658 }
659 Object forEach = null;
660 try {
661
662 final Object iterableValue = node.jjtGetChild(1).jjtAccept(this, data);
663
664 if (iterableValue == null) {
665 return null;
666 }
667
668 final int numChildren = node.jjtGetNumChildren();
669 final JexlNode statement = numChildren >= 3 ? node.jjtGetChild(numChildren - 1) : null;
670
671 forEach = operators.tryOverload(node, JexlOperator.FOR_EACH, iterableValue);
672 final Iterator<?> itemsIterator = forEach instanceof Iterator
673 ? (Iterator<?>) forEach
674 : uberspect.getIterator(iterableValue);
675 if (itemsIterator == null) {
676 return null;
677 }
678 int cnt = 0;
679 while (itemsIterator.hasNext()) {
680 cancelCheck(node);
681
682 if (lexical && cnt++ > 0) {
683
684 block.pop();
685
686 if (loopSymbol && !defineVariable((ASTVar) loopVariable, locals)) {
687 return redefinedVariable(node, loopVariable.getName());
688 }
689 }
690
691 final Object value = itemsIterator.next();
692 if (symbol < 0) {
693 setContextVariable(node, loopVariable.getName(), value);
694 } else {
695 frame.set(symbol, value);
696 }
697 if (statement != null) {
698 try {
699
700 result = statement.jjtAccept(this, data);
701 } catch (final JexlException.Break stmtBreak) {
702 break;
703 } catch (final JexlException.Continue stmtContinue) {
704
705 }
706 }
707 }
708 } finally {
709
710 closeIfSupported(forEach);
711
712 if (lexical) {
713 block = block.pop();
714 }
715 }
716 return result;
717 }
718
719 private Object forLoop(final ASTForeachStatement node, final Object data) {
720 Object result = null;
721 int nc;
722 final int form = node.getLoopForm();
723 final LexicalFrame locals;
724
725 if ((form & 1) != 0) {
726 nc = 1;
727 final JexlNode init = node.jjtGetChild(0);
728 ASTVar loopVariable = null;
729 if (init instanceof ASTAssignment) {
730 final JexlNode child = init.jjtGetChild(0);
731 if (child instanceof ASTVar) {
732 loopVariable = (ASTVar) child;
733 }
734 } else if (init instanceof ASTVar){
735 loopVariable = (ASTVar) init;
736 }
737 if (loopVariable != null) {
738 final boolean lexical = loopVariable.isLexical() || options.isLexical();
739 locals = lexical ? new LexicalFrame(frame, block) : null;
740 if (locals != null) {
741 block = locals;
742 }
743 } else {
744 locals = null;
745 }
746
747 init.jjtAccept(this, data);
748
749 for (JexlNode moreAssignment = node.jjtGetChild(nc);
750 moreAssignment instanceof ASTAssignment;
751 moreAssignment = node.jjtGetChild(++nc)) {
752 moreAssignment.jjtAccept(this, data);
753 }
754 } else {
755 locals = null;
756 nc = 0;
757 }
758 try {
759
760 final JexlNode predicate = (form & 2) != 0? node.jjtGetChild(nc++) : null;
761
762 final JexlNode step = (form & 4) != 0? node.jjtGetChild(nc++) : null;
763
764 final JexlNode statement = (form & 8) != 0 ? node.jjtGetChild(nc) : null;
765
766 while (predicate == null || testPredicate(predicate, predicate.jjtAccept(this, data))) {
767 cancelCheck(node);
768
769 if (statement != null) {
770 try {
771
772 result = statement.jjtAccept(this, data);
773 } catch (final JexlException.Break stmtBreak) {
774 break;
775 } catch (final JexlException.Continue stmtContinue) {
776
777 }
778 }
779
780 if (step != null) {
781 step.jjtAccept(this, data);
782 }
783 }
784 } finally {
785
786 if (locals != null) {
787 block = block.pop();
788 }
789 }
790 return result;
791 }
792
793 @Override
794 protected Object visit(final ASTWhileStatement node, final Object data) {
795 Object result = null;
796
797 final JexlNode condition = node.jjtGetChild(0);
798 while (testPredicate(condition, condition.jjtAccept(this, data))) {
799 cancelCheck(node);
800 if (node.jjtGetNumChildren() > 1) {
801 try {
802
803 result = node.jjtGetChild(1).jjtAccept(this, data);
804 } catch (final JexlException.Break stmtBreak) {
805 break;
806 } catch (final JexlException.Continue stmtContinue) {
807
808 }
809 }
810 }
811 return result;
812 }
813
814 @Override
815 protected Object visit(final ASTDoWhileStatement node, final Object data) {
816 Object result = null;
817 final int nc = node.jjtGetNumChildren();
818
819 final JexlNode condition = node.jjtGetChild(nc - 1);
820 do {
821 cancelCheck(node);
822 if (nc > 1) {
823 try {
824
825 result = node.jjtGetChild(0).jjtAccept(this, data);
826 } catch (final JexlException.Break stmtBreak) {
827 break;
828 } catch (final JexlException.Continue stmtContinue) {
829
830 }
831 }
832 } while (testPredicate(condition, condition.jjtAccept(this, data)));
833 return result;
834 }
835
836 @Override
837 protected Object visit(final ASTAndNode node, final Object data) {
838
839
840
841
842
843 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
844 try {
845 final boolean leftValue = arithmetic.toBoolean(left);
846 if (!leftValue) {
847 return Boolean.FALSE;
848 }
849 } catch (final ArithmeticException xrt) {
850 throw new JexlException(node.jjtGetChild(0), "boolean coercion error", xrt);
851 }
852 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
853 try {
854 final boolean rightValue = arithmetic.toBoolean(right);
855 if (!rightValue) {
856 return Boolean.FALSE;
857 }
858 } catch (final ArithmeticException xrt) {
859 throw new JexlException(node.jjtGetChild(1), "boolean coercion error", xrt);
860 }
861 return Boolean.TRUE;
862 }
863
864 @Override
865 protected Object visit(final ASTOrNode node, final Object data) {
866 final Object left = node.jjtGetChild(0).jjtAccept(this, data);
867 try {
868 final boolean leftValue = arithmetic.toBoolean(left);
869 if (leftValue) {
870 return Boolean.TRUE;
871 }
872 } catch (final ArithmeticException xrt) {
873 throw new JexlException(node.jjtGetChild(0), "boolean coercion error", xrt);
874 }
875 final Object right = node.jjtGetChild(1).jjtAccept(this, data);
876 try {
877 final boolean rightValue = arithmetic.toBoolean(right);
878 if (rightValue) {
879 return Boolean.TRUE;
880 }
881 } catch (final ArithmeticException xrt) {
882 throw new JexlException(node.jjtGetChild(1), "boolean coercion error", xrt);
883 }
884 return Boolean.FALSE;
885 }
886
887 @Override
888 protected Object visit(final ASTNullLiteral node, final Object data) {
889 return null;
890 }
891
892 @Override
893 protected Object visit(final ASTTrueNode node, final Object data) {
894 return Boolean.TRUE;
895 }
896
897 @Override
898 protected Object visit(final ASTFalseNode node, final Object data) {
899 return Boolean.FALSE;
900 }
901
902 @Override
903 protected Object visit(final ASTNumberLiteral node, final Object data) {
904 if (data != null && node.isInteger()) {
905 return getAttribute(data, node.getLiteral(), node);
906 }
907 return node.getLiteral();
908 }
909
910 @Override
911 protected Object visit(final ASTStringLiteral node, final Object data) {
912 if (data != null) {
913 return getAttribute(data, node.getLiteral(), node);
914 }
915 return node.getLiteral();
916 }
917
918 @Override
919 protected Object visit(final ASTRegexLiteral node, final Object data) {
920 return node.getLiteral();
921 }
922
923 @Override
924 protected Object visit(final ASTArrayLiteral node, final Object data) {
925 final int childCount = node.jjtGetNumChildren();
926 final JexlArithmetic.ArrayBuilder ab = arithmetic.arrayBuilder(childCount);
927 boolean extended = false;
928 for (int i = 0; i < childCount; i++) {
929 cancelCheck(node);
930 final JexlNode child = node.jjtGetChild(i);
931 if (child instanceof ASTExtendedLiteral) {
932 extended = true;
933 } else {
934 final Object entry = node.jjtGetChild(i).jjtAccept(this, data);
935 ab.add(entry);
936 }
937 }
938 return ab.create(extended);
939 }
940
941 @Override
942 protected Object visit(final ASTExtendedLiteral node, final Object data) {
943 return node;
944 }
945
946 @Override
947 protected Object visit(final ASTSetLiteral node, final Object data) {
948 final int childCount = node.jjtGetNumChildren();
949 final JexlArithmetic.SetBuilder mb = arithmetic.setBuilder(childCount);
950 for (int i = 0; i < childCount; i++) {
951 cancelCheck(node);
952 final Object entry = node.jjtGetChild(i).jjtAccept(this, data);
953 mb.add(entry);
954 }
955 return mb.create();
956 }
957
958 @Override
959 protected Object visit(final ASTMapLiteral node, final Object data) {
960 final int childCount = node.jjtGetNumChildren();
961 final JexlArithmetic.MapBuilder mb = arithmetic.mapBuilder(childCount);
962 for (int i = 0; i < childCount; i++) {
963 cancelCheck(node);
964 final Object[] entry = (Object[]) (node.jjtGetChild(i)).jjtAccept(this, data);
965 mb.put(entry[0], entry[1]);
966 }
967 return mb.create();
968 }
969
970 @Override
971 protected Object visit(final ASTMapEntry node, final Object data) {
972 final Object key = node.jjtGetChild(0).jjtAccept(this, data);
973 final Object value = node.jjtGetChild(1).jjtAccept(this, data);
974 return new Object[]{key, value};
975 }
976
977 @Override
978 protected Object visit(final ASTTernaryNode node, final Object data) {
979 Object condition;
980 try {
981 condition = node.jjtGetChild(0).jjtAccept(this, data);
982 } catch(final JexlException xany) {
983 if (!(xany.getCause() instanceof JexlArithmetic.NullOperand)) {
984 throw xany;
985 }
986 condition = null;
987 }
988
989 if (node.jjtGetNumChildren() == 3) {
990 if (condition != null && arithmetic.toBoolean(condition)) {
991 return node.jjtGetChild(1).jjtAccept(this, data);
992 }
993 return node.jjtGetChild(2).jjtAccept(this, data);
994 }
995
996 if (condition != null && arithmetic.toBoolean(condition)) {
997 return condition;
998 }
999 return node.jjtGetChild(1).jjtAccept(this, data);
1000 }
1001
1002 @Override
1003 protected Object visit(final ASTNullpNode node, final Object data) {
1004 Object lhs;
1005 try {
1006 lhs = node.jjtGetChild(0).jjtAccept(this, data);
1007 } catch(final JexlException xany) {
1008 if (!(xany.getCause() instanceof JexlArithmetic.NullOperand)) {
1009 throw xany;
1010 }
1011 lhs = null;
1012 }
1013
1014 return lhs != null? lhs : node.jjtGetChild(1).jjtAccept(this, data);
1015 }
1016
1017 @Override
1018 protected Object visit(final ASTSizeFunction node, final Object data) {
1019 try {
1020 final Object val = node.jjtGetChild(0).jjtAccept(this, data);
1021 return operators.size(node, val);
1022 } catch(final JexlException xany) {
1023 return 0;
1024 }
1025 }
1026
1027 @Override
1028 protected Object visit(final ASTEmptyFunction node, final Object data) {
1029 try {
1030 final Object value = node.jjtGetChild(0).jjtAccept(this, data);
1031 return operators.empty(node, value);
1032 } catch(final JexlException xany) {
1033 return true;
1034 }
1035 }
1036
1037
1038
1039
1040
1041
1042
1043 protected Object visitLexicalNode(final JexlNode node, final Object data) {
1044 block = new LexicalFrame(frame, null);
1045 try {
1046 return node.jjtAccept(this, data);
1047 } finally {
1048 block = block.pop();
1049 }
1050 }
1051
1052
1053
1054
1055
1056
1057
1058 protected Object runClosure(final Closure closure, final Object data) {
1059 final ASTJexlScript script = closure.getScript();
1060
1061 final int numChildren = script.jjtGetNumChildren();
1062 if (numChildren == 0) {
1063 return null;
1064 }
1065 block = new LexicalFrame(frame, block).defineArgs();
1066 try {
1067 final JexlNode body = script instanceof ASTJexlLambda
1068 ? script.jjtGetChild(numChildren - 1)
1069 : script;
1070 return interpret(body);
1071 } finally {
1072 block = block.pop();
1073 }
1074 }
1075
1076 @Override
1077 protected Object visit(final ASTJexlScript script, final Object data) {
1078 if (script instanceof ASTJexlLambda && !((ASTJexlLambda) script).isTopLevel()) {
1079 final Closure closure = new Closure(this, (ASTJexlLambda) script);
1080
1081 final JexlNode child0 = script.jjtGetChild(0);
1082 if (child0 instanceof ASTVar) {
1083 final ASTVar var = (ASTVar) child0;
1084 this.visit(var, data);
1085 final int symbol = var.getSymbol();
1086 frame.set(symbol, closure);
1087
1088 closure.setCaptured(symbol, closure);
1089 }
1090 return closure;
1091 }
1092 block = new LexicalFrame(frame, block).defineArgs();
1093 try {
1094 final int numChildren = script.jjtGetNumChildren();
1095 Object result = null;
1096 for (int i = 0; i < numChildren; i++) {
1097 final JexlNode child = script.jjtGetChild(i);
1098 result = child.jjtAccept(this, data);
1099 cancelCheck(child);
1100 }
1101 return result;
1102 } finally {
1103 block = block.pop();
1104 }
1105 }
1106
1107 @Override
1108 protected Object visit(final ASTReferenceExpression node, final Object data) {
1109 return node.jjtGetChild(0).jjtAccept(this, data);
1110 }
1111
1112 @Override
1113 protected Object visit(final ASTIdentifier identifier, final Object data) {
1114 cancelCheck(identifier);
1115 return data != null
1116 ? getAttribute(data, identifier.getName(), identifier)
1117 : getVariable(frame, block, identifier);
1118 }
1119
1120 @Override
1121 protected Object visit(final ASTArrayAccess node, final Object data) {
1122
1123 Object object = data;
1124
1125 final int numChildren = node.jjtGetNumChildren();
1126 for (int i = 0; i < numChildren; i++) {
1127 final JexlNode nindex = node.jjtGetChild(i);
1128 if (object == null) {
1129 return unsolvableProperty(nindex, stringifyProperty(nindex), false, null);
1130 }
1131 final Object index = nindex.jjtAccept(this, null);
1132 cancelCheck(node);
1133 object = getAttribute(object, index, nindex);
1134 }
1135 return object;
1136 }
1137
1138 @Override
1139 protected Object visit(final ASTQualifiedIdentifier node, final Object data) {
1140 final String name = node.getName();
1141
1142 String fqcn = fqcnSolver.resolveClassName(name);
1143 if (fqcn != null) {
1144 return fqcn;
1145 }
1146
1147 if (context instanceof JexlContext.ClassNameResolver) {
1148 final JexlContext.ClassNameResolver resolver = (JexlContext.ClassNameResolver) context;
1149 fqcn = resolver.resolveClassName(name);
1150 if (fqcn != null) {
1151 return fqcn;
1152 }
1153 }
1154 return name;
1155 }
1156
1157
1158
1159
1160
1161
1162
1163 private Object evalIdentifier(final ASTIdentifierAccess node) {
1164 if (!(node instanceof ASTIdentifierAccessJxlt)) {
1165 return node.getIdentifier();
1166 }
1167 final ASTIdentifierAccessJxlt accessJxlt = (ASTIdentifierAccessJxlt) node;
1168 final String src = node.getName();
1169 Throwable cause = null;
1170 TemplateEngine.TemplateExpression expr = (TemplateEngine.TemplateExpression) accessJxlt.getExpression();
1171 try {
1172 if (expr == null) {
1173 final TemplateEngine jxlt = jexl.jxlt();
1174 expr = jxlt.parseExpression(node.jexlInfo(), src, frame != null ? frame.getScope() : null);
1175 accessJxlt.setExpression(expr);
1176 }
1177 if (expr != null) {
1178 final Object name = expr.evaluate(context, frame, options);
1179 if (name != null) {
1180 final Integer id = ASTIdentifierAccess.parseIdentifier(name.toString());
1181 return id != null ? id : name;
1182 }
1183 }
1184 } catch (final JxltEngine.Exception xjxlt) {
1185 cause = xjxlt;
1186 }
1187 return node.isSafe() ? null : unsolvableProperty(node, src, true, cause);
1188 }
1189
1190 @Override
1191 protected Object visit(final ASTIdentifierAccess node, final Object data) {
1192 if (data == null) {
1193 return null;
1194 }
1195 final Object id = evalIdentifier(node);
1196 return getAttribute(data, id, node);
1197 }
1198
1199 @Override
1200 protected Object visit(final ASTReference node, final Object data) {
1201 cancelCheck(node);
1202 final int numChildren = node.jjtGetNumChildren();
1203 final JexlNode parent = node.jjtGetParent();
1204
1205 Object object = null;
1206 JexlNode objectNode = null;
1207 JexlNode ptyNode = null;
1208 StringBuilder ant = null;
1209 boolean antish = !(parent instanceof ASTReference) && options.isAntish();
1210 int v = 1;
1211 main:
1212 for (int c = 0; c < numChildren; c++) {
1213 objectNode = node.jjtGetChild(c);
1214 if (objectNode instanceof ASTMethodNode) {
1215 antish = false;
1216 if (object == null) {
1217
1218 if (ant != null) {
1219 final JexlNode child = objectNode.jjtGetChild(0);
1220 if (child instanceof ASTIdentifierAccess) {
1221 final int alen = ant.length();
1222 ant.append('.');
1223 ant.append(((ASTIdentifierAccess) child).getName());
1224 object = context.get(ant.toString());
1225 if (object != null) {
1226 object = visit((ASTMethodNode) objectNode, object, context);
1227 continue;
1228 }
1229
1230 ant.delete(alen, ant.length());
1231 ptyNode = objectNode;
1232 }
1233 }
1234 break;
1235 }
1236 } else if (objectNode instanceof ASTArrayAccess) {
1237 antish = false;
1238 if (object == null) {
1239 ptyNode = objectNode;
1240 break;
1241 }
1242 }
1243
1244 object = objectNode.jjtAccept(this, object);
1245 cancelCheck(node);
1246 if (object != null) {
1247
1248 antish = false;
1249 } else if (antish) {
1250
1251 if (ant == null) {
1252
1253 final JexlNode first = node.jjtGetChild(0);
1254 if (!(first instanceof ASTIdentifier)) {
1255
1256 ptyNode = objectNode;
1257 break main;
1258 }
1259 final ASTIdentifier afirst = (ASTIdentifier) first;
1260 ant = new StringBuilder(afirst.getName());
1261 continue;
1262
1263 }
1264
1265 for (; v <= c; ++v) {
1266 final JexlNode child = node.jjtGetChild(v);
1267 if (!(child instanceof ASTIdentifierAccess)) {
1268
1269 ptyNode = objectNode;
1270 break main;
1271 }
1272 final ASTIdentifierAccess achild = (ASTIdentifierAccess) child;
1273 if (achild.isSafe() || achild.isExpression()) {
1274 break main;
1275 }
1276 ant.append('.');
1277 ant.append(achild.getName());
1278 }
1279
1280 object = context.get(ant.toString());
1281 } else if (c != numChildren - 1) {
1282
1283 ptyNode = c == 0 && numChildren > 1 ? node.jjtGetChild(1) : objectNode;
1284 break;
1285 }
1286 }
1287
1288 if (object == null) {
1289 if (ptyNode != null) {
1290 if (ptyNode.isSafeLhs(isSafe())) {
1291 return null;
1292 }
1293 if (ant != null) {
1294 final String aname = ant.toString();
1295 final boolean defined = isVariableDefined(frame, block, aname);
1296 return unsolvableVariable(node, aname, !defined);
1297 }
1298 return unsolvableProperty(node,
1299 stringifyProperty(ptyNode), ptyNode == objectNode, null);
1300 }
1301 if (antish) {
1302 if (node.isSafeLhs(isSafe())) {
1303 return null;
1304 }
1305 final String aname = ant != null ? ant.toString() : "?";
1306 final boolean defined = isVariableDefined(frame, block, aname);
1307
1308 if (defined && !isStrictOperand(node)) {
1309 return null;
1310 }
1311 return unsolvableVariable(node, aname, !defined);
1312 }
1313 }
1314 return object;
1315 }
1316
1317 @Override
1318 protected Object visit(final ASTAssignment node, final Object data) {
1319 return executeAssign(node, null, data);
1320 }
1321
1322 @Override
1323 protected Object visit(final ASTSetAddNode node, final Object data) {
1324 return executeAssign(node, JexlOperator.SELF_ADD, data);
1325 }
1326
1327 @Override
1328 protected Object visit(final ASTSetSubNode node, final Object data) {
1329 return executeAssign(node, JexlOperator.SELF_SUBTRACT, data);
1330 }
1331
1332 @Override
1333 protected Object visit(final ASTSetMultNode node, final Object data) {
1334 return executeAssign(node, JexlOperator.SELF_MULTIPLY, data);
1335 }
1336
1337 @Override
1338 protected Object visit(final ASTSetDivNode node, final Object data) {
1339 return executeAssign(node, JexlOperator.SELF_DIVIDE, data);
1340 }
1341
1342 @Override
1343 protected Object visit(final ASTSetModNode node, final Object data) {
1344 return executeAssign(node, JexlOperator.SELF_MOD, data);
1345 }
1346
1347 @Override
1348 protected Object visit(final ASTSetAndNode node, final Object data) {
1349 return executeAssign(node, JexlOperator.SELF_AND, data);
1350 }
1351
1352 @Override
1353 protected Object visit(final ASTSetOrNode node, final Object data) {
1354 return executeAssign(node, JexlOperator.SELF_OR, data);
1355 }
1356
1357 @Override
1358 protected Object visit(final ASTSetXorNode node, final Object data) {
1359 return executeAssign(node, JexlOperator.SELF_XOR, data);
1360 }
1361
1362 @Override
1363 protected Object visit(final ASTSetShiftLeftNode node, final Object data) {
1364 return executeAssign(node, JexlOperator.SELF_SHIFTLEFT, data);
1365 }
1366
1367 @Override
1368 protected Object visit(final ASTSetShiftRightNode node, final Object data) {
1369 return executeAssign(node, JexlOperator.SELF_SHIFTRIGHT, data);
1370 }
1371
1372 @Override
1373 protected Object visit(final ASTSetShiftRightUnsignedNode node, final Object data) {
1374 return executeAssign(node, JexlOperator.SELF_SHIFTRIGHTU, data);
1375 }
1376
1377 @Override
1378 protected Object visit(final ASTGetDecrementNode node, final Object data) {
1379 return executeAssign(node, JexlOperator.GET_AND_DECREMENT, data);
1380 }
1381
1382 @Override
1383 protected Object visit(final ASTGetIncrementNode node, final Object data) {
1384 return executeAssign(node, JexlOperator.GET_AND_INCREMENT, data);
1385 }
1386
1387 @Override
1388 protected Object visit(final ASTDecrementGetNode node, final Object data) {
1389 return executeAssign(node, JexlOperator.DECREMENT_AND_GET, data);
1390 }
1391
1392 @Override
1393 protected Object visit(final ASTIncrementGetNode node, final Object data) {
1394 return executeAssign(node, JexlOperator.INCREMENT_AND_GET, data);
1395 }
1396
1397
1398
1399
1400
1401
1402
1403
1404 protected Object executeAssign(final JexlNode node, final JexlOperator assignop, final Object data) {
1405 cancelCheck(node);
1406
1407 final JexlNode left = node.jjtGetChild(0);
1408 final ASTIdentifier var;
1409 Object object = null;
1410 final int symbol;
1411
1412 if (left instanceof ASTIdentifier) {
1413 var = (ASTIdentifier) left;
1414 symbol = var.getSymbol();
1415 if (symbol >= 0 && (var.isLexical() || options.isLexical())) {
1416 if (var instanceof ASTVar) {
1417 if (!defineVariable((ASTVar) var, block)) {
1418 return redefinedVariable(var, var.getName());
1419 }
1420 } else if (var.isShaded() && (var.isLexical() || options.isLexicalShade())) {
1421 return undefinedVariable(var, var.getName());
1422 }
1423 }
1424 } else {
1425 var = null;
1426 symbol = -1;
1427 }
1428 boolean antish = options.isAntish();
1429
1430 final int last = left.jjtGetNumChildren() - 1;
1431
1432 final Object right = node.jjtGetNumChildren() < 2? null: node.jjtGetChild(1).jjtAccept(this, data);
1433
1434 Object actual = right;
1435
1436 if (var != null) {
1437 if (symbol >= 0) {
1438
1439 if (last < 0) {
1440 if (assignop == null) {
1441
1442 if (right instanceof Closure) {
1443 ((Closure) right).setCaptured(symbol, right);
1444 }
1445 frame.set(symbol, right);
1446 } else {
1447
1448 final Object self = getVariable(frame, block, var);
1449 final Consumer<Object> f = r -> frame.set(symbol, r);
1450 actual = operators.tryAssignOverload(node, assignop, f, self, right);
1451 }
1452 return actual;
1453 }
1454 object = getVariable(frame, block, var);
1455
1456 antish = false;
1457 } else {
1458
1459 final String name = var.getName();
1460 if (last < 0) {
1461 if (assignop == null) {
1462 setContextVariable(node, name, right);
1463 } else {
1464
1465 final Object self = context.get(name);
1466 final Consumer<Object> f = r -> setContextVariable(node, name, r);
1467 actual = operators.tryAssignOverload(node, assignop, f, self, right);
1468 }
1469 return actual;
1470 }
1471 object = context.get(name);
1472
1473 if (object != null) {
1474 antish = false;
1475 }
1476 }
1477 } else if (!(left instanceof ASTReference)) {
1478 throw new JexlException(left, "illegal assignment form 0");
1479 }
1480
1481 JexlNode objectNode = null;
1482 StringBuilder ant = null;
1483 int v = 1;
1484
1485 main: for (int c = symbol >= 0 ? 1 : 0; c < last; ++c) {
1486 objectNode = left.jjtGetChild(c);
1487 object = objectNode.jjtAccept(this, object);
1488 if (object != null) {
1489
1490 antish = false;
1491 } else if (antish) {
1492
1493 if (ant == null) {
1494 final JexlNode first = left.jjtGetChild(0);
1495 final ASTIdentifier firstId = first instanceof ASTIdentifier
1496 ? (ASTIdentifier) first
1497 : null;
1498 if ((firstId == null) || (firstId.getSymbol() >= 0)) {
1499
1500 antish = false;
1501 break main;
1502 }
1503 ant = new StringBuilder(firstId.getName());
1504 }
1505
1506 for (; v <= c; ++v) {
1507 final JexlNode child = left.jjtGetChild(v);
1508 final ASTIdentifierAccess aid = child instanceof ASTIdentifierAccess
1509 ? (ASTIdentifierAccess) child
1510 : null;
1511
1512 if ((aid == null) || aid.isSafe() || aid.isExpression()) {
1513 antish = false;
1514 break main;
1515 }
1516 ant.append('.');
1517 ant.append(aid.getName());
1518 }
1519
1520 object = context.get(ant.toString());
1521 } else {
1522 throw new JexlException(objectNode, "illegal assignment form");
1523 }
1524 }
1525
1526 JexlNode propertyNode = left.jjtGetChild(last);
1527 final ASTIdentifierAccess propertyId = propertyNode instanceof ASTIdentifierAccess
1528 ? (ASTIdentifierAccess) propertyNode
1529 : null;
1530 final Object property;
1531 if (propertyId != null) {
1532
1533 if (antish && ant != null && object == null && !propertyId.isSafe() && !propertyId.isExpression()) {
1534 ant.append('.');
1535 ant.append(propertyId.getName());
1536 final String name = ant.toString();
1537 if (assignop == null) {
1538 setContextVariable(propertyNode, name, right);
1539 } else {
1540 final Object self = context.get(ant.toString());
1541 final JexlNode pnode = propertyNode;
1542 final Consumer<Object> assign = r -> setContextVariable(pnode, name, r);
1543 actual = operators.tryAssignOverload(node, assignop, assign, self, right);
1544 }
1545 return actual;
1546 }
1547
1548 property = evalIdentifier(propertyId);
1549 } else if (propertyNode instanceof ASTArrayAccess) {
1550
1551 final int numChildren = propertyNode.jjtGetNumChildren() - 1;
1552 for (int i = 0; i < numChildren; i++) {
1553 final JexlNode nindex = propertyNode.jjtGetChild(i);
1554 final Object index = nindex.jjtAccept(this, null);
1555 object = getAttribute(object, index, nindex);
1556 }
1557 propertyNode = propertyNode.jjtGetChild(numChildren);
1558 property = propertyNode.jjtAccept(this, null);
1559 } else {
1560 throw new JexlException(objectNode, "illegal assignment form");
1561 }
1562
1563
1564 if (object == null) {
1565
1566 return unsolvableProperty(objectNode, "<null>.<?>", true, null);
1567 }
1568
1569 if (assignop == null) {
1570 setAttribute(object, property, right, propertyNode);
1571 } else {
1572 final Object self = getAttribute(object, property, propertyNode);
1573 final Object o = object;
1574 final JexlNode n = propertyNode;
1575 final Consumer<Object> assign = r -> setAttribute(o, property, r, n);
1576 actual = operators.tryAssignOverload(node, assignop, assign, self, right);
1577 }
1578 return actual;
1579 }
1580
1581 @Override
1582 protected Object visit(final ASTDefineVars node, final Object data) {
1583 final int argc = node.jjtGetNumChildren();
1584 Object result = null;
1585 for (int i = 0; i < argc; i++) {
1586 result = node.jjtGetChild(i).jjtAccept(this, data);
1587 }
1588 return result;
1589 }
1590
1591 @Override
1592 protected Object[] visit(final ASTArguments node, final Object data) {
1593 final int argc = node.jjtGetNumChildren();
1594 final Object[] argv = new Object[argc];
1595 for (int i = 0; i < argc; i++) {
1596 argv[i] = node.jjtGetChild(i).jjtAccept(this, data);
1597 }
1598 return argv;
1599 }
1600
1601 @Override
1602 protected Object visit(final ASTMethodNode node, final Object data) {
1603 return visit(node, null, data);
1604 }
1605
1606
1607
1608
1609
1610
1611
1612
1613 private Object visit(final ASTMethodNode node, final Object antish, final Object data) {
1614 Object object = antish;
1615
1616 final JexlNode methodNode = node.jjtGetChild(0);
1617 Object method;
1618
1619 if (methodNode instanceof ASTIdentifierAccess) {
1620 method = methodNode;
1621 if (object == null) {
1622 object = data;
1623 if (object == null) {
1624
1625 return node.isSafeLhs(isSafe())
1626 ? null
1627 : unsolvableMethod(methodNode, "<null>.<?>(...)");
1628 }
1629 } else {
1630
1631 method = object;
1632 }
1633 } else {
1634 method = methodNode.jjtAccept(this, data);
1635 }
1636 Object result = method;
1637 for (int a = 1; a < node.jjtGetNumChildren(); ++a) {
1638 if (result == null) {
1639
1640 return node.isSafeLhs(isSafe())
1641 ? null
1642 : unsolvableMethod(methodNode, "<?>.<null>(...)");
1643 }
1644 final ASTArguments argNode = (ASTArguments) node.jjtGetChild(a);
1645 result = call(node, object, result, argNode);
1646 object = result;
1647 }
1648 return result;
1649 }
1650
1651 @Override
1652 protected Object visit(final ASTFunctionNode node, final Object data) {
1653 final ASTIdentifier functionNode = (ASTIdentifier) node.jjtGetChild(0);
1654 final String nsid = functionNode.getNamespace();
1655 final Object namespace = (nsid != null)? resolveNamespace(nsid, node) : context;
1656 final ASTArguments argNode = (ASTArguments) node.jjtGetChild(1);
1657 return call(node, namespace, functionNode, argNode);
1658 }
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677 protected Object call(final JexlNode node, final Object target, final Object funcNode, final ASTArguments argNode) {
1678 cancelCheck(node);
1679
1680 final Object[] argv = visit(argNode, null);
1681 final String methodName;
1682 boolean cacheable = cache;
1683 boolean isavar = false;
1684 Object functor = funcNode;
1685
1686 if (functor instanceof ASTIdentifier) {
1687
1688 final ASTIdentifier methodIdentifier = (ASTIdentifier) functor;
1689 final int symbol = methodIdentifier.getSymbol();
1690 methodName = methodIdentifier.getName();
1691 functor = null;
1692
1693 if (target == context) {
1694 if (frame != null && frame.has(symbol)) {
1695 functor = frame.get(symbol);
1696 isavar = functor != null;
1697 } else if (context.has(methodName)) {
1698 functor = context.get(methodName);
1699 isavar = functor != null;
1700 }
1701
1702 cacheable &= !isavar;
1703 }
1704 } else if (functor instanceof ASTIdentifierAccess) {
1705
1706 methodName = ((ASTIdentifierAccess) functor).getName();
1707 functor = null;
1708 cacheable = true;
1709 } else if (functor != null) {
1710
1711 methodName = null;
1712 cacheable = false;
1713 } else if (!node.isSafeLhs(isSafe())) {
1714 return unsolvableMethod(node, "?(...)");
1715 } else {
1716
1717 return null;
1718 }
1719
1720
1721 final CallDispatcher call = new CallDispatcher(node, cacheable);
1722 try {
1723
1724 final Object eval = call.tryEval(target, methodName, argv);
1725 if (JexlEngine.TRY_FAILED != eval) {
1726 return eval;
1727 }
1728 boolean functorp = false;
1729 boolean narrow = false;
1730
1731 while (true) {
1732 call.narrow = narrow;
1733
1734 if (functor == null || functorp) {
1735
1736 if (call.isTargetMethod(target, methodName, argv)) {
1737 return call.eval(methodName);
1738 }
1739 if (target == context) {
1740
1741 final Object namespace = resolveNamespace(null, node);
1742 if (namespace != null
1743 && namespace != context
1744 && call.isTargetMethod(namespace, methodName, argv)) {
1745 return call.eval(methodName);
1746 }
1747
1748
1749 if (call.isArithmeticMethod(methodName, argv)) {
1750 return call.eval(methodName);
1751 }
1752
1753 } else {
1754
1755
1756 final Object[] pargv = functionArguments(target, narrow, argv);
1757 if (call.isContextMethod(methodName, pargv)) {
1758 return call.eval(methodName);
1759 }
1760
1761 if (call.isArithmeticMethod(methodName, pargv)) {
1762 return call.eval(methodName);
1763 }
1764
1765 if (!narrow) {
1766 final JexlPropertyGet get = uberspect.getPropertyGet(target, methodName);
1767 if (get != null) {
1768 functor = get.tryInvoke(target, methodName);
1769 functorp = functor != null;
1770 }
1771 }
1772 }
1773 }
1774
1775
1776 if (functor != null) {
1777
1778 if (functor instanceof JexlScript) {
1779 return ((JexlScript) functor).execute(context, argv);
1780 }
1781 if (functor instanceof JexlMethod) {
1782 return ((JexlMethod) functor).invoke(target, argv);
1783 }
1784 final String mCALL = "call";
1785
1786 if (call.isTargetMethod(functor, mCALL, argv)) {
1787 return call.eval(mCALL);
1788 }
1789
1790 if (isavar) {
1791 if (call.isContextMethod(methodName, argv)) {
1792 return call.eval(methodName);
1793 }
1794 if (call.isArithmeticMethod(methodName, argv)) {
1795 return call.eval(methodName);
1796 }
1797 }
1798
1799
1800 final Object[] pargv = functionArguments(functor, narrow, argv);
1801 if (call.isContextMethod(mCALL, pargv)) {
1802 return call.eval(mCALL);
1803 }
1804 if (call.isArithmeticMethod(mCALL, pargv)) {
1805 return call.eval(mCALL);
1806 }
1807 }
1808
1809
1810 if (narrow || !arithmetic.narrowArguments(argv)) {
1811 break;
1812 }
1813 narrow = true;
1814
1815 }
1816 } catch (final JexlException.Method xmethod) {
1817
1818 } catch (final JexlException.TryFailed xany) {
1819 throw invocationException(node, methodName, xany);
1820 } catch (final JexlException xthru) {
1821 throw xthru;
1822 } catch (final Exception xany) {
1823 throw invocationException(node, methodName, xany);
1824 }
1825
1826 return node.isSafeLhs(isSafe())
1827 ? null
1828 : unsolvableMethod(node, methodName, argv);
1829 }
1830
1831 @Override
1832 protected Object visit(final ASTConstructorNode node, final Object data) {
1833 if (isCancelled()) {
1834 throw new JexlException.Cancel(node);
1835 }
1836
1837 final Object target = node.jjtGetChild(0).jjtAccept(this, data);
1838
1839 final int argc = node.jjtGetNumChildren() - 1;
1840 Object[] argv = new Object[argc];
1841 for (int i = 0; i < argc; i++) {
1842 argv[i] = node.jjtGetChild(i + 1).jjtAccept(this, data);
1843 }
1844
1845 try {
1846 final boolean cacheable = cache;
1847
1848 if (cacheable) {
1849 final Object cached = node.jjtGetValue();
1850 if (cached instanceof Funcall) {
1851 final Object eval = ((Funcall) cached).tryInvoke(this, null, target, argv);
1852 if (JexlEngine.TRY_FAILED != eval) {
1853 return eval;
1854 }
1855 }
1856 }
1857 boolean narrow = false;
1858 Funcall funcall = null;
1859 JexlMethod ctor;
1860 while (true) {
1861
1862 ctor = uberspect.getConstructor(target, argv);
1863 if (ctor != null) {
1864 if (cacheable && ctor.isCacheable()) {
1865 funcall = new Funcall(ctor, narrow);
1866 }
1867 break;
1868 }
1869
1870 final Object[] nargv = callArguments(context, narrow, argv);
1871 ctor = uberspect.getConstructor(target, nargv);
1872 if (ctor != null) {
1873 if (cacheable && ctor.isCacheable()) {
1874 funcall = new ContextualCtor(ctor, narrow);
1875 }
1876 argv = nargv;
1877 break;
1878 }
1879
1880
1881 if (!narrow && arithmetic.narrowArguments(argv)) {
1882 narrow = true;
1883 continue;
1884 }
1885
1886 break;
1887 }
1888
1889 if (ctor != null) {
1890 final Object eval = ctor.invoke(target, argv);
1891
1892 if (funcall != null) {
1893 node.jjtSetValue(funcall);
1894 }
1895 return eval;
1896 }
1897 final String tstr = target != null ? target.toString() : "?";
1898 return unsolvableMethod(node, tstr, argv);
1899 } catch (final JexlException.Method xmethod) {
1900 throw xmethod;
1901 } catch (final Exception xany) {
1902 final String tstr = target != null ? target.toString() : "?";
1903 throw invocationException(node, tstr, xany);
1904 }
1905 }
1906
1907 @Override
1908 protected Object visit(final ASTJxltLiteral node, final Object data) {
1909 TemplateEngine.TemplateExpression tp = (TemplateEngine.TemplateExpression) node.jjtGetValue();
1910 if (tp == null) {
1911 final TemplateEngine jxlt = jexl.jxlt();
1912 JexlInfo info = node.jexlInfo();
1913 if (this.block != null) {
1914 info = new JexlNode.Info(node, info);
1915 }
1916 tp = jxlt.parseExpression(info, node.getLiteral(), frame != null ? frame.getScope() : null);
1917 node.jjtSetValue(tp);
1918 }
1919 if (tp != null) {
1920 return tp.evaluate(context, frame, options);
1921 }
1922 return null;
1923 }
1924
1925 @Override
1926 protected Object visit(final ASTAnnotation node, final Object data) {
1927 throw new UnsupportedOperationException(ASTAnnotation.class.getName() + ": Not supported.");
1928 }
1929
1930 @Override
1931 protected Object visit(final ASTAnnotatedStatement node, final Object data) {
1932 return processAnnotation(node, 0, data);
1933 }
1934
1935
1936
1937
1938 public class AnnotatedCall implements Callable<Object> {
1939
1940 private final ASTAnnotatedStatement stmt;
1941
1942 private final int index;
1943
1944 private final Object data;
1945
1946 private boolean processed = false;
1947
1948
1949
1950
1951
1952
1953
1954 AnnotatedCall(final ASTAnnotatedStatement astmt, final int aindex, final Object adata) {
1955 stmt = astmt;
1956 index = aindex;
1957 data = adata;
1958 }
1959
1960
1961 @Override
1962 public Object call() throws Exception {
1963 processed = true;
1964 try {
1965 return processAnnotation(stmt, index, data);
1966 } catch (JexlException.Return | JexlException.Break | JexlException.Continue xreturn) {
1967 return xreturn;
1968 }
1969 }
1970
1971
1972
1973
1974 public boolean isProcessed() {
1975 return processed;
1976 }
1977
1978
1979
1980
1981 public Object getStatement() {
1982 return stmt;
1983 }
1984 }
1985
1986
1987
1988
1989
1990
1991
1992
1993 protected Object processAnnotation(final ASTAnnotatedStatement stmt, final int index, final Object data) {
1994
1995 final int last = stmt.jjtGetNumChildren() - 1;
1996 if (index == last) {
1997 final JexlNode cblock = stmt.jjtGetChild(last);
1998
1999 final JexlArithmetic jexla = arithmetic.options(context);
2000 if (jexla == arithmetic) {
2001 return cblock.jjtAccept(Interpreter.this, data);
2002 }
2003 if (!arithmetic.getClass().equals(jexla.getClass()) && logger.isWarnEnabled()) {
2004 logger.warn("expected arithmetic to be " + arithmetic.getClass().getSimpleName()
2005 + ", got " + jexla.getClass().getSimpleName()
2006 );
2007 }
2008 final Interpreter ii = new Interpreter(Interpreter.this, jexla);
2009 final Object r = cblock.jjtAccept(ii, data);
2010 if (ii.isCancelled()) {
2011 Interpreter.this.cancel();
2012 }
2013 return r;
2014 }
2015
2016 final AnnotatedCall jstmt = new AnnotatedCall(stmt, index + 1, data);
2017
2018 final ASTAnnotation anode = (ASTAnnotation) stmt.jjtGetChild(index);
2019 final String aname = anode.getName();
2020
2021 final Object[] argv = anode.jjtGetNumChildren() > 0
2022 ? visit((ASTArguments) anode.jjtGetChild(0), null) : null;
2023
2024 Object result;
2025 try {
2026 result = processAnnotation(aname, argv, jstmt);
2027
2028 if (!jstmt.isProcessed()) {
2029 return annotationError(anode, aname, null);
2030 }
2031 } catch (final JexlException xany) {
2032 throw xany;
2033 } catch (final Exception xany) {
2034 return annotationError(anode, aname, xany);
2035 }
2036
2037 if (result instanceof JexlException) {
2038 throw (JexlException) result;
2039 }
2040 return result;
2041 }
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051 protected Object processAnnotation(final String annotation, final Object[] args, final Callable<Object> stmt) throws Exception {
2052 return context instanceof JexlContext.AnnotationProcessor
2053 ? ((JexlContext.AnnotationProcessor) context).processAnnotation(annotation, args, stmt)
2054 : stmt.call();
2055 }
2056 }