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