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
020import org.apache.commons.jexl3.introspection.JexlMethod;
021
022import java.lang.reflect.Array;
023import java.lang.reflect.Constructor;
024import java.lang.reflect.InvocationTargetException;
025import java.lang.reflect.Method;
026import java.math.BigDecimal;
027import java.math.BigInteger;
028import java.math.MathContext;
029import java.util.Collection;
030import java.util.Map;
031import java.util.concurrent.atomic.AtomicBoolean;
032import java.util.regex.Matcher;
033import java.util.regex.Pattern;
034
035import static java.lang.StrictMath.floor;
036
037/**
038 * Perform arithmetic, implements JexlOperator methods.
039 *
040 * <p>This is the class to derive to implement new operator behaviors.</p>
041 *
042 * <p>The 5 base arithmetic operators (+, - , *, /, %) follow the same evaluation rules regarding their arguments.</p>
043 * <ol>
044 *   <li>If both are null, result is 0</li>
045 *   <li>If either is a BigDecimal, coerce both to BigDecimal and perform operation</li>
046 *   <li>If either is a floating point number, coerce both to Double and perform operation</li>
047 *   <li>Else treat as BigInteger, perform operation and attempt to narrow result:
048 *     <ol>
049 *       <li>if both arguments can be narrowed to Integer, narrow result to Integer</li>
050 *       <li>if both arguments can be narrowed to Long, narrow result to Long</li>
051 *       <li>Else return result as BigInteger</li>
052 *     </ol>
053 *   </li>
054 * </ol>
055 *
056 * Note that the only exception thrown by JexlArithmetic is and must be ArithmeticException.
057 *
058 * @see JexlOperator
059 * @since 2.0
060 */
061public class JexlArithmetic {
062
063    /** Marker class for null operand exceptions. */
064    public static class NullOperand extends ArithmeticException {
065        private static final long serialVersionUID = 4720876194840764770L;
066    }
067
068    /** Double.MAX_VALUE as BigDecimal. */
069    protected static final BigDecimal BIGD_DOUBLE_MAX_VALUE = BigDecimal.valueOf(Double.MAX_VALUE);
070
071    /** Double.MIN_VALUE as BigDecimal. */
072    protected static final BigDecimal BIGD_DOUBLE_MIN_VALUE = BigDecimal.valueOf(Double.MIN_VALUE);
073
074    /** Long.MAX_VALUE as BigInteger. */
075    protected static final BigInteger BIGI_LONG_MAX_VALUE = BigInteger.valueOf(Long.MAX_VALUE);
076
077    /** Long.MIN_VALUE as BigInteger. */
078    protected static final BigInteger BIGI_LONG_MIN_VALUE = BigInteger.valueOf(Long.MIN_VALUE);
079
080    /** Default BigDecimal scale. */
081    protected static final int BIGD_SCALE = -1;
082
083    /** Whether this JexlArithmetic instance behaves in strict or lenient mode. */
084    private final boolean strict;
085
086    /** The big decimal math context. */
087    private final MathContext mathContext;
088
089    /** The big decimal scale. */
090    private final int mathScale;
091
092    /** The dynamic constructor. */
093    private final Constructor<? extends JexlArithmetic> ctor;
094
095    /**
096     * Creates a JexlArithmetic.
097     * <p>If you derive your own arithmetic, implement the
098     * other constructor that may be needed when dealing with options.
099     *
100     * @param astrict whether this arithmetic is strict or lenient
101     */
102    public JexlArithmetic(final boolean astrict) {
103        this(astrict, null, Integer.MIN_VALUE);
104    }
105
106    /**
107     * Creates a JexlArithmetic.
108     * <p>The constructor to define in derived classes.
109     *
110     * @param astrict     whether this arithmetic is lenient or strict
111     * @param bigdContext the math context instance to use for +,-,/,*,% operations on big decimals.
112     * @param bigdScale   the scale used for big decimals.
113     */
114    public JexlArithmetic(final boolean astrict, final MathContext bigdContext, final int bigdScale) {
115        this.strict = astrict;
116        this.mathContext = bigdContext == null ? MathContext.DECIMAL128 : bigdContext;
117        this.mathScale = bigdScale == Integer.MIN_VALUE ? BIGD_SCALE : bigdScale;
118        Constructor<? extends JexlArithmetic> actor = null;
119        try {
120            actor = getClass().getConstructor(boolean.class, MathContext.class, int.class);
121        } catch (final Exception xany) {
122            // ignore
123        }
124        this.ctor = actor;
125    }
126
127    /**
128     * Apply options to this arithmetic which eventually may create another instance.
129     * @see #createWithOptions(boolean, java.math.MathContext, int)
130     *
131     * @param options the {@link JexlEngine.Options} to use
132     * @return an arithmetic with those options set
133     */
134    public JexlArithmetic options(final JexlOptions options) {
135        if (options != null) {
136            final boolean ostrict = options.isStrictArithmetic();
137            MathContext bigdContext = options.getMathContext();
138            if (bigdContext == null) {
139                bigdContext = getMathContext();
140            }
141            int bigdScale = options.getMathScale();
142            if (bigdScale == Integer.MIN_VALUE) {
143                bigdScale = getMathScale();
144            }
145            if (ostrict != isStrict()
146                || bigdScale != getMathScale()
147                || bigdContext != getMathContext()) {
148                return createWithOptions(ostrict, bigdContext, bigdScale);
149            }
150        }
151        return this;
152    }
153
154    /**
155     * Apply options to this arithmetic which eventually may create another instance.
156     * @see #createWithOptions(boolean, java.math.MathContext, int)
157     *
158     * @param options the {@link JexlEngine.Options} to use
159     * @return an arithmetic with those options set
160     * @deprecated 3.2
161     */
162    @Deprecated
163    public JexlArithmetic options(final JexlEngine.Options options) {
164        if (options != null) {
165            Boolean ostrict = options.isStrictArithmetic();
166            if (ostrict == null) {
167                ostrict = isStrict();
168            }
169            MathContext bigdContext = options.getArithmeticMathContext();
170            if (bigdContext == null) {
171                bigdContext = getMathContext();
172            }
173            int bigdScale = options.getArithmeticMathScale();
174            if (bigdScale == Integer.MIN_VALUE) {
175                bigdScale = getMathScale();
176            }
177            if (ostrict != isStrict()
178                || bigdScale != getMathScale()
179                || bigdContext != getMathContext()) {
180                return createWithOptions(ostrict, bigdContext, bigdScale);
181            }
182        }
183        return this;
184    }
185
186    /**
187     * Apply options to this arithmetic which eventually may create another instance.
188     * @see #createWithOptions(boolean, java.math.MathContext, int)
189     *
190     * @param context the context that may extend {@link JexlContext.OptionsHandle} to use
191     * @return a new arithmetic instance or this
192     * @since 3.1
193     */
194    public JexlArithmetic options(final JexlContext context) {
195        if (context instanceof JexlContext.OptionsHandle) {
196            return options(((JexlContext.OptionsHandle) context).getEngineOptions());
197        }
198        if (context instanceof JexlEngine.Options) {
199            return options((JexlEngine.Options) context);
200        }
201        return this;
202    }
203
204    /**
205     * Creates a JexlArithmetic instance.
206     * Called by options(...) method when another instance of the same class of arithmetic is required.
207     * @see #options(org.apache.commons.jexl3.JexlEngine.Options)
208     *
209     * @param astrict     whether this arithmetic is lenient or strict
210     * @param bigdContext the math context instance to use for +,-,/,*,% operations on big decimals.
211     * @param bigdScale   the scale used for big decimals.
212     * @return default is a new JexlArithmetic instance
213     * @since 3.1
214     */
215    protected JexlArithmetic createWithOptions(final boolean astrict, final MathContext bigdContext, final int bigdScale) {
216        if (ctor != null) {
217            try {
218                return ctor.newInstance(astrict, bigdContext, bigdScale);
219            } catch (IllegalAccessException | IllegalArgumentException
220                    | InstantiationException | InvocationTargetException xany) {
221                // it was worth the try
222            }
223        }
224        return new JexlArithmetic(astrict, bigdContext, bigdScale);
225    }
226
227    /**
228     * The interface that uberspects JexlArithmetic classes.
229     * <p>This allows overloaded operator methods discovery.</p>
230     */
231    public interface Uberspect {
232        /**
233         * Checks whether this uberspect has overloads for a given operator.
234         *
235         * @param operator the operator to check
236         * @return true if an overload exists, false otherwise
237         */
238        boolean overloads(JexlOperator operator);
239
240        /**
241         * Gets the most specific method for an operator.
242         *
243         * @param operator the operator
244         * @param arg      the arguments
245         * @return the most specific method or null if no specific override could be found
246         */
247        JexlMethod getOperator(JexlOperator operator, Object... arg);
248    }
249
250    /**
251     * Helper interface used when creating an array literal.
252     *
253     * <p>The default implementation creates an array and attempts to type it strictly.</p>
254     *
255     * <ul>
256     *   <li>If all objects are of the same type, the array returned will be an array of that same type</li>
257     *   <li>If all objects are Numbers, the array returned will be an array of Numbers</li>
258     *   <li>If all objects are convertible to a primitive type, the array returned will be an array
259     *       of the primitive type</li>
260     * </ul>
261     */
262    public interface ArrayBuilder {
263
264        /**
265         * Adds a literal to the array.
266         *
267         * @param value the item to add
268         */
269        void add(Object value);
270
271        /**
272         * Creates the actual "array" instance.
273         *
274         * @param extended true when the last argument is ', ...'
275         * @return the array
276         */
277        Object create(boolean extended);
278    }
279
280    /**
281     * Called by the interpreter when evaluating a literal array.
282     *
283     * @param size the number of elements in the array
284     * @return the array builder
285     */
286    public ArrayBuilder arrayBuilder(final int size) {
287        return new org.apache.commons.jexl3.internal.ArrayBuilder(size);
288    }
289
290    /**
291     * Helper interface used when creating a set literal.
292     * <p>The default implementation creates a java.util.HashSet.</p>
293     */
294    public interface SetBuilder {
295        /**
296         * Adds a literal to the set.
297         *
298         * @param value the item to add
299         */
300        void add(Object value);
301
302        /**
303         * Creates the actual "set" instance.
304         *
305         * @return the set
306         */
307        Object create();
308    }
309
310    /**
311     * Called by the interpreter when evaluating a literal set.
312     *
313     * @param size the number of elements in the set
314     * @return the array builder
315     */
316    public SetBuilder setBuilder(final int size) {
317        return new org.apache.commons.jexl3.internal.SetBuilder(size);
318    }
319
320    /**
321     * Helper interface used when creating a map literal.
322     * <p>The default implementation creates a java.util.HashMap.</p>
323     */
324    public interface MapBuilder {
325        /**
326         * Adds a new entry to the map.
327         *
328         * @param key   the map entry key
329         * @param value the map entry value
330         */
331        void put(Object key, Object value);
332
333        /**
334         * Creates the actual "map" instance.
335         *
336         * @return the map
337         */
338        Object create();
339    }
340
341    /**
342     * Called by the interpreter when evaluating a literal map.
343     *
344     * @param size the number of elements in the map
345     * @return the map builder
346     */
347    public MapBuilder mapBuilder(final int size) {
348        return new org.apache.commons.jexl3.internal.MapBuilder(size);
349    }
350
351    /**
352     * Creates a literal range.
353     * <p>The default implementation only accepts integers and longs.</p>
354     *
355     * @param from the included lower bound value (null if none)
356     * @param to   the included upper bound value (null if none)
357     * @return the range as an iterable
358     * @throws ArithmeticException as an option if creation fails
359     */
360    public Iterable<?> createRange(final Object from, final Object to) throws ArithmeticException {
361        final long lfrom = toLong(from);
362        final long lto = toLong(to);
363        if ((lfrom >= Integer.MIN_VALUE && lfrom <= Integer.MAX_VALUE)
364                && (lto >= Integer.MIN_VALUE && lto <= Integer.MAX_VALUE)) {
365            return org.apache.commons.jexl3.internal.IntegerRange.create((int) lfrom, (int) lto);
366        }
367        return org.apache.commons.jexl3.internal.LongRange.create(lfrom, lto);
368    }
369
370    /**
371     * Checks if an operand is considered null.
372     * @param value the operand
373     * @return true if operand is considered null
374     */
375    protected boolean isNullOperand(final Object value) {
376        return value == null;
377    }
378
379    /**
380     * Throws an NullOperand exception if arithmetic is strict-cast.
381     * <p>This method is called by the cast methods ({@link #toBoolean(boolean, Object)},
382     * {@link #toInteger(boolean, Object)}, {@link #toDouble(boolean, Object)},
383     * {@link #toString(boolean, Object)}, {@link #toBigInteger(boolean, Object)},
384     * {@link #toBigDecimal(boolean, Object)}) when they encounter a null argument.</p>
385     *
386     * @param strictCast whether strict cast is required
387     * @param defaultValue the default value to return, if not strict
388     * @param <T> the value type
389     * @return the default value is strict is false
390     * @throws JexlArithmetic.NullOperand if strict-cast
391     * @since 3.3
392     */
393    protected <T> T controlNullOperand(final boolean strictCast, final T defaultValue) {
394        if (strictCast) {
395            throw new NullOperand();
396        }
397        return defaultValue;
398    }
399
400    /**
401     * The result of +,/,-,*,% when both operands are null.
402     * @param operator the actual operator
403     * @return Integer(0) if lenient
404     * @throws  JexlArithmetic.NullOperand if strict-cast
405     * @since 3.3
406     */
407    protected Object controlNullNullOperands(final JexlOperator operator) {
408        if (isStrict(operator)) {
409            throw new NullOperand();
410        }
411        return 0;
412    }
413
414    /**
415     * Coerce to a primitive boolean.
416     * <p>Double.NaN, null, "false" and empty string coerce to false.</p>
417     *
418     * @param val value to coerce
419     * @param strict true if the calling operator or casting is strict, false otherwise
420     * @return the boolean value if coercion is possible, true if value was not null.
421     */
422    protected boolean toBoolean(final boolean strict, final Object val) {
423        return isNullOperand(val)? controlNullOperand(strict, false) : toBoolean(val);
424    }
425
426    /**
427     * Coerce to a primitive boolean.
428     * <p>Double.NaN, null, "false" and empty string coerce to false.</p>
429     *
430     * @param val value to coerce
431     * @return the boolean value if coercion is possible, true if value was not null.
432     */
433    public boolean toBoolean(final Object val) {
434        if (val instanceof Boolean) {
435            return ((Boolean) val);
436        }
437        if (val instanceof Number) {
438            final double number = toDouble(strict, val);
439            return !Double.isNaN(number) && number != 0.d;
440        }
441        if (val instanceof AtomicBoolean) {
442            return ((AtomicBoolean) val).get();
443        }
444        if (val instanceof String) {
445            final String strval = val.toString();
446            return !strval.isEmpty() && !"false".equals(strval);
447        }
448        if (val == null) {
449            return controlNullOperand(strict, false);
450        }
451        // non-null value is true
452        return true;
453    }
454
455    /**
456     * Coerce to a primitive int.
457     * <p>Double.NaN, null and empty string coerce to zero.</p>
458     * <p>Boolean false is 0, true is 1.</p>
459     *
460     * @param strict true if the calling operator or casting is strict, false otherwise
461     * @param val value to coerce
462     * @return the value coerced to int
463     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
464     * @since 3.3
465     */
466    protected int toInteger(final boolean strict, final Object val) {
467        return isNullOperand(val)? controlNullOperand(strict, 0) : toInteger(val);
468    }
469
470    /**
471     * Coerce to a primitive int.
472     * <p>Double.NaN, null and empty string coerce to zero.</p>
473     * <p>Boolean false is 0, true is 1.</p>
474     *
475     * @param val value to coerce
476     * @return the value coerced to int
477     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
478     */
479    public int toInteger(final Object val) {
480        if (val instanceof Double) {
481            final double dval = (Double) val;
482            return Double.isNaN(dval)? 0 : (int) dval;
483        }
484        if (val instanceof Number) {
485            return ((Number) val).intValue();
486        }
487        if (val instanceof String) {
488            return parseInteger((String) val);
489        }
490        if (val instanceof Boolean) {
491            return ((Boolean) val) ? 1 : 0;
492        }
493        if (val instanceof AtomicBoolean) {
494            return ((AtomicBoolean) val).get() ? 1 : 0;
495        }
496        if (val instanceof Character) {
497            return ((Character) val);
498        }
499        if (val == null) {
500            return controlNullOperand(strict, 0);
501        }
502        throw new ArithmeticException("Integer coercion: "
503                + val.getClass().getName() + ":(" + val + ")");
504    }
505
506    /**
507     * Coerce to a primitive long.
508     * <p>Double.NaN, null and empty string coerce to zero.</p>
509     * <p>Boolean false is 0, true is 1.</p>
510     *
511     * @param strict true if the calling operator or casting is strict, false otherwise
512     * @param val value to coerce
513     * @return the value coerced to long
514     * @throws ArithmeticException if value is null and mode is strict or if coercion is not possible
515     * @since 3.3
516     */
517    protected long toLong(final boolean strict, final Object val) {
518        return isNullOperand(val)? controlNullOperand(strict, 0L) : toLong(val);
519    }
520
521    /**
522     * Coerce to a primitive long.
523     * <p>Double.NaN, null and empty string coerce to zero.</p>
524     * <p>Boolean false is 0, true is 1.</p>
525     *
526     * @param val value to coerce
527     * @return the value coerced to long
528     * @throws ArithmeticException if value is null and mode is strict or if coercion is not possible
529     */
530    public long toLong(final Object val) {
531        if (val instanceof Double) {
532            final double dval = (Double) val;
533            return Double.isNaN(dval)? 0L : (long) dval;
534        }
535        if (val instanceof Number) {
536            return ((Number) val).longValue();
537        }
538        if (val instanceof String) {
539            return parseLong((String) val);
540        }
541        if (val instanceof Boolean) {
542            return ((Boolean) val) ? 1L : 0L;
543        }
544        if (val instanceof AtomicBoolean) {
545            return ((AtomicBoolean) val).get() ? 1L : 0L;
546        }
547        if (val instanceof Character) {
548            return ((Character) val);
549        }
550        if (val == null) {
551            return controlNullOperand(strict, 0L);
552        }
553        throw new ArithmeticException("Long coercion: "
554                + val.getClass().getName() + ":(" + val + ")");
555    }
556
557    /**
558     * Coerce to a BigInteger.
559     * <p>Double.NaN, null and empty string coerce to zero.</p>
560     * <p>Boolean false is 0, true is 1.</p>
561     *
562     * @param strict true if the calling operator or casting is strict, false otherwise
563     * @param val the object to be coerced.
564     * @return a BigDecimal
565     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
566     * @since 3.3
567     */
568    protected BigInteger toBigInteger(final boolean strict, final Object val) {
569        return isNullOperand(val)? controlNullOperand(strict, BigInteger.ZERO) : toBigInteger(val);
570    }
571
572    /**
573     * Coerce to a BigInteger.
574     * <p>Double.NaN, null and empty string coerce to zero.</p>
575     * <p>Boolean false is 0, true is 1.</p>
576     *
577     * @param val the object to be coerced.
578     * @return a BigDecimal
579     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
580     */
581    public BigInteger toBigInteger(final Object val) {
582        if (val instanceof BigInteger) {
583            return (BigInteger) val;
584        }
585        if (val instanceof Double) {
586            final Double dval = (Double) val;
587            if (Double.isNaN(dval)) {
588                return BigInteger.ZERO;
589            }
590            return BigInteger.valueOf(dval.longValue());
591        }
592        if (val instanceof BigDecimal) {
593            return ((BigDecimal) val).toBigInteger();
594        }
595        if (val instanceof Number) {
596            return BigInteger.valueOf(((Number) val).longValue());
597        }
598        if (val instanceof Boolean) {
599            return BigInteger.valueOf(((Boolean) val) ? 1L : 0L);
600        }
601        if (val instanceof AtomicBoolean) {
602            return BigInteger.valueOf(((AtomicBoolean) val).get() ? 1L : 0L);
603        }
604        if (val instanceof String) {
605            return parseBigInteger((String) val);
606        }
607        if (val instanceof Character) {
608            final int i = ((Character) val);
609            return BigInteger.valueOf(i);
610        }
611        if (val == null) {
612            return controlNullOperand(strict, BigInteger.ZERO);
613        }
614        throw new ArithmeticException("BigInteger coercion: "
615                + val.getClass().getName() + ":(" + val + ")");
616    }
617
618    /**
619     * Coerce to a BigDecimal.
620     * <p>Double.NaN, null and empty string coerce to zero.</p>
621     * <p>Boolean false is 0, true is 1.</p>
622     *
623     * @param strict true if the calling operator or casting is strict, false otherwise
624     * @param val the object to be coerced.
625     * @return a BigDecimal.
626     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
627     * @since 3.3
628     */
629    protected BigDecimal toBigDecimal(final boolean strict, final Object val) {
630        return isNullOperand(val)? controlNullOperand(strict, BigDecimal.ZERO) : toBigDecimal(val);
631    }
632
633    /**
634     * Coerce to a BigDecimal.
635     * <p>Double.NaN, null and empty string coerce to zero.</p>
636     * <p>Boolean false is 0, true is 1.</p>
637     *
638     * @param val the object to be coerced.
639     * @return a BigDecimal.
640     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
641     */
642    public BigDecimal toBigDecimal(final Object val) {
643        if (val instanceof BigDecimal) {
644            return roundBigDecimal((BigDecimal) val);
645        }
646        if (val instanceof Double) {
647            if (Double.isNaN(((Double) val))) {
648                return BigDecimal.ZERO;
649            }
650            return roundBigDecimal(new BigDecimal(val.toString(), getMathContext()));
651        }
652        if (val instanceof Number) {
653            return roundBigDecimal(new BigDecimal(val.toString(), getMathContext()));
654        }
655        if (val instanceof Boolean) {
656            return BigDecimal.valueOf(((Boolean) val) ? 1. : 0.);
657        }
658        if (val instanceof AtomicBoolean) {
659            return BigDecimal.valueOf(((AtomicBoolean) val).get() ? 1L : 0L);
660        }
661        if (val instanceof String) {
662            final String string = (String) val;
663            if ("".equals(string)) {
664                return BigDecimal.ZERO;
665            }
666            return roundBigDecimal(new BigDecimal(string, getMathContext()));
667        }
668        if (val instanceof Character) {
669            final int i = ((Character) val);
670            return new BigDecimal(i);
671        }
672        if (val == null) {
673            return controlNullOperand(strict, BigDecimal.ZERO);
674        }
675        throw new ArithmeticException("BigDecimal coercion: "
676                + val.getClass().getName() + ":(" + val + ")");
677    }
678
679    /**
680     * Coerce to a primitive double.
681     * <p>Double.NaN, null and empty string coerce to zero.</p>
682     * <p>Boolean false is 0, true is 1.</p>
683     *
684     * @param strict true if the calling operator or casting is strict, false otherwise
685     * @param val value to coerce.
686     * @return The double coerced value.
687     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
688     * @since 3.3
689     */
690    protected double toDouble(final boolean strict, final Object val) {
691        return isNullOperand(val)? controlNullOperand(strict, 0.d) : toDouble(val);
692    }
693
694    /**
695     * Coerce to a primitive double.
696     * <p>Double.NaN, null and empty string coerce to zero.</p>
697     * <p>Boolean false is 0, true is 1.</p>
698     *
699     * @param val value to coerce.
700     * @return The double coerced value.
701     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
702     */
703    public double toDouble(final Object val) {
704        if (val instanceof Double) {
705            return ((Double) val);
706        }
707        if (val instanceof Number) {
708            //The below construct is used rather than ((Number)val).doubleValue() to ensure
709            //equality between comparing new Double( 6.4 / 3 ) and the jexl expression of 6.4 / 3
710            return Double.parseDouble(String.valueOf(val));
711        }
712        if (val instanceof Boolean) {
713            return ((Boolean) val) ? 1. : 0.;
714        }
715        if (val instanceof AtomicBoolean) {
716            return ((AtomicBoolean) val).get() ? 1. : 0.;
717        }
718        if (val instanceof String) {
719            return parseDouble((String) val);
720        }
721        if (val instanceof Character) {
722            return ((Character) val);
723        }
724        if (val == null) {
725            return controlNullOperand(strict, 0.d);
726        }
727        throw new ArithmeticException("Double coercion: "
728                + val.getClass().getName() + ":(" + val + ")");
729    }
730
731    /**
732     * Coerce to a string.
733     * <p>Double.NaN coerce to the empty string.</p>
734     *
735     * @param strict true if the calling operator or casting is strict, false otherwise
736     * @param val value to coerce.
737     * @return The String coerced value.
738     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
739     * @since 3.3
740     */
741    protected String toString(final boolean strict, final Object val) {
742        return isNullOperand(val)? controlNullOperand(strict, "") : toString(val);
743    }
744
745    /**
746     * Coerce to a string.
747     * <p>Double.NaN coerce to the empty string.</p>
748     *
749     * @param val value to coerce.
750     * @return The String coerced value.
751     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
752     */
753    public String toString(final Object val) {
754        if (val instanceof Double) {
755            final Double dval = (Double) val;
756            if (Double.isNaN(dval)) {
757                return "";
758            }
759            return dval.toString();
760        }
761        return val == null? controlNullOperand(strict, "") : val.toString();
762    }
763
764    /**
765     * Checks whether this JexlArithmetic instance
766     * strictly considers null as an error when used as operand unexpectedly.
767     *
768     * @return true if strict, false if lenient
769     */
770    public boolean isStrict() {
771        return strict;
772    }
773
774    /**
775     * Checks whether this arithmetic considers a given operator as strict or null-safe.
776     * <p>When an operator is strict, it does <em>not</em> accept null arguments when the arithmetic is strict.
777     * If null-safe (ie not-strict), the operator does accept null arguments even if the arithmetic itself is strict.</p>
778     * <p>The default implementation considers equal/not-equal operators as null-safe so one can check for null as in
779     * <code>if (myvar == null) {...}</code>. Note that this operator is used for equal and not-equal syntax. The complete
780     * list of operators that are not strict are (==, [], []=, ., .=, empty, size, contains). </p>
781     * <p>An arithmetic refining its strict behavior handling for more operators must declare which by overriding
782     * this method.</p>
783     * @param operator the operator to check for null-argument(s) handling
784     * @return true if operator considers null arguments as errors, false if operator has appropriate semantics
785     * for null argument(s)
786     */
787    public boolean isStrict(final JexlOperator operator) {
788        if (operator != null) {
789            switch (operator) {
790                case EQ:
791                case ARRAY_GET:
792                case ARRAY_SET:
793                case PROPERTY_GET:
794                case PROPERTY_SET:
795                case EMPTY:
796                case SIZE:
797                case CONTAINS:
798                    return false;
799                default:
800                    return isStrict();
801            }
802        }
803        return isStrict();
804    }
805
806    /**
807     * The MathContext instance used for +,-,/,*,% operations on big decimals.
808     *
809     * @return the math context
810     */
811    public MathContext getMathContext() {
812        return mathContext;
813    }
814
815    /**
816     * The BigDecimal scale used for comparison and coericion operations.
817     *
818     * @return the scale
819     */
820    public int getMathScale() {
821        return mathScale;
822    }
823
824    /**
825     * Ensure a big decimal is rounded by this arithmetic scale and rounding mode.
826     *
827     * @param number the big decimal to round
828     * @return the rounded big decimal
829     */
830    protected BigDecimal roundBigDecimal(final BigDecimal number) {
831        final int mscale = getMathScale();
832        if (mscale >= 0) {
833            return number.setScale(mscale, getMathContext().getRoundingMode());
834        }
835        return number;
836    }
837
838    /**
839     * The result of +,/,-,*,% when both operands are null.
840     *
841     * @return Integer(0) if lenient
842     * @throws JexlArithmetic.NullOperand if strict
843     * @deprecated 3.3
844     */
845    @Deprecated
846    protected Object controlNullNullOperands() {
847        if (isStrict()) {
848            throw new NullOperand();
849        }
850        return 0;
851    }
852
853    /**
854     * Throws an NullOperand exception if arithmetic is strict-cast.
855     *
856     * @throws  JexlArithmetic.NullOperand if strict
857     * @deprecated 3.3
858     */
859    @Deprecated
860    protected void controlNullOperand() {
861        if (isStrict()) {
862            throw new NullOperand();
863        }
864    }
865
866    /**
867     * The float regular expression pattern.
868     * <p>
869     * The decimal and exponent parts are optional and captured allowing to determine if the number is a real
870     * by checking whether one of these 2 capturing groups is not empty.
871     */
872    public static final Pattern FLOAT_PATTERN = Pattern.compile("^[+-]?\\d*(\\.\\d*)?([eE][+-]?\\d+)?$");
873
874    /**
875     * Test if the passed value is a floating point number, i.e. a float, double
876     * or string with ( "." | "E" | "e").
877     *
878     * @param val the object to be tested
879     * @return true if it is, false otherwise.
880     */
881    protected boolean isFloatingPointNumber(final Object val) {
882        if (val instanceof Float || val instanceof Double) {
883            return true;
884        }
885        if (val instanceof CharSequence) {
886            final Matcher m = FLOAT_PATTERN.matcher((CharSequence) val);
887            // first group is decimal, second is exponent;
888            // one of them must exist hence start({1,2}) >= 0
889            return m.matches() && (m.start(1) >= 0 || m.start(2) >= 0);
890        }
891        return false;
892    }
893
894    /**
895     * Is Object a floating point number.
896     *
897     * @param o Object to be analyzed.
898     * @return true if it is a Float or a Double.
899     */
900    protected boolean isFloatingPoint(final Object o) {
901        return o instanceof Float || o instanceof Double;
902    }
903
904    /**
905     * Is Object a whole number.
906     *
907     * @param o Object to be analyzed.
908     * @return true if Integer, Long, Byte, Short or Character.
909     */
910    protected boolean isNumberable(final Object o) {
911        return o instanceof Integer
912                || o instanceof Long
913                || o instanceof Byte
914                || o instanceof Short
915                || o instanceof Character;
916    }
917
918    /**
919     * The last method called before returning a result from a script execution.
920     * @param returned the returned value
921     * @return the controlled returned value
922     */
923    public Object controlReturn(final Object returned) {
924        return returned;
925    }
926
927    /**
928     * Given a Number, return the value using the smallest type the result
929     * will fit into.
930     * <p>This works hand in hand with parameter 'widening' in java
931     * method calls, e.g. a call to substring(int,int) with an int and a long
932     * will fail, but a call to substring(int,int) with an int and a short will
933     * succeed.</p>
934     *
935     * @param original the original number.
936     * @return a value of the smallest type the original number will fit into.
937     */
938    public Number narrow(final Number original) {
939        return narrowNumber(original, null);
940    }
941
942    /**
943     * Whether we consider the narrow class as a potential candidate for narrowing the source.
944     *
945     * @param narrow the target narrow class
946     * @param source the original source class
947     * @return true if attempt to narrow source to target is accepted
948     */
949    protected boolean narrowAccept(final Class<?> narrow, final Class<?> source) {
950        return narrow == null || narrow.equals(source);
951    }
952
953    /**
954     * Given a Number, return the value attempting to narrow it to a target class.
955     *
956     * @param original the original number
957     * @param narrow   the attempted target class
958     * @return the narrowed number or the source if no narrowing was possible
959     */
960    public Number narrowNumber(final Number original, final Class<?> narrow) {
961        if (original == null) {
962            return null;
963        }
964        Number result = original;
965        if (original instanceof BigDecimal) {
966            final BigDecimal bigd = (BigDecimal) original;
967            // if it is bigger than a double, it can not be narrowed
968            if (bigd.compareTo(BIGD_DOUBLE_MAX_VALUE) > 0
969                || bigd.compareTo(BIGD_DOUBLE_MIN_VALUE) < 0) {
970                return original;
971            }
972            try {
973                final long l = bigd.longValueExact();
974                // coerce to int when possible (int being so often used in method parms)
975                if (narrowAccept(narrow, Integer.class)
976                        && l <= Integer.MAX_VALUE
977                        && l >= Integer.MIN_VALUE) {
978                    return (int) l;
979                }
980                if (narrowAccept(narrow, Long.class)) {
981                    return l;
982                }
983            } catch (final ArithmeticException xa) {
984                // ignore, no exact value possible
985            }
986        }
987        if (original instanceof Double || original instanceof Float) {
988            final double value = original.doubleValue();
989            if (narrowAccept(narrow, Float.class)
990                    && value <= Float.MAX_VALUE
991                    && value >= Float.MIN_VALUE) {
992                result = result.floatValue();
993            }
994            // else it fits in a double only
995        } else {
996            if (original instanceof BigInteger) {
997                final BigInteger bigi = (BigInteger) original;
998                // if it is bigger than a Long, it can not be narrowed
999                if (bigi.compareTo(BIGI_LONG_MAX_VALUE) > 0
1000                        || bigi.compareTo(BIGI_LONG_MIN_VALUE) < 0) {
1001                    return original;
1002                }
1003            }
1004            final long value = original.longValue();
1005            if (narrowAccept(narrow, Byte.class)
1006                    && value <= Byte.MAX_VALUE
1007                    && value >= Byte.MIN_VALUE) {
1008                // it will fit in a byte
1009                result = (byte) value;
1010            } else if (narrowAccept(narrow, Short.class)
1011                    && value <= Short.MAX_VALUE
1012                    && value >= Short.MIN_VALUE) {
1013                result = (short) value;
1014            } else if (narrowAccept(narrow, Integer.class)
1015                    && value <= Integer.MAX_VALUE
1016                    && value >= Integer.MIN_VALUE) {
1017                result = (int) value;
1018            }
1019            // else it fits in a long
1020        }
1021        return result;
1022    }
1023
1024    /**
1025     * Given a BigInteger, narrow it to an Integer or Long if it fits and the arguments
1026     * class allow it.
1027     * <p>
1028     * The rules are:
1029     * if either arguments is a BigInteger, no narrowing will occur
1030     * if either arguments is a Long, no narrowing to Integer will occur
1031     * </p>
1032     *
1033     * @param lhs  the left-hand side operand that lead to the bigi result
1034     * @param rhs  the right-hand side operand that lead to the bigi result
1035     * @param bigi the BigInteger to narrow
1036     * @return an Integer or Long if narrowing is possible, the original BigInteger otherwise
1037     */
1038    protected Number narrowBigInteger(final Object lhs, final Object rhs, final BigInteger bigi) {
1039        //coerce to long if possible
1040        if ((isNumberable(lhs) || isNumberable(rhs))
1041                && bigi.compareTo(BIGI_LONG_MAX_VALUE) <= 0
1042                && bigi.compareTo(BIGI_LONG_MIN_VALUE) >= 0) {
1043            // coerce to int if possible
1044            final long l = bigi.longValue();
1045            // coerce to int when possible (int being so often used in method parms)
1046            if (!(lhs instanceof Long || rhs instanceof Long)
1047                    && l <= Integer.MAX_VALUE
1048                    && l >= Integer.MIN_VALUE) {
1049                return (int) l;
1050            }
1051            return l;
1052        }
1053        return bigi;
1054    }
1055
1056    /**
1057     * Given a BigDecimal, attempt to narrow it to an Integer or Long if it fits and
1058     * one of the arguments is a numberable.
1059     *
1060     * @param lhs  the left-hand side operand that lead to the bigd result
1061     * @param rhs  the right-hand side operand that lead to the bigd result
1062     * @param bigd the BigDecimal to narrow
1063     * @return an Integer or Long if narrowing is possible, the original BigDecimal otherwise
1064     */
1065    protected Number narrowBigDecimal(final Object lhs, final Object rhs, final BigDecimal bigd) {
1066        if (isNumberable(lhs) || isNumberable(rhs)) {
1067            try {
1068                final long l = bigd.longValueExact();
1069                // coerce to int when possible (int being so often used in method parms)
1070                if (l <= Integer.MAX_VALUE && l >= Integer.MIN_VALUE) {
1071                    return (int) l;
1072                }
1073                return l;
1074            } catch (final ArithmeticException xa) {
1075                // ignore, no exact value possible
1076            }
1077        }
1078        return bigd;
1079    }
1080
1081    /**
1082     * Replace all numbers in an arguments array with the smallest type that will fit.
1083     *
1084     * @param args the argument array
1085     * @return true if some arguments were narrowed and args array is modified,
1086     *         false if no narrowing occurred and args array has not been modified
1087     */
1088    public boolean narrowArguments(final Object[] args) {
1089        boolean narrowed = false;
1090        if (args != null) {
1091            for (int a = 0; a < args.length; ++a) {
1092                final Object arg = args[a];
1093                if (arg instanceof Number) {
1094                    final Number narg = (Number) arg;
1095                    final Number narrow = narrow(narg);
1096                    if (!narg.equals(narrow)) {
1097                        args[a] = narrow;
1098                        narrowed = true;
1099                    }
1100                }
1101            }
1102        }
1103        return narrowed;
1104    }
1105
1106    /**
1107     * Given a long, attempt to narrow it to an int.
1108     * <p>Narrowing will only occur if no operand is a Long.
1109     * @param lhs  the left hand side operand that lead to the long result
1110     * @param rhs  the right hand side operand that lead to the long result
1111     * @param r the long to narrow
1112     * @return an Integer if narrowing is possible, the original Long otherwise
1113     */
1114    protected Number narrowLong(final Object lhs, final Object rhs, final long r) {
1115        if (!(lhs instanceof Long || rhs instanceof Long) && (int) r == r) {
1116            return (int) r;
1117        }
1118        return r;
1119    }
1120
1121    /**
1122     * Checks if value class is a number that can be represented exactly in a long.
1123     *
1124     * @param value  argument
1125     * @return true if argument can be represented by a long
1126     */
1127    protected Number asLongNumber(final Object value) {
1128        return value instanceof Long
1129                || value instanceof Integer
1130                || value instanceof Short
1131                || value instanceof Byte
1132                        ? (Number) value
1133                        : null;
1134    }
1135
1136    /**
1137     * Increments argument by 1.
1138     * @param val the argument
1139     * @return val + 1
1140     */
1141    public Object increment(final Object val) {
1142        return increment(val, 1);
1143    }
1144
1145    /**
1146     * Decrements argument by 1.
1147     * @param val the argument
1148     * @return val - 1
1149     */
1150    public Object decrement(final Object val) {
1151        return increment(val, -1);
1152    }
1153
1154    /**
1155     * Add value to number argument.
1156     * @param val the number
1157     * @param incr the value to add
1158     * @return val + incr
1159     */
1160    protected Object increment(final Object val, final int incr) {
1161        if (val == null) {
1162            return incr;
1163        }
1164        if (val instanceof Integer) {
1165            return ((Integer) val) + incr;
1166        }
1167        if (val instanceof Double) {
1168            return ((Double) val) + incr;
1169        }
1170        if (val instanceof Long) {
1171            return ((Long) val) + incr;
1172        }
1173        if (val instanceof BigDecimal) {
1174            final BigDecimal bd = (BigDecimal) val;
1175            return bd.add(BigDecimal.valueOf(incr), this.mathContext);
1176        }
1177        if (val instanceof BigInteger) {
1178            final BigInteger bi = (BigInteger) val;
1179            return bi.add(BigInteger.valueOf(incr));
1180        }
1181        if (val instanceof Float) {
1182            return ((Float) val) + incr;
1183        }
1184        if (val instanceof Short) {
1185            return (short) (((Short) val) + incr);
1186        }
1187        if (val instanceof Byte) {
1188            return (byte) (((Byte) val) + incr);
1189        }
1190        throw new ArithmeticException("Object "+(incr < 0? "decrement":"increment")+":(" + val + ")");
1191    }
1192
1193    /**
1194     * Add two values together.
1195     * <p>
1196     * If any numeric add fails on coercion to the appropriate type,
1197     * treat as Strings and do concatenation.
1198     * </p>
1199     *
1200     * @param left  left argument
1201     * @param right  right argument
1202     * @return left + right.
1203     */
1204    public Object add(final Object left, final Object right) {
1205        if (left == null && right == null) {
1206            return controlNullNullOperands(JexlOperator.ADD);
1207        }
1208        final boolean strconcat = strict
1209                            ? left instanceof String || right instanceof String
1210                            : left instanceof String && right instanceof String;
1211        if (!strconcat) {
1212            try {
1213                // if both (non-null) args fit as long
1214                final Number ln = asLongNumber(left);
1215                final Number rn = asLongNumber(right);
1216                if (ln != null && rn != null) {
1217                    final long x = ln.longValue();
1218                    final long y = rn.longValue();
1219                    final long result = x + y;
1220                    // detect overflow, see java8 Math.addExact
1221                    if (((x ^ result) & (y ^ result)) < 0) {
1222                        return BigInteger.valueOf(x).add(BigInteger.valueOf(y));
1223                    }
1224                    return narrowLong(left, right, result);
1225                }
1226                final boolean strictCast = isStrict(JexlOperator.ADD);
1227                // if either are bigdecimal use that type
1228                if (left instanceof BigDecimal || right instanceof BigDecimal) {
1229                    final BigDecimal l = toBigDecimal(strictCast, left);
1230                    final BigDecimal r = toBigDecimal(strictCast, right);
1231                    final BigDecimal result = l.add(r, getMathContext());
1232                    return narrowBigDecimal(left, right, result);
1233                }
1234                // if either are floating point (double or float) use double
1235                if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
1236                    final double l = toDouble(strictCast, left);
1237                    final double r = toDouble(strictCast, right);
1238                    return l + r;
1239                }
1240                // otherwise treat as (big) integers
1241                final BigInteger l = toBigInteger(strictCast, left);
1242                final BigInteger r = toBigInteger(strictCast, right);
1243                final BigInteger result = l.add(r);
1244                return narrowBigInteger(left, right, result);
1245            } catch (final ArithmeticException nfe) {
1246                // ignore and continue in sequence
1247            }
1248        }
1249        return (left == null? "" : toString(left)).concat(right == null ? "" : toString(right));
1250    }
1251
1252    /**
1253     * Divide the left value by the right.
1254     *
1255     * @param left  left argument
1256     * @param right  right argument
1257     * @return left / right
1258     * @throws ArithmeticException if right == 0
1259     */
1260    public Object divide(final Object left, final Object right) {
1261        if (left == null && right == null) {
1262            return controlNullNullOperands(JexlOperator.DIVIDE);
1263        }
1264        // if both (non-null) args fit as long
1265        final Number ln = asLongNumber(left);
1266        final Number rn = asLongNumber(right);
1267        if (ln != null && rn != null) {
1268            final long x = ln.longValue();
1269            final long y = rn.longValue();
1270            if (y == 0L) {
1271                throw new ArithmeticException("/");
1272            }
1273            final long result = x  / y;
1274            return narrowLong(left, right, result);
1275        }
1276        final boolean strictCast = isStrict(JexlOperator.DIVIDE);
1277        // if either are bigdecimal use that type
1278        if (left instanceof BigDecimal || right instanceof BigDecimal) {
1279            final BigDecimal l = toBigDecimal(strictCast, left);
1280            final BigDecimal r = toBigDecimal(strictCast, right);
1281            if (BigDecimal.ZERO.equals(r)) {
1282                throw new ArithmeticException("/");
1283            }
1284            final BigDecimal result = l.divide(r, getMathContext());
1285            return narrowBigDecimal(left, right, result);
1286        }
1287        // if either are floating point (double or float) use double
1288        if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
1289            final double l = toDouble(strictCast, left);
1290            final double r = toDouble(strictCast, right);
1291            if (r == 0.0) {
1292                throw new ArithmeticException("/");
1293            }
1294            return l / r;
1295        }
1296        // otherwise treat as integers
1297        final BigInteger l = toBigInteger(strictCast, left);
1298        final BigInteger r = toBigInteger(strictCast, right);
1299        if (BigInteger.ZERO.equals(r)) {
1300            throw new ArithmeticException("/");
1301        }
1302        final BigInteger result = l.divide(r);
1303        return narrowBigInteger(left, right, result);
1304    }
1305
1306    /**
1307     * left value modulo right.
1308     *
1309     * @param left  left argument
1310     * @param right  right argument
1311     * @return left % right
1312     * @throws ArithmeticException if right == 0.0
1313     */
1314    public Object mod(final Object left, final Object right) {
1315        if (left == null && right == null) {
1316            return controlNullNullOperands(JexlOperator.MOD);
1317        }
1318        // if both (non-null) args fit as long
1319        final Number ln = asLongNumber(left);
1320        final Number rn = asLongNumber(right);
1321        if (ln != null && rn != null) {
1322            final long x = ln.longValue();
1323            final long y = rn.longValue();
1324            if (y == 0L) {
1325                throw new ArithmeticException("%");
1326            }
1327            final long result = x % y;
1328            return narrowLong(left, right,  result);
1329        }
1330        final boolean strictCast = isStrict(JexlOperator.MOD);
1331        // if either are bigdecimal use that type
1332        if (left instanceof BigDecimal || right instanceof BigDecimal) {
1333            final BigDecimal l = toBigDecimal(strictCast, left);
1334            final BigDecimal r = toBigDecimal(strictCast, right);
1335            if (BigDecimal.ZERO.equals(r)) {
1336                throw new ArithmeticException("%");
1337            }
1338            final BigDecimal remainder = l.remainder(r, getMathContext());
1339            return narrowBigDecimal(left, right, remainder);
1340        }
1341        // if either are floating point (double or float) use double
1342        if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
1343            final double l = toDouble(strictCast, left);
1344            final double r = toDouble(strictCast, right);
1345            if (r == 0.0) {
1346                throw new ArithmeticException("%");
1347            }
1348            return l % r;
1349        }
1350        // otherwise treat as integers
1351        final BigInteger l = toBigInteger(strictCast, left);
1352        final BigInteger r = toBigInteger(strictCast, right);
1353        if (BigInteger.ZERO.equals(r)) {
1354            throw new ArithmeticException("%");
1355        }
1356        final BigInteger result = l.mod(r);
1357        return narrowBigInteger(left, right, result);
1358    }
1359
1360    /**
1361     * Checks if the product of the arguments overflows a {@code long}.
1362     * <p>see java8 Math.multiplyExact
1363     * @param x the first value
1364     * @param y the second value
1365     * @param r the product
1366     * @return true if product fits a long, false if it overflows
1367     */
1368    @SuppressWarnings("MagicNumber")
1369    protected static boolean isMultiplyExact(final long x, final long y, final long r) {
1370        final long ax = Math.abs(x);
1371        final long ay = Math.abs(y);
1372        return !(((ax | ay) >>> (Integer.SIZE - 1) != 0)
1373                  && (((y != 0) && (r / y != x))
1374                      || (x == Long.MIN_VALUE && y == -1)));
1375    }
1376
1377    /**
1378     * Multiply the left value by the right.
1379     *
1380     * @param left  left argument
1381     * @param right  right argument
1382     * @return left * right.
1383     */
1384    public Object multiply(final Object left, final Object right) {
1385        if (left == null && right == null) {
1386            return controlNullNullOperands(JexlOperator.MULTIPLY);
1387        }
1388        // if both (non-null) args fit as int
1389        final Number ln = asLongNumber(left);
1390        final Number rn = asLongNumber(right);
1391        if (ln != null && rn != null) {
1392            final long x = ln.longValue();
1393            final long y = rn.longValue();
1394            final long result = x * y;
1395            // detect overflow
1396            if (!isMultiplyExact(x, y, result)) {
1397                return BigInteger.valueOf(x).multiply(BigInteger.valueOf(y));
1398            }
1399            return narrowLong(left, right, result);
1400        }
1401        final boolean strictCast = isStrict(JexlOperator.MULTIPLY);
1402        // if either are bigdecimal use that type
1403        if (left instanceof BigDecimal || right instanceof BigDecimal) {
1404            final BigDecimal l = toBigDecimal(strictCast, left);
1405            final BigDecimal r = toBigDecimal(strictCast, right);
1406            final BigDecimal result = l.multiply(r, getMathContext());
1407            return narrowBigDecimal(left, right, result);
1408        }
1409        // if either are floating point (double or float) use double
1410        if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
1411            final double l = toDouble(strictCast, left);
1412            final double r = toDouble(strictCast, right);
1413            return l * r;
1414        }
1415        // otherwise treat as integers
1416        final BigInteger l = toBigInteger(strictCast, left);
1417        final BigInteger r = toBigInteger(strictCast, right);
1418        final BigInteger result = l.multiply(r);
1419        return narrowBigInteger(left, right, result);
1420    }
1421
1422    /**
1423     * Subtract the right value from the left.
1424     *
1425     * @param left  left argument
1426     * @param right  right argument
1427     * @return left - right.
1428     */
1429    public Object subtract(final Object left, final Object right) {
1430        if (left == null && right == null) {
1431            return controlNullNullOperands(JexlOperator.SUBTRACT);
1432        }
1433        // if both (non-null) args fit as long
1434        final Number ln = asLongNumber(left);
1435        final Number rn = asLongNumber(right);
1436        if (ln != null && rn != null) {
1437            final long x = ln.longValue();
1438            final long y = rn.longValue();
1439            final long result = x - y;
1440            // detect overflow, see java8 Math.subtractExact
1441            if (((x ^ y) & (x ^ result)) < 0) {
1442                return BigInteger.valueOf(x).subtract(BigInteger.valueOf(y));
1443            }
1444            return narrowLong(left, right, result);
1445        }
1446        final boolean strictCast = isStrict(JexlOperator.SUBTRACT);
1447        // if either are bigdecimal use that type
1448        if (left instanceof BigDecimal || right instanceof BigDecimal) {
1449            final BigDecimal l = toBigDecimal(strictCast, left);
1450            final BigDecimal r = toBigDecimal(strictCast, right);
1451            final BigDecimal result = l.subtract(r, getMathContext());
1452            return narrowBigDecimal(left, right, result);
1453        }
1454        // if either are floating point (double or float) use double
1455        if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
1456            final double l = toDouble(strictCast, left);
1457            final double r = toDouble(strictCast, right);
1458            return l - r;
1459        }
1460        // otherwise treat as integers
1461        final BigInteger l = toBigInteger(strictCast, left);
1462        final BigInteger r = toBigInteger(strictCast, right);
1463        final BigInteger result = l.subtract(r);
1464        return narrowBigInteger(left, right, result);
1465    }
1466
1467    /**
1468     * Negates a value (unary minus for numbers).
1469     *
1470     * @see #isNegateStable()
1471     * @param val the value to negate
1472     * @return the negated value
1473     */
1474    public Object negate(final Object val) {
1475        if (val == null) {
1476            return null;
1477        }
1478        if (val instanceof Integer) {
1479            return -((Integer) val);
1480        }
1481        if (val instanceof Double) {
1482            return - ((Double) val);
1483        }
1484        if (val instanceof Long) {
1485            return -((Long) val);
1486        }
1487        if (val instanceof BigDecimal) {
1488            return ((BigDecimal) val).negate();
1489        }
1490        if (val instanceof BigInteger) {
1491            return ((BigInteger) val).negate();
1492        }
1493        if (val instanceof Float) {
1494            return -((Float) val);
1495        }
1496        if (val instanceof Short) {
1497            return (short) -((Short) val);
1498        }
1499        if (val instanceof Byte) {
1500            return (byte) -((Byte) val);
1501        }
1502        if (val instanceof Boolean) {
1503            return !(Boolean) val;
1504        }
1505        if (val instanceof AtomicBoolean) {
1506            return !((AtomicBoolean) val).get();
1507        }
1508        throw new ArithmeticException("Object negate:(" + val + ")");
1509    }
1510
1511    /**
1512     * Whether negate called with a given argument will always return the same result.
1513     * <p>This is used to determine whether negate results on number literals can be cached.
1514     * If the result on calling negate with the same constant argument may change between calls,
1515     * which means the function is not deterministic, this method must return false.
1516     * @return true if negate is idempotent, false otherwise
1517     */
1518    public boolean isNegateStable() {
1519        return true;
1520    }
1521
1522    /**
1523     * Positivize value (unary plus for numbers).
1524     * <p>C/C++/C#/Java perform integral promotion of the operand, ie
1525     * cast to int if type can be represented as int without loss of precision.
1526     * @see #isPositivizeStable()
1527     * @param val the value to positivize
1528     * @return the positive value
1529     */
1530    public Object positivize(final Object val) {
1531        if (val == null) {
1532            return null;
1533        }
1534        if (val instanceof Short) {
1535            return ((Short) val).intValue();
1536        }
1537        if (val instanceof Byte) {
1538            return ((Byte) val).intValue();
1539        }
1540        if (val instanceof Number) {
1541            return val;
1542        }
1543        if (val instanceof Character) {
1544            return (int) (Character) val;
1545        }
1546        if (val instanceof Boolean) {
1547            return val;
1548        }
1549        if (val instanceof AtomicBoolean) {
1550            return ((AtomicBoolean) val).get();
1551        }
1552        throw new ArithmeticException("Object positivize:(" + val + ")");
1553    }
1554
1555    /**
1556     * Whether positivize called with a given argument will always return the same result.
1557     * <p>This is used to determine whether positivize results on number literals can be cached.
1558     * If the result on calling positivize with the same constant argument may change between calls,
1559     * which means the function is not deterministic, this method must return false.
1560     * @return true if positivize is idempotent, false otherwise
1561     */
1562    public boolean isPositivizeStable() {
1563        return true;
1564    }
1565
1566    /**
1567     * Test if a condition is true or false.
1568     * @param object the object to use as condition
1569     * @return true or false
1570     * @since 3.3
1571     */
1572    public boolean testPredicate(final Object object) {
1573        final boolean strictCast = isStrict(JexlOperator.CONDITION);
1574        return toBoolean(strictCast, object);
1575    }
1576
1577    /**
1578     * Test if left contains right (right matches/in left).
1579     * <p>Beware that this &quot;contains &quot; method arguments order is the opposite of the
1580     * &quot;in/matches&quot; operator arguments.
1581     * <code>x =~ y</code> means <code>y contains x</code> thus <code>contains(x, y)</code>.</p>
1582     * <p>When this method returns null during evaluation, the operator code continues trying to find
1583     * one through the uberspect.</p>
1584     * @param container the container
1585     * @param value the value
1586     * @return test result or null if there is no arithmetic solution
1587     */
1588    public Boolean contains(final Object container, final Object value) {
1589        if (value == null && container == null) {
1590            //if both are null L == R
1591            return true;
1592        }
1593        if (value == null || container == null) {
1594            // we know both aren't null, therefore L != R
1595            return false;
1596        }
1597        // use arithmetic / pattern matching ?
1598        if (container instanceof java.util.regex.Pattern) {
1599            return ((java.util.regex.Pattern) container).matcher(value.toString()).matches();
1600        }
1601        if (container instanceof CharSequence) {
1602            return value.toString().matches(container.toString());
1603        }
1604        // try contains on map key
1605        if (container instanceof Map<?, ?>) {
1606            if (value instanceof Map<?, ?>) {
1607                return ((Map<?, ?>) container).keySet().containsAll(((Map<?, ?>) value).keySet());
1608            }
1609            return ((Map<?, ?>) container).containsKey(value);
1610        }
1611        // try contains on collection
1612        return collectionContains(container, value);
1613    }
1614
1615    /**
1616     * Checks whether a potential collection contains another.
1617     * <p>Made protected to make it easier to override if needed.</p>
1618     * @param collection the container which can be a collection or an array (even of primitive)
1619     * @param value the value which can be a collection or an array (even of primitive) or a singleton
1620     * @return test result or null if there is no arithmetic solution
1621     */
1622    protected Boolean collectionContains(final Object collection, final Object value) {
1623        // convert arrays if needed
1624        final Object left = arrayWrap(collection);
1625        if (left instanceof Collection<?>) {
1626            final Object right = arrayWrap(value);
1627            if (right instanceof Collection<?>) {
1628                return ((Collection<?>) left).containsAll((Collection<?>) right);
1629            }
1630            return ((Collection<?>) left).contains(value);
1631        }
1632        return null;
1633    }
1634
1635    /**
1636     * Attempts transformation of potential array in an abstract list or leave as is.
1637     * <p>An array (as in int[]) is not convenient to call methods so when encountered we turn them into lists</p>
1638     * @param container an array or on object
1639     * @return an abstract list wrapping the array instance or the initial argument
1640     * @see org.apache.commons.jexl3.internal.introspection.ArrayListWrapper
1641     */
1642    private static Object arrayWrap(final Object container) {
1643        return container.getClass().isArray()
1644                ? new org.apache.commons.jexl3.internal.introspection.ArrayListWrapper(container)
1645                : container;
1646    }
1647
1648    /**
1649     * Test if left ends with right.
1650     *
1651     * @param left  left argument
1652     * @param right  right argument
1653     * @return left $= right if there is no arithmetic solution
1654     */
1655    public Boolean endsWith(final Object left, final Object right) {
1656        if (left == null && right == null) {
1657            //if both are null L == R
1658            return true;
1659        }
1660        if (left == null || right == null) {
1661            // we know both aren't null, therefore L != R
1662            return false;
1663        }
1664        if (left instanceof CharSequence) {
1665            return (toString(left)).endsWith(toString(right));
1666        }
1667        return null;
1668    }
1669
1670    /**
1671     * Test if left starts with right.
1672     *
1673     * @param left  left argument
1674     * @param right  right argument
1675     * @return left ^= right or null if there is no arithmetic solution
1676     */
1677    public Boolean startsWith(final Object left, final Object right) {
1678        if (left == null && right == null) {
1679            //if both are null L == R
1680            return true;
1681        }
1682        if (left == null || right == null) {
1683            // we know both aren't null, therefore L != R
1684            return false;
1685        }
1686        if (left instanceof CharSequence) {
1687            return (toString(left)).startsWith(toString(right));
1688        }
1689        return null;
1690    }
1691
1692    /**
1693     * Check for emptiness of various types: Number, Collection, Array, Map, String.
1694     * <p>Override or overload this method to add new signatures to the size operators.
1695     * @param object the object to check the emptiness of
1696     * @return the boolean or false if object is not null
1697     * @since 3.2
1698     */
1699    public Boolean empty(final Object object) {
1700        return object == null || isEmpty(object, false);
1701    }
1702
1703    /**
1704     * Check for emptiness of various types: Number, Collection, Array, Map, String.
1705     *
1706     * @param object the object to check the emptiness of
1707     * @return the boolean or null if there is no arithmetic solution
1708     */
1709    public Boolean isEmpty(final Object object) {
1710        return isEmpty(object, object == null);
1711    }
1712
1713    /**
1714     * Check for emptiness of various types: Number, Collection, Array, Map, String.
1715     *
1716     * @param object the object to check the emptiness of
1717     * @param def the default value if object emptyness can not be determined
1718     * @return the boolean or null if there is no arithmetic solution
1719     */
1720    public Boolean isEmpty(final Object object, final Boolean def) {
1721        if (object != null) {
1722            if (object instanceof Number) {
1723                final double d = ((Number) object).doubleValue();
1724                return Double.isNaN(d) || d == 0.d;
1725            }
1726            if (object instanceof CharSequence) {
1727                return ((CharSequence) object).length() == 0;
1728            }
1729            if (object.getClass().isArray()) {
1730                return Array.getLength(object) == 0;
1731            }
1732            if (object instanceof Collection<?>) {
1733                return ((Collection<?>) object).isEmpty();
1734            }
1735            // Map isn't a collection
1736            if (object instanceof Map<?, ?>) {
1737                return ((Map<?, ?>) object).isEmpty();
1738            }
1739        }
1740        return def;
1741    }
1742
1743    /**
1744     * Calculate the <code>size</code> of various types: Collection, Array, Map, String.
1745     *
1746     * @param object the object to get the size of
1747     * @return the <i>size</i> of object, 0 if null, 1 if there is no <i>better</i> solution
1748     */
1749    public Integer size(final Object object) {
1750        return size(object, object == null? 0 : 1);
1751    }
1752
1753    /**
1754     * Calculate the <code>size</code> of various types: Collection, Array, Map, String.
1755     *
1756     * @param object the object to get the size of
1757     * @param def the default value if object size can not be determined
1758     * @return the size of object or null if there is no arithmetic solution
1759     */
1760    public Integer size(final Object object, final Integer def) {
1761        if (object instanceof CharSequence) {
1762            return ((CharSequence) object).length();
1763        }
1764        if (object.getClass().isArray()) {
1765            return Array.getLength(object);
1766        }
1767        if (object instanceof Collection<?>) {
1768            return ((Collection<?>) object).size();
1769        }
1770        if (object instanceof Map<?, ?>) {
1771            return ((Map<?, ?>) object).size();
1772        }
1773        return def;
1774    }
1775
1776    /**
1777     * Performs a bitwise and.
1778     *
1779     * @param left  the left operand
1780     * @param right the right operator
1781     * @return left &amp; right
1782     */
1783    public Object and(final Object left, final Object right) {
1784        final long l = toLong(left);
1785        final long r = toLong(right);
1786        return l & r;
1787    }
1788
1789    /**
1790     * Performs a bitwise or.
1791     *
1792     * @param left  the left operand
1793     * @param right the right operator
1794     * @return left | right
1795     */
1796    public Object or(final Object left, final Object right) {
1797        final long l = toLong(left);
1798        final long r = toLong(right);
1799        return l | r;
1800    }
1801
1802    /**
1803     * Performs a bitwise xor.
1804     *
1805     * @param left  the left operand
1806     * @param right the right operator
1807     * @return left ^ right
1808     */
1809    public Object xor(final Object left, final Object right) {
1810        final long l = toLong(left);
1811        final long r = toLong(right);
1812        return l ^ r;
1813    }
1814
1815    /**
1816     * Performs a bitwise complement.
1817     *
1818     * @param val the operand
1819     * @return ~val
1820     */
1821    public Object complement(final Object val) {
1822        final boolean strictCast = isStrict(JexlOperator.COMPLEMENT);
1823        final long l = toLong(strictCast, val);
1824        return ~l;
1825    }
1826
1827    /**
1828     * Performs a logical not.
1829     *
1830     * @param val the operand
1831     * @return !val
1832     */
1833    public Object not(final Object val) {
1834        final boolean strictCast = isStrict(JexlOperator.NOT);
1835        return !toBoolean(strictCast, val);
1836    }
1837
1838    /**
1839     * Shifts a bit pattern to the right.
1840     *
1841     * @param left  left argument
1842     * @param right  right argument
1843     * @return left &lt;&lt; right.
1844     */
1845    public Object shiftLeft(final Object left, final Object right) {
1846        final long l = toLong(left);
1847        final int r = toInteger(right);
1848        return l << r;
1849    }
1850
1851    /**
1852     * Shifts a bit pattern to the right.
1853     *
1854     * @param left  left argument
1855     * @param right  right argument
1856     * @return left &gt;&gt; right.
1857     */
1858    public Object shiftRight(final Object left, final Object right) {
1859        final long l = toLong(left);
1860        final long r = toInteger(right);
1861        return l >> r;
1862    }
1863
1864    /**
1865     * Shifts a bit pattern to the right unsigned.
1866     *
1867     * @param left  left argument
1868     * @param right  right argument
1869     * @return left &gt;&gt;&gt; right.
1870     */
1871    public Object shiftRightUnsigned(final Object left, final Object right) {
1872        final long l = toLong(left);
1873        final long r = toInteger(right);
1874        return l >>> r;
1875    }
1876
1877    /**
1878     * Any override of this method (pre 3.3) should be modified to match the new signature.
1879     * @param left left operand
1880     * @param right right operand
1881     * @param symbol the operator symbol
1882     * @return -1 if left &lt; right; +1 if left &gt; right; 0 if left == right
1883     * {@link JexlArithmetic#compare(Object, Object, JexlOperator)}
1884     * @deprecated 3.3
1885     */
1886    @Deprecated
1887    protected int compare(final Object left, final Object right, final String symbol) {
1888        JexlOperator operator;
1889        try {
1890            operator = JexlOperator.valueOf(symbol);
1891        } catch (final IllegalArgumentException xill) {
1892            // ignore
1893            operator = JexlOperator.EQ;
1894        }
1895        return doCompare(left, right, operator);
1896    }
1897
1898    /**
1899     * Determines if the compare method(Object, Object, String) is overriden in this class or one of its
1900     * superclasses.
1901     */
1902    private final boolean compare321 = computeCompare321(this);
1903    private static boolean computeCompare321(final JexlArithmetic arithmetic) {
1904        Class<?> arithmeticClass = arithmetic.getClass();
1905        while(arithmeticClass != JexlArithmetic.class) {
1906            try {
1907                Method cmp = arithmeticClass.getDeclaredMethod("compare", Object.class, Object.class, String.class);
1908               if (cmp.getDeclaringClass() != JexlArithmetic.class) {
1909                   return true;
1910               }
1911            } catch (NoSuchMethodException xany) {
1912                arithmeticClass = arithmeticClass.getSuperclass();
1913            }
1914        }
1915        return false;
1916    }
1917
1918    /**
1919     * Performs a comparison.
1920     *
1921     * @param left     the left operand
1922     * @param right    the right operator
1923     * @param operator the operator
1924     * @return -1 if left &lt; right; +1 if left &gt; right; 0 if left == right
1925     * @throws ArithmeticException if either left or right is null
1926     */
1927    protected int compare(final Object left, final Object right, final JexlOperator operator) {
1928        // this is a temporary way of allowing pre-3.3 code that overrode compare() to still call
1929        // the user method. This method will merge with doCompare in 3.4 and the compare321 flag will disappear.
1930        return compare321
1931                ? compare(left, right, operator.toString())
1932                : doCompare(left, right, operator);
1933    }
1934
1935    private int doCompare(final Object left, final Object right, final JexlOperator operator) {
1936        final boolean strictCast = isStrict(operator);
1937        if (left != null && right != null) {
1938            if (left instanceof BigDecimal || right instanceof BigDecimal) {
1939                final BigDecimal l = toBigDecimal(strictCast, left);
1940                final BigDecimal r = toBigDecimal(strictCast, right);
1941                return l.compareTo(r);
1942            }
1943            if (left instanceof BigInteger || right instanceof BigInteger) {
1944                try {
1945                    final BigInteger l = toBigInteger(strictCast, left);
1946                    final BigInteger r = toBigInteger(strictCast, right);
1947                    return l.compareTo(r);
1948                } catch (final ArithmeticException xconvert) {
1949                    // ignore it, continue in sequence
1950                }
1951            }
1952            if (isFloatingPoint(left) || isFloatingPoint(right)) {
1953                final double lhs = toDouble(strictCast, left);
1954                final double rhs = toDouble(strictCast, right);
1955                if (Double.isNaN(lhs)) {
1956                    if (Double.isNaN(rhs)) {
1957                        return 0;
1958                    }
1959                    return -1;
1960                }
1961                if (Double.isNaN(rhs)) {
1962                    // lhs is not NaN
1963                    return +1;
1964                }
1965                return Double.compare(lhs, rhs);
1966            }
1967            if (isNumberable(left) || isNumberable(right)) {
1968                try {
1969                    final long lhs = toLong(strictCast, left);
1970                    final long rhs = toLong(strictCast, right);
1971                    return Long.compare(lhs, rhs);
1972                } catch (final ArithmeticException xconvert) {
1973                    // ignore it, continue in sequence
1974                }
1975            }
1976            if (left instanceof String || right instanceof String) {
1977                return toString(left).compareTo(toString(right));
1978            }
1979            if (JexlOperator.EQ == operator) {
1980                return left.equals(right) ? 0 : -1;
1981            }
1982            if (left instanceof Comparable<?>) {
1983                @SuppressWarnings("unchecked") // OK because of instanceof check above
1984                final Comparable<Object> comparable = (Comparable<Object>) left;
1985                return comparable.compareTo(right);
1986            }
1987        }
1988        throw new ArithmeticException("Object comparison:(" + left + " " + operator + " " + right + ")");
1989    }
1990
1991    /**
1992     * Test if left and right are equal.
1993     *
1994     * @param left  left argument
1995     * @param right right argument
1996     * @return the test result
1997     */
1998    public boolean equals(final Object left, final Object right) {
1999        if (left == right) {
2000            return true;
2001        }
2002        if (left == null || right == null) {
2003            return false;
2004        }
2005        final boolean strictCast = isStrict(JexlOperator.EQ);
2006        if (left instanceof Boolean || right instanceof Boolean) {
2007            return toBoolean(left) == toBoolean(strictCast, right);
2008        }
2009        return compare(left, right, JexlOperator.EQ) == 0;
2010    }
2011
2012    /**
2013     * Test if left &lt; right.
2014     *
2015     * @param left  left argument
2016     * @param right right argument
2017     * @return the test result
2018     */
2019    public boolean lessThan(final Object left, final Object right) {
2020        if ((left == right) || (left == null) || (right == null)) {
2021            return false;
2022        }
2023        return compare(left, right, JexlOperator.LT) < 0;
2024
2025    }
2026
2027    /**
2028     * Test if left &gt; right.
2029     *
2030     * @param left  left argument
2031     * @param right right argument
2032     * @return the test result
2033     */
2034    public boolean greaterThan(final Object left, final Object right) {
2035        if ((left == right) || left == null || right == null) {
2036            return false;
2037        }
2038        return compare(left, right, JexlOperator.GT) > 0;
2039    }
2040
2041    /**
2042     * Test if left &lt;= right.
2043     *
2044     * @param left  left argument
2045     * @param right right argument
2046     * @return the test result
2047     */
2048    public boolean lessThanOrEqual(final Object left, final Object right) {
2049        if (left == right) {
2050            return true;
2051        }
2052        if (left == null || right == null) {
2053            return false;
2054        }
2055        return compare(left, right, JexlOperator.LTE) <= 0;
2056    }
2057
2058    /**
2059     * Test if left &gt;= right.
2060     *
2061     * @param left  left argument
2062     * @param right right argument
2063     * @return the test result
2064     */
2065    public boolean greaterThanOrEqual(final Object left, final Object right) {
2066        if (left == right) {
2067            return true;
2068        }
2069        if (left == null || right == null) {
2070            return false;
2071        }
2072        return compare(left, right, JexlOperator.GTE) >= 0;
2073    }
2074
2075    /**
2076     * Convert a string to a double.
2077     * <>Empty string is considered as NaN.</>
2078     * @param arg the arg
2079     * @return a double
2080     * @throws ArithmeticException if the string can not be coerced into a double
2081     */
2082    private double parseDouble(final String arg) throws ArithmeticException {
2083        try {
2084            return arg.isEmpty()? Double.NaN : Double.parseDouble(arg);
2085        } catch (final NumberFormatException e) {
2086            final ArithmeticException arithmeticException = new ArithmeticException("Double coercion: ("+ arg +")");
2087            arithmeticException.initCause(e);
2088            throw arithmeticException;
2089        }
2090    }
2091
2092    /**
2093     * Converts a string to a long.
2094     * <p>This ensure the represented number is a natural (not a real).</p>
2095     * @param arg the arg
2096     * @return a long
2097     * @throws ArithmeticException if the string can not be coerced into a long
2098     */
2099    private long parseLong(final String arg) throws ArithmeticException {
2100        final double d = parseDouble(arg);
2101        if (Double.isNaN(d)) {
2102            return 0L;
2103        }
2104        final double f = floor(d);
2105        if (d == f) {
2106            return (long) d;
2107        }
2108        throw new ArithmeticException("Long coercion: ("+ arg +")");
2109    }
2110
2111    /**
2112     * Converts a string to an int.
2113     * <p>This ensure the represented number is a natural (not a real).</p>
2114     * @param arg the arg
2115     * @return an int
2116     * @throws ArithmeticException if the string can not be coerced into a long
2117     */
2118    private int parseInteger(final String arg) throws ArithmeticException {
2119        final long l = parseLong(arg);
2120        final int i = (int) l;
2121        if (i == l) {
2122            return i;
2123        }
2124        throw new ArithmeticException("Int coercion: ("+ arg +")");
2125    }
2126
2127    /**
2128     * Converts a string to a big integer.
2129     * <>Empty string is considered as 0.</>
2130     * @param arg the arg
2131     * @return a big integer
2132     * @throws ArithmeticException if the string can not be coerced into a big integer
2133     */
2134    private BigInteger parseBigInteger(final String arg) throws ArithmeticException {
2135        if (arg.isEmpty()) {
2136            return BigInteger.ZERO;
2137        }
2138        try {
2139            return new BigInteger(arg);
2140        } catch (final NumberFormatException xformat) {
2141            // ignore, try harder
2142        }
2143        return BigInteger.valueOf(parseLong(arg));
2144    }
2145
2146    /**
2147     * Use or overload and() instead.
2148     * @param lhs left hand side
2149     * @param rhs right hand side
2150     * @return lhs &amp; rhs
2151     * @see JexlArithmetic#and
2152     * @deprecated 3.0
2153     */
2154    @Deprecated
2155    public final Object bitwiseAnd(final Object lhs, final Object rhs) {
2156        return and(lhs, rhs);
2157    }
2158
2159    /**
2160     * Use or overload or() instead.
2161     *
2162     * @param lhs left hand side
2163     * @param rhs right hand side
2164     * @return lhs | rhs
2165     * @see JexlArithmetic#or
2166     * @deprecated 3.0
2167     */
2168    @Deprecated
2169    public final Object bitwiseOr(final Object lhs, final Object rhs) {
2170        return or(lhs, rhs);
2171    }
2172
2173    /**
2174     * Use or overload xor() instead.
2175     *
2176     * @param lhs left hand side
2177     * @param rhs right hand side
2178     * @return lhs ^ rhs
2179     * @see JexlArithmetic#xor
2180     * @deprecated 3.0
2181     */
2182    @Deprecated
2183    public final Object bitwiseXor(final Object lhs, final Object rhs) {
2184        return xor(lhs, rhs);
2185    }
2186
2187    /**
2188     * Use or overload not() instead.
2189     *
2190     * @param arg argument
2191     * @return !arg
2192     * @see JexlArithmetic#not
2193     * @deprecated 3.0
2194     */
2195    @Deprecated
2196    public final Object logicalNot(final Object arg) {
2197        return not(arg);
2198    }
2199
2200    /**
2201     * Use or overload contains() instead.
2202     *
2203     * @param lhs left hand side
2204     * @param rhs right hand side
2205     * @return contains(rhs, lhs)
2206     * @see JexlArithmetic#contains
2207     * @deprecated 3.0
2208     */
2209    @Deprecated
2210    public final Object matches(final Object lhs, final Object rhs) {
2211        return contains(rhs, lhs);
2212    }
2213}