package com.oracle.truffle.js.nodes.interop;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.CachedLanguage;
import com.oracle.truffle.api.dsl.GenerateUncached;
import com.oracle.truffle.api.dsl.ImportStatic;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.js.lang.JavaScriptLanguage;
import com.oracle.truffle.js.nodes.JSGuards;
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.builtins.JSFunction;
import com.oracle.truffle.js.runtime.builtins.JSFunctionObject;
import com.oracle.truffle.js.runtime.interop.InteropAsyncFunction;
import com.oracle.truffle.js.runtime.interop.InteropBoundFunction;
import com.oracle.truffle.js.runtime.objects.JSLazyString;
import com.oracle.truffle.js.runtime.objects.Undefined;
@ImportStatic({JSGuards.class, JSFunction.class})
@GenerateUncached
public abstract class ExportValueNode extends JavaScriptBaseNode {
ExportValueNode() {
}
public final Object execute(Object value) {
return execute(value, Undefined.instance, false);
}
public abstract Object execute(Object value, Object thiz, boolean bindMemberFunctions);
public static boolean isInteropCompletePromises(JavaScriptLanguage lang) {
return lang.getJSContext().getContextOptions().interopCompletePromises();
}
@Specialization(guards = {"!bindFunctions", "!isInteropCompletePromises(language) || !isAsyncFunction(function)"})
protected static DynamicObject doFunctionNoBind(JSFunctionObject function, @SuppressWarnings("unused") Object thiz, @SuppressWarnings("unused") boolean bindFunctions,
@CachedLanguage @SuppressWarnings("unused") JavaScriptLanguage language) {
return function;
}
@Specialization(guards = {"bindFunctions", "isUndefined(thiz)", "!isInteropCompletePromises(language) || !isAsyncFunction(function)"})
protected static DynamicObject doFunctionUndefinedThis(JSFunctionObject function, @SuppressWarnings("unused") Object thiz, @SuppressWarnings("unused") boolean bindFunctions,
@CachedLanguage @SuppressWarnings("unused") JavaScriptLanguage language) {
return function;
}
@Specialization(guards = {"bindFunctions", "!isUndefined(thiz)", "!isBoundJSFunction(function)", "!isInteropCompletePromises(language) || !isAsyncFunction(function)"})
protected static TruffleObject doBindUnboundFunction(JSFunctionObject function, Object thiz, @SuppressWarnings("unused") boolean bindFunctions,
@CachedLanguage @SuppressWarnings("unused") JavaScriptLanguage language) {
return new InteropBoundFunction(function, thiz);
}
@Specialization(guards = {"bindFunctions", "isBoundJSFunction(function)", "!isInteropCompletePromises(language) || !isAsyncFunction(function)"})
protected static DynamicObject doBoundFunction(JSFunctionObject function, @SuppressWarnings("unused") Object thiz, @SuppressWarnings("unused") boolean bindFunctions,
@CachedLanguage @SuppressWarnings("unused") JavaScriptLanguage language) {
return function;
}
@Specialization(guards = {"isInteropCompletePromises(language)", "isAsyncFunction(function)"})
protected static TruffleObject doAsyncFunction(JSFunctionObject function, @SuppressWarnings("unused") Object thiz, @SuppressWarnings("unused") boolean bindFunctions,
@CachedLanguage @SuppressWarnings("unused") JavaScriptLanguage language) {
return new InteropAsyncFunction(function);
}
@Specialization
protected static double doSafeInteger(SafeInteger value, @SuppressWarnings("unused") Object thiz, @SuppressWarnings("unused") boolean bindFunctions) {
return value.doubleValue();
}
@Specialization(guards = {"!isJSFunction(value)"})
protected static DynamicObject doObject(DynamicObject value, @SuppressWarnings("unused") Object thiz, @SuppressWarnings("unused") boolean bindFunctions) {
return value;
}
@Specialization
protected static int doInt(int value, @SuppressWarnings("unused") Object thiz, @SuppressWarnings("unused") boolean bindFunctions) {
return value;
}
@Specialization
protected static long doLong(long value, @SuppressWarnings("unused") Object thiz, @SuppressWarnings("unused") boolean bindFunctions) {
return value;
}
@Specialization
protected static double doDouble(double value, @SuppressWarnings("unused") Object thiz, @SuppressWarnings("unused") boolean bindFunctions) {
return value;
}
@Specialization
protected static boolean doBoolean(boolean value, @SuppressWarnings("unused") Object thiz, @SuppressWarnings("unused") boolean bindFunctions) {
return value;
}
@Specialization
protected static BigInt doBigInt(BigInt value, @SuppressWarnings("unused") Object thiz, @SuppressWarnings("unused") boolean bindFunctions) {
return value;
}
@Specialization
protected static String doString(String value, @SuppressWarnings("unused") Object thiz, @SuppressWarnings("unused") boolean bindFunctions) {
return value;
}
@Specialization(guards = {"!isJSFunction(value)"}, replaces = "doObject")
protected static TruffleObject doTruffleObject(TruffleObject value, @SuppressWarnings("unused") Object thiz, @SuppressWarnings("unused") boolean bindFunctions) {
return value;
}
@TruffleBoundary
@Specialization(guards = {"!isTruffleObject(thiz)", "!isString(thiz)", "!isBoolean(thiz)", "!isNumberDouble(thiz)", "!isNumberLong(thiz)", "!isNumberInteger(thiz)"})
protected static Object doOther(Object value, @SuppressWarnings("unused") Object thiz, @SuppressWarnings("unused") boolean bindFunctions) {
throw Errors.createTypeErrorFormat("Cannot convert to TruffleObject: %s", value == null ? null : value.getClass().getSimpleName());
}
public static ExportValueNode create() {
return ExportValueNodeGen.create();
}
public static ExportValueNode getUncached() {
return ExportValueNodeGen.getUncached();
}
}