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