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