package com.oracle.truffle.js.nodes.cast;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.js.nodes.JavaScriptBaseNode;
import com.oracle.truffle.js.runtime.BigInt;
import com.oracle.truffle.js.runtime.Errors;
import com.oracle.truffle.js.runtime.JSRuntime;
import com.oracle.truffle.js.runtime.SafeInteger;
import com.oracle.truffle.js.runtime.Symbol;
public abstract class JSToIntegerAsIntNode extends JavaScriptBaseNode {
@Child private JSToNumberNode toNumberNode;
public static JSToIntegerAsIntNode create() {
return JSToIntegerAsIntNodeGen.create();
}
public abstract int executeInt(Object operand);
@Specialization
protected static int doInteger(int value) {
return value;
}
@Specialization
protected static int doBoolean(boolean value) {
return JSRuntime.booleanToNumber(value);
}
@Specialization(guards = "isLongRepresentableAsInt32(value.longValue())")
protected static int doSafeIntegerInt32Range(SafeInteger value) {
return value.intValue();
}
@Specialization(guards = "!isLongRepresentableAsInt32(value.longValue())")
protected static int doSafeIntegerOther(SafeInteger value) {
if (value.isNegative()) {
return Integer.MIN_VALUE;
} else {
return Integer.MAX_VALUE;
}
}
protected static boolean inInt32Range(double value) {
return value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE;
}
@Specialization(guards = "inInt32Range(value)")
protected static int doDoubleInt32Range(double value) {
return (int) ((long) value & 0xFFFFFFFFL);
}
@Specialization(guards = "!inInt32Range(value)")
protected static int doDoubleOther(double value) {
if (Double.isNaN(value)) {
return 0;
} else if (value > 0) {
return Integer.MAX_VALUE;
} else {
return Integer.MIN_VALUE;
}
}
@Specialization(guards = "isUndefined(value)")
protected static int doUndefined(@SuppressWarnings("unused") Object value) {
return 0;
}
@Specialization(guards = "isJSNull(value)")
protected static int doNull(@SuppressWarnings("unused") Object value) {
return 0;
}
@Specialization
protected final int doSymbol(@SuppressWarnings("unused") Symbol value) {
throw Errors.createTypeErrorCannotConvertToNumber("a Symbol value", this);
}
@Specialization
protected final int doBigInt(@SuppressWarnings("unused") BigInt value) {
throw Errors.createTypeErrorCannotConvertToNumber("a BigInt value", this);
}
@Specialization
protected int doString(String value,
@Cached("create()") JSToIntegerAsIntNode nestedToIntegerNode,
@Cached("create()") JSStringToNumberNode stringToNumberNode) {
return nestedToIntegerNode.executeInt(stringToNumberNode.executeString(value));
}
@Specialization(guards = "isJSObject(value)")
protected int doJSObject(DynamicObject value) {
return JSRuntime.toInt32(getToNumberNode().executeNumber(value));
}
@Specialization(guards = "isForeignObject(object)")
protected int doForeignObject(Object object) {
return JSRuntime.toInt32(getToNumberNode().executeNumber(object));
}
private JSToNumberNode getToNumberNode() {
if (toNumberNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
toNumberNode = insert(JSToNumberNode.create());
}
return toNumberNode;
}
}