001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.jexl3;
019
020import org.apache.commons.jexl3.introspection.JexlMethod;
021
022import java.lang.reflect.Array;
023import java.lang.reflect.Constructor;
024import java.lang.reflect.InvocationTargetException;
025import java.math.BigDecimal;
026import java.math.BigInteger;
027import java.math.MathContext;
028import java.util.Collection;
029import java.util.Map;
030import java.util.concurrent.atomic.AtomicBoolean;
031import java.util.regex.Matcher;
032import java.util.regex.Pattern;
033
034/**
035 * Perform arithmetic, implements JexlOperator methods.
036 *
037 * <p>This is the class to derive to implement new operator behaviors.</p>
038 *
039 * <p>The 5 base arithmetic operators (+, - , *, /, %) follow the same evaluation rules regarding their arguments.</p>
040 * <ol>
041 *   <li>If both are null, result is 0</li>
042 *   <li>If either is a BigDecimal, coerce both to BigDecimal and perform operation</li>
043 *   <li>If either is a floating point number, coerce both to Double and perform operation</li>
044 *   <li>Else treat as BigInteger, perform operation and attempt to narrow result:
045 *     <ol>
046 *       <li>if both arguments can be narrowed to Integer, narrow result to Integer</li>
047 *       <li>if both arguments can be narrowed to Long, narrow result to Long</li>
048 *       <li>Else return result as BigInteger</li>
049 *     </ol>
050 *   </li>
051 * </ol>
052 *
053 * Note that the only exception thrown by JexlArithmetic is and must be ArithmeticException.
054 *
055 * @see JexlOperator
056 * @since 2.0
057 */
058public class JexlArithmetic {
059
060    /** Marker class for null operand exceptions. */
061    public static class NullOperand extends ArithmeticException {}
062
063    /** Double.MAX_VALUE as BigDecimal. */
064    protected static final BigDecimal BIGD_DOUBLE_MAX_VALUE = BigDecimal.valueOf(Double.MAX_VALUE);
065
066    /** Double.MIN_VALUE as BigDecimal. */
067    protected static final BigDecimal BIGD_DOUBLE_MIN_VALUE = BigDecimal.valueOf(Double.MIN_VALUE);
068
069    /** Long.MAX_VALUE as BigInteger. */
070    protected static final BigInteger BIGI_LONG_MAX_VALUE = BigInteger.valueOf(Long.MAX_VALUE);
071
072    /** Long.MIN_VALUE as BigInteger. */
073    protected static final BigInteger BIGI_LONG_MIN_VALUE = BigInteger.valueOf(Long.MIN_VALUE);
074
075    /** Default BigDecimal scale. */
076    protected static final int BIGD_SCALE = -1;
077
078    /** Whether this JexlArithmetic instance behaves in strict or lenient mode. */
079    private final boolean strict;
080
081    /** The big decimal math context. */
082    private final MathContext mathContext;
083
084    /** The big decimal scale. */
085    private final int mathScale;
086
087    /** The dynamic constructor. */
088    private final Constructor<? extends JexlArithmetic> ctor;
089
090    /**
091     * Creates a JexlArithmetic.
092     * <p>If you derive your own arithmetic, implement the
093     * other constructor that may be needed when dealing with options.
094     *
095     * @param astrict whether this arithmetic is strict or lenient
096     */
097    public JexlArithmetic(final boolean astrict) {
098        this(astrict, null, Integer.MIN_VALUE);
099    }
100
101    /**
102     * Creates a JexlArithmetic.
103     * <p>The constructor to define in derived classes.
104     *
105     * @param astrict     whether this arithmetic is lenient or strict
106     * @param bigdContext the math context instance to use for +,-,/,*,% operations on big decimals.
107     * @param bigdScale   the scale used for big decimals.
108     */
109    public JexlArithmetic(final boolean astrict, final MathContext bigdContext, final int bigdScale) {
110        this.strict = astrict;
111        this.mathContext = bigdContext == null ? MathContext.DECIMAL128 : bigdContext;
112        this.mathScale = bigdScale == Integer.MIN_VALUE ? BIGD_SCALE : bigdScale;
113        Constructor<? extends JexlArithmetic> actor = null;
114        try {
115            actor = getClass().getConstructor(boolean.class, MathContext.class, int.class);
116        } catch (final Exception xany) {
117            // ignore
118        }
119        this.ctor = actor;
120    }
121
122    /**
123     * Apply options to this arithmetic which eventually may create another instance.
124     * @see #createWithOptions(boolean, java.math.MathContext, int)
125     *
126     * @param options the {@link JexlEngine.Options} to use
127     * @return an arithmetic with those options set
128     */
129    public JexlArithmetic options(final JexlOptions options) {
130        if (options != null) {
131            final boolean ostrict = options.isStrictArithmetic();
132            MathContext bigdContext = options.getMathContext();
133            if (bigdContext == null) {
134                bigdContext = getMathContext();
135            }
136            int bigdScale = options.getMathScale();
137            if (bigdScale == Integer.MIN_VALUE) {
138                bigdScale = getMathScale();
139            }
140            if (ostrict != isStrict()
141                || bigdScale != getMathScale()
142                || bigdContext != getMathContext()) {
143                return createWithOptions(ostrict, bigdContext, bigdScale);
144            }
145        }
146        return this;
147    }
148
149    /**
150     * Apply options to this arithmetic which eventually may create another instance.
151     * @see #createWithOptions(boolean, java.math.MathContext, int)
152     *
153     * @param options the {@link JexlEngine.Options} to use
154     * @return an arithmetic with those options set
155     * @deprecated 3.2
156     */
157    @Deprecated
158    public JexlArithmetic options(final JexlEngine.Options options) {
159        if (options != null) {
160            Boolean ostrict = options.isStrictArithmetic();
161            if (ostrict == null) {
162                ostrict = isStrict();
163            }
164            MathContext bigdContext = options.getArithmeticMathContext();
165            if (bigdContext == null) {
166                bigdContext = getMathContext();
167            }
168            int bigdScale = options.getArithmeticMathScale();
169            if (bigdScale == Integer.MIN_VALUE) {
170                bigdScale = getMathScale();
171            }
172            if (ostrict != isStrict()
173                || bigdScale != getMathScale()
174                || bigdContext != getMathContext()) {
175                return createWithOptions(ostrict, bigdContext, bigdScale);
176            }
177        }
178        return this;
179    }
180
181    /**
182     * Apply options to this arithmetic which eventually may create another instance.
183     * @see #createWithOptions(boolean, java.math.MathContext, int)
184     *
185     * @param context the context that may extend {@link JexlContext.OptionsHandle} to use
186     * @return a new arithmetic instance or this
187     * @since 3.1
188     */
189    public JexlArithmetic options(final JexlContext context) {
190        if (context instanceof JexlContext.OptionsHandle) {
191            return options(((JexlContext.OptionsHandle) context).getEngineOptions());
192        }
193        if (context instanceof JexlEngine.Options) {
194            return options((JexlEngine.Options) context);
195        }
196        return this;
197    }
198
199    /**
200     * Creates a JexlArithmetic instance.
201     * Called by options(...) method when another instance of the same class of arithmetic is required.
202     * @see #options(org.apache.commons.jexl3.JexlEngine.Options)
203     *
204     * @param astrict     whether this arithmetic is lenient or strict
205     * @param bigdContext the math context instance to use for +,-,/,*,% operations on big decimals.
206     * @param bigdScale   the scale used for big decimals.
207     * @return default is a new JexlArithmetic instance
208     * @since 3.1
209     */
210    protected JexlArithmetic createWithOptions(final boolean astrict, final MathContext bigdContext, final int bigdScale) {
211        if (ctor != null) {
212            try {
213                return ctor.newInstance(astrict, bigdContext, bigdScale);
214            } catch (IllegalAccessException | IllegalArgumentException
215                    | InstantiationException | InvocationTargetException xany) {
216                // it was worth the try
217            }
218        }
219        return new JexlArithmetic(astrict, bigdContext, bigdScale);
220    }
221
222    /**
223     * The interface that uberspects JexlArithmetic classes.
224     * <p>This allows overloaded operator methods discovery.</p>
225     */
226    public interface Uberspect {
227        /**
228         * Checks whether this uberspect has overloads for a given operator.
229         *
230         * @param operator the operator to check
231         * @return true if an overload exists, false otherwise
232         */
233        boolean overloads(JexlOperator operator);
234
235        /**
236         * Gets the most specific method for an operator.
237         *
238         * @param operator the operator
239         * @param arg      the arguments
240         * @return the most specific method or null if no specific override could be found
241         */
242        JexlMethod getOperator(JexlOperator operator, Object... arg);
243    }
244
245    /**
246     * Helper interface used when creating an array literal.
247     *
248     * <p>The default implementation creates an array and attempts to type it strictly.</p>
249     *
250     * <ul>
251     *   <li>If all objects are of the same type, the array returned will be an array of that same type</li>
252     *   <li>If all objects are Numbers, the array returned will be an array of Numbers</li>
253     *   <li>If all objects are convertible to a primitive type, the array returned will be an array
254     *       of the primitive type</li>
255     * </ul>
256     */
257    public interface ArrayBuilder {
258
259        /**
260         * Adds a literal to the array.
261         *
262         * @param value the item to add
263         */
264        void add(Object value);
265
266        /**
267         * Creates the actual "array" instance.
268         *
269         * @param extended true when the last argument is ', ...'
270         * @return the array
271         */
272        Object create(boolean extended);
273    }
274
275    /**
276     * Called by the interpreter when evaluating a literal array.
277     *
278     * @param size the number of elements in the array
279     * @return the array builder
280     */
281    public ArrayBuilder arrayBuilder(final int size) {
282        return new org.apache.commons.jexl3.internal.ArrayBuilder(size);
283    }
284
285    /**
286     * Helper interface used when creating a set literal.
287     * <p>The default implementation creates a java.util.HashSet.</p>
288     */
289    public interface SetBuilder {
290        /**
291         * Adds a literal to the set.
292         *
293         * @param value the item to add
294         */
295        void add(Object value);
296
297        /**
298         * Creates the actual "set" instance.
299         *
300         * @return the set
301         */
302        Object create();
303    }
304
305    /**
306     * Called by the interpreter when evaluating a literal set.
307     *
308     * @param size the number of elements in the set
309     * @return the array builder
310     */
311    public SetBuilder setBuilder(final int size) {
312        return new org.apache.commons.jexl3.internal.SetBuilder(size);
313    }
314
315    /**
316     * Helper interface used when creating a map literal.
317     * <p>The default implementation creates a java.util.HashMap.</p>
318     */
319    public interface MapBuilder {
320        /**
321         * Adds a new entry to the map.
322         *
323         * @param key   the map entry key
324         * @param value the map entry value
325         */
326        void put(Object key, Object value);
327
328        /**
329         * Creates the actual "map" instance.
330         *
331         * @return the map
332         */
333        Object create();
334    }
335
336    /**
337     * Called by the interpreter when evaluating a literal map.
338     *
339     * @param size the number of elements in the map
340     * @return the map builder
341     */
342    public MapBuilder mapBuilder(final int size) {
343        return new org.apache.commons.jexl3.internal.MapBuilder(size);
344    }
345
346    /**
347     * Creates a literal range.
348     * <p>The default implementation only accepts integers and longs.</p>
349     *
350     * @param from the included lower bound value (null if none)
351     * @param to   the included upper bound value (null if none)
352     * @return the range as an iterable
353     * @throws ArithmeticException as an option if creation fails
354     */
355    public Iterable<?> createRange(final Object from, final Object to) throws ArithmeticException {
356        final long lfrom = toLong(from);
357        final long lto = toLong(to);
358        if ((lfrom >= Integer.MIN_VALUE && lfrom <= Integer.MAX_VALUE)
359                && (lto >= Integer.MIN_VALUE && lto <= Integer.MAX_VALUE)) {
360            return org.apache.commons.jexl3.internal.IntegerRange.create((int) lfrom, (int) lto);
361        }
362        return org.apache.commons.jexl3.internal.LongRange.create(lfrom, lto);
363    }
364
365    /**
366     * Checks whether this JexlArithmetic instance
367     * strictly considers null as an error when used as operand unexpectedly.
368     *
369     * @return true if strict, false if lenient
370     */
371    public boolean isStrict() {
372        return this.strict;
373    }
374
375    /**
376     * The MathContext instance used for +,-,/,*,% operations on big decimals.
377     *
378     * @return the math context
379     */
380    public MathContext getMathContext() {
381        return mathContext;
382    }
383
384    /**
385     * The BigDecimal scale used for comparison and coericion operations.
386     *
387     * @return the scale
388     */
389    public int getMathScale() {
390        return mathScale;
391    }
392
393    /**
394     * Ensure a big decimal is rounded by this arithmetic scale and rounding mode.
395     *
396     * @param number the big decimal to round
397     * @return the rounded big decimal
398     */
399    protected BigDecimal roundBigDecimal(final BigDecimal number) {
400        final int mscale = getMathScale();
401        if (mscale >= 0) {
402            return number.setScale(mscale, getMathContext().getRoundingMode());
403        }
404        return number;
405    }
406
407    /**
408     * The result of +,/,-,*,% when both operands are null.
409     *
410     * @return Integer(0) if lenient
411     * @throws ArithmeticException if strict
412     */
413    protected Object controlNullNullOperands() {
414        if (isStrict()) {
415            throw new NullOperand();
416        }
417        return 0;
418    }
419
420    /**
421     * Throw a NPE if arithmetic is strict.
422     *
423     * @throws ArithmeticException if strict
424     */
425    protected void controlNullOperand() {
426        if (isStrict()) {
427            throw new NullOperand();
428        }
429    }
430
431    /**
432     * The float regular expression pattern.
433     * <p>
434     * The decimal and exponent parts are optional and captured allowing to determine if the number is a real
435     * by checking whether one of these 2 capturing groups is not empty.
436     */
437    public static final Pattern FLOAT_PATTERN = Pattern.compile("^[+-]?\\d*(\\.\\d*)?([eE][+-]?\\d+)?$");
438
439    /**
440     * Test if the passed value is a floating point number, i.e. a float, double
441     * or string with ( "." | "E" | "e").
442     *
443     * @param val the object to be tested
444     * @return true if it is, false otherwise.
445     */
446    protected boolean isFloatingPointNumber(final Object val) {
447        if (val instanceof Float || val instanceof Double) {
448            return true;
449        }
450        if (val instanceof CharSequence) {
451            final Matcher m = FLOAT_PATTERN.matcher((CharSequence) val);
452            // first group is decimal, second is exponent;
453            // one of them must exist hence start({1,2}) >= 0
454            return m.matches() && (m.start(1) >= 0 || m.start(2) >= 0);
455        }
456        return false;
457    }
458
459    /**
460     * Is Object a floating point number.
461     *
462     * @param o Object to be analyzed.
463     * @return true if it is a Float or a Double.
464     */
465    protected boolean isFloatingPoint(final Object o) {
466        return o instanceof Float || o instanceof Double;
467    }
468
469    /**
470     * Is Object a whole number.
471     *
472     * @param o Object to be analyzed.
473     * @return true if Integer, Long, Byte, Short or Character.
474     */
475    protected boolean isNumberable(final Object o) {
476        return o instanceof Integer
477                || o instanceof Long
478                || o instanceof Byte
479                || o instanceof Short
480                || o instanceof Character;
481    }
482
483    /**
484     * Given a Number, return back the value using the smallest type the result
485     * will fit into.
486     * <p>This works hand in hand with parameter 'widening' in java
487     * method calls, e.g. a call to substring(int,int) with an int and a long
488     * will fail, but a call to substring(int,int) with an int and a short will
489     * succeed.</p>
490     *
491     * @param original the original number.
492     * @return a value of the smallest type the original number will fit into.
493     */
494    public Number narrow(final Number original) {
495        return narrowNumber(original, null);
496    }
497
498    /**
499     * Whether we consider the narrow class as a potential candidate for narrowing the source.
500     *
501     * @param narrow the target narrow class
502     * @param source the original source class
503     * @return true if attempt to narrow source to target is accepted
504     */
505    protected boolean narrowAccept(final Class<?> narrow, final Class<?> source) {
506        return narrow == null || narrow.equals(source);
507    }
508
509    /**
510     * Given a Number, return back the value attempting to narrow it to a target class.
511     *
512     * @param original the original number
513     * @param narrow   the attempted target class
514     * @return the narrowed number or the source if no narrowing was possible
515     */
516    public Number narrowNumber(final Number original, final Class<?> narrow) {
517        if (original == null) {
518            return null;
519        }
520        Number result = original;
521        if (original instanceof BigDecimal) {
522            final BigDecimal bigd = (BigDecimal) original;
523            // if it's bigger than a double it can't be narrowed
524            if (bigd.compareTo(BIGD_DOUBLE_MAX_VALUE) > 0
525                || bigd.compareTo(BIGD_DOUBLE_MIN_VALUE) < 0) {
526                return original;
527            }
528            try {
529                final long l = bigd.longValueExact();
530                // coerce to int when possible (int being so often used in method parms)
531                if (narrowAccept(narrow, Integer.class)
532                        && l <= Integer.MAX_VALUE
533                        && l >= Integer.MIN_VALUE) {
534                    return (int) l;
535                }
536                if (narrowAccept(narrow, Long.class)) {
537                    return l;
538                }
539            } catch (final ArithmeticException xa) {
540                // ignore, no exact value possible
541            }
542        }
543        if (original instanceof Double || original instanceof Float) {
544            final double value = original.doubleValue();
545            if (narrowAccept(narrow, Float.class)
546                    && value <= Float.MAX_VALUE
547                    && value >= Float.MIN_VALUE) {
548                result = result.floatValue();
549            }
550            // else it fits in a double only
551        } else {
552            if (original instanceof BigInteger) {
553                final BigInteger bigi = (BigInteger) original;
554                // if it's bigger than a Long it can't be narrowed
555                if (bigi.compareTo(BIGI_LONG_MAX_VALUE) > 0
556                        || bigi.compareTo(BIGI_LONG_MIN_VALUE) < 0) {
557                    return original;
558                }
559            }
560            final long value = original.longValue();
561            if (narrowAccept(narrow, Byte.class)
562                    && value <= Byte.MAX_VALUE
563                    && value >= Byte.MIN_VALUE) {
564                // it will fit in a byte
565                result = (byte) value;
566            } else if (narrowAccept(narrow, Short.class)
567                    && value <= Short.MAX_VALUE
568                    && value >= Short.MIN_VALUE) {
569                result = (short) value;
570            } else if (narrowAccept(narrow, Integer.class)
571                    && value <= Integer.MAX_VALUE
572                    && value >= Integer.MIN_VALUE) {
573                result = (int) value;
574            }
575            // else it fits in a long
576        }
577        return result;
578    }
579
580    /**
581     * Given a BigInteger, narrow it to an Integer or Long if it fits and the arguments
582     * class allow it.
583     * <p>
584     * The rules are:
585     * if either arguments is a BigInteger, no narrowing will occur
586     * if either arguments is a Long, no narrowing to Integer will occur
587     * </p>
588     *
589     * @param lhs  the left hand side operand that lead to the bigi result
590     * @param rhs  the right hand side operand that lead to the bigi result
591     * @param bigi the BigInteger to narrow
592     * @return an Integer or Long if narrowing is possible, the original BigInteger otherwise
593     */
594    protected Number narrowBigInteger(final Object lhs, final Object rhs, final BigInteger bigi) {
595        //coerce to long if possible
596        if (!(lhs instanceof BigInteger || rhs instanceof BigInteger)
597                && bigi.compareTo(BIGI_LONG_MAX_VALUE) <= 0
598                && bigi.compareTo(BIGI_LONG_MIN_VALUE) >= 0) {
599            // coerce to int if possible
600            final long l = bigi.longValue();
601            // coerce to int when possible (int being so often used in method parms)
602            if (!(lhs instanceof Long || rhs instanceof Long)
603                    && l <= Integer.MAX_VALUE
604                    && l >= Integer.MIN_VALUE) {
605                return (int) l;
606            }
607            return l;
608        }
609        return bigi;
610    }
611
612    /**
613     * Given a BigDecimal, attempt to narrow it to an Integer or Long if it fits if
614     * one of the arguments is a numberable.
615     *
616     * @param lhs  the left hand side operand that lead to the bigd result
617     * @param rhs  the right hand side operand that lead to the bigd result
618     * @param bigd the BigDecimal to narrow
619     * @return an Integer or Long if narrowing is possible, the original BigInteger otherwise
620     */
621    protected Number narrowBigDecimal(final Object lhs, final Object rhs, final BigDecimal bigd) {
622        if (isNumberable(lhs) || isNumberable(rhs)) {
623            try {
624                final long l = bigd.longValueExact();
625                // coerce to int when possible (int being so often used in method parms)
626                if (l <= Integer.MAX_VALUE && l >= Integer.MIN_VALUE) {
627                    return (int) l;
628                }
629                return l;
630            } catch (final ArithmeticException xa) {
631                // ignore, no exact value possible
632            }
633        }
634        return bigd;
635    }
636
637    /**
638     * Replace all numbers in an arguments array with the smallest type that will fit.
639     *
640     * @param args the argument array
641     * @return true if some arguments were narrowed and args array is modified,
642     *         false if no narrowing occurred and args array has not been modified
643     */
644    public boolean narrowArguments(final Object[] args) {
645        boolean narrowed = false;
646        if (args != null) {
647            for (int a = 0; a < args.length; ++a) {
648                final Object arg = args[a];
649                if (arg instanceof Number) {
650                    final Number narg = (Number) arg;
651                    final Number narrow = narrow(narg);
652                    if (!narg.equals(narrow)) {
653                        args[a] = narrow;
654                        narrowed = true;
655                    }
656                }
657            }
658        }
659        return narrowed;
660    }
661
662    /**
663     * Given a long, attempt to narrow it to an int.
664     * <p>Narrowing will only occur if no operand is a Long.
665     * @param lhs  the left hand side operand that lead to the long result
666     * @param rhs  the right hand side operand that lead to the long result
667     * @param r the long to narrow
668     * @return an Integer if narrowing is possible, the original Long otherwise
669     */
670    protected Number narrowLong(final Object lhs, final Object rhs, final long r) {
671        if (!(lhs instanceof Long || rhs instanceof Long) && (int) r == r) {
672            return (int) r;
673        }
674        return r;
675    }
676
677    /**
678     * Checks if value class is a number that can be represented exactly in a long.
679     *
680     * @param value  argument
681     * @return true if argument can be represented by a long
682     */
683    protected Number asLongNumber(final Object value) {
684        return value instanceof Long
685                || value instanceof Integer
686                || value instanceof Short
687                || value instanceof Byte
688                        ? (Number) value
689                        : null;
690    }
691
692    /**
693     * Add two values together.
694     * <p>
695     * If any numeric add fails on coercion to the appropriate type,
696     * treat as Strings and do concatenation.
697     * </p>
698     *
699     * @param left  left argument
700     * @param right  right argument
701     * @return left + right.
702     */
703    public Object add(final Object left, final Object right) {
704        if (left == null && right == null) {
705            return controlNullNullOperands();
706        }
707        final boolean strconcat = strict
708                            ? left instanceof String || right instanceof String
709                            : left instanceof String && right instanceof String;
710        if (!strconcat) {
711            try {
712                // if both (non null) args fit as long
713                final Number ln = asLongNumber(left);
714                final Number rn = asLongNumber(right);
715                if (ln != null && rn != null) {
716                    final long x = ln.longValue();
717                    final long y = rn.longValue();
718                    final long result = x + y;
719                    // detect overflow, see java8 Math.addExact
720                    if (((x ^ result) & (y ^ result)) < 0) {
721                        return BigInteger.valueOf(x).add(BigInteger.valueOf(y));
722                    }
723                    return narrowLong(left, right, result);
724                }
725                // if either are bigdecimal use that type
726                if (left instanceof BigDecimal || right instanceof BigDecimal) {
727                    final BigDecimal l = toBigDecimal(left);
728                    final BigDecimal r = toBigDecimal(right);
729                    final BigDecimal result = l.add(r, getMathContext());
730                    return narrowBigDecimal(left, right, result);
731                }
732                // if either are floating point (double or float) use double
733                if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
734                    final double l = toDouble(left);
735                    final double r = toDouble(right);
736                    return l + r;
737                }
738                // otherwise treat as (big) integers
739                final BigInteger l = toBigInteger(left);
740                final BigInteger r = toBigInteger(right);
741                final BigInteger result = l.add(r);
742                return narrowBigInteger(left, right, result);
743            } catch (final java.lang.NumberFormatException nfe) {
744                if (left == null || right == null) {
745                    controlNullOperand();
746                }
747            }
748        }
749        return toString(left).concat(toString(right));
750    }
751
752    /**
753     * Divide the left value by the right.
754     *
755     * @param left  left argument
756     * @param right  right argument
757     * @return left / right
758     * @throws ArithmeticException if right == 0
759     */
760    public Object divide(final Object left, final Object right) {
761        if (left == null && right == null) {
762            return controlNullNullOperands();
763        }
764        // if both (non null) args fit as long
765        final Number ln = asLongNumber(left);
766        final Number rn = asLongNumber(right);
767        if (ln != null && rn != null) {
768            final long x = ln.longValue();
769            final long y = rn.longValue();
770            if (y == 0L) {
771                throw new ArithmeticException("/");
772            }
773            final long result = x  / y;
774            return narrowLong(left, right, result);
775        }
776        // if either are bigdecimal use that type
777        if (left instanceof BigDecimal || right instanceof BigDecimal) {
778            final BigDecimal l = toBigDecimal(left);
779            final BigDecimal r = toBigDecimal(right);
780            if (BigDecimal.ZERO.equals(r)) {
781                throw new ArithmeticException("/");
782            }
783            final BigDecimal result = l.divide(r, getMathContext());
784            return narrowBigDecimal(left, right, result);
785        }
786        // if either are floating point (double or float) use double
787        if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
788            final double l = toDouble(left);
789            final double r = toDouble(right);
790            if (r == 0.0) {
791                throw new ArithmeticException("/");
792            }
793            return l / r;
794        }
795        // otherwise treat as integers
796        final BigInteger l = toBigInteger(left);
797        final BigInteger r = toBigInteger(right);
798        if (BigInteger.ZERO.equals(r)) {
799            throw new ArithmeticException("/");
800        }
801        final BigInteger result = l.divide(r);
802        return narrowBigInteger(left, right, result);
803    }
804
805    /**
806     * left value modulo right.
807     *
808     * @param left  left argument
809     * @param right  right argument
810     * @return left % right
811     * @throws ArithmeticException if right == 0.0
812     */
813    public Object mod(final Object left, final Object right) {
814        if (left == null && right == null) {
815            return controlNullNullOperands();
816        }
817        // if both (non null) args fit as long
818        final Number ln = asLongNumber(left);
819        final Number rn = asLongNumber(right);
820        if (ln != null && rn != null) {
821            final long x = ln.longValue();
822            final long y = rn.longValue();
823            if (y == 0L) {
824                throw new ArithmeticException("%");
825            }
826            final long result = x % y;
827            return narrowLong(left, right,  result);
828        }
829        // if either are bigdecimal use that type
830        if (left instanceof BigDecimal || right instanceof BigDecimal) {
831            final BigDecimal l = toBigDecimal(left);
832            final BigDecimal r = toBigDecimal(right);
833            if (BigDecimal.ZERO.equals(r)) {
834                throw new ArithmeticException("%");
835            }
836            final BigDecimal remainder = l.remainder(r, getMathContext());
837            return narrowBigDecimal(left, right, remainder);
838        }
839        // if either are floating point (double or float) use double
840        if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
841            final double l = toDouble(left);
842            final double r = toDouble(right);
843            if (r == 0.0) {
844                throw new ArithmeticException("%");
845            }
846            return l % r;
847        }
848        // otherwise treat as integers
849        final BigInteger l = toBigInteger(left);
850        final BigInteger r = toBigInteger(right);
851        if (BigInteger.ZERO.equals(r)) {
852            throw new ArithmeticException("%");
853        }
854        final BigInteger result = l.mod(r);
855        return narrowBigInteger(left, right, result);
856    }
857
858    /**
859     * Checks if the product of the arguments overflows a {@code long}.
860     * <p>see java8 Math.multiplyExact
861     * @param x the first value
862     * @param y the second value
863     * @param r the product
864     * @return true if product fits a long, false if it overflows
865     */
866    @SuppressWarnings("MagicNumber")
867    protected static boolean isMultiplyExact(final long x, final long y, final long r) {
868        final long ax = Math.abs(x);
869        final long ay = Math.abs(y);
870        return !(((ax | ay) >>> (Integer.SIZE - 1) != 0)
871                  && (((y != 0) && (r / y != x))
872                      || (x == Long.MIN_VALUE && y == -1)));
873    }
874
875    /**
876     * Multiply the left value by the right.
877     *
878     * @param left  left argument
879     * @param right  right argument
880     * @return left * right.
881     */
882    public Object multiply(final Object left, final Object right) {
883        if (left == null && right == null) {
884            return controlNullNullOperands();
885        }
886        // if both (non null) args fit as int
887        final Number ln = asLongNumber(left);
888        final Number rn = asLongNumber(right);
889        if (ln != null && rn != null) {
890            final long x = ln.longValue();
891            final long y = rn.longValue();
892            final long result = x * y;
893            // detect overflow
894            if (!isMultiplyExact(x, y, result)) {
895                return BigInteger.valueOf(x).multiply(BigInteger.valueOf(y));
896            }
897            return narrowLong(left, right, result);
898        }
899        // if either are bigdecimal use that type
900        if (left instanceof BigDecimal || right instanceof BigDecimal) {
901            final BigDecimal l = toBigDecimal(left);
902            final BigDecimal r = toBigDecimal(right);
903            final BigDecimal result = l.multiply(r, getMathContext());
904            return narrowBigDecimal(left, right, result);
905        }
906        // if either are floating point (double or float) use double
907        if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
908            final double l = toDouble(left);
909            final double r = toDouble(right);
910            return l * r;
911        }
912        // otherwise treat as integers
913        final BigInteger l = toBigInteger(left);
914        final BigInteger r = toBigInteger(right);
915        final BigInteger result = l.multiply(r);
916        return narrowBigInteger(left, right, result);
917    }
918
919    /**
920     * Subtract the right value from the left.
921     *
922     * @param left  left argument
923     * @param right  right argument
924     * @return left - right.
925     */
926    public Object subtract(final Object left, final Object right) {
927        if (left == null && right == null) {
928            return controlNullNullOperands();
929        }
930        // if both (non null) args fit as long
931        final Number ln = asLongNumber(left);
932        final Number rn = asLongNumber(right);
933        if (ln != null && rn != null) {
934            final long x = ln.longValue();
935            final long y = rn.longValue();
936            final long result = x - y;
937            // detect overflow, see java8 Math.subtractExact
938            if (((x ^ y) & (x ^ result)) < 0) {
939                return BigInteger.valueOf(x).subtract(BigInteger.valueOf(y));
940            }
941            return narrowLong(left, right, result);
942        }
943        // if either are bigdecimal use that type
944        if (left instanceof BigDecimal || right instanceof BigDecimal) {
945            final BigDecimal l = toBigDecimal(left);
946            final BigDecimal r = toBigDecimal(right);
947            final BigDecimal result = l.subtract(r, getMathContext());
948            return narrowBigDecimal(left, right, result);
949        }
950        // if either are floating point (double or float) use double
951        if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
952            final double l = toDouble(left);
953            final double r = toDouble(right);
954            return l - r;
955        }
956        // otherwise treat as integers
957        final BigInteger l = toBigInteger(left);
958        final BigInteger r = toBigInteger(right);
959        final BigInteger result = l.subtract(r);
960        return narrowBigInteger(left, right, result);
961    }
962
963    /**
964     * Negates a value (unary minus for numbers).
965     *
966     * @param val the value to negate
967     * @return the negated value
968     */
969    public Object negate(final Object val) {
970        if (val == null) {
971            controlNullOperand();
972            return null;
973        }
974        if (val instanceof Integer) {
975            return -((Integer) val);
976        }
977        if (val instanceof Double) {
978            return - ((Double) val);
979        }
980        if (val instanceof Long) {
981            return -((Long) val);
982        }
983        if (val instanceof BigDecimal) {
984            return ((BigDecimal) val).negate();
985        }
986        if (val instanceof BigInteger) {
987            return ((BigInteger) val).negate();
988        }
989        if (val instanceof Float) {
990            return -((Float) val);
991        }
992        if (val instanceof Short) {
993            return (short) -((Short) val);
994        }
995        if (val instanceof Byte) {
996            return (byte) -((Byte) val);
997        }
998        if (val instanceof Boolean) {
999            return !(Boolean) val;
1000        }
1001        if (val instanceof AtomicBoolean) {
1002            return !((AtomicBoolean) val).get();
1003        }
1004        throw new ArithmeticException("Object negate:(" + val + ")");
1005    }
1006
1007    /**
1008     * Whether negate called with a given argument will always return the same result.
1009     * <p>This is used to determine whether negate results on number literals can be cached.
1010     * If the result on calling negate with the same constant argument may change between calls,
1011     * which means the function is not deterministic, this method must return false.
1012     * @see #isNegateStable()
1013     * @return true if negate is idempotent, false otherwise
1014     */
1015    public boolean isNegateStable() {
1016        return true;
1017    }
1018
1019    /**
1020     * Positivize value (unary plus for numbers).
1021     * <p>C/C++/C#/Java perform integral promotion of the operand, ie
1022     * cast to int if type can represented as int without loss of precision.
1023     * @see #isPositivizeStable()
1024     * @param val the value to positivize
1025     * @return the positive value
1026     */
1027    public Object positivize(final Object val) {
1028        if (val == null) {
1029            controlNullOperand();
1030            return null;
1031        }
1032        if (val instanceof Short) {
1033            return ((Short) val).intValue();
1034        }
1035        if (val instanceof Byte) {
1036            return ((Byte) val).intValue();
1037        }
1038        if (val instanceof Number) {
1039            return val;
1040        }
1041        if (val instanceof Character) {
1042            return (int) (Character) val;
1043        }
1044        if (val instanceof Boolean) {
1045            return val;
1046        }
1047        if (val instanceof AtomicBoolean) {
1048            return ((AtomicBoolean) val).get();
1049        }
1050        throw new ArithmeticException("Object positivize:(" + val + ")");
1051    }
1052
1053    /**
1054     * Whether positivize called with a given argument will always return the same result.
1055     * <p>This is used to determine whether positivize results on number literals can be cached.
1056     * If the result on calling positivize with the same constant argument may change between calls,
1057     * which means the function is not deterministic, this method must return false.
1058     * @return true if positivize is idempotent, false otherwise
1059     */
1060    public boolean isPositivizeStable() {
1061        return true;
1062    }
1063
1064    /**
1065     * Test if left contains right (right matches/in left).
1066     * <p>Beware that this method arguments are the opposite of the operator arguments.
1067     * 'x in y' means 'y contains x'.</p>
1068     *
1069     * @param container the container
1070     * @param value the value
1071     * @return test result or null if there is no arithmetic solution
1072     */
1073    public Boolean contains(final Object container, final Object value) {
1074        if (value == null && container == null) {
1075            //if both are null L == R
1076            return true;
1077        }
1078        if (value == null || container == null) {
1079            // we know both aren't null, therefore L != R
1080            return false;
1081        }
1082        // use arithmetic / pattern matching ?
1083        if (container instanceof java.util.regex.Pattern) {
1084            return ((java.util.regex.Pattern) container).matcher(value.toString()).matches();
1085        }
1086        if (container instanceof CharSequence) {
1087            return value.toString().matches(container.toString());
1088        }
1089        // try contains on map key
1090        if (container instanceof Map<?, ?>) {
1091            if (value instanceof Map<?, ?>) {
1092                return ((Map<?, ?>) container).keySet().containsAll(((Map<?, ?>) value).keySet());
1093            }
1094            return ((Map<?, ?>) container).containsKey(value);
1095        }
1096        // try contains on collection
1097        if (container instanceof Collection<?>) {
1098            if (value instanceof Collection<?>) {
1099                return ((Collection<?>) container).containsAll((Collection<?>) value);
1100            }
1101            // left in right ? <=> right.contains(left) ?
1102            return ((Collection<?>) container).contains(value);
1103        }
1104        return null;
1105    }
1106
1107    /**
1108     * Test if left ends with right.
1109     *
1110     * @param left  left argument
1111     * @param right  right argument
1112     * @return left $= right if there is no arithmetic solution
1113     */
1114    public Boolean endsWith(final Object left, final Object right) {
1115        if (left == null && right == null) {
1116            //if both are null L == R
1117            return true;
1118        }
1119        if (left == null || right == null) {
1120            // we know both aren't null, therefore L != R
1121            return false;
1122        }
1123        if (left instanceof CharSequence) {
1124            return (toString(left)).endsWith(toString(right));
1125        }
1126        return null;
1127    }
1128
1129    /**
1130     * Test if left starts with right.
1131     *
1132     * @param left  left argument
1133     * @param right  right argument
1134     * @return left ^= right or null if there is no arithmetic solution
1135     */
1136    public Boolean startsWith(final Object left, final Object right) {
1137        if (left == null && right == null) {
1138            //if both are null L == R
1139            return true;
1140        }
1141        if (left == null || right == null) {
1142            // we know both aren't null, therefore L != R
1143            return false;
1144        }
1145        if (left instanceof CharSequence) {
1146            return (toString(left)).startsWith(toString(right));
1147        }
1148        return null;
1149    }
1150
1151    /**
1152     * Check for emptiness of various types: Number, Collection, Array, Map, String.
1153     * <p>Override or overload this method to add new signatures to the size operators.
1154     * @param object the object to check the emptiness of
1155     * @return the boolean or false if object is not null
1156     * @since 3.2
1157     */
1158    public Boolean empty(final Object object) {
1159        return object == null || isEmpty(object, false);
1160    }
1161
1162    /**
1163     * Check for emptiness of various types: Number, Collection, Array, Map, String.
1164     *
1165     * @param object the object to check the emptiness of
1166     * @return the boolean or null if there is no arithmetic solution
1167     */
1168    public Boolean isEmpty(final Object object) {
1169        return isEmpty(object, object == null);
1170    }
1171
1172    /**
1173     * Check for emptiness of various types: Number, Collection, Array, Map, String.
1174     *
1175     * @param object the object to check the emptiness of
1176     * @param def the default value if object emptyness can not be determined
1177     * @return the boolean or null if there is no arithmetic solution
1178     */
1179    public Boolean isEmpty(final Object object, final Boolean def) {
1180        if (object instanceof Number) {
1181            final double d = ((Number) object).doubleValue();
1182            return Double.isNaN(d) || d == 0.d;
1183        }
1184        if (object instanceof CharSequence) {
1185            return ((CharSequence) object).length() == 0;
1186        }
1187        if (object.getClass().isArray()) {
1188            return Array.getLength(object) == 0;
1189        }
1190        if (object instanceof Collection<?>) {
1191            return ((Collection<?>) object).isEmpty();
1192        }
1193        // Map isn't a collection
1194        if (object instanceof Map<?, ?>) {
1195            return ((Map<?, ?>) object).isEmpty();
1196        }
1197        return def;
1198    }
1199
1200    /**
1201     * Calculate the <code>size</code> of various types: Collection, Array, Map, String.
1202     *
1203     * @param object the object to get the size of
1204     * @return the <i>size</i> of object, 0 if null, 1 if there is no <i>better</i> solution
1205     */
1206    public Integer size(final Object object) {
1207        return size(object, object == null? 0 : 1);
1208    }
1209
1210    /**
1211     * Calculate the <code>size</code> of various types: Collection, Array, Map, String.
1212     *
1213     * @param object the object to get the size of
1214     * @param def the default value if object size can not be determined
1215     * @return the size of object or null if there is no arithmetic solution
1216     */
1217    public Integer size(final Object object, final Integer def) {
1218        if (object instanceof CharSequence) {
1219            return ((CharSequence) object).length();
1220        }
1221        if (object.getClass().isArray()) {
1222            return Array.getLength(object);
1223        }
1224        if (object instanceof Collection<?>) {
1225            return ((Collection<?>) object).size();
1226        }
1227        if (object instanceof Map<?, ?>) {
1228            return ((Map<?, ?>) object).size();
1229        }
1230        return def;
1231    }
1232
1233    /**
1234     * Performs a bitwise and.
1235     *
1236     * @param left  the left operand
1237     * @param right the right operator
1238     * @return left &amp; right
1239     */
1240    public Object and(final Object left, final Object right) {
1241        final long l = toLong(left);
1242        final long r = toLong(right);
1243        return l & r;
1244    }
1245
1246    /**
1247     * Performs a bitwise or.
1248     *
1249     * @param left  the left operand
1250     * @param right the right operator
1251     * @return left | right
1252     */
1253    public Object or(final Object left, final Object right) {
1254        final long l = toLong(left);
1255        final long r = toLong(right);
1256        return l | r;
1257    }
1258
1259    /**
1260     * Performs a bitwise xor.
1261     *
1262     * @param left  the left operand
1263     * @param right the right operator
1264     * @return left ^ right
1265     */
1266    public Object xor(final Object left, final Object right) {
1267        final long l = toLong(left);
1268        final long r = toLong(right);
1269        return l ^ r;
1270    }
1271
1272    /**
1273     * Performs a bitwise complement.
1274     *
1275     * @param val the operand
1276     * @return ~val
1277     */
1278    public Object complement(final Object val) {
1279        final long l = toLong(val);
1280        return ~l;
1281    }
1282
1283    /**
1284     * Performs a logical not.
1285     *
1286     * @param val the operand
1287     * @return !val
1288     */
1289    public Object not(final Object val) {
1290        return !toBoolean(val);
1291    }
1292
1293    /**
1294     * Performs a comparison.
1295     *
1296     * @param left     the left operand
1297     * @param right    the right operator
1298     * @param operator the operator
1299     * @return -1 if left &lt; right; +1 if left &gt; right; 0 if left == right
1300     * @throws ArithmeticException if either left or right is null
1301     */
1302    protected int compare(final Object left, final Object right, final String operator) {
1303        if (left != null && right != null) {
1304            if (left instanceof BigDecimal || right instanceof BigDecimal) {
1305                final BigDecimal l = toBigDecimal(left);
1306                final BigDecimal r = toBigDecimal(right);
1307                return l.compareTo(r);
1308            }
1309            if (left instanceof BigInteger || right instanceof BigInteger) {
1310                final BigInteger l = toBigInteger(left);
1311                final BigInteger r = toBigInteger(right);
1312                return l.compareTo(r);
1313            }
1314            if (isFloatingPoint(left) || isFloatingPoint(right)) {
1315                final double lhs = toDouble(left);
1316                final double rhs = toDouble(right);
1317                if (Double.isNaN(lhs)) {
1318                    if (Double.isNaN(rhs)) {
1319                        return 0;
1320                    }
1321                    return -1;
1322                }
1323                if (Double.isNaN(rhs)) {
1324                    // lhs is not NaN
1325                    return +1;
1326                }
1327                if (lhs < rhs) {
1328                    return -1;
1329                }
1330                if (lhs > rhs) {
1331                    return +1;
1332                }
1333                return 0;
1334            }
1335            if (isNumberable(left) || isNumberable(right)) {
1336                final long lhs = toLong(left);
1337                final long rhs = toLong(right);
1338                if (lhs < rhs) {
1339                    return -1;
1340                }
1341                if (lhs > rhs) {
1342                    return +1;
1343                }
1344                return 0;
1345            }
1346            if (left instanceof String || right instanceof String) {
1347                return toString(left).compareTo(toString(right));
1348            }
1349            if ("==".equals(operator)) {
1350                return left.equals(right) ? 0 : -1;
1351            }
1352            if (left instanceof Comparable<?>) {
1353                @SuppressWarnings("unchecked") // OK because of instanceof check above
1354                final Comparable<Object> comparable = (Comparable<Object>) left;
1355                return comparable.compareTo(right);
1356            }
1357            if (right instanceof Comparable<?>) {
1358                @SuppressWarnings("unchecked") // OK because of instanceof check above
1359                final Comparable<Object> comparable = (Comparable<Object>) right;
1360                return comparable.compareTo(left);
1361            }
1362        }
1363        throw new ArithmeticException("Object comparison:(" + left + " " + operator + " " + right + ")");
1364    }
1365
1366    /**
1367     * Test if left and right are equal.
1368     *
1369     * @param left  left argument
1370     * @param right right argument
1371     * @return the test result
1372     */
1373    public boolean equals(final Object left, final Object right) {
1374        if (left == right) {
1375            return true;
1376        }
1377        if (left == null || right == null) {
1378            return false;
1379        }
1380        if (left instanceof Boolean || right instanceof Boolean) {
1381            return toBoolean(left) == toBoolean(right);
1382        }
1383        return compare(left, right, "==") == 0;
1384    }
1385
1386    /**
1387     * Test if left &lt; right.
1388     *
1389     * @param left  left argument
1390     * @param right right argument
1391     * @return the test result
1392     */
1393    public boolean lessThan(final Object left, final Object right) {
1394        if ((left == right) || (left == null) || (right == null)) {
1395            return false;
1396        }
1397        return compare(left, right, "<") < 0;
1398
1399    }
1400
1401    /**
1402     * Test if left &gt; right.
1403     *
1404     * @param left  left argument
1405     * @param right right argument
1406     * @return the test result
1407     */
1408    public boolean greaterThan(final Object left, final Object right) {
1409        if ((left == right) || left == null || right == null) {
1410            return false;
1411        }
1412        return compare(left, right, ">") > 0;
1413    }
1414
1415    /**
1416     * Test if left &lt;= right.
1417     *
1418     * @param left  left argument
1419     * @param right right argument
1420     * @return the test result
1421     */
1422    public boolean lessThanOrEqual(final Object left, final Object right) {
1423        if (left == right) {
1424            return true;
1425        }
1426        if (left == null || right == null) {
1427            return false;
1428        }
1429        return compare(left, right, "<=") <= 0;
1430    }
1431
1432    /**
1433     * Test if left &gt;= right.
1434     *
1435     * @param left  left argument
1436     * @param right right argument
1437     * @return the test result
1438     */
1439    public boolean greaterThanOrEqual(final Object left, final Object right) {
1440        if (left == right) {
1441            return true;
1442        }
1443        if (left == null || right == null) {
1444            return false;
1445        }
1446        return compare(left, right, ">=") >= 0;
1447    }
1448
1449    /**
1450     * Coerce to a primitive boolean.
1451     * <p>Double.NaN, null, "false" and empty string coerce to false.</p>
1452     *
1453     * @param val value to coerce
1454     * @return the boolean value if coercion is possible, true if value was not null.
1455     */
1456    public boolean toBoolean(final Object val) {
1457        if (val == null) {
1458            controlNullOperand();
1459            return false;
1460        }
1461        if (val instanceof Boolean) {
1462            return ((Boolean) val);
1463        }
1464        if (val instanceof Number) {
1465            final double number = toDouble(val);
1466            return !Double.isNaN(number) && number != 0.d;
1467        }
1468        if (val instanceof AtomicBoolean) {
1469            return ((AtomicBoolean) val).get();
1470        }
1471        if (val instanceof String) {
1472            final String strval = val.toString();
1473            return !strval.isEmpty() && !"false".equals(strval);
1474        }
1475        // non null value is true
1476        return true;
1477    }
1478
1479    /**
1480     * Coerce to a primitive int.
1481     * <p>Double.NaN, null and empty string coerce to zero.</p>
1482     * <p>Boolean false is 0, true is 1.</p>
1483     *
1484     * @param val value to coerce
1485     * @return the value coerced to int
1486     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
1487     */
1488    public int toInteger(final Object val) {
1489        if (val == null) {
1490            controlNullOperand();
1491            return 0;
1492        }
1493        if (val instanceof Double) {
1494            final Double dval = (Double) val;
1495            if (Double.isNaN(dval)) {
1496                return 0;
1497            }
1498            return dval.intValue();
1499        }
1500        if (val instanceof Number) {
1501            return ((Number) val).intValue();
1502        }
1503        if (val instanceof String) {
1504            if ("".equals(val)) {
1505                return 0;
1506            }
1507            return Integer.parseInt((String) val);
1508        }
1509        if (val instanceof Boolean) {
1510            return ((Boolean) val) ? 1 : 0;
1511        }
1512        if (val instanceof AtomicBoolean) {
1513            return ((AtomicBoolean) val).get() ? 1 : 0;
1514        }
1515        if (val instanceof Character) {
1516            return ((Character) val);
1517        }
1518
1519        throw new ArithmeticException("Integer coercion: "
1520                + val.getClass().getName() + ":(" + val + ")");
1521    }
1522
1523    /**
1524     * Coerce to a primitive long.
1525     * <p>Double.NaN, null and empty string coerce to zero.</p>
1526     * <p>Boolean false is 0, true is 1.</p>
1527     *
1528     * @param val value to coerce
1529     * @return the value coerced to long
1530     * @throws ArithmeticException if value is null and mode is strict or if coercion is not possible
1531     */
1532    public long toLong(final Object val) {
1533        if (val == null) {
1534            controlNullOperand();
1535            return 0L;
1536        }
1537        if (val instanceof Double) {
1538            final Double dval = (Double) val;
1539            if (Double.isNaN(dval)) {
1540                return 0L;
1541            }
1542            return dval.longValue();
1543        }
1544        if (val instanceof Number) {
1545            return ((Number) val).longValue();
1546        }
1547        if (val instanceof String) {
1548            if ("".equals(val)) {
1549                return 0L;
1550            }
1551            return Long.parseLong((String) val);
1552        }
1553        if (val instanceof Boolean) {
1554            return ((Boolean) val) ? 1L : 0L;
1555        }
1556        if (val instanceof AtomicBoolean) {
1557            return ((AtomicBoolean) val).get() ? 1L : 0L;
1558        }
1559        if (val instanceof Character) {
1560            return ((Character) val);
1561        }
1562
1563        throw new ArithmeticException("Long coercion: "
1564                + val.getClass().getName() + ":(" + val + ")");
1565    }
1566
1567    /**
1568     * Coerce to a BigInteger.
1569     * <p>Double.NaN, null and empty string coerce to zero.</p>
1570     * <p>Boolean false is 0, true is 1.</p>
1571     *
1572     * @param val the object to be coerced.
1573     * @return a BigDecimal
1574     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
1575     */
1576    public BigInteger toBigInteger(final Object val) {
1577        if (val == null) {
1578            controlNullOperand();
1579            return BigInteger.ZERO;
1580        }
1581        if (val instanceof BigInteger) {
1582            return (BigInteger) val;
1583        }
1584        if (val instanceof Double) {
1585            final Double dval = (Double) val;
1586            if (Double.isNaN(dval)) {
1587                return BigInteger.ZERO;
1588            }
1589            return BigInteger.valueOf(dval.longValue());
1590        }
1591        if (val instanceof BigDecimal) {
1592            return ((BigDecimal) val).toBigInteger();
1593        }
1594        if (val instanceof Number) {
1595            return BigInteger.valueOf(((Number) val).longValue());
1596        }
1597        if (val instanceof Boolean) {
1598            return BigInteger.valueOf(((Boolean) val) ? 1L : 0L);
1599        }
1600        if (val instanceof AtomicBoolean) {
1601            return BigInteger.valueOf(((AtomicBoolean) val).get() ? 1L : 0L);
1602        }
1603        if (val instanceof String) {
1604            final String string = (String) val;
1605            if ("".equals(string)) {
1606                return BigInteger.ZERO;
1607            }
1608            return new BigInteger(string);
1609        }
1610        if (val instanceof Character) {
1611            final int i = ((Character) val);
1612            return BigInteger.valueOf(i);
1613        }
1614
1615        throw new ArithmeticException("BigInteger coercion: "
1616                + val.getClass().getName() + ":(" + val + ")");
1617    }
1618
1619    /**
1620     * Coerce to a BigDecimal.
1621     * <p>Double.NaN, null and empty string coerce to zero.</p>
1622     * <p>Boolean false is 0, true is 1.</p>
1623     *
1624     * @param val the object to be coerced.
1625     * @return a BigDecimal.
1626     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
1627     */
1628    public BigDecimal toBigDecimal(final Object val) {
1629        if (val instanceof BigDecimal) {
1630            return roundBigDecimal((BigDecimal) val);
1631        }
1632        if (val == null) {
1633            controlNullOperand();
1634            return BigDecimal.ZERO;
1635        }
1636        if (val instanceof Double) {
1637            if (Double.isNaN(((Double) val))) {
1638                return BigDecimal.ZERO;
1639            }
1640            return roundBigDecimal(new BigDecimal(val.toString(), getMathContext()));
1641        }
1642        if (val instanceof Number) {
1643            return roundBigDecimal(new BigDecimal(val.toString(), getMathContext()));
1644        }
1645        if (val instanceof Boolean) {
1646            return BigDecimal.valueOf(((Boolean) val) ? 1. : 0.);
1647        }
1648        if (val instanceof AtomicBoolean) {
1649            return BigDecimal.valueOf(((AtomicBoolean) val).get() ? 1L : 0L);
1650        }
1651        if (val instanceof String) {
1652            final String string = (String) val;
1653            if ("".equals(string)) {
1654                return BigDecimal.ZERO;
1655            }
1656            return roundBigDecimal(new BigDecimal(string, getMathContext()));
1657        }
1658        if (val instanceof Character) {
1659            final int i = ((Character) val);
1660            return new BigDecimal(i);
1661        }
1662        throw new ArithmeticException("BigDecimal coercion: "
1663                + val.getClass().getName() + ":(" + val + ")");
1664    }
1665
1666    /**
1667     * Coerce to a primitive double.
1668     * <p>Double.NaN, null and empty string coerce to zero.</p>
1669     * <p>Boolean false is 0, true is 1.</p>
1670     *
1671     * @param val value to coerce.
1672     * @return The double coerced value.
1673     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
1674     */
1675    public double toDouble(final Object val) {
1676        if (val == null) {
1677            controlNullOperand();
1678            return 0;
1679        }
1680        if (val instanceof Double) {
1681            return ((Double) val);
1682        }
1683        if (val instanceof Number) {
1684            //The below construct is used rather than ((Number)val).doubleValue() to ensure
1685            //equality between comparing new Double( 6.4 / 3 ) and the jexl expression of 6.4 / 3
1686            return Double.parseDouble(String.valueOf(val));
1687        }
1688        if (val instanceof Boolean) {
1689            return ((Boolean) val) ? 1. : 0.;
1690        }
1691        if (val instanceof AtomicBoolean) {
1692            return ((AtomicBoolean) val).get() ? 1. : 0.;
1693        }
1694        if (val instanceof String) {
1695            final String string = (String) val;
1696            if ("".equals(string)) {
1697                return Double.NaN;
1698            }
1699            // the spec seems to be iffy about this.  Going to give it a wack anyway
1700            return Double.parseDouble(string);
1701        }
1702        if (val instanceof Character) {
1703            final int i = ((Character) val);
1704            return i;
1705        }
1706        throw new ArithmeticException("Double coercion: "
1707                + val.getClass().getName() + ":(" + val + ")");
1708    }
1709
1710    /**
1711     * Coerce to a string.
1712     * <p>Double.NaN coerce to the empty string.</p>
1713     *
1714     * @param val value to coerce.
1715     * @return The String coerced value.
1716     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
1717     */
1718    public String toString(final Object val) {
1719        if (val == null) {
1720            controlNullOperand();
1721            return "";
1722        }
1723        if (!(val instanceof Double)) {
1724            return val.toString();
1725        }
1726        final Double dval = (Double) val;
1727        if (Double.isNaN(dval)) {
1728            return "";
1729        }
1730        return dval.toString();
1731    }
1732
1733    /**
1734     * Use or overload and() instead.
1735     * @param lhs left hand side
1736     * @param rhs right hand side
1737     * @return lhs &amp; rhs
1738     * @see JexlArithmetic#and
1739     * @deprecated
1740     */
1741    @Deprecated
1742    public final Object bitwiseAnd(final Object lhs, final Object rhs) {
1743        return and(lhs, rhs);
1744    }
1745
1746    /**
1747     * Use or overload or() instead.
1748     *
1749     * @param lhs left hand side
1750     * @param rhs right hand side
1751     * @return lhs | rhs
1752     * @see JexlArithmetic#or
1753     * @deprecated
1754     */
1755    @Deprecated
1756    public final Object bitwiseOr(final Object lhs, final Object rhs) {
1757        return or(lhs, rhs);
1758    }
1759
1760    /**
1761     * Use or overload xor() instead.
1762     *
1763     * @param lhs left hand side
1764     * @param rhs right hand side
1765     * @return lhs ^ rhs
1766     * @see JexlArithmetic#xor
1767     * @deprecated
1768     */
1769    @Deprecated
1770    public final Object bitwiseXor(final Object lhs, final Object rhs) {
1771        return xor(lhs, rhs);
1772    }
1773
1774    /**
1775     * Use or overload not() instead.
1776     *
1777     * @param arg argument
1778     * @return !arg
1779     * @see JexlArithmetic#not
1780     * @deprecated
1781     */
1782    @Deprecated
1783    public final Object logicalNot(final Object arg) {
1784        return not(arg);
1785    }
1786
1787    /**
1788     * Use or overload contains() instead.
1789     *
1790     * @param lhs left hand side
1791     * @param rhs right hand side
1792     * @return contains(rhs, lhs)
1793     * @see JexlArithmetic#contains
1794     * @deprecated
1795     */
1796    @Deprecated
1797    public final Object matches(final Object lhs, final Object rhs) {
1798        return contains(rhs, lhs);
1799    }
1800}