2 * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
3 * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "IteratorOperations.h"
30 #include "CatchScope.h"
32 #include "JSCInlines.h"
33 #include "ObjectConstructor.h"
39 JSValue iteratorNext(ExecState* exec, IterationRecord iterationRecord, JSValue argument)
42 auto scope = DECLARE_THROW_SCOPE(vm);
44 JSValue iterator = iterationRecord.iterator;
45 JSValue nextFunction = iterationRecord.nextMethod;
47 CallData nextFunctionCallData;
48 CallType nextFunctionCallType = getCallData(nextFunction, nextFunctionCallData);
49 if (nextFunctionCallType == CallType::None)
50 return throwTypeError(exec, scope);
52 MarkedArgumentBuffer nextFunctionArguments;
53 if (!argument.isEmpty())
54 nextFunctionArguments.append(argument);
55 JSValue result = call(exec, nextFunction, nextFunctionCallType, nextFunctionCallData, iterator, nextFunctionArguments);
56 RETURN_IF_EXCEPTION(scope, JSValue());
58 if (!result.isObject())
59 return throwTypeError(exec, scope, ASCIILiteral("Iterator result interface is not an object."));
64 JSValue iteratorValue(ExecState* exec, JSValue iterResult)
66 return iterResult.get(exec, exec->vm().propertyNames->value);
69 bool iteratorComplete(ExecState* exec, JSValue iterResult)
71 JSValue done = iterResult.get(exec, exec->vm().propertyNames->done);
72 return done.toBoolean(exec);
75 JSValue iteratorStep(ExecState* exec, IterationRecord iterationRecord)
78 auto scope = DECLARE_THROW_SCOPE(vm);
80 JSValue result = iteratorNext(exec, iterationRecord);
81 RETURN_IF_EXCEPTION(scope, JSValue());
82 bool done = iteratorComplete(exec, result);
83 RETURN_IF_EXCEPTION(scope, JSValue());
85 return jsBoolean(false);
89 void iteratorClose(ExecState* exec, IterationRecord iterationRecord)
92 auto throwScope = DECLARE_THROW_SCOPE(vm);
93 auto catchScope = DECLARE_CATCH_SCOPE(vm);
95 Exception* exception = nullptr;
96 if (UNLIKELY(catchScope.exception())) {
97 exception = catchScope.exception();
98 catchScope.clearException();
100 JSValue returnFunction = iterationRecord.iterator.get(exec, vm.propertyNames->returnKeyword);
101 RETURN_IF_EXCEPTION(throwScope, void());
103 if (returnFunction.isUndefined()) {
105 throwException(exec, throwScope, exception);
109 CallData returnFunctionCallData;
110 CallType returnFunctionCallType = getCallData(returnFunction, returnFunctionCallData);
111 if (returnFunctionCallType == CallType::None) {
113 throwException(exec, throwScope, exception);
115 throwTypeError(exec, throwScope);
119 MarkedArgumentBuffer returnFunctionArguments;
120 JSValue innerResult = call(exec, returnFunction, returnFunctionCallType, returnFunctionCallData, iterationRecord.iterator, returnFunctionArguments);
123 throwException(exec, throwScope, exception);
127 RETURN_IF_EXCEPTION(throwScope, void());
129 if (!innerResult.isObject()) {
130 throwTypeError(exec, throwScope, ASCIILiteral("Iterator result interface is not an object."));
135 static const PropertyOffset donePropertyOffset = 0;
136 static const PropertyOffset valuePropertyOffset = 1;
138 Structure* createIteratorResultObjectStructure(VM& vm, JSGlobalObject& globalObject)
140 Structure* iteratorResultStructure = vm.prototypeMap.emptyObjectStructureForPrototype(&globalObject, globalObject.objectPrototype(), JSFinalObject::defaultInlineCapacity());
141 PropertyOffset offset;
142 iteratorResultStructure = Structure::addPropertyTransition(vm, iteratorResultStructure, vm.propertyNames->done, 0, offset);
143 RELEASE_ASSERT(offset == donePropertyOffset);
144 iteratorResultStructure = Structure::addPropertyTransition(vm, iteratorResultStructure, vm.propertyNames->value, 0, offset);
145 RELEASE_ASSERT(offset == valuePropertyOffset);
146 return iteratorResultStructure;
149 JSObject* createIteratorResultObject(ExecState* exec, JSValue value, bool done)
152 JSObject* resultObject = constructEmptyObject(exec, exec->lexicalGlobalObject()->iteratorResultObjectStructure());
153 resultObject->putDirect(vm, donePropertyOffset, jsBoolean(done));
154 resultObject->putDirect(vm, valuePropertyOffset, value);
158 bool hasIteratorMethod(ExecState& state, JSValue value)
160 auto& vm = state.vm();
161 auto scope = DECLARE_THROW_SCOPE(vm);
163 if (!value.isObject())
166 JSObject* object = asObject(value);
169 JSValue applyMethod = object->getMethod(&state, callData, callType, vm.propertyNames->iteratorSymbol, ASCIILiteral("Symbol.iterator property should be callable"));
170 RETURN_IF_EXCEPTION(scope, false);
172 return !applyMethod.isUndefined();
175 JSValue iteratorMethod(ExecState& state, JSObject* object)
177 auto& vm = state.vm();
178 auto scope = DECLARE_THROW_SCOPE(vm);
182 JSValue method = object->getMethod(&state, callData, callType, vm.propertyNames->iteratorSymbol, ASCIILiteral("Symbol.iterator property should be callable"));
183 RETURN_IF_EXCEPTION(scope, jsUndefined());
188 IterationRecord iteratorForIterable(ExecState& state, JSObject* object, JSValue iteratorMethod)
191 auto scope = DECLARE_THROW_SCOPE(vm);
193 CallData iteratorMethodCallData;
194 CallType iteratorMethodCallType = getCallData(iteratorMethod, iteratorMethodCallData);
195 if (iteratorMethodCallType == CallType::None) {
196 throwTypeError(&state, scope);
200 ArgList iteratorMethodArguments;
201 JSValue iterator = call(&state, iteratorMethod, iteratorMethodCallType, iteratorMethodCallData, object, iteratorMethodArguments);
202 RETURN_IF_EXCEPTION(scope, { });
204 if (!iterator.isObject()) {
205 throwTypeError(&state, scope);
209 JSValue nextMethod = iterator.getObject()->get(&state, vm.propertyNames->next);
210 RETURN_IF_EXCEPTION(scope, { });
212 return { iterator, nextMethod };
215 IterationRecord iteratorForIterable(ExecState* state, JSValue iterable)
217 VM& vm = state->vm();
218 auto scope = DECLARE_THROW_SCOPE(vm);
220 JSValue iteratorFunction = iterable.get(state, vm.propertyNames->iteratorSymbol);
221 RETURN_IF_EXCEPTION(scope, { });
223 CallData iteratorFunctionCallData;
224 CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData);
225 if (iteratorFunctionCallType == CallType::None) {
226 throwTypeError(state, scope);
230 ArgList iteratorFunctionArguments;
231 JSValue iterator = call(state, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments);
232 RETURN_IF_EXCEPTION(scope, { });
234 if (!iterator.isObject()) {
235 throwTypeError(state, scope);
239 JSValue nextMethod = iterator.getObject()->get(state, vm.propertyNames->next);
240 RETURN_IF_EXCEPTION(scope, { });
242 return { iterator, nextMethod };