/* --------------------------------------------------------- *
* __________ 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;
}
}
}