001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * https://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.jexl3; 019 020import java.util.function.Consumer; 021 022/** 023 * The JEXL operators. 024 * 025 * These are the operators that are executed by JexlArithmetic methods. 026 * 027 * <p>Each of them associates a symbol to a method signature. 028 * For instance, '+' is associated to 'T add(L x, R y)'.</p> 029 * 030 * <p>The default JexlArithmetic implements generic versions of these methods using Object as arguments. 031 * You can use your own derived JexlArithmetic that override and/or overload those operator methods. 032 * Note that these are overloads by convention, not actual Java overloads. 033 * The following rules apply to all operator methods:</p> 034 * <ul> 035 * <li>Operator methods should be public</li> 036 * <li>Operators return type should be respected when primitive (int, boolean,...)</li> 037 * <li>Operators may be overloaded multiple times with different signatures</li> 038 * <li>Operators may return JexlEngine.TRY_AGAIN to fallback on default JEXL implementation</li> 039 * </ul> 040 * 041 * For side effect operators, operators that modify the left-hand size value (+=, -=, etc.), the user implemented 042 * overload methods may return: 043 * <ul> 044 * <li>JexlEngine.TRY_FAIL to let the default fallback behavior be executed.</li> 045 * <li>Any other value will be used as the new value to be assigned to the left-hand-side.</li> 046 * </ul> 047 * Note that side effect operators always return the left-hand side value (with an exception for postfix ++ and --). 048 * 049 * @since 3.0 050 */ 051public enum JexlOperator { 052 /** 053 * Add operator. 054 * <br><strong>Syntax:</strong> {@code x + y} 055 * <br><strong>Method:</strong> {@code T add(L x, R y);}. 056 * @see JexlArithmetic#add(Object, Object) 057 */ 058 ADD("+", "add", 2), 059 060 /** 061 * Subtract operator. 062 * <br><strong>Syntax:</strong> {@code x - y} 063 * <br><strong>Method:</strong> {@code T subtract(L x, R y);}. 064 * @see JexlArithmetic#subtract(Object, Object) 065 */ 066 SUBTRACT("-", "subtract", 2), 067 068 /** 069 * Multiply operator. 070 * <br><strong>Syntax:</strong> {@code x * y} 071 * <br><strong>Method:</strong> {@code T multiply(L x, R y);}. 072 * @see JexlArithmetic#multiply(Object, Object) 073 */ 074 MULTIPLY("*", "multiply", 2), 075 076 /** 077 * Divide operator. 078 * <br><strong>Syntax:</strong> {@code x / y} 079 * <br><strong>Method:</strong> {@code T divide(L x, R y);}. 080 * @see JexlArithmetic#divide(Object, Object) 081 */ 082 DIVIDE("/", "divide", 2), 083 084 /** 085 * Modulo operator. 086 * <br><strong>Syntax:</strong> {@code x % y} 087 * <br><strong>Method:</strong> {@code T mod(L x, R y);}. 088 * @see JexlArithmetic#mod(Object, Object) 089 */ 090 MOD("%", "mod", 2), 091 092 /** 093 * Bitwise-and operator. 094 * <br><strong>Syntax:</strong> {@code x & y} 095 * <br><strong>Method:</strong> {@code T and(L x, R y);}. 096 * @see JexlArithmetic#and(Object, Object) 097 */ 098 AND("&", "and", 2), 099 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 * <p> 382 * Returns this from 'self*' overload method to let the engine know the side effect has been performed and 383 * there is no need to assign the result. 384 * </p> 385 * 386 * @deprecated 3.5.0 387 */ 388 @Deprecated 389 ASSIGN("=", null, null), 390 391 /** 392 * Property get operator as in: x.y. 393 * <br><strong>Syntax:</strong> {@code x.y} 394 * <br><strong>Method:</strong> {@code Object propertyGet(L x, R y);}. 395 */ 396 PROPERTY_GET(".", "propertyGet", 2), 397 398 /** 399 * Property set operator as in: x.y = z. 400 * <br><strong>Syntax:</strong> {@code x.y = z} 401 * <br><strong>Method:</strong> {@code void propertySet(L x, R y, V z);}. 402 */ 403 PROPERTY_SET(".=", "propertySet", 3), 404 405 /** 406 * Array get operator as in: x[y]. 407 * <br><strong>Syntax:</strong> {@code x.y} 408 * <br><strong>Method:</strong> {@code Object arrayGet(L x, R y);}. 409 */ 410 ARRAY_GET("[]", "arrayGet", 2), 411 412 /** 413 * Array set operator as in: x[y] = z. 414 * <br><strong>Syntax:</strong> {@code x[y] = z} 415 * <br><strong>Method:</strong> {@code void arraySet(L x, R y, V z);}. 416 */ 417 ARRAY_SET("[]=", "arraySet", 3), 418 419 /** 420 * Iterator generator as in for(var x : y). 421 * If the returned Iterator is AutoCloseable, close will be called after the last execution of the loop block. 422 * <br><strong>Syntax:</strong> <code>for(var x : y){...}</code> 423 * <br><strong>Method:</strong> {@code Iterator<Object> forEach(R y);}. 424 * @since 3.1 425 */ 426 FOR_EACH("for(...)", "forEach", 1), 427 428 /** 429 * Test condition in if, for, while. 430 * <br><strong>Method:</strong> {@code boolean testCondition(R y);}. 431 * @since 3.3 432 */ 433 CONDITION("?", "testCondition", 1), 434 435 /** 436 * Compare overload as in compare(x, y). 437 * <br><strong>Method:</strong> {@code boolean compare(L x, R y);}. 438 * @since 3.5.0 439 */ 440 COMPARE("<>", "compare", 2), 441 442 /** 443 * Not-Contains operator. 444 * <p>Not overridable, calls !(contain(...))</p> 445 */ 446 NOT_CONTAINS("!~", null, CONTAINS), 447 448 /** 449 * Not-Starts-With operator. 450 * <p>Not overridable, calls !(startsWith(...))</p> 451 */ 452 NOT_STARTSWITH("!^", null, STARTSWITH), 453 454 /** 455 * Not-Ends-With operator. 456 * <p>Not overridable, calls !(endsWith(...))</p> 457 */ 458 NOT_ENDSWITH("!$", null, ENDSWITH),; 459 460 /** 461 * The operator symbol. 462 */ 463 private final String operator; 464 465 /** 466 * The associated operator method name. 467 */ 468 private final String methodName; 469 470 /** 471 * The method arity (ie number of arguments). 472 */ 473 private final int arity; 474 475 /** 476 * The base operator. 477 */ 478 private final JexlOperator base; 479 480 /** 481 * Creates a base operator. 482 * 483 * @param o the operator name 484 * @param m the method name associated to this operator in a JexlArithmetic 485 * @param argc the number of parameters for the method 486 */ 487 JexlOperator(final String o, final String m, final int argc) { 488 this(o, m, null, argc); 489 } 490 491 /** 492 * Creates a side effect operator with arity == 2. 493 * 494 * @param o the operator name 495 * @param m the method name associated to this operator in a JexlArithmetic 496 * @param b the base operator, ie + for += 497 */ 498 JexlOperator(final String o, final String m, final JexlOperator b) { 499 this(o, m, b, 2); 500 } 501 502 /** 503 * Creates a side effect operator. 504 * 505 * @param o the operator name 506 * @param m the method name associated to this operator in a JexlArithmetic 507 * @param b the base operator, ie + for += 508 * @param a the operator arity 509 */ 510 JexlOperator(final String o, final String m, final JexlOperator b, final int a) { 511 this.operator = o; 512 this.methodName = m; 513 this.arity = a; 514 this.base = b; 515 } 516 517 /** 518 * Gets this operator number of parameters. 519 * 520 * @return the method arity 521 */ 522 public int getArity() { 523 return arity; 524 } 525 526 /** 527 * Gets the base operator. 528 * 529 * @return the base operator 530 */ 531 public final JexlOperator getBaseOperator() { 532 return base; 533 } 534 535 /** 536 * Gets this operator method name in a JexlArithmetic. 537 * 538 * @return the method name 539 */ 540 public final String getMethodName() { 541 return methodName; 542 } 543 544 /** 545 * Gets this operator symbol. 546 * 547 * @return the symbol 548 */ 549 public final String getOperatorSymbol() { 550 return operator; 551 } 552 553 /** 554 * Uberspect that solves and evaluates JexlOperator overloads. 555 * <p>This is used by the interpreter to find and execute operator overloads implemented in a derived 556 * JexlArithmetic - or in some cases, as methods of the left argument type (contains, size, ...).</p> 557 * <p>This also allows reusing the core logic when extending the applicative type-system; for 558 * instance, implementing a Comparator class that calls compare 559 * (<code>operator.tryOverload(this, JexlOperator.COMPARE, left, right)</code>, etc.</p> 560 * @since 3.5.0 561 */ 562 public interface Uberspect extends JexlArithmetic.Uberspect { 563 /** 564 * Try to find the most specific method and evaluate an operator. 565 * <p>This method does not call {@link #overloads(JexlOperator)} and shall not be called with an 566 * assignment operator; use {@link #tryAssignOverload(JexlCache.Reference, JexlOperator, Consumer, Object...)} 567 * in that case.</p> 568 * 569 * @param reference an optional reference caching resolved method or failing signature 570 * @param operator the operator 571 * @param args the arguments 572 * @return TRY_FAILED if no specific method could be found, the evaluation result otherwise 573 */ 574 Object tryOverload(JexlCache.Reference reference, JexlOperator operator, Object...args); 575 576 /** 577 * Evaluates an assign operator. 578 * <p> 579 * This takes care of finding and caching the operator method when appropriate. 580 * If an overloads returns a value not-equal to TRY_FAILED, it means the side-effect is complete. 581 * Otherwise, {@code a += b <=> a = a + b} 582 * </p> 583 * @param node an optional reference caching resolved method or failing signature 584 * @param operator the operator 585 * @param assign the actual function that performs the side effect 586 * @param args the arguments, the first one being the target of assignment 587 * @return JexlEngine.TRY_FAILED if no operation was performed, 588 * the value to use as the side effect argument otherwise 589 */ 590 Object tryAssignOverload(final JexlCache.Reference node, 591 final JexlOperator operator, 592 final Consumer<Object> assign, 593 final Object... args); 594 595 /** 596 * Calculate the {@code size} of various types: 597 * Collection, Array, Map, String, and anything that has an int size() method. 598 * <p>Seeks an overload or use the default arithmetic implementation.</p> 599 * <p>Note that the result may not be an integer. 600 * 601 * @param node an optional reference caching resolved method or failing signature 602 * @param object the object to get the size of 603 * @return the evaluation result 604 */ 605 Object size(final JexlCache.Reference node, final Object object); 606 607 /** 608 * Check for emptiness of various types: Collection, Array, Map, String, and anything that has a boolean isEmpty() 609 * method. 610 * <p>Seeks an overload or use the default arithmetic implementation.</p> 611 * <p>Note that the result may not be a boolean. 612 * 613 * @param node the node holding the object 614 * @param object the object to check the emptiness of 615 * @return the evaluation result 616 */ 617 Object empty(final JexlCache.Reference node, final Object object); 618 619 /** 620 * The 'match'/'in' operator implementation. 621 * <p>Seeks an overload or use the default arithmetic implementation.</p> 622 * <p> 623 * Note that 'x in y' or 'x matches y' means 'y contains x' ; 624 * the JEXL operator arguments order syntax is the reverse of this method call. 625 * </p> 626 * @param node an optional reference caching resolved method or failing signature 627 * @param operator the calling operator, =~ or !~ 628 * @param right the left operand 629 * @param left the right operand 630 * @return true if left matches right, false otherwise 631 */ 632 boolean contains(final JexlCache.Reference node, 633 final JexlOperator operator, 634 final Object left, 635 final Object right); 636 637 /** 638 * The 'startsWith' operator implementation. 639 * <p>Seeks an overload or use the default arithmetic implementation.</p> 640 * @param node an optional reference caching resolved method or failing signature 641 * @param operator the calling operator, $= or $! 642 * @param left the left operand 643 * @param right the right operand 644 * @return true if left starts with right, false otherwise 645 */ 646 boolean startsWith(final JexlCache.Reference node, 647 final JexlOperator operator, 648 final Object left, 649 final Object right); 650 651 /** 652 * The 'endsWith' operator implementation. 653 * <p>Seeks an overload or use the default arithmetic implementation.</p> 654 * @param node an optional reference caching resolved method or failing signature 655 * @param operator the calling operator, ^= or ^! 656 * @param left the left operand 657 * @param right the right operand 658 * @return true if left ends with right, false otherwise 659 */ 660 boolean endsWith(final JexlCache.Reference node, 661 final JexlOperator operator, 662 final Object left, 663 final Object right); 664 } 665}