    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
    020/**
    021 * The JEXL operators.
    022 *
    023 * These are the operators that are executed by JexlArithmetic methods.
    024 *
    025 * <p>Each of them  associates a symbol to a method signature.
    026 * For instance, '+' is associated to 'T add(L x, R y)'.</p>
    027 *
    028 * <p>The default JexlArithmetic implements generic versions of these methods using Object as arguments.
    029 * You can use your own derived JexlArithmetic that override and/or overload those operator methods.
    030 * Note that these are overloads by convention, not actual Java overloads.
    031 * The following rules apply to all operator methods:</p>
    032 * <ul>
    033 * <li>Operator methods should be public</li>
    034 * <li>Operators return type should be respected when primitive (int, boolean,...)</li>
    035 * <li>Operators may be overloaded multiple times with different signatures</li>
    036 * <li>Operators may return JexlEngine.TRY_AGAIN to fallback on default JEXL implementation</li>
    037 * </ul>
    038 *
    039 * For side effect operators, operators that modify the left-hand size value (+=, -=, etc), the user implemented
    040 * overload methods may return:
    041 * <ul>
    042 *     <li>JexlEngine.TRY_FAIL to let the default fallback behavior be executed.</li>
    043 *     <li>Any other value will be used as the new value to be assigned to the left-hand-side.</li>
    044 * </ul>
    045 * Note that side effect operators always return the left-hand side value (with an exception for postfix ++ and --).
    046 *
    047 * @since 3.0
    048 */
    049public enum JexlOperator {
    050
    051    /**
    052     * Add operator.
    053     * <br><strong>Syntax:</strong> <code>x + y</code>
    054     * <br><strong>Method:</strong> <code>T add(L x, R y);</code>.
    055     * @see JexlArithmetic#add(Object, Object)
    056     */
    057    ADD("+", "add", 2),
    058
    059    /**
    060     * Subtract operator.
    061     * <br><strong>Syntax:</strong> <code>x - y</code>
    062     * <br><strong>Method:</strong> <code>T subtract(L x, R y);</code>.
    063     * @see JexlArithmetic#subtract(Object, Object)
    064     */
    065    SUBTRACT("-", "subtract", 2),
    066
    067    /**
    068     * Multiply operator.
    069     * <br><strong>Syntax:</strong> <code>x * y</code>
    070     * <br><strong>Method:</strong> <code>T multiply(L x, R y);</code>.
    071     * @see JexlArithmetic#multiply(Object, Object)
    072     */
    073    MULTIPLY("*", "multiply", 2),
    074
    075    /**
    076     * Divide operator.
    077     * <br><strong>Syntax:</strong> <code>x / y</code>
    078     * <br><strong>Method:</strong> <code>T divide(L x, R y);</code>.
    079     * @see JexlArithmetic#divide(Object, Object)
    080     */
    081    DIVIDE("/", "divide", 2),
    082
    083    /**
    084     * Modulo operator.
    085     * <br><strong>Syntax:</strong> <code>x % y</code>
    086     * <br><strong>Method:</strong> <code>T mod(L x, R y);</code>.
    087     * @see JexlArithmetic#mod(Object, Object)
    088     */
    089    MOD("%", "mod", 2),
    090
    091    /**
    092     * Bitwise-and operator.
    093     * <br><strong>Syntax:</strong> <code>x &amp; y</code>
    094     * <br><strong>Method:</strong> <code>T and(L x, R y);</code>.
    095     * @see JexlArithmetic#and(Object, Object)
    096     */
    097    AND("&", "and", 2),
    098
    099    /**
    100     * Bitwise-or operator.
    101     * <br><strong>Syntax:</strong> <code>x | y</code>
    102     * <br><strong>Method:</strong> <code>T or(L x, R y);</code>.
    103     * @see JexlArithmetic#or(Object, Object)
    104     */
    105    OR("|", "or", 2),
    106
    107    /**
    108     * Bitwise-xor operator.
    109     * <br><strong>Syntax:</strong> <code>x ^ y</code>
    110     * <br><strong>Method:</strong> <code>T xor(L x, R y);</code>.
    111     * @see JexlArithmetic#xor(Object, Object)
    112     */
    113    XOR("^", "xor", 2),
    114
    115    /**
    116     * Bit-pattern right-shift operator.
    117     * <br><strong>Syntax:</strong> <code>x &gt;&gt; y</code>
    118     * <br><strong>Method:</strong> <code>T rightShift(L x, R y);</code>.
    119     * @see JexlArithmetic#shiftRight(Object, Object)
    120     */
    121    SHIFTRIGHT(">>", "shiftRight", 2),
    122
    123    /**
    124     * Bit-pattern right-shift unsigned operator.
    125     * <br><strong>Syntax:</strong> <code>x &gt;&gt;&gt; y</code>
    126     * <br><strong>Method:</strong> <code>T rightShiftUnsigned(L x, R y);</code>.
    127     * @see JexlArithmetic#shiftRightUnsigned(Object, Object)
    128     */
    129    SHIFTRIGHTU(">>>", "shiftRightUnsigned", 2),
    130
    131    /**
    132     * Bit-pattern left-shift operator.
    133     * <br><strong>Syntax:</strong> <code>x &lt;&lt; y</code>
    134     * <br><strong>Method:</strong> <code>T leftShift(L x, R y);</code>.
    135     * @see JexlArithmetic#shiftLeft(Object, Object)
    136     */
    137    SHIFTLEFT("<<", "shiftLeft", 2),
    138
    139    /**
    140     * Equals operator.
    141     * <br><strong>Syntax:</strong> <code>x == y</code>
    142     * <br><strong>Method:</strong> <code>boolean equals(L x, R y);</code>.
    143     * @see JexlArithmetic#equals(Object, Object)
    144     */
    145    EQ("==", "equals", 2),
    146
    147    /**
    148     * Equal-strict operator.
    149     * <br><strong>Syntax:</strong> <code>x === y</code>
    150     * <br><strong>Method:</strong> <code>boolean strictEquals(L x, R y);</code>.
    151     * @see JexlArithmetic#strictEquals(Object, Object)
    152     */
    153    EQSTRICT("===", "strictEquals", 2),
    154
    155    /**
    156     * Less-than operator.
    157     * <br><strong>Syntax:</strong> <code>x &lt; y</code>
    158     * <br><strong>Method:</strong> <code>boolean lessThan(L x, R y);</code>.
    159     * @see JexlArithmetic#lessThan(Object, Object)
    160     */
    161    LT("<", "lessThan", 2),
    162
    163    /**
    164     * Less-than-or-equal operator.
    165     * <br><strong>Syntax:</strong> <code>x &lt;= y</code>
    166     * <br><strong>Method:</strong> <code>boolean lessThanOrEqual(L x, R y);</code>.
    167     * @see JexlArithmetic#lessThanOrEqual(Object, Object)
    168     */
    169    LTE("<=", "lessThanOrEqual", 2),
    170
    171    /**
    172     * Greater-than operator.
    173     * <br><strong>Syntax:</strong> <code>x &gt; y</code>
    174     * <br><strong>Method:</strong> <code>boolean greaterThan(L x, R y);</code>.
    175     * @see JexlArithmetic#greaterThan(Object, Object)
    176     */
    177    GT(">", "greaterThan", 2),
    178
    179    /**
    180     * Greater-than-or-equal operator.
    181     * <br><strong>Syntax:</strong> <code>x &gt;= y</code>
    182     * <br><strong>Method:</strong> <code>boolean greaterThanOrEqual(L x, R y);</code>.
    183     * @see JexlArithmetic#greaterThanOrEqual(Object, Object)
    184     */
    185    GTE(">=", "greaterThanOrEqual", 2),
    186
    187    /**
    188     * Contains operator.
    189     * <br><strong>Syntax:</strong> <code>x =~ y</code>
    190     * <br><strong>Method:</strong> <code>boolean contains(L x, R y);</code>.
    191     * @see JexlArithmetic#contains(Object, Object)
    192     */
    193    CONTAINS("=~", "contains", 2),
    194
    195    /**
    196     * Starts-with operator.
    197     * <br><strong>Syntax:</strong> <code>x =^ y</code>
    198     * <br><strong>Method:</strong> <code>boolean startsWith(L x, R y);</code>.
    199     * @see JexlArithmetic#startsWith(Object, Object)
    200     */
    201    STARTSWITH("=^", "startsWith", 2),
    202
    203    /**
    204     * Ends-with operator.
    205     * <br><strong>Syntax:</strong> <code>x =$ y</code>
    206     * <br><strong>Method:</strong> <code>boolean endsWith(L x, R y);</code>.
    207     * @see JexlArithmetic#endsWith(Object, Object)
    208     */
    209    ENDSWITH("=$", "endsWith", 2),
    210
    211    /**
    212     * Not operator.
    213     * <br><strong>Syntax:</strong> <code>!x</code>
    214     * <br><strong>Method:</strong> <code>T not(L x);</code>.
    215     * @see JexlArithmetic#not(Object)
    216     */
    217    NOT("!", "not", 1),
    218
    219    /**
    220     * Complement operator.
    221     * <br><strong>Syntax:</strong> <code>~x</code>
    222     * <br><strong>Method:</strong> <code>T complement(L x);</code>.
    223     * @see JexlArithmetic#complement(Object)
    224     */
    225    COMPLEMENT("~", "complement", 1),
    226
    227    /**
    228     * Negate operator.
    229     * <br><strong>Syntax:</strong> <code>-x</code>
    230     * <br><strong>Method:</strong> <code>T negate(L x);</code>.
    231     * @see JexlArithmetic#negate(Object)
    232     */
    233    NEGATE("-", "negate", 1),
    234
    235    /**
    236     * Positivize operator.
    237     * <br><strong>Syntax:</strong> <code>+x</code>
    238     * <br><strong>Method:</strong> <code>T positivize(L x);</code>.
    239     * @see JexlArithmetic#positivize(Object)
    240     */
    241    POSITIVIZE("+", "positivize", 1),
    242
    243    /**
    244     * Empty operator.
    245     * <br><strong>Syntax:</strong> <code>empty x</code> or <code>empty(x)</code>
    246     * <br><strong>Method:</strong> <code>boolean empty(L x);</code>.
    247     * @see JexlArithmetic#empty(Object)
    248     */
    249    EMPTY("empty", "empty", 1),
    250
    251    /**
    252     * Size operator.
    253     * <br><strong>Syntax:</strong> <code>size x</code> or <code>size(x)</code>
    254     * <br><strong>Method:</strong> <code>int size(L x);</code>.
    255     * @see JexlArithmetic#size(Object)
    256     */
    257    SIZE("size", "size", 1),
    258
    259    /**
    260     * Self-add operator.
    261     * <br><strong>Syntax:</strong> <code>x += y</code>
    262     * <br><strong>Method:</strong> <code>T selfAdd(L x, R y);</code>.
    263     */
    264    SELF_ADD("+=", "selfAdd", ADD),
    265
    266    /**
    267     * Self-subtract operator.
    268     * <br><strong>Syntax:</strong> <code>x -= y</code>
    269     * <br><strong>Method:</strong> <code>T selfSubtract(L x, R y);</code>.
    270     */
    271    SELF_SUBTRACT("-=", "selfSubtract", SUBTRACT),
    272
    273    /**
    274     * Self-multiply operator.
    275     * <br><strong>Syntax:</strong> <code>x *= y</code>
    276     * <br><strong>Method:</strong> <code>T selfMultiply(L x, R y);</code>.
    277     */
    278    SELF_MULTIPLY("*=", "selfMultiply", MULTIPLY),
    279
    280    /**
    281     * Self-divide operator.
    282     * <br><strong>Syntax:</strong> <code>x /= y</code>
    283     * <br><strong>Method:</strong> <code>T selfDivide(L x, R y);</code>.
    284     */
    285    SELF_DIVIDE("/=", "selfDivide", DIVIDE),
    286
    287    /**
    288     * Self-modulo operator.
    289     * <br><strong>Syntax:</strong> <code>x %= y</code>
    290     * <br><strong>Method:</strong> <code>T selfMod(L x, R y);</code>.
    291     */
    292    SELF_MOD("%=", "selfMod", MOD),
    293
    294    /**
    295     * Self-and operator.
    296     * <br><strong>Syntax:</strong> <code>x &amp;= y</code>
    297     * <br><strong>Method:</strong> <code>T selfAnd(L x, R y);</code>.
    298     */
    299    SELF_AND("&=", "selfAnd", AND),
    300
    301    /**
    302     * Self-or operator.
    303     * <br><strong>Syntax:</strong> <code>x |= y</code>
    304     * <br><strong>Method:</strong> <code>T selfOr(L x, R y);</code>.
    305     */
    306    SELF_OR("|=", "selfOr", OR),
    307
    308    /**
    309     * Self-xor operator.
    310     * <br><strong>Syntax:</strong> <code>x ^= y</code>
    311     * <br><strong>Method:</strong> <code>T selfXor(L x, R y);</code>.
    312     */
    313    SELF_XOR("^=", "selfXor", XOR),
    314
    315    /**
    316     * Self-right-shift operator.
    317     * <br><strong>Syntax:</strong> <code>x &gt;&gt;= y</code>
    318     * <br><strong>Method:</strong> <code>T selfShiftRight(L x, R y);</code>.
    319     */
    320    SELF_SHIFTRIGHT(">>=", "selfShiftRight", SHIFTRIGHT),
    321
    322    /**
    323     * Self-right-shift unsigned operator.
    324     * <br><strong>Syntax:</strong> <code>x &gt;&gt;&gt; y</code>
    325     * <br><strong>Method:</strong> <code>T selfShiftRightUnsigned(L x, R y);</code>.
    326     */
    327    SELF_SHIFTRIGHTU(">>>=", "selfShiftRightUnsigned", SHIFTRIGHTU),
    328
    329    /**
    330     * Self-left-shift operator.
    331     * <br><strong>Syntax:</strong> <code>x &lt;&lt; y</code>
    332     * <br><strong>Method:</strong> <code>T selfShiftLeft(L x, R y);</code>.
    333     */
    334    SELF_SHIFTLEFT("<<=", "selfShiftLeft", SHIFTLEFT),
    335
    336    /**
    337     * Increment pseudo-operator.
    338     * <br>No syntax, used as helper for the prefix and postfix versions of <code>++</code>.
    339     * @see JexlArithmetic#increment(Object)
    340     */
    341    INCREMENT("+1", "increment", 1),
    342
    343    /**
    344     * Decrement pseudo-operator.
    345     * <br>No syntax, used as helper for the prefix and postfix versions of <code>--</code>.
    346     * @see JexlArithmetic#decrement(Object)
    347     */
    348    DECREMENT("-1", "decrement", 1),
    349
    350    /**
    351     * Prefix ++ operator, increments and returns the value after incrementing.
    352     * <br><strong>Syntax:</strong> <code>++x</code>
    353     * <br><strong>Method:</strong> <code>T incrementAndGet(L x);</code>.
    354     */
    355    INCREMENT_AND_GET("++.", "incrementAndGet", INCREMENT, 1),
    356
    357    /**
    358     * Postfix ++, increments and returns the value before incrementing.
    359     * <br><strong>Syntax:</strong> <code>x++</code>
    360     * <br><strong>Method:</strong> <code>T getAndIncrement(L x);</code>.
    361     */
    362    GET_AND_INCREMENT(".++", "getAndIncrement", INCREMENT, 1),
    363
    364    /**
    365     * Prefix --, decrements and returns the value after decrementing.
    366     * <br><strong>Syntax:</strong> <code>--x</code>
    367     * <br><strong>Method:</strong> <code>T decrementAndGet(L x);</code>.
    368     */
    369    DECREMENT_AND_GET("--.", "decrementAndGet", DECREMENT, 1),
    370
    371    /**
    372     * Postfix --, decrements and returns the value before decrementing.
    373     * <br><strong>Syntax:</strong> <code>x--</code>
    374     * <br><strong>Method:</strong> <code>T getAndDecrement(L x);</code>.
    375     */
    376    GET_AND_DECREMENT(".--", "getAndDecrement", DECREMENT, 1),
    377
    378    /**
    379     * Marker for side effect.
    380     * <br>Returns this from 'self*' overload method to let the engine know the side effect has been performed and
    381     * there is no need to assign the result.
    382     */
    383    ASSIGN("=", null, null),
    384
    385    /**
    386     * Property get operator as in: x.y.
    387     * <br><strong>Syntax:</strong> <code>x.y</code>
    388     * <br><strong>Method:</strong> <code>Object propertyGet(L x, R y);</code>.
    389     */
    390    PROPERTY_GET(".", "propertyGet", 2),
    391
    392    /**
    393     * Property set operator as in: x.y = z.
    394     * <br><strong>Syntax:</strong> <code>x.y = z</code>
    395     * <br><strong>Method:</strong> <code>void propertySet(L x, R y, V z);</code>.
    396     */
    397    PROPERTY_SET(".=", "propertySet", 3),
    398
    399    /**
    400     * Array get operator as in: x[y].
    401     * <br><strong>Syntax:</strong> <code>x.y</code>
    402     * <br><strong>Method:</strong> <code>Object arrayGet(L x, R y);</code>.
    403     */
    404    ARRAY_GET("[]", "arrayGet", 2),
    405
    406    /**
    407     * Array set operator as in: x[y] = z.
    408     * <br><strong>Syntax:</strong> <code>x[y] = z</code>
    409     * <br><strong>Method:</strong> <code>void arraySet(L x, R y, V z);</code>.
    410     */
    411    ARRAY_SET("[]=", "arraySet", 3),
    412
    413    /**
    414     * Iterator generator as in for(var x : y).
    415     * If the returned Iterator is AutoCloseable, close will be called after the last execution of the loop block.
    416     * <br><strong>Syntax:</strong> <code>for(var x : y){...} </code>
    417     * <br><strong>Method:</strong> <code>Iterator&lt;Object&gt; forEach(R y);</code>.
    418     * @since 3.1
    419     */
    420    FOR_EACH("for(...)", "forEach", 1),
    421
    422    /**
    423     * Test condition in if, for, while.
    424     * <br><strong>Method:</strong> <code>boolean testCondition(R y);</code>.
    425     * @since 3.3
    426     */
    427    CONDITION("?", "testCondition", 1);
    428
    429    /**
    430     * The operator symbol.
    431     */
    432    private final String operator;
    433
    434    /**
    435     * The associated operator method name.
    436     */
    437    private final String methodName;
    438
    439    /**
    440     * The method arity (ie number of arguments).
    441     */
    442    private final int arity;
    443
    444    /**
    445     * The base operator.
    446     */
    447    private final JexlOperator base;
    448
    449    /**
    450     * Creates a base operator.
    451     *
    452     * @param o    the operator name
    453     * @param m    the method name associated to this operator in a JexlArithmetic
    454     * @param argc the number of parameters for the method
    455     */
    456    JexlOperator(final String o, final String m, final int argc) {
    457        this(o, m, null, argc);
    458    }
    459
    460    /**
    461     * Creates a side effect operator with arity == 2.
    462     *
    463     * @param o the operator name
    464     * @param m the method name associated to this operator in a JexlArithmetic
    465     * @param b the base operator, ie + for +=
    466     */
    467    JexlOperator(final String o, final String m, final JexlOperator b) {
    468        this(o, m, b, 2);
    469    }
    470
    471    /**
    472     * Creates a side effect operator.
    473     *
    474     * @param o the operator name
    475     * @param m the method name associated to this operator in a JexlArithmetic
    476     * @param b the base operator, ie + for +=
    477     * @param a the operator arity
    478     */
    479    JexlOperator(final String o, final String m, final JexlOperator b, final int a) {
    480        this.operator = o;
    481        this.methodName = m;
    482        this.arity = a;
    483        this.base = b;
    484    }
    485
    486    /**
    487     * Gets this operator number of parameters.
    488     *
    489     * @return the method arity
    490     */
    491    public int getArity() {
    492        return arity;
    493    }
    494
    495    /**
    496     * Gets the base operator.
    497     *
    498     * @return the base operator
    499     */
    500    public final JexlOperator getBaseOperator() {
    501        return base;
    502    }
    503
    504    /**
    505     * Gets this operator method name in a JexlArithmetic.
    506     *
    507     * @return the method name
    508     */
    509    public final String getMethodName() {
    510        return methodName;
    511    }
    512
    513    /**
    514     * Gets this operator symbol.
    515     *
    516     * @return the symbol
    517     */
    518    public final String getOperatorSymbol() {
    519        return operator;
    520    }
    521
    522}