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 * http://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 * <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}