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}