1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.jexl3;
19
20 import java.util.function.Consumer;
21
22 /**
23 * The JEXL operators.
24 *
25 * These are the operators that are executed by JexlArithmetic methods.
26 *
27 * <p>Each of them associates a symbol to a method signature.
28 * For instance, '+' is associated to 'T add(L x, R y)'.</p>
29 *
30 * <p>The default JexlArithmetic implements generic versions of these methods using Object as arguments.
31 * You can use your own derived JexlArithmetic that override and/or overload those operator methods.
32 * Note that these are overloads by convention, not actual Java overloads.
33 * The following rules apply to all operator methods:</p>
34 * <ul>
35 * <li>Operator methods should be public</li>
36 * <li>Operators return type should be respected when primitive (int, boolean,...)</li>
37 * <li>Operators may be overloaded multiple times with different signatures</li>
38 * <li>Operators may return JexlEngine.TRY_AGAIN to fallback on default JEXL implementation</li>
39 * </ul>
40 *
41 * For side effect operators, operators that modify the left-hand size value (+=, -=, etc.), the user implemented
42 * overload methods may return:
43 * <ul>
44 * <li>JexlEngine.TRY_FAIL to let the default fallback behavior be executed.</li>
45 * <li>Any other value will be used as the new value to be assigned to the left-hand-side.</li>
46 * </ul>
47 * Note that side effect operators always return the left-hand side value (with an exception for postfix ++ and --).
48 *
49 * @since 3.0
50 */
51 public enum JexlOperator {
52
53 /**
54 * Add operator.
55 * <br><strong>Syntax:</strong> {@code x + y}
56 * <br><strong>Method:</strong> {@code T add(L x, R y);}.
57 *
58 * @see JexlArithmetic#add(Object, Object)
59 */
60 ADD("+", "add", 2),
61
62 /**
63 * Subtract operator.
64 * <br><strong>Syntax:</strong> {@code x - y}
65 * <br><strong>Method:</strong> {@code T subtract(L x, R y);}.
66 *
67 * @see JexlArithmetic#subtract(Object, Object)
68 */
69 SUBTRACT("-", "subtract", 2),
70
71 /**
72 * Multiply operator.
73 * <br><strong>Syntax:</strong> {@code x * y}
74 * <br><strong>Method:</strong> {@code T multiply(L x, R y);}.
75 *
76 * @see JexlArithmetic#multiply(Object, Object)
77 */
78 MULTIPLY("*", "multiply", 2),
79
80 /**
81 * Divide operator.
82 * <br><strong>Syntax:</strong> {@code x / y}
83 * <br><strong>Method:</strong> {@code T divide(L x, R y);}.
84 *
85 * @see JexlArithmetic#divide(Object, Object)
86 */
87 DIVIDE("/", "divide", 2),
88
89 /**
90 * Modulo operator.
91 * <br><strong>Syntax:</strong> {@code x % y}
92 * <br><strong>Method:</strong> {@code T mod(L x, R y);}.
93 *
94 * @see JexlArithmetic#mod(Object, Object)
95 */
96 MOD("%", "mod", 2),
97
98 /**
99 * Bitwise-and operator.
100 * <br><strong>Syntax:</strong> {@code x & y}
101 * <br><strong>Method:</strong> {@code T and(L x, R y);}.
102 *
103 * @see JexlArithmetic#and(Object, Object)
104 */
105 AND("&", "and", 2),
106
107 /**
108 * Bitwise-or operator.
109 * <br><strong>Syntax:</strong> {@code x | y}
110 * <br><strong>Method:</strong> {@code T or(L x, R y);}.
111 *
112 * @see JexlArithmetic#or(Object, Object)
113 */
114 OR("|", "or", 2),
115
116 /**
117 * Bitwise-xor operator.
118 * <br><strong>Syntax:</strong> {@code x ^ y}
119 * <br><strong>Method:</strong> {@code T xor(L x, R y);}.
120 *
121 * @see JexlArithmetic#xor(Object, Object)
122 */
123 XOR("^", "xor", 2),
124
125 /**
126 * Bit-pattern right-shift operator.
127 * <br><strong>Syntax:</strong> {@code x >> y}
128 * <br><strong>Method:</strong> {@code T rightShift(L x, R y);}.
129 *
130 * @see JexlArithmetic#shiftRight(Object, Object)
131 */
132 SHIFTRIGHT(">>", "shiftRight", 2),
133
134 /**
135 * Bit-pattern right-shift unsigned operator.
136 * <br><strong>Syntax:</strong> {@code x >>> y}
137 * <br><strong>Method:</strong> {@code T rightShiftUnsigned(L x, R y);}.
138 *
139 * @see JexlArithmetic#shiftRightUnsigned(Object, Object)
140 */
141 SHIFTRIGHTU(">>>", "shiftRightUnsigned", 2),
142
143 /**
144 * Bit-pattern left-shift operator.
145 * <br><strong>Syntax:</strong> {@code x << y}
146 * <br><strong>Method:</strong> {@code T leftShift(L x, R y);}.
147 *
148 * @see JexlArithmetic#shiftLeft(Object, Object)
149 */
150 SHIFTLEFT("<<", "shiftLeft", 2),
151
152 /**
153 * Equals operator.
154 * <br><strong>Syntax:</strong> {@code x == y}
155 * <br><strong>Method:</strong> {@code boolean equals(L x, R y);}.
156 *
157 * @see JexlArithmetic#equals(Object, Object)
158 */
159 EQ("==", "equals", 2),
160
161 /**
162 * Equal-strict operator.
163 * <br><strong>Syntax:</strong> {@code x === y}
164 * <br><strong>Method:</strong> {@code boolean strictEquals(L x, R y);}.
165 *
166 * @see JexlArithmetic#strictEquals(Object, Object)
167 */
168 EQSTRICT("===", "strictEquals", 2),
169
170 /**
171 * Less-than operator.
172 * <br><strong>Syntax:</strong> {@code x < y}
173 * <br><strong>Method:</strong> {@code boolean lessThan(L x, R y);}.
174 *
175 * @see JexlArithmetic#lessThan(Object, Object)
176 */
177 LT("<", "lessThan", 2),
178
179 /**
180 * Less-than-or-equal operator.
181 * <br><strong>Syntax:</strong> {@code x <= y}
182 * <br><strong>Method:</strong> {@code boolean lessThanOrEqual(L x, R y);}.
183 *
184 * @see JexlArithmetic#lessThanOrEqual(Object, Object)
185 */
186 LTE("<=", "lessThanOrEqual", 2),
187
188 /**
189 * Greater-than operator.
190 * <br><strong>Syntax:</strong> {@code x > y}
191 * <br><strong>Method:</strong> {@code boolean greaterThan(L x, R y);}.
192 *
193 * @see JexlArithmetic#greaterThan(Object, Object)
194 */
195 GT(">", "greaterThan", 2),
196
197 /**
198 * Greater-than-or-equal operator.
199 * <br><strong>Syntax:</strong> {@code x >= y}
200 * <br><strong>Method:</strong> {@code boolean greaterThanOrEqual(L x, R y);}.
201 *
202 * @see JexlArithmetic#greaterThanOrEqual(Object, Object)
203 */
204 GTE(">=", "greaterThanOrEqual", 2),
205
206 /**
207 * Contains operator.
208 * <br><strong>Syntax:</strong> {@code x =~ y}
209 * <br><strong>Method:</strong> {@code boolean contains(L x, R y);}.
210 *
211 * @see JexlArithmetic#contains(Object, Object)
212 */
213 CONTAINS("=~", "contains", 2),
214
215 /**
216 * Starts-with operator.
217 * <br><strong>Syntax:</strong> {@code x =^ y}
218 * <br><strong>Method:</strong> {@code boolean startsWith(L x, R y);}.
219 *
220 * @see JexlArithmetic#startsWith(Object, Object)
221 */
222 STARTSWITH("=^", "startsWith", 2),
223
224 /**
225 * Ends-with operator.
226 * <br><strong>Syntax:</strong> {@code x =$ y}
227 * <br><strong>Method:</strong> {@code boolean endsWith(L x, R y);}.
228 *
229 * @see JexlArithmetic#endsWith(Object, Object)
230 */
231 ENDSWITH("=$", "endsWith", 2),
232
233 /**
234 * Not operator.
235 * <br><strong>Syntax:</strong> {@code !x}
236 * <br><strong>Method:</strong> {@code T not(L x);}.
237 *
238 * @see JexlArithmetic#not(Object)
239 */
240 NOT("!", "not", 1),
241
242 /**
243 * Complement operator.
244 * <br><strong>Syntax:</strong> {@code ~x}
245 * <br><strong>Method:</strong> {@code T complement(L x);}.
246 *
247 * @see JexlArithmetic#complement(Object)
248 */
249 COMPLEMENT("~", "complement", 1),
250
251 /**
252 * Negate operator.
253 * <br><strong>Syntax:</strong> {@code -x}
254 * <br><strong>Method:</strong> {@code T negate(L x);}.
255 *
256 * @see JexlArithmetic#negate(Object)
257 */
258 NEGATE("-", "negate", 1),
259
260 /**
261 * Positivize operator.
262 * <br><strong>Syntax:</strong> {@code +x}
263 * <br><strong>Method:</strong> {@code T positivize(L x);}.
264 *
265 * @see JexlArithmetic#positivize(Object)
266 */
267 POSITIVIZE("+", "positivize", 1),
268
269 /**
270 * Empty operator.
271 * <br><strong>Syntax:</strong> {@code empty x} or {@code empty(x)}
272 * <br><strong>Method:</strong> {@code boolean empty(L x);}.
273 *
274 * @see JexlArithmetic#empty(Object)
275 */
276 EMPTY("empty", "empty", 1),
277
278 /**
279 * Size operator.
280 * <br><strong>Syntax:</strong> {@code size x} or {@code size(x)}
281 * <br><strong>Method:</strong> {@code int size(L x);}.
282 *
283 * @see JexlArithmetic#size(Object)
284 */
285 SIZE("size", "size", 1),
286
287 /**
288 * Self-add operator.
289 * <br><strong>Syntax:</strong> {@code x += y}
290 * <br><strong>Method:</strong> {@code T selfAdd(L x, R y);}.
291 */
292 SELF_ADD("+=", "selfAdd", ADD),
293
294 /**
295 * Self-subtract operator.
296 * <br><strong>Syntax:</strong> {@code x -= y}
297 * <br><strong>Method:</strong> {@code T selfSubtract(L x, R y);}.
298 */
299 SELF_SUBTRACT("-=", "selfSubtract", SUBTRACT),
300
301 /**
302 * Self-multiply operator.
303 * <br><strong>Syntax:</strong> {@code x *= y}
304 * <br><strong>Method:</strong> {@code T selfMultiply(L x, R y);}.
305 */
306 SELF_MULTIPLY("*=", "selfMultiply", MULTIPLY),
307
308 /**
309 * Self-divide operator.
310 * <br><strong>Syntax:</strong> {@code x /= y}
311 * <br><strong>Method:</strong> {@code T selfDivide(L x, R y);}.
312 */
313 SELF_DIVIDE("/=", "selfDivide", DIVIDE),
314
315 /**
316 * Self-modulo operator.
317 * <br><strong>Syntax:</strong> {@code x %= y}
318 * <br><strong>Method:</strong> {@code T selfMod(L x, R y);}.
319 */
320 SELF_MOD("%=", "selfMod", MOD),
321
322 /**
323 * Self-and operator.
324 * <br><strong>Syntax:</strong> {@code x &= y}
325 * <br><strong>Method:</strong> {@code T selfAnd(L x, R y);}.
326 */
327 SELF_AND("&=", "selfAnd", AND),
328
329 /**
330 * Self-or operator.
331 * <br><strong>Syntax:</strong> {@code x |= y}
332 * <br><strong>Method:</strong> {@code T selfOr(L x, R y);}.
333 */
334 SELF_OR("|=", "selfOr", OR),
335
336 /**
337 * Self-xor operator.
338 * <br><strong>Syntax:</strong> {@code x ^= y}
339 * <br><strong>Method:</strong> {@code T selfXor(L x, R y);}.
340 */
341 SELF_XOR("^=", "selfXor", XOR),
342
343 /**
344 * Self-right-shift operator.
345 * <br><strong>Syntax:</strong> {@code x >>= y}
346 * <br><strong>Method:</strong> {@code T selfShiftRight(L x, R y);}.
347 */
348 SELF_SHIFTRIGHT(">>=", "selfShiftRight", SHIFTRIGHT),
349
350 /**
351 * Self-right-shift unsigned operator.
352 * <br><strong>Syntax:</strong> {@code x >>> y}
353 * <br><strong>Method:</strong> {@code T selfShiftRightUnsigned(L x, R y);}.
354 */
355 SELF_SHIFTRIGHTU(">>>=", "selfShiftRightUnsigned", SHIFTRIGHTU),
356
357 /**
358 * Self-left-shift operator.
359 * <br><strong>Syntax:</strong> {@code x << y}
360 * <br><strong>Method:</strong> {@code T selfShiftLeft(L x, R y);}.
361 */
362 SELF_SHIFTLEFT("<<=", "selfShiftLeft", SHIFTLEFT),
363
364 /**
365 * Increment pseudo-operator.
366 * <br>No syntax, used as helper for the prefix and postfix versions of {@code ++}.
367 *
368 * @see JexlArithmetic#increment(Object)
369 */
370 INCREMENT("+1", "increment", 1),
371
372 /**
373 * Decrement pseudo-operator.
374 * <br>No syntax, used as helper for the prefix and postfix versions of {@code --}.
375 *
376 * @see JexlArithmetic#decrement(Object)
377 */
378 DECREMENT("-1", "decrement", 1),
379
380 /**
381 * Prefix ++ operator, increments and returns the value after incrementing.
382 * <br><strong>Syntax:</strong> {@code ++x}
383 * <br><strong>Method:</strong> {@code T incrementAndGet(L x);}.
384 */
385 INCREMENT_AND_GET("++.", "incrementAndGet", INCREMENT, 1),
386
387 /**
388 * Postfix ++, increments and returns the value before incrementing.
389 * <br><strong>Syntax:</strong> {@code x++}
390 * <br><strong>Method:</strong> {@code T getAndIncrement(L x);}.
391 */
392 GET_AND_INCREMENT(".++", "getAndIncrement", INCREMENT, 1),
393
394 /**
395 * Prefix --, decrements and returns the value after decrementing.
396 * <br><strong>Syntax:</strong> {@code --x}
397 * <br><strong>Method:</strong> {@code T decrementAndGet(L x);}.
398 */
399 DECREMENT_AND_GET("--.", "decrementAndGet", DECREMENT, 1),
400
401 /**
402 * Postfix --, decrements and returns the value before decrementing.
403 * <br><strong>Syntax:</strong> {@code x--}
404 * <br><strong>Method:</strong> {@code T getAndDecrement(L x);}.
405 */
406 GET_AND_DECREMENT(".--", "getAndDecrement", DECREMENT, 1),
407
408 /**
409 * Marker for side effect.
410 * <p>
411 * Returns this from 'self*' overload method to let the engine know the side effect has been performed and
412 * there is no need to assign the result.
413 * </p>
414 *
415 * @deprecated 3.5.0
416 */
417 @Deprecated
418 ASSIGN("=", null, null),
419
420 /**
421 * Property get operator as in: x.y.
422 * <br><strong>Syntax:</strong> {@code x.y}
423 * <br><strong>Method:</strong> {@code Object propertyGet(L x, R y);}.
424 */
425 PROPERTY_GET(".", "propertyGet", 2),
426
427 /**
428 * Property set operator as in: x.y = z.
429 * <br><strong>Syntax:</strong> {@code x.y = z}
430 * <br><strong>Method:</strong> {@code void propertySet(L x, R y, V z);}.
431 */
432 PROPERTY_SET(".=", "propertySet", 3),
433
434 /**
435 * Array get operator as in: x[y].
436 * <br><strong>Syntax:</strong> {@code x.y}
437 * <br><strong>Method:</strong> {@code Object arrayGet(L x, R y);}.
438 */
439 ARRAY_GET("[]", "arrayGet", 2),
440
441 /**
442 * Array set operator as in: x[y] = z.
443 * <br><strong>Syntax:</strong> {@code x[y] = z}
444 * <br><strong>Method:</strong> {@code void arraySet(L x, R y, V z);}.
445 */
446 ARRAY_SET("[]=", "arraySet", 3),
447
448 /**
449 * Iterator generator as in for(var x : y).
450 * If the returned Iterator is AutoCloseable, close will be called after the last execution of the loop block.
451 * <br><strong>Syntax:</strong> <code>for(var x : y){...}</code>
452 * <br><strong>Method:</strong> {@code Iterator<Object> forEach(R y);}.
453 *
454 * @since 3.1
455 */
456 FOR_EACH("for(...)", "forEach", 1),
457
458 /**
459 * Test condition in if, for, while.
460 * <br><strong>Method:</strong> {@code boolean testCondition(R y);}.
461 *
462 * @since 3.3
463 */
464 CONDITION("?", "testCondition", 1),
465
466 /**
467 * Compare overload as in compare(x, y).
468 * <br><strong>Method:</strong> {@code boolean compare(L x, R y);}.
469 *
470 * @since 3.5.0
471 */
472 COMPARE("<>", "compare", 2),
473
474 /**
475 * Not-Contains operator.
476 * <p>Not overridable, calls !(contain(...))</p>
477 */
478 NOT_CONTAINS("!~", null, CONTAINS),
479
480 /**
481 * Not-Starts-With operator.
482 * <p>Not overridable, calls !(startsWith(...))</p>
483 */
484 NOT_STARTSWITH("!^", null, STARTSWITH),
485
486 /**
487 * Not-Ends-With operator.
488 * <p>Not overridable, calls !(endsWith(...))</p>
489 */
490 NOT_ENDSWITH("!$", null, ENDSWITH),;
491
492 /**
493 * The operator symbol.
494 */
495 private final String operator;
496
497 /**
498 * The associated operator method name.
499 */
500 private final String methodName;
501
502 /**
503 * The method arity (ie number of arguments).
504 */
505 private final int arity;
506
507 /**
508 * The base operator.
509 */
510 private final JexlOperator base;
511
512 /**
513 * Creates a base operator.
514 *
515 * @param o the operator name
516 * @param m the method name associated to this operator in a JexlArithmetic
517 * @param argc the number of parameters for the method
518 */
519 JexlOperator(final String o, final String m, final int argc) {
520 this(o, m, null, argc);
521 }
522
523 /**
524 * Creates a side effect operator with arity == 2.
525 *
526 * @param o the operator name
527 * @param m the method name associated to this operator in a JexlArithmetic
528 * @param b the base operator, ie + for +=
529 */
530 JexlOperator(final String o, final String m, final JexlOperator b) {
531 this(o, m, b, 2);
532 }
533
534 /**
535 * Creates a side effect operator.
536 *
537 * @param o the operator name
538 * @param m the method name associated to this operator in a JexlArithmetic
539 * @param b the base operator, ie + for +=
540 * @param a the operator arity
541 */
542 JexlOperator(final String o, final String m, final JexlOperator b, final int a) {
543 this.operator = o;
544 this.methodName = m;
545 this.arity = a;
546 this.base = b;
547 }
548
549 /**
550 * Gets this operator number of parameters.
551 *
552 * @return the method arity
553 */
554 public int getArity() {
555 return arity;
556 }
557
558 /**
559 * Gets the base operator.
560 *
561 * @return the base operator
562 */
563 public final JexlOperator getBaseOperator() {
564 return base;
565 }
566
567 /**
568 * Gets this operator method name in a JexlArithmetic.
569 *
570 * @return the method name
571 */
572 public final String getMethodName() {
573 return methodName;
574 }
575
576 /**
577 * Gets this operator symbol.
578 *
579 * @return the symbol
580 */
581 public final String getOperatorSymbol() {
582 return operator;
583 }
584
585 /**
586 * Uberspect that solves and evaluates JexlOperator overloads.
587 * <p>This is used by the interpreter to find and execute operator overloads implemented in a derived
588 * JexlArithmetic - or in some cases, as methods of the left argument type (contains, size, ...).</p>
589 * <p>This also allows reusing the core logic when extending the applicative type-system; for
590 * instance, implementing a Comparator class that calls compare
591 * (<code>operator.tryOverload(this, JexlOperator.COMPARE, left, right)</code>, etc.</p>
592 *
593 * @since 3.5.0
594 */
595 public interface Uberspect extends JexlArithmetic.Uberspect {
596
597 /**
598 * Try to find the most specific method and evaluate an operator.
599 * <p>This method does not call {@link #overloads(JexlOperator)} and shall not be called with an
600 * assignment operator; use {@link #tryAssignOverload(JexlCache.Reference, JexlOperator, Consumer, Object...)}
601 * in that case.</p>
602 *
603 * @param reference an optional reference caching resolved method or failing signature
604 * @param operator the operator
605 * @param args the arguments
606 * @return TRY_FAILED if no specific method could be found, the evaluation result otherwise
607 */
608 Object tryOverload(JexlCache.Reference reference, JexlOperator operator, Object...args);
609
610 /**
611 * Evaluates an assign operator.
612 * <p>
613 * This takes care of finding and caching the operator method when appropriate.
614 * If an overloads returns a value not-equal to TRY_FAILED, it means the side-effect is complete.
615 * Otherwise, {@code a += b <=> a = a + b}
616 * </p>
617 *
618 * @param node an optional reference caching resolved method or failing signature
619 * @param operator the operator
620 * @param assign the actual function that performs the side effect
621 * @param args the arguments, the first one being the target of assignment
622 * @return JexlEngine.TRY_FAILED if no operation was performed,
623 * the value to use as the side effect argument otherwise
624 */
625 Object tryAssignOverload(final JexlCache.Reference node,
626 final JexlOperator operator,
627 final Consumer<Object> assign,
628 final Object... args);
629
630 /**
631 * Calculate the {@code size} of various types:
632 * Collection, Array, Map, String, and anything that has an int size() method.
633 * <p>Seeks an overload or use the default arithmetic implementation.</p>
634 * <p>Note that the result may not be an integer.
635 *
636 * @param node an optional reference caching resolved method or failing signature
637 * @param object the object to get the size of
638 * @return the evaluation result
639 */
640 Object size(final JexlCache.Reference node, final Object object);
641
642 /**
643 * Check for emptiness of various types: Collection, Array, Map, String, and anything that has a boolean isEmpty()
644 * method.
645 * <p>Seeks an overload or use the default arithmetic implementation.</p>
646 * <p>Note that the result may not be a boolean.
647 *
648 * @param node the node holding the object
649 * @param object the object to check the emptiness of
650 * @return the evaluation result
651 */
652 Object empty(final JexlCache.Reference node, final Object object);
653
654 /**
655 * The 'match'/'in' operator implementation.
656 * <p>Seeks an overload or use the default arithmetic implementation.</p>
657 * <p>
658 * Note that 'x in y' or 'x matches y' means 'y contains x' ;
659 * the JEXL operator arguments order syntax is the reverse of this method call.
660 * </p>
661 *
662 * @param node an optional reference caching resolved method or failing signature
663 * @param operator the calling operator, =~ or !~
664 * @param right the left operand
665 * @param left the right operand
666 * @return true if left matches right, false otherwise
667 */
668 boolean contains(final JexlCache.Reference node,
669 final JexlOperator operator,
670 final Object left,
671 final Object right);
672
673 /**
674 * The 'startsWith' operator implementation.
675 * <p>Seeks an overload or use the default arithmetic implementation.</p>
676 *
677 * @param node an optional reference caching resolved method or failing signature
678 * @param operator the calling operator, $= or $!
679 * @param left the left operand
680 * @param right the right operand
681 * @return true if left starts with right, false otherwise
682 */
683 boolean startsWith(final JexlCache.Reference node,
684 final JexlOperator operator,
685 final Object left,
686 final Object right);
687
688 /**
689 * The 'endsWith' operator implementation.
690 * <p>Seeks an overload or use the default arithmetic implementation.</p>
691 *
692 * @param node an optional reference caching resolved method or failing signature
693 * @param operator the calling operator, ^= or ^!
694 * @param left the left operand
695 * @param right the right operand
696 * @return true if left ends with right, false otherwise
697 */
698 boolean endsWith(final JexlCache.Reference node,
699 final JexlOperator operator,
700 final Object left,
701 final Object right);
702 }
703 }