/* --------------------------------------------------------- * * __________ 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.io.Serializable; import java.math.BigDecimal; import java.math.BigInteger; import com.sector91.delta.script.DScriptContext; import com.sector91.delta.script.DScriptErr; import com.sector91.delta.script.DeltaScript; import com.sector91.delta.script.NumberTypes; import com.sector91.delta.script.Operator; import com.sector91.delta.script.annotations.DSDynamicField; import com.sector91.delta.script.annotations.DSInaccessible; import com.sector91.delta.script.annotations.DSName; import com.sector91.delta.script.annotations.DSType; /** * <p>Any scalar numeric value in DeltaScript, including integers, decimals, and * booleans. All scalar types can be compared to each other and converted * between each other, and support the same basic math operations. Scalars are * immutable.</p> * * <p>All scalars have a <i>number type</i>; see {@link NumberTypes} for more * information.</p> * * @author Adam R. Nelson * @version 4.13.11.0 */ @DSType("Scalar") public abstract class DS_Scalar extends DS_AbstractObject implements DS_Numeric, Comparable<DS_Scalar>, Serializable { private static final long serialVersionUID = DeltaScript.VERSION.majorVersion(); public static final String TYPE_NAME = "Scalar"; @Override public int compare(DS_Object other) throws DScriptErr { if (other instanceof DS_Scalar) return compareTo((DS_Scalar)other); throw DScriptErr.invalidCompare(this, other); } @DSInaccessible public int compareTo(DS_Scalar o) { final int cmpType = getNumberType() | o.getNumberType(); switch (cmpType) { case BOOL: case SHORT_INT: return intValue() - o.intValue(); case LONG_INT: return Long.signum(longValue() - o.longValue()); case SHORT_FLOAT: return Float.compare(floatValue(), o.floatValue()); case LONG_FLOAT: return Double.compare(doubleValue(), o.doubleValue()); case REAL_INT: return bigIntegerValue().compareTo(o.bigIntegerValue()); case REAL_DECIMAL: // Handle the special case of infinity: floats and doubles can be // infinite, but BigDecimals cannot. if (!isInfinite() && o.isInfinite()) return o.signum(); else if (isInfinite() && !o.isInfinite()) return signum(); return bigDecimalValue().compareTo(o.bigDecimalValue()); default: throw new UnsupportedOperationException("Invalid number type: " + cmpType); } } public boolean equals(DS_Object other) { if (other instanceof DS_Scalar) { final DS_Scalar o = (DS_Scalar)other; final int cmpType; if (!o.isIntegral()) cmpType = (getNumberType() & o.getNumberType()) | SHORT_FLOAT; else cmpType = getNumberType() | o.getNumberType(); return testEquality(o, cmpType); } return false; } protected boolean testEquality(DS_Scalar o, int cmpType) { switch (cmpType) { case BOOL: case SHORT_INT: return intValue() == o.intValue(); case LONG_INT: return longValue() == o.longValue(); case SHORT_FLOAT: return floatValue() == o.floatValue(); case LONG_FLOAT: return doubleValue() == o.doubleValue(); case REAL_INT: return bigIntegerValue().equals(o.bigIntegerValue()); case REAL_DECIMAL: return bigDecimalValue().compareTo(o.bigDecimalValue()) == 0; } return false; } @SuppressWarnings("incomplete-switch") @Override public DS_Object operator(Operator op, DS_Object other) { if (other instanceof DS_Scalar) { final DS_Scalar o = (DS_Scalar)other; final int cmpType = getNumberType() | o.getNumberType(); switch (op) { case ADD: return ScalarFactory.add(this, o, cmpType); case SUBTRACT: return ScalarFactory.sub(this, o, cmpType); case MULTIPLY: return ScalarFactory.mul(this, o, cmpType); case DIVIDE: return ScalarFactory.div(this, o, cmpType); case MODULUS: return ScalarFactory.mod(this, o, cmpType); case EXPONENT: return ScalarFactory.exp(this, o, cmpType); case RANGE_INC: return new DS_Range(this, o, true, cmpType | SHORT_INT); case RANGE_EXC: return new DS_Range(this, o, false, cmpType | SHORT_INT); case RANGE_STEP: // "by" - Create boxes with "N1 by N2 [by N3...]" final float w = floatValue(); final float h = ((DS_Scalar)other).floatValue(); return DScriptContext.getContextGeometry().rect(0, 0, w, h); } } else if (other == null) { switch (op) { case INCREMENT: return increment(1); case DECREMENT: return increment(-1); case UNARY_MINUS: return negate(); case ABSOLUTE: return absolute(); case RANDOM: return random(); } } return super.operator(op, other); } @DSInaccessible public abstract int getNumberType(); @DSInaccessible public abstract DS_Scalar random(); @DSName({"sgn", "signum"}) @DSDynamicField public abstract int signum(); @DSInaccessible public abstract DS_Scalar negate(); @DSInaccessible public abstract DS_Scalar absolute(); @DSInaccessible public abstract DS_Scalar increment(int amount); public abstract DS_Integer floor(); public abstract DS_Integer ceil(); public abstract DS_Integer round(); @DSName("sin") @DSDynamicField public DS_Decimal sin() {return ScalarFactory.fromDouble(Math.sin(doubleValue()));} @DSName("cos") @DSDynamicField public DS_Decimal cos() {return ScalarFactory.fromDouble(Math.cos(doubleValue()));} @DSName("tan") @DSDynamicField public DS_Decimal tan() {return ScalarFactory.fromDouble(Math.tan(doubleValue()));} @DSName("asin") @DSDynamicField public DS_Decimal asin() {return ScalarFactory.fromDouble(Math.asin(doubleValue()));} @DSName("acos") @DSDynamicField public DS_Decimal acos() {return ScalarFactory.fromDouble(Math.acos(doubleValue()));} @DSName("atan") @DSDynamicField public DS_Decimal atan() {return ScalarFactory.fromDouble(Math.atan(doubleValue()));} public abstract DS_Scalar sqrt(); /** * <p>Returns true if the "default" representation of this number is an * integer (rather than a floating-point number).</p> * * @since 0.11.10.0 */ @DSInaccessible public abstract boolean isIntegral(); public abstract boolean isInfinite(); public abstract boolean isNaN(); @Override public abstract boolean booleanValue(); /** * <p>Returns an {@code int} representation of this scalar, if one exists. * Throws an exception if this scalar cannot be represented as an * {@code int} value.</p> * * @throws DScriptErr If this scalar does not have an {@code int} * representation. */ @DSInaccessible public abstract int intValue(); /** * <p>Returns a {@code long} representation of this scalar, if one exists. * Throws an exception if this scalar cannot be represented as a * {@code long} value.</p> * * @throws DScriptErr If this scalar does not have a {@code long} * representation. */ @DSInaccessible public abstract long longValue(); /** * <p>Returns a {@code float} representation of this scalar, if one exists. * Throws an exception if this scalar cannot be represented as a * {@code float} value.</p> * * @throws DScriptErr If this scalar does not have a {@code float} * representation. */ @DSInaccessible public abstract float floatValue(); /** * <p>Returns a {@code double} representation of this scalar, if one * exists. Throws an exception if this scalar cannot be represented as * a {@code double} value.</p> * * @throws DScriptErr If this scalar does not have a {@code double} * representation. * @since 0.11.10.0 */ @DSInaccessible public abstract double doubleValue(); /** * <p>Returns a {@link BigInteger} representation of this scalar, if one * exists. Throws an exception if this scalar cannot be represented as * a {@code BigInteger} value.</p> * * @throws DScriptErr If this scalar does not have a {@code BigInteger} * representation. * @since 4.13.1.0 */ @DSInaccessible public abstract BigInteger bigIntegerValue(); /** * <p>Returns a {@link BigDecimal} representation of this scalar, if one * exists. Throws an exception if this scalar cannot be represented as * a {@code BigDecimal} value.</p> * * @throws DScriptErr If this scalar does not have a {@code BigDecimal} * representation. * @since 4.13.1.0 */ @DSInaccessible public abstract BigDecimal bigDecimalValue(); @DSInaccessible public final Object valueFor(int nType) { switch (nType) { case BOOL: return booleanValue(); case SHORT_INT: return intValue(); case LONG_INT: return longValue(); case SHORT_FLOAT: return floatValue(); case LONG_FLOAT: return doubleValue(); case REAL_INT: return bigIntegerValue(); case REAL_DECIMAL: return bigDecimalValue(); default: return null; } } @DSInaccessible public final DS_Scalar castTo(int nType) { if (nType == getNumberType()) return this; else switch (nType) { case BOOL: return DS_Boolean.box(booleanValue()); case SHORT_INT: return ScalarFactory.fromNumber(intValue(), nType); case LONG_INT: return ScalarFactory.fromNumber(longValue(), nType); case SHORT_FLOAT: return ScalarFactory.fromNumber(floatValue(), nType); case LONG_FLOAT: return ScalarFactory.fromNumber(doubleValue(), nType); case REAL_INT: return ScalarFactory.fromNumber(bigIntegerValue(), nType); case REAL_DECIMAL: return ScalarFactory.fromNumber(bigDecimalValue(), nType); default: return null; } } }