void _ejs_promise_init(ejsval global) { _ejs_Promise = _ejs_function_new_without_proto (_ejs_null, _ejs_atom_Promise, (EJSClosureFunc)_ejs_Promise_impl); _ejs_object_setprop (global, _ejs_atom_Promise, _ejs_Promise); _ejs_gc_add_root (&_ejs_Promise_prototype); _ejs_Promise_prototype = _ejs_object_new(_ejs_null, &_ejs_Object_specops); _ejs_object_setprop (_ejs_Promise, _ejs_atom_prototype, _ejs_Promise_prototype); _ejs_object_define_value_property (_ejs_Promise_prototype, _ejs_atom_constructor, _ejs_Promise, EJS_PROP_NOT_ENUMERABLE | EJS_PROP_CONFIGURABLE | EJS_PROP_WRITABLE); #define PROTO_METHOD(x) EJS_INSTALL_ATOM_FUNCTION_FLAGS (_ejs_Promise_prototype, x, _ejs_Promise_prototype_##x, EJS_PROP_NOT_ENUMERABLE) #define OBJ_METHOD(x) EJS_INSTALL_ATOM_FUNCTION_FLAGS (_ejs_Promise, x, _ejs_Promise_##x, EJS_PROP_NOT_ENUMERABLE) PROTO_METHOD(catch); PROTO_METHOD(then); _ejs_object_define_value_property (_ejs_Promise_prototype, _ejs_Symbol_toStringTag, _ejs_atom_Promise, EJS_PROP_NOT_ENUMERABLE | EJS_PROP_NOT_WRITABLE | EJS_PROP_CONFIGURABLE); OBJ_METHOD(all); OBJ_METHOD(race); OBJ_METHOD(reject); OBJ_METHOD(resolve); #undef PROTO_METHOD EJS_INSTALL_SYMBOL_FUNCTION_FLAGS (_ejs_Promise, create, _ejs_Promise_create, EJS_PROP_NOT_ENUMERABLE); _ejs_gc_add_root(&_ejs_identity_function); _ejs_identity_function = _ejs_function_new_anon(_ejs_undefined, identity); _ejs_gc_add_root(&_ejs_thrower_function); _ejs_thrower_function = _ejs_function_new_anon(_ejs_undefined, thrower); }
// ECMA262 25.4.1.6.1 CreatePromiseCapabilityRecord( promise, constructor ) static ejsval CreatePromiseCapabilityRecord (ejsval promise, ejsval constructor) { // 1. Assert: promise is an uninitialized object created as if by invoking @@create on constructor. // 2. Assert: IsConstructor(constructor) is true. // 3. Let promiseCapability be a new PromiseCapability { [[Promise]]: promise, [[Resolve]]: undefined, [[Reject]]: undefined }. ejsval promiseCapability = EJS_CAPABILITY_NEW(); EJS_CAPABILITY_SET_PROMISE(promiseCapability, promise); EJS_CAPABILITY_SET_RESOLVE(promiseCapability, _ejs_undefined); EJS_CAPABILITY_SET_REJECT(promiseCapability, _ejs_undefined); // 4. Let executor be a new built-in function object as defined in GetCapabilitiesExecutor Functions (25.4.1.5.1). ejsval executor = _ejs_function_new_anon (promiseCapability, capabilitiesExecutor); // 5. Set the [[Capability]] internal slot of executor to promiseCapability. // 6. Let constructorResult be the result of calling the [[Call]] internal method of constructor, passing promise and (executor) as the arguments. // 7. ReturnIfAbrupt(constructorResult). ejsval constructorResult = _ejs_invoke_closure (constructor, promise, 1, &executor); // 8. If IsCallable(promiseCapability.[[Resolve]]) is false, then throw a TypeError exception. if (!EJSVAL_IS_CALLABLE(EJS_CAPABILITY_GET_RESOLVE(promiseCapability))) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, ""); // XXX // 9. If IsCallable(promiseCapability.[[Reject]]) is false, then throw a TypeError exception. if (!EJSVAL_IS_CALLABLE(EJS_CAPABILITY_GET_REJECT(promiseCapability))) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, ""); // XXX // 10. If Type(constructorResult) is Object and SameValue(promise, constructorResult) is false, then throw a TypeError exception. if (EJSVAL_IS_OBJECT(constructorResult) && !SameValue(promise, constructorResult)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "1"); // XXX // 11. Return promiseCapability. return promiseCapability; }
// ECMA262 25.4.1.3 CreateResolvingFunctions ( promise ) static void CreateResolvingFunctions(ejsval promise, ejsval* out_resolve, ejsval* out_reject) { // 1. Let alreadyResolved be a new Record { [[value]]: false }. ejsval resolvingFunctions_env = _ejs_closureenv_new(2); *_ejs_closureenv_get_slot_ref(resolvingFunctions_env, 0) = _ejs_false; *_ejs_closureenv_get_slot_ref(resolvingFunctions_env, 1) = promise; // 2. Let resolve be a new built-in function object as defined in Promise Resolve Functions (25.4.1.4). // 3. Set the [[Promise]] internal slot of resolve to promise. // 4. Set the [[AlreadyResolved]] internal slot of resolve to alreadyResolved. *out_resolve = _ejs_function_new_anon(resolvingFunctions_env, resolve); // 5. Let reject be a new built-in function object as defined in Promise Reject Functions (25.4.1.3.1). // 6. Set the [[Promise]] internal slot of reject to promise. // 7. Set the [[AlreadyResolved]] internal slot of reject to alreadyResolved. *out_reject = _ejs_function_new_anon(resolvingFunctions_env, reject); // 8. Return a new Record { [[Resolve]]: resolve, [[Reject]]: reject }. }
// ECMA262 15.3.4.5 static ejsval _ejs_Function_prototype_bind (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { /* 1. Let Target be the this value. */ ejsval Target = _this; /* 2. If IsCallable(Target) is false, throw a TypeError exception. */ if (!EJSVAL_IS_CALLABLE(Target)) { _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "object not a function"); } ejsval thisArg = _ejs_undefined; if (argc > 0) thisArg = args[0]; /* 3. Let A be a new (possibly empty) internal list of all of the argument values provided after thisArg (arg1, arg2 etc), in order. */ int bound_argc = argc > 1 ? argc - 1 : 0; /* 4. Let F be a new native ECMAScript object . */ ejsval bound_env = EJS_BOUNDFUNC_ENV_NEW(bound_argc); EJS_BOUNDFUNC_ENV_SET_TARGET(bound_env, Target); EJS_BOUNDFUNC_ENV_SET_THIS(bound_env, thisArg); EJS_BOUNDFUNC_ENV_SET_ARGC(bound_env, NUMBER_TO_EJSVAL(bound_argc)); for (int i = 0; i < bound_argc; i ++) { EJS_BOUNDFUNC_ENV_SET_ARG(bound_env, i, args[i+1]); } ejsval F = _ejs_function_new_anon (bound_env, bound_wrapper); EJSFunction *F_ = (EJSFunction*)EJSVAL_TO_OBJECT(F); F_->bound = EJS_TRUE; #if not_anymore /* 5. Set all the internal methods, except for [[Get]], of F as specified in 8.12. */ /* 6. Set the [[Get]] internal property of F as specified in 15.3.5.4. */ /* 7. Set the [[TargetFunction]] internal property of F to Target. */ /* 8. Set the [[BoundThis]] internal property of F to the value of thisArg. */ F_->bound_this = thisArg; /* 9. Set the [[BoundArgs]] internal property of F to A. */ F_->bound_argc = bound_argc; F_->bound_args = bound_args; /* 10. Set the [[Class]] internal property of F to "Function". */ /* 11. Set the [[Prototype]] internal property of F to the standard built-in Function prototype object as specified in 15.3.3.1. */ /* 12. Set the [[Call]] internal property of F as described in 15.3.4.5.1. */ /* 13. Set the [[Construct]] internal property of F as described in 15.3.4.5.2. */ /* 14. Set the [[HasInstance]] internal property of F as described in 15.3.4.5.3. */ /* 15. If the [[Class]] internal property of Target is "Function", then */ /* a. Let L be the length property of Target minus the length of A. */ /* b. Set the length own property of F to either 0 or L, whichever is larger. */ /* 16. Else set the length own property of F to 0. */ /* 17. Set the attributes of the length own property of F to the values specified in 15.3.5.1. */ /* 18. Set the [[Extensible]] internal property of F to true. */ /* 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3). */ /* 20. Call the [[DefineOwnProperty]] internal method of F with arguments "caller", PropertyDescriptor */ /* {[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, and false. */ /* 21. Call the [[DefineOwnProperty]] internal method of F with arguments "arguments", PropertyDescriptor */ /* {[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, and false. */ /* 22. Return F. */ #endif return F; }
// 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 ++; } }