fcl/types/Num.java
2021-06-25 13:57:34 +02:00

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;
}
}