    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     * Less-than operator.
    149     * <br><strong>Syntax:</strong> <code>x &lt; y</code>
    150     * <br><strong>Method:</strong> <code>boolean lessThan(L x, R y);</code>.
    151     * @see JexlArithmetic#lessThan(Object, Object)
    152     */
    153    LT("<", "lessThan", 2),
    154
    155    /**
    156     * Less-than-or-equal operator.
    157     * <br><strong>Syntax:</strong> <code>x &lt;= y</code>
    158     * <br><strong>Method:</strong> <code>boolean lessThanOrEqual(L x, R y);</code>.
    159     * @see JexlArithmetic#lessThanOrEqual(Object, Object)
    160     */
    161    LTE("<=", "lessThanOrEqual", 2),
    162
    163    /**
    164     * Greater-than operator.
    165     * <br><strong>Syntax:</strong> <code>x &gt; y</code>
    166     * <br><strong>Method:</strong> <code>boolean greaterThan(L x, R y);</code>.
    167     * @see JexlArithmetic#greaterThan(Object, Object)
    168     */
    169    GT(">", "greaterThan", 2),
    170
    171    /**
    172     * Greater-than-or-equal operator.
    173     * <br><strong>Syntax:</strong> <code>x &gt;= y</code>
    174     * <br><strong>Method:</strong> <code>boolean greaterThanOrEqual(L x, R y);</code>.
    175     * @see JexlArithmetic#greaterThanOrEqual(Object, Object)
    176     */
    177    GTE(">=", "greaterThanOrEqual", 2),
    178
    179    /**
    180     * Contains operator.
    181     * <br><strong>Syntax:</strong> <code>x =~ y</code>
    182     * <br><strong>Method:</strong> <code>boolean contains(L x, R y);</code>.
    183     * @see JexlArithmetic#contains(Object, Object)
    184     */
    185    CONTAINS("=~", "contains", 2),
    186
    187    /**
    188     * Starts-with operator.
    189     * <br><strong>Syntax:</strong> <code>x =^ y</code>
    190     * <br><strong>Method:</strong> <code>boolean startsWith(L x, R y);</code>.
    191     * @see JexlArithmetic#startsWith(Object, Object)
    192     */
    193    STARTSWITH("=^", "startsWith", 2),
    194
    195    /**
    196     * Ends-with operator.
    197     * <br><strong>Syntax:</strong> <code>x =$ y</code>
    198     * <br><strong>Method:</strong> <code>boolean endsWith(L x, R y);</code>.
    199     * @see JexlArithmetic#endsWith(Object, Object)
    200     */
    201    ENDSWITH("=$", "endsWith", 2),
    202
    203    /**
    204     * Not operator.
    205     * <br><strong>Syntax:</strong> <code>!x</code>
    206     * <br><strong>Method:</strong> <code>T not(L x);</code>.
    207     * @see JexlArithmetic#not(Object)
    208     */
    209    NOT("!", "not", 1),
    210
    211    /**
    212     * Complement operator.
    213     * <br><strong>Syntax:</strong> <code>~x</code>
    214     * <br><strong>Method:</strong> <code>T complement(L x);</code>.
    215     * @see JexlArithmetic#complement(Object)
    216     */
    217    COMPLEMENT("~", "complement", 1),
    218
    219    /**
    220     * Negate operator.
    221     * <br><strong>Syntax:</strong> <code>-x</code>
    222     * <br><strong>Method:</strong> <code>T negate(L x);</code>.
    223     * @see JexlArithmetic#negate(Object)
    224     */
    225    NEGATE("-", "negate", 1),
    226
    227    /**
    228     * Positivize operator.
    229     * <br><strong>Syntax:</strong> <code>+x</code>
    230     * <br><strong>Method:</strong> <code>T positivize(L x);</code>.
    231     * @see JexlArithmetic#positivize(Object)
    232     */
    233    POSITIVIZE("+", "positivize", 1),
    234
    235    /**
    236     * Empty operator.
    237     * <br><strong>Syntax:</strong> <code>empty x</code> or <code>empty(x)</code>
    238     * <br><strong>Method:</strong> <code>boolean empty(L x);</code>.
    239     * @see JexlArithmetic#empty(Object)
    240     */
    241    EMPTY("empty", "empty", 1),
    242
    243    /**
    244     * Size operator.
    245     * <br><strong>Syntax:</strong> <code>size x</code> or <code>size(x)</code>
    246     * <br><strong>Method:</strong> <code>int size(L x);</code>.
    247     * @see JexlArithmetic#size(Object)
    248     */
    249    SIZE("size", "size", 1),
    250
    251    /**
    252     * Self-add operator.
    253     * <br><strong>Syntax:</strong> <code>x += y</code>
    254     * <br><strong>Method:</strong> <code>T selfAdd(L x, R y);</code>.
    255     */
    256    SELF_ADD("+=", "selfAdd", ADD),
    257
    258    /**
    259     * Self-subtract operator.
    260     * <br><strong>Syntax:</strong> <code>x -= y</code>
    261     * <br><strong>Method:</strong> <code>T selfSubtract(L x, R y);</code>.
    262     */
    263    SELF_SUBTRACT("-=", "selfSubtract", SUBTRACT),
    264
    265    /**
    266     * Self-multiply operator.
    267     * <br><strong>Syntax:</strong> <code>x *= y</code>
    268     * <br><strong>Method:</strong> <code>T selfMultiply(L x, R y);</code>.
    269     */
    270    SELF_MULTIPLY("*=", "selfMultiply", MULTIPLY),
    271
    272    /**
    273     * Self-divide operator.
    274     * <br><strong>Syntax:</strong> <code>x /= y</code>
    275     * <br><strong>Method:</strong> <code>T selfDivide(L x, R y);</code>.
    276     */
    277    SELF_DIVIDE("/=", "selfDivide", DIVIDE),
    278
    279    /**
    280     * Self-modulo operator.
    281     * <br><strong>Syntax:</strong> <code>x %= y</code>
    282     * <br><strong>Method:</strong> <code>T selfMod(L x, R y);</code>.
    283     */
    284    SELF_MOD("%=", "selfMod", MOD),
    285
    286    /**
    287     * Self-and operator.
    288     * <br><strong>Syntax:</strong> <code>x &amp;= y</code>
    289     * <br><strong>Method:</strong> <code>T selfAnd(L x, R y);</code>.
    290     */
    291    SELF_AND("&=", "selfAnd", AND),
    292
    293    /**
    294     * Self-or operator.
    295     * <br><strong>Syntax:</strong> <code>x |= y</code>
    296     * <br><strong>Method:</strong> <code>T selfOr(L x, R y);</code>.
    297     */
    298    SELF_OR("|=", "selfOr", OR),
    299
    300    /**
    301     * Self-xor operator.
    302     * <br><strong>Syntax:</strong> <code>x ^= y</code>
    303     * <br><strong>Method:</strong> <code>T selfXor(L x, R y);</code>.
    304     */
    305    SELF_XOR("^=", "selfXor", XOR),
    306
    307    /**
    308     * Self-right-shift operator.
    309     * <br><strong>Syntax:</strong> <code>x &gt;&gt;= y</code>
    310     * <br><strong>Method:</strong> <code>T selfShiftRight(L x, R y);</code>.
    311     */
    312    SELF_SHIFTRIGHT(">>=", "selfShiftRight", SHIFTRIGHT),
    313
    314    /**
    315     * Self-right-shift unsigned operator.
    316     * <br><strong>Syntax:</strong> <code>x &gt;&gt;&gt; y</code>
    317     * <br><strong>Method:</strong> <code>T selfShiftRightUnsigned(L x, R y);</code>.
    318     */
    319    SELF_SHIFTRIGHTU(">>>=", "selfShiftRightUnsigned", SHIFTRIGHTU),
    320
    321    /**
    322     * Self-left-shift operator.
    323     * <br><strong>Syntax:</strong> <code>x &lt;&lt; y</code>
    324     * <br><strong>Method:</strong> <code>T selfShiftLeft(L x, R y);</code>.
    325     */
    326    SELF_SHIFTLEFT("<<=", "selfShiftLeft", SHIFTLEFT),
    327
    328    /**
    329     * Increment pseudo-operator.
    330     * <br>No syntax, used as helper for the prefix and postfix versions of <code>++</code>.
    331     * @see JexlArithmetic#increment(Object)
    332     */
    333    INCREMENT("+1", "increment", 1),
    334
    335    /**
    336     * Decrement pseudo-operator.
    337     * <br>No syntax, used as helper for the prefix and postfix versions of <code>--</code>.
    338     * @see JexlArithmetic#decrement(Object)
    339     */
    340    DECREMENT("-1", "decrement", 1),
    341
    342    /**
    343     * Prefix ++ operator, increments and returns the value after incrementing.
    344     * <br><strong>Syntax:</strong> <code>++x</code>
    345     * <br><strong>Method:</strong> <code>T incrementAndGet(L x);</code>.
    346     */
    347    INCREMENT_AND_GET("++.", "incrementAndGet", INCREMENT, 1),
    348
    349    /**
    350     * Postfix ++, increments and returns the value before incrementing.
    351     * <br><strong>Syntax:</strong> <code>x++</code>
    352     * <br><strong>Method:</strong> <code>T getAndIncrement(L x);</code>.
    353     */
    354    GET_AND_INCREMENT(".++", "getAndIncrement", INCREMENT, 1),
    355
    356    /**
    357     * Prefix --, decrements and returns the value after decrementing.
    358     * <br><strong>Syntax:</strong> <code>--x</code>
    359     * <br><strong>Method:</strong> <code>T decrementAndGet(L x);</code>.
    360     */
    361    DECREMENT_AND_GET("--.", "decrementAndGet", DECREMENT, 1),
    362
    363    /**
    364     * Postfix --, decrements and returns the value before decrementing.
    365     * <br><strong>Syntax:</strong> <code>x--</code>
    366     * <br><strong>Method:</strong> <code>T getAndDecrement(L x);</code>.
    367     */
    368    GET_AND_DECREMENT(".--", "getAndDecrement", DECREMENT, 1),
    369
    370    /**
    371     * Marker for side effect.
    372     * <br>Returns this from 'self*' overload method to let the engine know the side effect has been performed and
    373     * there is no need to assign the result.
    374     */
    375    ASSIGN("=", null, null),
    376
    377    /**
    378     * Property get operator as in: x.y.
    379     * <br><strong>Syntax:</strong> <code>x.y</code>
    380     * <br><strong>Method:</strong> <code>Object propertyGet(L x, R y);</code>.
    381     */
    382    PROPERTY_GET(".", "propertyGet", 2),
    383
    384    /**
    385     * Property set operator as in: x.y = z.
    386     * <br><strong>Syntax:</strong> <code>x.y = z</code>
    387     * <br><strong>Method:</strong> <code>void propertySet(L x, R y, V z);</code>.
    388     */
    389    PROPERTY_SET(".=", "propertySet", 3),
    390
    391    /**
    392     * Array get operator as in: x[y].
    393     * <br><strong>Syntax:</strong> <code>x.y</code>
    394     * <br><strong>Method:</strong> <code>Object arrayGet(L x, R y);</code>.
    395     */
    396    ARRAY_GET("[]", "arrayGet", 2),
    397
    398    /**
    399     * Array set operator as in: x[y] = z.
    400     * <br><strong>Syntax:</strong> <code>x[y] = z</code>
    401     * <br><strong>Method:</strong> <code>void arraySet(L x, R y, V z);</code>.
    402     */
    403    ARRAY_SET("[]=", "arraySet", 3),
    404
    405    /**
    406     * Iterator generator as in for(var x : y).
    407     * If the returned Iterator is AutoCloseable, close will be called after the last execution of the loop block.
    408     * <br><strong>Syntax:</strong> <code>for(var x : y){...} </code>
    409     * <br><strong>Method:</strong> <code>Iterator&lt;Object&gt; forEach(R y);</code>.
    410     * @since 3.1
    411     */
    412    FOR_EACH("for(...)", "forEach", 1),
    413
    414    /**
    415     * Test condition in if, for, while.
    416     * <br><strong>Method:</strong> <code>boolean testCondition(R y);</code>.
    417     * @since 3.3
    418     */
    419    CONDITION("?", "testCondition", 1);
    420
    421    /**
    422     * The operator symbol.
    423     */
    424    private final String operator;
    425
    426    /**
    427     * The associated operator method name.
    428     */
    429    private final String methodName;
    430
    431    /**
    432     * The method arity (ie number of arguments).
    433     */
    434    private final int arity;
    435
    436    /**
    437     * The base operator.
    438     */
    439    private final JexlOperator base;
    440
    441    /**
    442     * Creates a base operator.
    443     *
    444     * @param o    the operator name
    445     * @param m    the method name associated to this operator in a JexlArithmetic
    446     * @param argc the number of parameters for the method
    447     */
    448    JexlOperator(final String o, final String m, final int argc) {
    449        this(o, m, null, argc);
    450    }
    451
    452    /**
    453     * Creates a side effect operator with arity == 2.
    454     *
    455     * @param o the operator name
    456     * @param m the method name associated to this operator in a JexlArithmetic
    457     * @param b the base operator, ie + for +=
    458     */
    459    JexlOperator(final String o, final String m, final JexlOperator b) {
    460        this(o, m, b, 2);
    461    }
    462
    463    /**
    464     * Creates a side effect operator.
    465     *
    466     * @param o the operator name
    467     * @param m the method name associated to this operator in a JexlArithmetic
    468     * @param b the base operator, ie + for +=
    469     * @param a the operator arity
    470     */
    471    JexlOperator(final String o, final String m, final JexlOperator b, final int a) {
    472        this.operator = o;
    473        this.methodName = m;
    474        this.arity = a;
    475        this.base = b;
    476    }
    477
    478    /**
    479     * Gets this operator symbol.
    480     *
    481     * @return the symbol
    482     */
    483    public final String getOperatorSymbol() {
    484        return operator;
    485    }
    486
    487    /**
    488     * Gets this operator method name in a JexlArithmetic.
    489     *
    490     * @return the method name
    491     */
    492    public final String getMethodName() {
    493        return methodName;
    494    }
    495
    496    /**
    497     * Gets this operator number of parameters.
    498     *
    499     * @return the method arity
    500     */
    501    public int getArity() {
    502        return arity;
    503    }
    504
    505    /**
    506     * Gets the base operator.
    507     *
    508     * @return the base operator
    509     */
    510    public final JexlOperator getBaseOperator() {
    511        return base;
    512    }
    513
    514}