// same as SameValue, except in its treatment of +/- 0 EJSBool SameValueZero(ejsval x, ejsval y) { // 1. ReturnIfAbrupt(x). // 2. ReturnIfAbrupt(y). // 3. If Type(x) is different from Type(y), return false. if (EJSVAL_TO_TAG(x) != EJSVAL_TO_TAG(y)) return EJS_FALSE; // 4. If Type(x) is Undefined, return true. if (EJSVAL_IS_UNDEFINED(x)) return EJS_TRUE; // 5. If Type(x) is Null, return true. if (EJSVAL_IS_NULL(x)) return EJS_TRUE; // 6. If Type(x) is Number, then if (EJSVAL_IS_NUMBER(x)) { // a. If x is NaN and y is NaN, return true. if (isnan(EJSVAL_TO_NUMBER(x)) && isnan(EJSVAL_TO_NUMBER(y))) return EJS_TRUE; // b. If x is +0 and y is -0, return true. if (EJSVAL_TO_NUMBER(x) == 0.0 && EJSDOUBLE_IS_NEGZERO(EJSVAL_TO_NUMBER(y))) return EJS_TRUE; // c. If x is -0 and y is +0, return tryue. if (EJSDOUBLE_IS_NEGZERO(EJSVAL_TO_NUMBER(x)) == 0.0 && EJSVAL_TO_NUMBER(y) == 0) return EJS_TRUE; // d. If x is the same Number value as y, return true. if (EJSVAL_TO_NUMBER(x) == EJSVAL_TO_NUMBER(y)) return EJS_TRUE; // e. Return false. return EJS_FALSE; } // 7. If Type(x) is String, then if (EJSVAL_IS_STRING(x)) { // a. If x and y are exactly the same sequence of code units (same length and same code units in corresponding positions) return true; // otherwise, return false. if (EJSVAL_TO_STRLEN(x) != EJSVAL_TO_STRLEN(y)) return EJS_FALSE; // XXX there is doubtless a more efficient way to compare two ropes, but we convert but to flat strings for now. return ucs2_strcmp (EJSVAL_TO_FLAT_STRING(x), EJSVAL_TO_FLAT_STRING(y)) ? EJS_FALSE : EJS_TRUE; } // 8. If Type(x) is Boolean, then if (EJSVAL_IS_BOOLEAN(x)) { // a. If x and y are both true or both false, then return true; otherwise, return false. return EJSVAL_TO_BOOLEAN(x) == EJSVAL_TO_BOOLEAN(y) ? EJS_TRUE : EJS_FALSE; } // 9. If Type(x) is Symbol, then if (EJSVAL_IS_SYMBOL(x)) { // a. If x and y are both the same Symbol value, then return true; otherwise, return false. EJS_NOT_IMPLEMENTED(); } // 10. Return true if x and y are the same Object value. Otherwise, return false. return EJSVAL_EQ(x, y); }
// ECMA262 25.4.4.1.1 Promise.all Resolve Element Functions static ejsval resolve_element (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { // 1. If the value of F's [[AlreadyCalled]] internal slot is true, then return undefined. if (EJSVAL_TO_BOOLEAN(EJS_RESOLVEELEMENT_GET_ALREADY_CALLED(env))) return _ejs_undefined; // 2. Set the value of F's [[AlreadyCalled]] internal slot to true. EJS_RESOLVEELEMENT_SET_ALREADY_CALLED(env, _ejs_true); // 3. Let index be the value of F's [[Index]] internal slot. ejsval index = EJS_RESOLVEELEMENT_GET_INDEX(env); // 4. Let values be the value of F's [[Values]] internal slot. ejsval values = EJS_RESOLVEELEMENT_GET_VALUES(env); // 5. Let promiseCapability be the value of F's [[Capabilities]] internal slot. ejsval promiseCapability = EJS_RESOLVEELEMENT_GET_CAPABILITIES(env); // 6. Let remainingElementsCount be the value of F's [[RemainingElements]] internal slot. // XXX remainingElementsCount needs to be a boxed value so that resolve_element functions can update it // XXX maybe an EJSNumber? supposed to be immutable, but we could fudge.. or another closure. // 7. Let result be CreateDataProperty(values, ToString(index), x). // 8. IfAbruptRejectPromise(result, promiseCapability). // 9. Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] - 1. // 10. If remainingElementsCount.[[value]] is 0, // a. Return the result of calling the [[Call]] internal method of promiseCapability.[[Resolve]] with undefined as thisArgument and (values) as argumentsList. // 11. Return undefined. return _ejs_undefined; }
// returns an EJSPrimString*. // maybe we could change it to return a char* to match ToDouble? that way string concat wouldn't create // temporary strings for non-PrimString objects only to throw them away after concatenation? ejsval ToString(ejsval exp) { if (EJSVAL_IS_MAGIC_IMPL(exp)) { // holes in dense arrays end up here return _ejs_atom_empty; } else if (EJSVAL_IS_NULL(exp)) return _ejs_atom_null; else if (EJSVAL_IS_UNDEFINED(exp)) return _ejs_atom_undefined; else if (EJSVAL_IS_BOOLEAN(exp)) return EJSVAL_TO_BOOLEAN(exp) ? _ejs_atom_true : _ejs_atom_false; else if (EJSVAL_IS_NUMBER(exp)) return NumberToString(EJSVAL_TO_NUMBER(exp)); else if (EJSVAL_IS_STRING(exp)) return exp; else if (EJSVAL_IS_OBJECT(exp)) { ejsval toString = _ejs_object_getprop (exp, _ejs_atom_toString); if (!EJSVAL_IS_FUNCTION(toString)) { return _ejs_Object_prototype_toString(_ejs_null, exp, 0, NULL); } // should we be checking if this returns a string? i'd assume so... return _ejs_invoke_closure (toString, exp, 0, NULL); } else EJS_NOT_IMPLEMENTED(); }
// ECMA262 25.4.1.4 Promise Resolve Functions static ejsval resolve(ejsval env, ejsval _this, uint32_t argc, ejsval *args) { ejsval resolution = _ejs_undefined; if (argc > 0) resolution = args[0]; // 1. Assert: F has a [[Promise]] internal slot whose value is an Object. // 2. Let promise be the value of F's [[Promise]] internal slot. ejsval promise = _ejs_closureenv_get_slot(env, 1); // 3. Let alreadyResolved by be the value of F's [[AlreadyResolved]] internal slot. ejsval alreadyResolved = _ejs_closureenv_get_slot(env, 0); // 4. If alreadyResolved. [[value]] is true, then return undefined. if (EJSVAL_TO_BOOLEAN(alreadyResolved)) { return _ejs_undefined; } // 5. Set alreadyResolved.[[value]] to true. *_ejs_closureenv_get_slot_ref(env, 0) = _ejs_true; // 6. If SameValue(resolution, promise) is true, then if (SameValue(resolution, promise)) { // a. Let selfResolutionError be a newly-created TypeError object. ejsval selfResolutionError = _ejs_nativeerror_new_utf8(EJS_TYPE_ERROR, ""); // XXX // b. Return RejectPromise(promise, selfResolutionError). return RejectPromise(promise, selfResolutionError); } // 7. If Type(resolution) is not Object, then if (!EJSVAL_IS_OBJECT(resolution)) { // a. Return FulfillPromise(promise, resolution). return FulfillPromise(promise, resolution); } // 8. Let then be Get(resolution, "then"). ejsval then = Get(resolution, _ejs_atom_then); // 9. If then is an abrupt completion, then // a. Return RejectPromise(promise, then.[[value]]). // XXX // 10. Let then be then.[[value]]. // 11. If IsCallable(then) is false, then if (!EJSVAL_IS_CALLABLE(then)) { // a. Return FulfillPromise(promise, resolution). return FulfillPromise(promise, resolution); } // 12. Perform EnqueueTask ("PromiseTasks", PromiseResolveThenableTask, (promise, resolution, then)) EnqueuePromiseResolveThenableTask (promise, resolution, then); // 13. Return undefined. return _ejs_undefined; }
EJSBool ToEJSBool(ejsval exp) { if (EJSVAL_IS_NULL(exp) || EJSVAL_IS_UNDEFINED(exp)) return EJS_FALSE; else if (EJSVAL_IS_BOOLEAN(exp)) return EJSVAL_TO_BOOLEAN(exp); else if (EJSVAL_IS_NUMBER(exp)) return EJSVAL_TO_NUMBER(exp) != 0; else if (EJSVAL_IS_STRING(exp)) return EJSVAL_TO_STRLEN(exp) != 0; else if (EJSVAL_IS_OBJECT(exp)) return EJS_TRUE; else EJS_NOT_IMPLEMENTED(); }
// ECMA262 25.4.1.3.1 Promise Reject Functions static ejsval reject(ejsval env, ejsval _this, uint32_t argc, ejsval *args) { ejsval reason = _ejs_undefined; if (argc > 0) reason = args[0]; // 1. Assert: F has a [[Promise]] internal slot whose value is an Object. // 2. Let promise be the value of F's [[Promise]] internal slot. ejsval promise = _ejs_closureenv_get_slot(env, 1); // 3. Let alreadyResolved by be the value of F's [[AlreadyResolved]] internal slot. ejsval alreadyResolved = _ejs_closureenv_get_slot(env, 0); // 4. If alreadyResolved.[[value]] is true, then return undefined. if (EJSVAL_TO_BOOLEAN(alreadyResolved)) return _ejs_undefined; // 5. Set alreadyResolved.[[value]] to true. *_ejs_closureenv_get_slot_ref(env, 0) = _ejs_true; // 6. Return RejectPromise(promise, reason). return RejectPromise(promise, reason); }
ejsval ToNumber(ejsval exp) { if (EJSVAL_IS_NUMBER(exp)) return exp; else if (EJSVAL_IS_BOOLEAN(exp)) return EJSVAL_TO_BOOLEAN(exp) ? _ejs_one : _ejs_zero; else if (EJSVAL_IS_STRING(exp)) { char* num_utf8 = ucs2_to_utf8(EJSVAL_TO_FLAT_STRING(exp)); char *endptr; double d = strtod(num_utf8, &endptr); if (*endptr != '\0') return _ejs_nan; ejsval rv = NUMBER_TO_EJSVAL(d); // XXX NaN free (num_utf8); return rv; } else if (EJSVAL_IS_UNDEFINED(exp)) return _ejs_nan; else if (EJSVAL_IS_OBJECT(exp)) { if (EJSVAL_IS_DATE(exp)) { return NUMBER_TO_EJSVAL(_ejs_date_get_time ((EJSDate*)EJSVAL_TO_OBJECT(exp))); } else if (EJSVAL_IS_ARRAY(exp)) { int len = EJS_ARRAY_LEN(exp); if (len == 0) return _ejs_zero; else if (len > 1) return _ejs_nan; else { // XXX we need to support sparse arrays here too EJS_ASSERT (EJSVAL_IS_DENSE_ARRAY(exp)); return ToNumber(EJS_DENSE_ARRAY_ELEMENTS(exp)[0]); } } else return _ejs_nan; } else EJS_NOT_IMPLEMENTED(); }
// 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 ++; } }
// ES6: 23.2.1.1 Set ( [ iterable ] ) static ejsval _ejs_Set_impl (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { // 1. Let set be the this value. ejsval set = _this; if (EJSVAL_IS_UNDEFINED(set)) { EJSObject* obj = (EJSObject*)_ejs_gc_new(EJSSet); _ejs_init_object (obj, _ejs_Set_prototype, &_ejs_Set_specops); set = OBJECT_TO_EJSVAL(obj); } // 2. If Type(set) is not Object then, throw a TypeError exception. if (!EJSVAL_IS_OBJECT(set)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set constructor called with non-object this."); // 3. If set does not have a [[SetData]] internal slot, then throw a TypeError exception. if (!EJSVAL_IS_SET(set)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set constructor called with non-Set this."); EJSSet* _set = EJSVAL_TO_SET(set); // 4. If set’s [[SetData]] internal slot is not undefined, then throw a TypeError exception. if (_set->head_insert) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set constructor called with an already initialized Set"); // 5. If iterable is not present, let iterable be undefined. ejsval iterable = _ejs_undefined; if (argc > 0) iterable = args[0]; ejsval iter = _ejs_undefined; ejsval adder = _ejs_undefined; // 6. If iterable is either undefined or null, then let iter be undefined. // 7. Else, if (!EJSVAL_IS_UNDEFINED(iterable) && !EJSVAL_IS_NULL(iterable)) { // a. Let iter be the result of GetIterator(iterable). // b. ReturnIfAbrupt(iter). iter = GetIterator (iterable, _ejs_undefined); // c. Let adder be the result of Get(set, "add"). // d. ReturnIfAbrupt(adder). adder = Get (set, _ejs_atom_add); // e. If IsCallable(adder) is false, throw a TypeError Exception. if (!EJSVAL_IS_CALLABLE(adder)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set.prototype.add is not a function"); } // 8. If the value of sets’s [[SetData]] internal slot is not undefined, then throw a TypeError exception. // 9. Assert: set has not been reentrantly initialized. // 10. Set set’s [[SetData]] internal slot to a new empty List. // 11. If iter is undefined, then return set. if (EJSVAL_IS_UNDEFINED(iter)) return set; // 12. Repeat for (;;) { // a. Let next be the result of IteratorStep(iter). // b. ReturnIfAbrupt(next). ejsval next = IteratorStep (iter); // c. If next is false, then 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 the result of calling the [[Call]] internal method of adder with set as thisArgument // and a List whose sole element is nextValue as argumentsList. // g. ReturnIfAbrupt(status). _ejs_invoke_closure (adder, set, 1, &nextValue); } return set; }
// 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); } }