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