// ES6: 23.2.3.9 // get Set.prototype.size static ejsval _ejs_Set_prototype_get_size (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { // 1. Let S be the this value. ejsval S = _this; // 2. If Type(S) is not Object, then throw a TypeError exception. if (!EJSVAL_IS_OBJECT(S)) { _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set size getter called with non-object this."); } // 3. If S does not have a [[SetData]] internal slot throw a TypeError exception. if (!EJSVAL_IS_SET(S)) { _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set size getter called with non-Set this."); } EJSSet* _set = EJSVAL_TO_SET(S); // 4. If S’s [[SetData]] internal slot is undefined, then throw a TypeError exception. // 5. Let entries be the List that is the value of S’s [[SetData]] internal slot. EJSSetValueEntry* entries = _set->head_insert; // 6. Let count be 0. uint32_t count = 0; // 7. For each e that is an element of entries for (EJSSetValueEntry* e = entries; e; e = e->next_insert) { // a. If e is not empty then if (!EJSVAL_IS_NO_ITER_VALUE_MAGIC(e->value)) // i. Set count to count+1. count ++; } // 8. Return count. return NUMBER_TO_EJSVAL(count); }
ejsval _ejs_set_iterator_new (ejsval set, EJSSetIteratorKind kind) { /* 1. If Type(set) is not Object, throw a TypeError exception. */ if (!EJSVAL_IS_OBJECT(set)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "set is not a Object"); /* 2. If set does not have a [[SetData]] internal slot throw a TypeError exception. */ if (!EJSVAL_IS_SET(set)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "value is not a Set"); /* 3. If set’s [[SetData]] internal slot is undefined, then throw a TypeError exception. */ /* 4. Let iterator be the result of ObjectCreate(%SetIteratorPrototype%, * ([[IteratedSet]], [[SetNextIndex]], [[SetIterationKind]])). */ EJSSetIterator *iter = _ejs_gc_new (EJSSetIterator); _ejs_init_object ((EJSObject*) iter, _ejs_SetIterator_prototype, &_ejs_SetIterator_specops); /* 5. Set iterator’s [[IteratedSet]] internal slot to set. */ iter->iterated = set; /* 6. Set iterator’s [[SetNextIndex]] internal slot to 0. */ iter->next_index = 0; /* 7. Set iterator’s [[SetIterationKind]] internal slot to kind. */ iter->kind = kind; /* 8. Return iterator */ return OBJECT_TO_EJSVAL(iter); }
// ES6: 23.1.3.1 // Map.prototype.clear () ejsval _ejs_Set_prototype_clear (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { // 1. Let S be this value. ejsval S = _this; // 2. If Type(S) is not Object, then throw a TypeError exception. if (!EJSVAL_IS_OBJECT(S)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set.prototype.clear called with non-object this."); // 3. If S does not have a [[SetData]] internal slot throw a TypeError exception. if (!EJSVAL_IS_SET(S)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set.prototype.clear called with non-Set this."); // 4. If S’s [[SetData]] internal slot is undefined, then throw a TypeError exception. // 5. Let entries be the List that is the value of S’s [[SetData]] internal slot. EJSSetValueEntry* entries = EJSVAL_TO_SET(S)->head_insert; // 6. Repeat for each e that is an element of entries, for (EJSSetValueEntry* e = entries; e; e = e->next_insert) { // a. Replace the element of entries whose value is e with an element whose value is empty. e->value = MAGIC_TO_EJSVAL_IMPL(EJS_NO_ITER_VALUE); } // 7. Return undefined. return _ejs_undefined; }
// ES6: 23.2.3.7 // Set.prototype.has ( value ) ejsval _ejs_Set_prototype_has (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { ejsval value = _ejs_undefined; if (argc > 0) value = args[0]; // 1. Let S be the this value. ejsval S = _this; // 2. If Type(S) is not Object, then throw a TypeError exception. if (!EJSVAL_IS_OBJECT(S)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set.prototype.has called with non-object this."); // 3. If S does not have a [[SetData]] internal slot throw a TypeError exception. if (!EJSVAL_IS_SET(S)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set.prototype.has called with non-Set this."); // 4. If S’s [[SetData]] internal slot is undefined, then throw a TypeError exception. EJSSet* _set = EJSVAL_TO_SET(S); // 5. Let entries be the List that is the value of S’s [[SetData]] internal slot. EJSSetValueEntry* entries = _set->head_insert; // 6. Repeat for each e that is an element of entries, for (EJSSetValueEntry* e = entries; e; e = e->next_insert) { // a. If e is not empty and SameValueZero(e, value) is true, then return true. if (SameValueZero (e->value, value)) return _ejs_true; } // 7. Return false. return _ejs_false; }
// ES6: 23.2.3.1 Set.prototype.add ( value ) ejsval _ejs_Set_prototype_add (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { ejsval value = _ejs_undefined; if (argc > 0) value = args[0]; // 1. Let S be the this value. ejsval S = _this; // 2. If Type(S) is not Object, then throw a TypeError exception. if (!EJSVAL_IS_OBJECT(S)) { _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set.prototype.add called with non-object this."); } // 3. If S does not have a [[SetData]] internal slot throw a TypeError exception. if (!EJSVAL_IS_SET(S)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set.prototype.set called with non-Set this."); // 4. If S’s [[SetData]] internal slot is undefined, then throw a TypeError exception. EJSSet* _set = EJSVAL_TO_SET(S); // 5. Let entries be the List that is the value of S’s [[SetData]] internal slot. EJSSetValueEntry* entries = _set->head_insert; EJSSetValueEntry* e; // 6. Repeat for each e that is an element of entries, for (e = entries; e; e = e->next_insert) { // a. If e is not empty and SameValueZero(e, value) is true, then if (SameValueZero(e->value, value)) // i. Return S. return S; } // 7. If value is −0, then let value be +0. if (EJSVAL_IS_NUMBER(value) && EJSDOUBLE_IS_NEGZERO(EJSVAL_TO_NUMBER(value))) value = NUMBER_TO_EJSVAL(0); // 8. Append value as the last element of entries. e = calloc (1, sizeof (EJSSetValueEntry)); e->value = value; if (!_set->head_insert) _set->head_insert = e; if (_set->tail_insert) { _set->tail_insert->next_insert = e; _set->tail_insert = e; } else { _set->tail_insert = e; } // 9. Return S. return S; }
// ES6: 23.2.3.6 Set.prototype.forEach ( callbackfn , thisArg = undefined ) ejsval _ejs_Set_prototype_forEach (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { ejsval callbackfn = _ejs_undefined; ejsval thisArg = _ejs_undefined; if (argc > 0) callbackfn = args[0]; if (argc > 1) thisArg = args[1]; // 1. Let S be the this value. ejsval S = _this; // 2. If Type(S) is not Object, then throw a TypeError exception. if (!EJSVAL_IS_OBJECT(S)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set.prototype.forEach called with non-object this."); // 3. If S does not have a [[SetData]] internal slot throw a TypeError exception. if (!EJSVAL_IS_SET(S)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set.prototype.forEach called with non-Set this."); // 4. If S’s [[SetData]] internal slot is undefined, then throw a TypeError exception. // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. if (!EJSVAL_IS_CALLABLE(callbackfn)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set.prototype.forEach callbackfn isn't a function."); // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. ejsval T = thisArg; EJSSet* set = EJSVAL_TO_SET(S); // 7. Let entries be the List that is the value of S’s [[SetData]] internal slot. EJSSetValueEntry* entries = set->head_insert; // 8. Repeat for each e that is an element of entries, in original insertion order for (EJSSetValueEntry *e = entries; e; e = e->next_insert) { // a. If e is not empty, then if (EJSVAL_IS_NO_ITER_VALUE_MAGIC(e->value)) continue; // i. Let funcResult be the result of calling the [[Call]] internal method of callbackfn with T as thisArgument and a List containing e, e, and S as argumentsList. // ii. ReturnIfAbrupt(funcResult). ejsval callback_args[3]; callback_args[0] = e->value; callback_args[1] = e->value; callback_args[2] = S; _ejs_invoke_closure (callbackfn, T, 3, callback_args); } // 9. Return undefined. return _ejs_undefined; }
// ES6: 23.4.3.3 // WeakSet.prototype.delete ( value ) static EJS_NATIVE_FUNC(_ejs_WeakSet_prototype_delete) { ejsval value = _ejs_undefined; if (argc > 0) value = args[0]; // 1. Let S be the this value. ejsval S = *_this; // 2. If Type(S) is not Object, then throw a TypeError exception. if (!EJSVAL_IS_OBJECT(S)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "delete called with non-object this."); // 3. If S does not have a [[WeakSetData]] internal slot throw a TypeError exception. if (!EJSVAL_IS_WEAKSET(S)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "delete called with non-WeakSet this."); // 4. If S’s [[WeakSetData]] internal slot is undefined, then throw a TypeError exception. // 5. If Type(value) is not Object, then return false. if (!EJSVAL_IS_OBJECT(value)) return _ejs_false; // 6. Let entries be the List that is the value of M’s [[WeakSetData]] internal slot. #if WEAK_COLLECTIONS_USE_INVERTED_REP ejsval iset = _ejs_object_getprop(value, _ejs_WeakSetData_symbol); if (EJSVAL_IS_NULL_OR_UNDEFINED(iset)) return _ejs_false; if (!EJSVAL_IS_SET(iset)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "[[WeakSetData]] internal error"); return _ejs_set_delete (iset, S); #else // 7. Repeat for each e that is an element of entries, // a. If e is not empty and SameValue(e, value) is true, then // i. Replace the element of entries whose value is e with an element whose value is empty. // ii. Return true. // 8. Return false. return _ejs_false; #endif }
// ES6: 23.4.3.1 // WeakSet.prototype.add ( value ) static EJS_NATIVE_FUNC(_ejs_WeakSet_prototype_add) { ejsval value = _ejs_undefined; if (argc > 0) value = args[0]; // 1. Let S be the this value. ejsval S = *_this; // 2. If Type(S) is not Object, then throw a TypeError exception. if (!EJSVAL_IS_OBJECT(S)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "add called with non-object this."); // 3. If S does not have a [[WeakSetData]] internal slot throw a TypeError exception. if (!EJSVAL_IS_WEAKSET(S)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "add called with non-WeakSet this."); // 4. If S’s [[WeakSetData]] internal slot is undefined, then throw a TypeError exception. // 6. If Type(value) is not Object, then throw a TypeError exception. if (!EJSVAL_IS_OBJECT(value)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "add called with non-Object value."); #if WEAK_COLLECTIONS_USE_INVERTED_REP ejsval iset = _ejs_object_getprop(value, _ejs_WeakSetData_symbol); if (EJSVAL_IS_NULL_OR_UNDEFINED(iset)) { iset = _ejs_set_new(); _ejs_object_setprop(value, _ejs_WeakSetData_symbol, iset); } if (!EJSVAL_IS_SET(iset)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "[[WeakSetData]] internal error"); _ejs_set_add (iset, S); return S; #else // 7. Let entries be the List that is the value of S’s [[WeakSetData]] internal slot. // a. If e is not empty and SameValue(e, value) is true, then // 1. Return S. // 8. Append value as the last element of entries. // 9. Return S. #endif }
// 23.2.3.4 Set.prototype.delete ( value ) ejsval _ejs_Set_prototype_delete (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { // NOTE The value empty is used as a specification device to // indicate that an entry has been deleted. Actual implementations // may take other actions such as physically removing the entry // from internal data structures. ejsval value = _ejs_undefined; if (argc > 0) value = args[0]; // 1. Let S be the this value. ejsval S = _this; // 2. If Type(S) is not Object, then throw a TypeError exception. if (!EJSVAL_IS_OBJECT(S)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set.prototype.delete called with non-object this."); // 3. If S does not have a [[SetData]] internal slot throw a TypeError exception. if (!EJSVAL_IS_SET(S)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set.prototype.delete called with non-Set this."); // 4. If S’s [[SetData]] internal slot is undefined, then throw a TypeError exception. // 5. Let entries be the List that is the value of S’s [[SetData]] internal slot. EJSSetValueEntry* entries = EJSVAL_TO_SET(S)->head_insert; // 6. Repeat for each e that is an element of entries, for (EJSSetValueEntry* e = entries; e; e = e->next_insert) { // a. If e is not empty and SameValueZero(e, value) is true, then if (SameValueZero(e->value, value)) { // i. Replace the element of entries whose value is e with an element whose value is empty. e->value = MAGIC_TO_EJSVAL_IMPL(EJS_NO_ITER_VALUE); // ii. Return true. return _ejs_true; } } // 7. Return false. return _ejs_false; }
// 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; }