package com.oracle.truffle.js.nodes.binary;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.instrumentation.Tag;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.js.nodes.JavaScriptNode;
import com.oracle.truffle.js.nodes.cast.JSToPrimitiveNode;
import com.oracle.truffle.js.nodes.cast.JSToStringOrNumberNode;
import com.oracle.truffle.js.runtime.BigInt;
import com.oracle.truffle.js.runtime.Boundaries;
import com.oracle.truffle.js.runtime.JSRuntime;
import com.oracle.truffle.js.runtime.SafeInteger;
import java.util.Set;
@NodeInfo(shortName = "<")
public abstract class JSLessThanNode extends JSCompareNode {
protected JSLessThanNode(JavaScriptNode left, JavaScriptNode right) {
super(left, right);
}
public static JSLessThanNode create(JavaScriptNode left, JavaScriptNode right) {
return JSLessThanNodeGen.create(left, right);
}
public static JSLessThanNode create() {
return JSLessThanNodeGen.create(null, null);
}
public abstract boolean executeBoolean(Object a, Object b);
@Specialization
protected boolean doInt(int a, int b) {
return a < b;
}
@Specialization
protected boolean doSafeInteger(int a, SafeInteger b) {
return a < b.longValue();
}
@Specialization
protected boolean doSafeInteger(SafeInteger a, int b) {
return a.longValue() < b;
}
@Specialization
protected boolean doSafeInteger(SafeInteger a, SafeInteger b) {
return a.longValue() < b.longValue();
}
@Specialization
protected boolean doDouble(double a, double b) {
return a < b;
}
@Specialization
protected boolean doString(String a, String b) {
return Boundaries.stringCompareTo(a, b) < 0;
}
@Specialization
protected boolean doStringDouble(String a, double b) {
return doDouble(stringToDouble(a), b);
}
@Specialization
protected boolean doDoubleString(double a, String b) {
return doDouble(a, stringToDouble(b));
}
@Specialization
protected boolean doStringBigInt(String a, BigInt b) {
BigInt aBigInt = JSRuntime.stringToBigInt(a);
return (aBigInt == null) ? false : doBigInt(aBigInt, b);
}
@Specialization
protected boolean doBigIntString(BigInt a, String b) {
BigInt bBigInt = JSRuntime.stringToBigInt(b);
return (bBigInt == null) ? false : doBigInt(a, bBigInt);
}
@Specialization
protected boolean doBigInt(BigInt a, BigInt b) {
return a.compareTo(b) < 0;
}
@Specialization
protected boolean doBigIntAndInt(BigInt a, int b) {
return a.compareTo(BigInt.valueOf(b)) < 0;
}
@Specialization
protected boolean doBigIntAndNumber(BigInt a, double b) {
if (Double.isNaN(b)) {
return false;
}
return a.compareValueTo(b) < 0;
}
@Specialization
protected boolean doIntAndBigInt(int a, BigInt b) {
return b.compareTo(BigInt.valueOf(a)) > 0;
}
@Specialization
protected boolean doNumberAndBigInt(double a, BigInt b) {
if (Double.isNaN(a)) {
return false;
}
return b.compareValueTo(a) > 0;
}
@Specialization(guards = {"isJavaNumber(a)", "isJavaNumber(b)"})
protected boolean doJavaNumber(Object a, Object b) {
return doDouble(JSRuntime.doubleValue((Number) a), JSRuntime.doubleValue((Number) b));
}
@Specialization(replaces = {"doInt", "doDouble", "doString", "doStringDouble", "doDoubleString", "doBigInt", "doBigIntAndNumber", "doNumberAndBigInt", "doJavaNumber"})
protected boolean doGeneric(Object a, Object b,
@Cached("create()") JSToStringOrNumberNode toStringOrNumber1,
@Cached("createHintNumber()") JSToPrimitiveNode toPrimitive1,
@Cached("create()") JSToStringOrNumberNode toStringOrNumber2,
@Cached("createHintNumber()") JSToPrimitiveNode toPrimitive2,
@Cached("create()") JSLessThanNode lessThanNode) {
return lessThanNode.executeBoolean(toStringOrNumber1.execute(toPrimitive1.execute(a)), toStringOrNumber2.execute(toPrimitive2.execute(b)));
}
@Override
protected JavaScriptNode copyUninitialized(Set<Class<? extends Tag>> materializedTags) {
return JSLessThanNodeGen.create(cloneUninitialized(getLeft(), materializedTags), cloneUninitialized(getRight(), materializedTags));
}
}