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