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