    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 &amp;= 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}