mirror of
https://github.com/zeroflag/fcl.git
synced 2025-01-11 20:01:10 +01:00
260 lines
8.9 KiB
Java
260 lines
8.9 KiB
Java
package com.vectron.fcl.types;
|
|
|
|
import com.vectron.fcl.exceptions.NotUnderstood;
|
|
import com.vectron.fcl.exceptions.TypeMismatched;
|
|
|
|
import java.text.NumberFormat;
|
|
import java.util.Objects;
|
|
|
|
import static com.vectron.fcl.Fcl.STRICT;
|
|
|
|
public class Num implements Obj, LogicOperand, ArithmeticOperand {
|
|
public static final Num ZERO = new Num(0);
|
|
public static final Num ONE = new Num(1);
|
|
public static final Num NAN = new Num(Double.NaN);
|
|
private static final NumberFormat format = NumberFormat.getNumberInstance();
|
|
private final Number value;
|
|
|
|
static {
|
|
format.setMaximumFractionDigits(4);
|
|
format.setGroupingUsed(false);
|
|
format.setParseIntegerOnly(false);
|
|
}
|
|
|
|
public Num(Number value) {
|
|
if (value instanceof Integer)
|
|
this.value = ((Integer)value).longValue();
|
|
else
|
|
this.value = value;
|
|
}
|
|
|
|
public static Num parse(String str) {
|
|
try {
|
|
return new Num(Long.parseLong(str));
|
|
} catch (NumberFormatException e1) {
|
|
try {
|
|
return new Num(Double.parseDouble(str));
|
|
} catch (NumberFormatException e2) {
|
|
throw new NotUnderstood("Undefined word: " + str);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
if (value instanceof Long) {
|
|
return Long.toString((Long) value);
|
|
} else if (value instanceof Double) {
|
|
return format.format(value);
|
|
}
|
|
return value.toString();
|
|
}
|
|
|
|
@Override
|
|
public Obj add(Obj other) {
|
|
if (value instanceof Long && other.value() instanceof Long)
|
|
return new Num((Long) value + (Long)other.value());
|
|
else if (value instanceof Long && other.value() instanceof Double)
|
|
return new Num((Long) value + (Double)other.value());
|
|
else if (value instanceof Double && other.value() instanceof Long)
|
|
return new Num((Double) value + (Long)other.value());
|
|
else if (value instanceof Double && other.value() instanceof Double)
|
|
return new Num((Double) value + (Double) other.value());
|
|
else if (other instanceof Lst)
|
|
return ((Lst) other).add(this);
|
|
else if (STRICT)
|
|
throw new TypeMismatched("+", this, other);
|
|
return Num.NAN;
|
|
}
|
|
|
|
@Override
|
|
public Obj sub(Obj other) {
|
|
if (value instanceof Long && other.value() instanceof Long)
|
|
return new Num((Long) value - (Long)other.value());
|
|
else if (value instanceof Long && other.value() instanceof Double)
|
|
return new Num((Long) value - (Double)other.value());
|
|
else if (value instanceof Double && other.value() instanceof Long)
|
|
return new Num((Double) value - (Long)other.value());
|
|
else if (value instanceof Double && other.value() instanceof Double)
|
|
return new Num((Double) value - (Double) other.value());
|
|
else if (STRICT)
|
|
throw new TypeMismatched("-", this, other);
|
|
return Num.NAN;
|
|
}
|
|
|
|
@Override
|
|
public Obj mul(Obj other) {
|
|
if (value instanceof Long && other.value() instanceof Long)
|
|
return new Num((Long) value * (Long)other.value());
|
|
else if (value instanceof Long && other.value() instanceof Double)
|
|
return new Num((Long) value * (Double)other.value());
|
|
else if (value instanceof Double && other.value() instanceof Long)
|
|
return new Num((Double) value * (Long)other.value());
|
|
else if (value instanceof Double && other.value() instanceof Double)
|
|
return new Num((Double) value * (Double) other.value());
|
|
else if (other instanceof Lst)
|
|
return ((Lst) other).mul(this);
|
|
else if (other instanceof Str)
|
|
return ((Str) other).mul(this);
|
|
else if (STRICT)
|
|
throw new TypeMismatched("*", this, other);
|
|
return Num.NAN;
|
|
}
|
|
|
|
@Override
|
|
public Obj div(Obj other) {
|
|
if (value instanceof Long && other.value() instanceof Long)
|
|
return new Num(((Long) value).doubleValue() / (Long) other.value());
|
|
else if (value instanceof Long && other.value() instanceof Double)
|
|
return new Num((Long) value / (Double)other.value());
|
|
else if (value instanceof Double && other.value() instanceof Long)
|
|
return new Num((Double) value / (Long)other.value());
|
|
else if (value instanceof Double && other.value() instanceof Double)
|
|
return new Num((Double) value / (Double) other.value());
|
|
else if (STRICT)
|
|
throw new TypeMismatched("/", this, other);
|
|
return Num.NAN;
|
|
}
|
|
|
|
public Num power(Num exponent) {
|
|
if (value instanceof Long && exponent.value instanceof Long)
|
|
return new Num(Math.pow(((Long) value).doubleValue(), ((Long) exponent.value).doubleValue()));
|
|
else if (value instanceof Long && exponent.value instanceof Double)
|
|
return new Num(Math.pow(((Long) value).doubleValue(), exponent.doubleValue()));
|
|
else if (value instanceof Double && exponent.value instanceof Long)
|
|
return new Num(Math.pow((Double)value, ((Long) exponent.value).doubleValue()));
|
|
else if (value instanceof Double && exponent.value instanceof Double)
|
|
return new Num(Math.pow((Double)value, exponent.doubleValue()));
|
|
else if (STRICT)
|
|
throw new TypeMismatched("POW", this, exponent);
|
|
return Num.NAN;
|
|
}
|
|
|
|
public Num mod(Num other) {
|
|
try {
|
|
return new Num(this.longValue() % other.longValue());
|
|
} catch (TypeMismatched e) {
|
|
if (STRICT) throw e;
|
|
return Num.NAN;
|
|
}
|
|
}
|
|
|
|
public Num intDiv(Num other) {
|
|
try {
|
|
return new Num(this.longValue() / other.longValue());
|
|
} catch (TypeMismatched e) {
|
|
if (STRICT) throw e;
|
|
return Num.NAN;
|
|
}
|
|
}
|
|
|
|
public Num round() {
|
|
if (value instanceof Long)
|
|
return this;
|
|
else if (value instanceof Double)
|
|
return new Num(Math.round(doubleValue()));
|
|
else if (STRICT)
|
|
throw new TypeMismatched("ROUND", this);
|
|
return Num.NAN;
|
|
}
|
|
|
|
@Override
|
|
public Num and(Obj other) {
|
|
if (value instanceof Long && other.value() instanceof Long)
|
|
return new Num((Long)value & other.longValue());
|
|
else if (STRICT)
|
|
throw new TypeMismatched("AND", this, other);
|
|
return Num.NAN;
|
|
}
|
|
|
|
@Override
|
|
public Num or(Obj other) {
|
|
if (value instanceof Long && other.value() instanceof Long)
|
|
return new Num((Long)value | other.longValue());
|
|
else if (STRICT)
|
|
throw new TypeMismatched("OR", this, other);
|
|
return Num.NAN;
|
|
}
|
|
|
|
@Override
|
|
public Num not() {
|
|
if (value instanceof Long)
|
|
return new Num(~(Long)value );
|
|
else if (STRICT)
|
|
throw new TypeMismatched("Unsupported types for NOT operator: " + value.getClass());
|
|
return Num.NAN;
|
|
}
|
|
|
|
public Bool greater(Num other) {
|
|
if (value instanceof Long && other.value instanceof Long)
|
|
return (Long) value > (Long)other.value ? Bool.TRUE : Bool.FALSE;
|
|
else if (value instanceof Long && other.value instanceof Double)
|
|
return (Long) value > (Double)other.value ? Bool.TRUE : Bool.FALSE;
|
|
else if (value instanceof Double && other.value instanceof Long)
|
|
return (Double) value > (Long)other.value ? Bool.TRUE : Bool.FALSE;
|
|
else if (value instanceof Double && other.value instanceof Double)
|
|
return (Double) value > (Double) other.value ? Bool.TRUE : Bool.FALSE;
|
|
else
|
|
throw new TypeMismatched("<", this, other);
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object o) {
|
|
if (this == o) return true;
|
|
if (o == null || getClass() != o.getClass()) return false;
|
|
Num num = (Num) o;
|
|
return value.equals(num.value);
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
return Objects.hash(value);
|
|
}
|
|
|
|
@Override
|
|
public long longValue() {
|
|
if (value instanceof Long)
|
|
return (Long) value;
|
|
else if (value instanceof Double)
|
|
return Math.round((Double) value);
|
|
else
|
|
throw new TypeMismatched(this, "long");
|
|
}
|
|
|
|
@Override
|
|
public int intValue() {
|
|
return ((Number)value).intValue();
|
|
}
|
|
|
|
@Override
|
|
public boolean boolValue() {
|
|
throw new TypeMismatched(this, "bool");
|
|
}
|
|
|
|
@Override
|
|
public Num asNum() {
|
|
return this;
|
|
}
|
|
|
|
@Override
|
|
public Str asStr() {
|
|
return new Str(toString());
|
|
}
|
|
|
|
@Override
|
|
public double doubleValue() {
|
|
return ((Number)value).doubleValue();
|
|
}
|
|
|
|
@Override
|
|
public Object value() {
|
|
return value;
|
|
}
|
|
|
|
@Override
|
|
public int compareTo(Obj other) {
|
|
return other instanceof Num
|
|
? Double.compare(doubleValue(), ((Num) other).doubleValue())
|
|
: -1;
|
|
}
|
|
}
|