// 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); }
// 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; }