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}