Пример #1
0
// 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);
}
Пример #2
0
// 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;
}
Пример #3
0
// 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();
}
Пример #4
0
// 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;
}
Пример #5
0
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();
}
Пример #6
0
// 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);
}
Пример #7
0
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();
}
Пример #8
0
// 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);
        }
    }
}
Пример #9
0
// 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 ++;
    }
}
Пример #10
0
// 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;
}
Пример #11
0
// 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);
    }
}