package com.oracle.truffle.js.nodes.access;
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.object.DynamicObject;
import com.oracle.truffle.api.profiles.ConditionProfile;
import com.oracle.truffle.js.nodes.JavaScriptNode;
import com.oracle.truffle.js.nodes.function.JSFunctionCallNode;
import com.oracle.truffle.js.nodes.unary.IsCallableNode;
import com.oracle.truffle.js.runtime.Errors;
import com.oracle.truffle.js.runtime.JSContext;
import com.oracle.truffle.js.runtime.Symbol;
import com.oracle.truffle.js.runtime.builtins.JSFunction;
import com.oracle.truffle.js.runtime.builtins.JSOrdinary;
import com.oracle.truffle.js.runtime.objects.IteratorRecord;
import com.oracle.truffle.js.runtime.objects.JSDynamicObject;
import com.oracle.truffle.js.runtime.objects.Undefined;
import java.util.Set;
public abstract class GetAsyncIteratorNode extends GetIteratorNode {
@Child private PropertySetNode setState;
@Child private GetMethodNode getIteratorMethodNode;
@Child private GetMethodNode getAsyncIteratorMethodNode;
private final ConditionProfile asyncToSync = ConditionProfile.createBinaryProfile();
protected GetAsyncIteratorNode(JSContext context, JavaScriptNode objectNode) {
super(context, objectNode);
this.setState = PropertySetNode.createSetHidden(JSFunction.ASYNC_FROM_SYNC_ITERATOR_KEY, context);
this.getAsyncIteratorMethodNode = GetMethodNode.create(context, null, Symbol.SYMBOL_ASYNC_ITERATOR);
}
@Override
@Specialization(guards = {"!isForeignObject(iteratedObject)"})
protected IteratorRecord doGetIterator(Object iteratedObject,
@Cached("create()") IsCallableNode isCallableNode,
@Cached("createCall()") JSFunctionCallNode methodCallNode,
@Cached("create()") IsJSObjectNode isObjectNode) {
Object method = getAsyncIteratorMethodNode.executeWithTarget(iteratedObject);
if (asyncToSync.profile(method == Undefined.instance)) {
Object syncMethod = getIteratorMethodNode().executeWithTarget(iteratedObject);
IteratorRecord syncIteratorRecord = getIterator(iteratedObject, syncMethod, isCallableNode, methodCallNode, isObjectNode);
DynamicObject asyncIterator = createAsyncFromSyncIterator(syncIteratorRecord);
return IteratorRecord.create(asyncIterator, getNextMethodNode.getValue(asyncIterator), false);
}
return getIterator(iteratedObject, method, isCallableNode, methodCallNode, isObjectNode);
}
@Override
protected JavaScriptNode copyUninitialized(Set<Class<? extends Tag>> materializedTags) {
return GetAsyncIteratorNodeGen.create(context, cloneUninitialized(objectNode, materializedTags));
}
private DynamicObject createAsyncFromSyncIterator(IteratorRecord syncIteratorRecord) {
DynamicObject syncIterator = syncIteratorRecord.getIterator();
if (!JSDynamicObject.isJSDynamicObject(syncIterator)) {
throw Errors.createTypeErrorNotAnObject(syncIterator, this);
}
DynamicObject obj = JSOrdinary.create(context, context.getAsyncFromSyncIteratorFactory());
setState.setValue(obj, syncIteratorRecord);
return obj;
}
}