// 25.4.2.2 PromiseResolveThenableTask ( promiseToResolve, thenable, then) static void PromiseResolveThenableTask (ejsval promiseToResolve, ejsval thenable, ejsval then) { // 1. Let resolvingFunctions be CreateResolvingFunctions(promiseToResolve). ejsval resolvingFunctions_resolve; ejsval resolvingFunctions_reject; CreateResolvingFunctions(promiseToResolve, &resolvingFunctions_resolve, &resolvingFunctions_reject); // 2. Let thenCallResult be the result of calling the [[Call]] internal method of then passing thenable as the thisArgument and (resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]]) as argumentsList. ejsval thenCallResult; ejsval args[] = { resolvingFunctions_resolve, resolvingFunctions_reject }; EJSBool success = _ejs_invoke_closure_catch(&thenCallResult, then, thenable, 2, args); // 3. If thenCallResult is an abrupt completion, if (!success) { // a. Let status be the result of calling the [[Call]] internal method of resolvingFunctions.[[Reject]] passing undefined as the thisArgument and (thenCallResult.[[value]]) as argumentsList. ejsval status; success = _ejs_invoke_closure_catch(&status, resolvingFunctions_reject, _ejs_undefined, 1, &thenCallResult); // b. NextTask status. EJS_NOT_IMPLEMENTED(); } // 4. NextTask thenCallResult. EJS_NOT_IMPLEMENTED(); }
// 25.4.3.1 Promise ( executor ) static ejsval _ejs_Promise_impl (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { ejsval executor = _ejs_undefined; if (argc > 0) executor = args[0]; // 1. Let promise be the this value. ejsval promise = _this; // 2. If Type(promise) is not Object, then throw a TypeError exception. if (!EJSVAL_IS_OBJECT(promise)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "`this' is not an object"); // 3. If promise does not have a [[PromiseState]] internal slot, then throw a TypeError exception. if (!EJSVAL_IS_PROMISE(promise)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "`this' is not an promise"); EJSPromise* _promise = EJSVAL_TO_PROMISE(promise); // 4. If promise's [[PromiseState]] internal slot is not undefined, then throw a TypeError exception. if (_promise->state != PROMISE_STATE_UNINITIALIZED) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Promise constructor called on previously created object"); // 5. If IsCallable(executor) is false, then throw a TypeError exception. if (!EJSVAL_IS_CALLABLE(executor)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "executor is not callable"); // 6. Return InitializePromise(promise, executor). // 1. Assert: promise has a [[PromiseState]] internal slot and it’s value is undefined. // 2. Assert: IsCallable(executor) is true. // 3. Set promise's [[PromiseState]] internal slot to "pending". _promise->state = PROMISE_STATE_PENDING; // 4. Set promise's [[PromiseFulfillReactions]] internal slot to a new empty List. _promise->fulfillReactions = NULL; // 5. Set promise's [[PromiseRejectReactions]] internal slot to a new empty List. _promise->rejectReactions = NULL; // 6. Let resolvingFunctions be CreateResolvingFunctions(promise). ejsval resolvingFunctions_resolve; ejsval resolvingFunctions_reject; CreateResolvingFunctions(promise, &resolvingFunctions_resolve, &resolvingFunctions_reject); // 7. Let completion be the result of calling the [[Call]] internal method of executor with undefined as thisArgument and (resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]]) a argumentsList. ejsval completion; ejsval executor_args[] = { resolvingFunctions_resolve, resolvingFunctions_reject }; EJSBool success = _ejs_invoke_closure_catch(&completion, executor, _ejs_undefined, 2, executor_args); // 8. If completion is an abrupt completion, then if (!success) { // a. Let status be the result of calling the [[Call]] internal method of resolvingFunctions.[[Reject]] with undefined as thisArgument and (completion.[[value]]) as argumentsList. // b. ReturnIfAbrupt(status). _ejs_invoke_closure(resolvingFunctions_reject, _ejs_undefined, 1, &completion); } // 9. Return promise. return promise; }
// 25.4.2.1 PromiseReactionTask ( reaction, argument ) static void PromiseReactionTask (EJSPromiseReaction* reaction, ejsval argument) { // 1. Assert: reaction is a PromiseReaction Record. // 2. Let promiseCapability be reaction.[[Capabilities]]. ejsval promiseCapability = reaction->capabilities; // 3. Let handler be reaction.[[Handler]]. ejsval handler = reaction->handler; EJSBool success; ejsval handlerResult = _ejs_undefined; // 4. If handler is "Identity", then let handlerResult be NormalCompletion(argument). if (SameValue(handler, _ejs_identity_function)) { success = EJS_TRUE; handlerResult = argument; } // 5. Else If handler is "Thrower", then let handlerResult be Completion{[[type]]: throw, [[value]]: argument, [[target]]: empty}. if (SameValue(handler, _ejs_thrower_function)) { success = EJS_FALSE; handlerResult = argument; } // 6. Else, Let let handlerResult be the result of calling the [[Call]] internal method of handler passing undefined as thisArgument and (argument) as argumentsList. else success = _ejs_invoke_closure_catch(&handlerResult, handler, _ejs_undefined, 1, &argument); ejsval status; // 7. If handlerResult is an abrupt completion, then if (!success) { // a. Let status be the result of calling the [[Call]] internal method of promiseCapability.[[Reject]] passing undefined as thisArgument and (handlerResult.[[value]]) as argumentsList. success = _ejs_invoke_closure_catch(&status, EJS_CAPABILITY_GET_REJECT(promiseCapability), _ejs_undefined, 1, &handlerResult); // b. NextTask status. return;//EJS_NOT_IMPLEMENTED(); } // 8. Let handlerResult be handlerResult.[[value]]. // 9. Let status be the result of calling the [[Call]] internal method of promiseCapability.[[Resolve]] passing undefined as thisArgument and (handlerResult) as argumentsList. success = _ejs_invoke_closure_catch(&status, EJS_CAPABILITY_GET_RESOLVE(promiseCapability), _ejs_undefined, 1, &handlerResult); // 10. NextTask status. }
// ECMA262 25.4.4.3 Promise.race ( iterable ) static ejsval _ejs_Promise_race (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { EJSBool success; ejsval iterable = _ejs_undefined; if (argc > 0) iterable = args[0]; // 1. Let C be the this value. ejsval C = _this; // 2. Let promiseCapability be NewPromiseCapability(C). // 3. ReturnIfAbrupt(promiseCapability). ejsval promiseCapability = NewPromiseCapability(C); // 4. Let iterator be GetIterator(iterable). ejsval iterator; success = GetIteratorP(&iterator, iterable); // 5. IfAbruptRejectPromise(iterator, promiseCapability). if (!success) { _ejs_invoke_closure(EJS_CAPABILITY_GET_REJECT(promiseCapability), _ejs_undefined, 1, &iterator); return EJS_CAPABILITY_GET_PROMISE(promiseCapability); } // 6. Repeat while (EJS_TRUE) { ejsval next; // a. Let next be IteratorStep(iterator). EJSBool success = IteratorStepP(&next, iterator); // b. IfAbruptRejectPromise(next, promiseCapability). if (!success) { _ejs_invoke_closure(EJS_CAPABILITY_GET_REJECT(promiseCapability), _ejs_undefined, 1, &next); return EJS_CAPABILITY_GET_PROMISE(promiseCapability); } // c. If next is false, return promiseCapability.[[Promise]]. if (EJSVAL_IS_BOOLEAN(next) && !EJSVAL_TO_BOOLEAN(next)) return EJS_CAPABILITY_GET_PROMISE(promiseCapability); // d. Let nextValue be IteratorValue(next). ejsval nextValue; success = IteratorValueP(&nextValue, next); // e. IfAbruptRejectPromise(nextValue, promiseCapability). if (!success) { _ejs_invoke_closure(EJS_CAPABILITY_GET_REJECT(promiseCapability), _ejs_undefined, 1, &nextValue); return EJS_CAPABILITY_GET_PROMISE(promiseCapability); } // f. Let nextPromise be Invoke(C, "resolve", (nextValue)). ejsval nextPromise; success = _ejs_invoke_closure_catch(&nextPromise, C, _ejs_atom_resolve, 1, &nextValue); // g. IfAbruptRejectPromise(nextPromise, promiseCapability). if (!success) { _ejs_invoke_closure(EJS_CAPABILITY_GET_REJECT(promiseCapability), _ejs_undefined, 1, &nextPromise); return EJS_CAPABILITY_GET_PROMISE(promiseCapability); } // h. Let result be Invoke(nextPromise, "then", (promiseCapability.[[Resolve]], promiseCapability.[[Reject]])). ejsval result; ejsval args[] = { EJS_CAPABILITY_GET_RESOLVE(promiseCapability), EJS_CAPABILITY_GET_REJECT(promiseCapability) }; success = _ejs_invoke_closure_catch(&result, nextPromise, _ejs_atom_then, 2, args); // i. IfAbruptRejectPromise(result, promiseCapability). if (!success) { _ejs_invoke_closure(EJS_CAPABILITY_GET_REJECT(promiseCapability), _ejs_undefined, 1, &result); return EJS_CAPABILITY_GET_PROMISE(promiseCapability); } } }
// ECMA262 25.4.4.1 Promise.all ( iterable ) static ejsval _ejs_Promise_all (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { EJSBool success; ejsval iterable = _ejs_undefined; if (argc > 0) iterable = args[0]; // 1. Let C be the this value. ejsval C = _this; // 2. Let promiseCapability be NewPromiseCapability(C). // 3. ReturnIfAbrupt(promiseCapability). ejsval promiseCapability = NewPromiseCapability(C); // 4. Let iterator be GetIterator(iterable). ejsval iterator; success = GetIteratorP(&iterator, iterable); // 5. IfAbruptRejectPromise(iterator, promiseCapability). if (!success) { _ejs_invoke_closure(EJS_CAPABILITY_GET_REJECT(promiseCapability), _ejs_undefined, 1, &iterator); return EJS_CAPABILITY_GET_PROMISE(promiseCapability); } // 6. Let values be ArrayCreate(0). ejsval values = _ejs_array_new(0, EJS_FALSE); // 7. Let remainingElementsCount be a new Record { [[value]]: 1 }. int remainingElementsCount = 1; // 8. Let index be 0. int index = 0; // 9. Repeat while (EJS_TRUE) { // a. Let next be IteratorStep(iterator). ejsval next; success = IteratorStepP(&next, iterator); // b. IfAbruptRejectPromise(next, promiseCapability). if (!success) { _ejs_invoke_closure(EJS_CAPABILITY_GET_REJECT(promiseCapability), _ejs_undefined, 1, &next); return EJS_CAPABILITY_GET_PROMISE(promiseCapability); } // c. If next is false, if (EJSVAL_IS_BOOLEAN(next) && !EJSVAL_TO_BOOLEAN(next)) { // i. Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] - 1. remainingElementsCount --; // ii. If remainingElementsCount.[[value]] is 0, if (remainingElementsCount == 0) { // 1. Let resolveResult be the result of calling the [[Call]] internal method of promiseCapability.[[Resolve]] with undefined as thisArgument and (values) as argumentsList. ejsval resolveResult; success = _ejs_invoke_closure_catch(&resolveResult, EJS_CAPABILITY_GET_RESOLVE(promiseCapability), _ejs_undefined, 1, &values); // 2. ReturnIfAbrupt(resolveResult). if (!success) { _ejs_invoke_closure(EJS_CAPABILITY_GET_REJECT(promiseCapability), _ejs_undefined, 1, &resolveResult); return EJS_CAPABILITY_GET_PROMISE(promiseCapability); } } // iii. Return promiseCapability.[[Promise]]. return EJS_CAPABILITY_GET_PROMISE(promiseCapability); } // d. Let nextValue be IteratorValue(next). ejsval nextValue; success = IteratorValueP(&nextValue, next); // e. IfAbruptRejectPromise(nextValue, promiseCapability). if (!success) { _ejs_invoke_closure(EJS_CAPABILITY_GET_REJECT(promiseCapability), _ejs_undefined, 1, &nextValue); return EJS_CAPABILITY_GET_PROMISE(promiseCapability); } // f. Let nextPromise be Invoke(C, "resolve", (nextValue)). ejsval nextPromise; success = _ejs_invoke_closure_catch (&nextPromise, Get(C, _ejs_atom_resolve), C, 1, &nextValue); // g. IfAbruptRejectPromise(nextPromise, promiseCapability). if (!success) { _ejs_invoke_closure(EJS_CAPABILITY_GET_REJECT(promiseCapability), _ejs_undefined, 1, &nextPromise); return EJS_CAPABILITY_GET_PROMISE(promiseCapability); } // h. Let resolveElement be a new built-in function object as defined in Promise.all Resolve Element Functions. ejsval resolvingElement_env = _ejs_closureenv_new(6); ejsval resolveElement = _ejs_function_new_anon(resolvingElement_env, resolve_element); // i. Set the [[AlreadyCalled]] internal slot of resolveElement to false. EJS_RESOLVEELEMENT_SET_ALREADY_CALLED(resolvingElement_env, _ejs_false); // j. Set the [[Index]] internal slot of resolveElement to index. EJS_RESOLVEELEMENT_SET_INDEX(resolvingElement_env, NUMBER_TO_EJSVAL(index)); // k. Set the [[Values]] internal slot of resolveElement to values. EJS_RESOLVEELEMENT_SET_VALUES(resolvingElement_env, values); // l. Set the [[Capabilities]] internal slot of resolveElement to promiseCapability. EJS_RESOLVEELEMENT_SET_CAPABILITIES(resolvingElement_env, promiseCapability); // m. Set the [[RemainingElements]] internal slot of resolveElement to remainingElementsCount. EJS_RESOLVEELEMENT_SET_REMAINING_ELEMENTS(resolvingElement_env, NUMBER_TO_EJSVAL(remainingElementsCount)); // n. Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] + 1. remainingElementsCount++; // o. Let result be Invoke(nextPromise, "then", (resolveElement, promiseCapability.[[Reject]])). ejsval thenargs[] = { resolveElement, EJS_CAPABILITY_GET_REJECT(promiseCapability) }; ejsval result; success = _ejs_invoke_closure_catch (&result, Get(nextPromise, _ejs_atom_then), nextPromise, 2, thenargs); // p. IfAbruptRejectPromise(result, promiseCapability). if (!success) { _ejs_invoke_closure(EJS_CAPABILITY_GET_REJECT(promiseCapability), _ejs_undefined, 1, &result); return EJS_CAPABILITY_GET_PROMISE(promiseCapability); } // q. Set index to index + 1. index ++; } }
// ES2015, June 2015 // 23.4.1.1 WeakSet ( [ iterable ] ) static EJS_NATIVE_FUNC(_ejs_WeakSet_impl) { ejsval iterable = _ejs_undefined; if (argc > 0) iterable = args[0]; // 1. If NewTarget is undefined, throw a TypeError exception. if (EJSVAL_IS_UNDEFINED(newTarget)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "WeakSet constructor must be called with new"); // 2. Let set be OrdinaryCreateFromConstructor(NewTarget, "%WeakSetPrototype%", «[[WeakSetData]]»). // 3. ReturnIfAbrupt(set). // 4. Set set’s [[WeakSetData]] internal slot to a new empty List. ejsval set = OrdinaryCreateFromConstructor(newTarget, _ejs_WeakSet_prototype, &_ejs_WeakSet_specops); *_this = set; // 5. If iterable is not present, let iterable be undefined. // 6. If iterable is either undefined or null, let iter be undefined. ejsval iter; ejsval adder; if (EJSVAL_IS_NULL_OR_UNDEFINED(iterable)) { iter = _ejs_undefined; } // 7. Else, else { // a. Let adder be Get(set, "add"). // b. ReturnIfAbrupt(adder). adder = Get (set, _ejs_atom_add); // c. If IsCallable(adder) is false, throw a TypeError exception. if (!IsCallable(adder)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "WeakSet.prototype.add is not a function"); // d. Let iter be GetIterator(iterable). // e. ReturnIfAbrupt(iter). iter = GetIterator(iterable, _ejs_undefined); } // 8. If iter is undefined, return set. if (EJSVAL_IS_UNDEFINED(iter)) return set; // 9. Repeat for (;;) { // a. Let next be IteratorStep(iter). // b. ReturnIfAbrupt(next). ejsval next = IteratorStep (iter); // c. If next is false, return set. if (!EJSVAL_TO_BOOLEAN(next)) return set; // d. Let nextValue be IteratorValue(next). // e. ReturnIfAbrupt(nextValue). ejsval nextValue = IteratorValue (next); // f. Let status be Call(adder, set, «nextValue »). // XXX _ejs_invoke_closure won't call proxy methods ejsval rv; EJSBool status = _ejs_invoke_closure_catch (&rv, adder, &set, 1, &nextValue, _ejs_undefined); // g. If status is an abrupt completion, return IteratorClose(iter, status). if (!status) return IteratorClose(iter, rv, EJS_TRUE); } }