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