/* --------------------------------------------------------- * * __________ D E L T A S C R I P T * * (_________() * * / === / - A fast, dynamic scripting language * * | == | - Version 4.13.11.0 * * / === / - Developed by Adam R. Nelson * * | = = | - 2011-2013 * * / === / - Distributed under GNU LGPL v3 * * (________() - http://github.com/ar-nelson/deltascript * * * * --------------------------------------------------------- */ package com.sector91.delta.script.objects; import static com.sector91.delta.script.NumberTypes.*; import java.math.BigDecimal; import java.math.BigInteger; import com.sector91.delta.script.DScriptContext; public final class ScalarFactory { private ScalarFactory() {} public static DS_Scalar fromString(String str, DScriptContext context) { if ("true".equals(str) || "false".equals(str)) // Boolean return DS_Boolean.box(Boolean.parseBoolean(str)); else if (str.indexOf('.')>-1 || str.indexOf('E')>-1) // Floating-point { switch (context.getDefaultFloatType()) { case SHORT_FLOAT: final float fval = Float.parseFloat(str); if (!Float.isInfinite(fval)) return new DS_ShortFloatScalar(fval); case LONG_FLOAT: final double dval = Double.parseDouble(str); if (!Double.isInfinite(dval)) return new DS_LongFloatScalar(dval); case REAL_DECIMAL: return new DS_RealDecimalScalar(new BigDecimal(str)); default: throw new IllegalStateException(context.getDefaultFloatType() + " is not a valid floating-point number type."); } } else // Integer { switch (context.getDefaultIntType()) { case SHORT_INT: try {return new DS_ShortIntScalar(Integer.parseInt(str));} catch (NumberFormatException ex) {/* Pass it on... */} case LONG_INT: try {return new DS_LongIntScalar(Long.parseLong(str));} catch (NumberFormatException ex) {/* Pass it on... */} case REAL_INT: return new DS_RealIntScalar(new BigInteger(str)); default: throw new IllegalStateException(context.getDefaultIntType() + " is not a valid integral number type."); } } } public static DS_Scalar fromString(String str, int nType) { switch (nType) { case BOOL: return DS_Boolean.box(Boolean.parseBoolean(str)); case SHORT_INT: return new DS_ShortIntScalar(Integer.parseInt(str)); case LONG_INT: return new DS_LongIntScalar(Long.parseLong(str)); case SHORT_FLOAT: return new DS_ShortFloatScalar(Float.parseFloat(str)); case LONG_FLOAT: return new DS_LongFloatScalar(Double.parseDouble(str)); case REAL_INT: return new DS_RealIntScalar(new BigInteger(str)); case REAL_DECIMAL: return new DS_RealDecimalScalar(new BigDecimal(str)); default: return null; } } public static DS_Integer fromInt(int n) {return new DS_ShortIntScalar(n);} public static DS_Integer fromLong(long n) {return new DS_LongIntScalar(n);} public static DS_Integer fromBigInteger(BigInteger n) {return new DS_RealIntScalar(n);} public static DS_Decimal fromFloat(float n) {return new DS_ShortFloatScalar(n);} public static DS_Decimal fromDouble(double n) {return new DS_LongFloatScalar(n);} public static DS_Decimal fromBigDecimal(BigDecimal n) {return new DS_RealDecimalScalar(n);} public static DS_Scalar fromNumber(int n, int nType) { switch (nType) { case BOOL: return DS_Boolean.box(n != 0); case SHORT_INT: return new DS_ShortIntScalar(n); case LONG_INT: return new DS_LongIntScalar(n); case SHORT_FLOAT: return new DS_ShortFloatScalar(n); case LONG_FLOAT: return new DS_LongFloatScalar(n); case REAL_INT: return new DS_RealIntScalar(BigInteger.valueOf(n)); case REAL_DECIMAL: return new DS_RealDecimalScalar(BigDecimal.valueOf(n)); default: return null; } } public static DS_Scalar fromNumber(float n, int nType) { switch (nType) { case BOOL: return DS_Boolean.box(n != 0); case SHORT_INT: return new DS_ShortIntScalar((int)n); case LONG_INT: return new DS_LongIntScalar((long)n); case SHORT_FLOAT: return new DS_ShortFloatScalar(n); case LONG_FLOAT: return new DS_LongFloatScalar(n); case REAL_INT: return new DS_RealIntScalar(BigInteger.valueOf((long)n)); case REAL_DECIMAL: return new DS_RealDecimalScalar(BigDecimal.valueOf(n)); default: return null; } } public static DS_Scalar fromNumber(long n, int nType) { switch (nType) { case BOOL: return DS_Boolean.box(n != 0); case SHORT_INT: return new DS_ShortIntScalar((int)n); case LONG_INT: return new DS_LongIntScalar(n); case SHORT_FLOAT: return new DS_ShortFloatScalar(n); case LONG_FLOAT: return new DS_LongFloatScalar(n); case REAL_INT: return new DS_RealIntScalar(BigInteger.valueOf(n)); case REAL_DECIMAL: try {return new DS_RealDecimalScalar(BigDecimal.valueOf(n));} catch (NumberFormatException ex) {return new DS_LongFloatScalar(n);} default: return null; } } public static DS_Scalar fromNumber(double n, int nType) { switch (nType) { case BOOL: return DS_Boolean.box(n != 0); case SHORT_INT: return new DS_ShortIntScalar((int)n); case LONG_INT: return new DS_LongIntScalar((long)n); case SHORT_FLOAT: return new DS_ShortFloatScalar((float)n); case LONG_FLOAT: return new DS_LongFloatScalar(n); case REAL_INT: return new DS_RealIntScalar(BigInteger.valueOf((long)n)); case REAL_DECIMAL: try {return new DS_RealDecimalScalar(BigDecimal.valueOf(n));} catch (NumberFormatException ex) {return new DS_LongFloatScalar(n);} default: return null; } } public static DS_Scalar fromNumber(BigInteger n, int nType) { switch (nType) { case BOOL: return DS_Boolean.box(!n.equals(BigInteger.ZERO)); case SHORT_INT: return new DS_ShortIntScalar(n.intValue()); case LONG_INT: return new DS_LongIntScalar(n.longValue()); case SHORT_FLOAT: return new DS_ShortFloatScalar(n.floatValue()); case LONG_FLOAT: return new DS_LongFloatScalar(n.doubleValue()); case REAL_INT: return new DS_RealIntScalar(n); case REAL_DECIMAL: return new DS_RealDecimalScalar(new BigDecimal(n)); default: return null; } } public static DS_Scalar fromNumber(BigDecimal n, int nType) { switch (nType) { case BOOL: return DS_Boolean.box(!n.equals(BigDecimal.ZERO)); case SHORT_INT: return new DS_ShortIntScalar(n.intValue()); case LONG_INT: return new DS_LongIntScalar(n.longValue()); case SHORT_FLOAT: return new DS_ShortFloatScalar(n.floatValue()); case LONG_FLOAT: return new DS_LongFloatScalar(n.doubleValue()); case REAL_INT: return new DS_RealIntScalar(n.toBigInteger()); case REAL_DECIMAL: return new DS_RealDecimalScalar(n); default: return null; } } public static DS_Scalar fromBoolean(boolean b, int nType) { switch (nType) { case BOOL: return DS_Boolean.box(b); case SHORT_INT: return new DS_ShortIntScalar(b?1:0); case LONG_INT: return new DS_LongIntScalar(b?1:0); case SHORT_FLOAT: return new DS_ShortFloatScalar(b?1f:0f); case LONG_FLOAT: return new DS_LongFloatScalar(b?1d:0d); case REAL_INT: return new DS_RealIntScalar(b?BigInteger.ONE:BigInteger.ZERO); case REAL_DECIMAL: return new DS_RealDecimalScalar(b?BigDecimal.ONE:BigDecimal.ZERO); default: return null; } } public static DS_Scalar add(DS_Scalar s1, DS_Scalar s2, int nType) { switch (nType) { case BOOL: return DS_Boolean.box(s1.intValue()+s2.intValue() != 0); case SHORT_INT: return fromNumber(s1.intValue()+s2.intValue(), nType); case LONG_INT: return fromNumber(s1.longValue()+s2.longValue(), nType); case SHORT_FLOAT: return fromNumber(s1.floatValue()+s2.floatValue(), nType); case LONG_FLOAT: return fromNumber(s1.doubleValue()+s2.doubleValue(), nType); case REAL_INT: return fromNumber(s1.bigIntegerValue().add(s2.bigIntegerValue()), nType); case REAL_DECIMAL: try { return fromNumber(s1.bigDecimalValue().add( s2.bigDecimalValue()), nType); } catch (NumberFormatException ex) // If Infinity/NaN encountered... { // ... then revert to double, which can represent these values. return fromNumber(s1.doubleValue()+s2.doubleValue(),LONG_FLOAT); } default: return null; } } public static DS_Scalar sub(DS_Scalar s1, DS_Scalar s2, int nType) { switch (nType) { case BOOL: return DS_Boolean.box(s1.intValue()-s2.intValue() != 0); case SHORT_INT: return fromNumber(s1.intValue()-s2.intValue(), nType); case LONG_INT: return fromNumber(s1.longValue()-s2.longValue(), nType); case SHORT_FLOAT: return fromNumber(s1.floatValue()-s2.floatValue(), nType); case LONG_FLOAT: return fromNumber(s1.doubleValue()-s2.doubleValue(), nType); case REAL_INT: return fromNumber(s1.bigIntegerValue().subtract( s2.bigIntegerValue()), nType); case REAL_DECIMAL: try { return fromNumber(s1.bigDecimalValue().subtract( s2.bigDecimalValue()), nType); } catch (NumberFormatException ex) // If Infinity/NaN encountered... { // ... then revert to double, which can represent these values. return fromNumber(s1.doubleValue()-s2.doubleValue(),LONG_FLOAT); } default: return null; } } public static DS_Scalar mul(DS_Scalar s1, DS_Scalar s2, int nType) { switch (nType) { case BOOL: return DS_Boolean.box(s1.intValue()*s2.intValue() != 0); case SHORT_INT: return fromNumber(s1.intValue()*s2.intValue(), nType); case LONG_INT: return fromNumber(s1.longValue()*s2.longValue(), nType); case SHORT_FLOAT: return fromNumber(s1.floatValue()*s2.floatValue(), nType); case LONG_FLOAT: return fromNumber(s1.doubleValue()*s2.doubleValue(), nType); case REAL_INT: return fromNumber(s1.bigIntegerValue().multiply( s2.bigIntegerValue()), nType); case REAL_DECIMAL: try { return fromNumber(s1.bigDecimalValue().multiply( s2.bigDecimalValue()), nType); } catch (NumberFormatException ex) // If Infinity/NaN encountered... { // ... then revert to double, which can represent these values. return fromNumber(s1.doubleValue()*s2.doubleValue(),LONG_FLOAT); } default: return null; } } public static DS_Scalar div(DS_Scalar s1, DS_Scalar s2, int nType) { switch (nType) { case BOOL: return DS_Boolean.box(s1.intValue()/s2.intValue() != 0); case SHORT_INT: return fromNumber(s1.intValue()/s2.intValue(), nType); case LONG_INT: return fromNumber(s1.longValue()/s2.longValue(), nType); case SHORT_FLOAT: return fromNumber(s1.floatValue()/s2.floatValue(), nType); case LONG_FLOAT: return fromNumber(s1.doubleValue()/s2.doubleValue(), nType); case REAL_INT: return fromNumber(s1.bigIntegerValue().divide( s2.bigIntegerValue()), nType); case REAL_DECIMAL: try { return fromNumber(s1.bigDecimalValue().divide( s2.bigDecimalValue()), nType); } catch (NumberFormatException ex) // If Infinity/NaN encountered... { // ... then revert to double, which can represent these values. return fromNumber(s1.doubleValue()/s2.doubleValue(),LONG_FLOAT); } default: return null; } } public static DS_Scalar mod(DS_Scalar s1, DS_Scalar s2, int nType) { switch (nType) { case BOOL: return DS_Boolean.box(s1.intValue()%s2.intValue() != 0); case SHORT_INT: return fromNumber(s1.intValue()%s2.intValue(), nType); case LONG_INT: return fromNumber(s1.longValue()%s2.longValue(), nType); case SHORT_FLOAT: return fromNumber(s1.floatValue()%s2.floatValue(), nType); case LONG_FLOAT: return fromNumber(s1.doubleValue()%s2.doubleValue(), nType); // The remainder() operation has the same negative-number behavior as // Java's % operator, even though it is not a "correct" mod operator. case REAL_INT: return fromNumber(s1.bigIntegerValue().remainder( s2.bigIntegerValue()), nType); case REAL_DECIMAL: try { return fromNumber(s1.bigDecimalValue().remainder( s2.bigDecimalValue()), nType); } catch (NumberFormatException ex) // If Infinity/NaN encountered... { // ... then revert to double, which can represent these values. return fromNumber(s1.doubleValue()%s2.doubleValue(),LONG_FLOAT); } default: return null; } } public static DS_Scalar exp(DS_Scalar s1, DS_Scalar s2, int nType) { switch (nType) { case BOOL: return DS_Boolean.box(Math.pow( s1.doubleValue(), s2.doubleValue()) != 0); case SHORT_INT: return fromNumber((int)Math.pow(s1.intValue(), s2.intValue()), nType); case LONG_INT: return fromNumber((long)Math.pow(s1.longValue(), s2.longValue()), nType); case SHORT_FLOAT: return fromNumber((float)Math.pow(s1.floatValue(), s2.floatValue()), nType); case LONG_FLOAT: return fromNumber(Math.pow(s1.doubleValue(), s2.doubleValue()), nType); case REAL_INT: return fromNumber(s1.bigIntegerValue().pow(s2.intValue()), nType); case REAL_DECIMAL: try { // FIXME: Loss of precision; figure out how to exp BigDecimal. final BigDecimal decimal = s2.bigDecimalValue(); if (decimal.equals(BigDecimal.valueOf(decimal.intValue()))) return fromNumber(s1.bigDecimalValue().pow( decimal.intValue()), nType); } catch (NumberFormatException ex) {/* Just give up and use doubles. */} catch (ArithmeticException ex) {/* Just give up and use doubles. */} return fromNumber(Math.pow(s1.doubleValue(), s2.doubleValue()), LONG_FLOAT); default: return null; } } }