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