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