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