// 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: 19.4.2.7 Symbol.keyFor ( sym ) static EJS_NATIVE_FUNC(_ejs_Symbol_keyFor) { ejsval sym = _ejs_undefined; if (argc > 0) sym = args[0]; // 1. If Type(sym) is not Symbol, then throw a TypeError exception. if (!EJSVAL_IS_SYMBOL(sym)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Symbol.keyFor called with non-symbol argument"); // 2. For each element e of the GlobalSymbolRegistry List (see 19.4.2.2), // a. If SameValue(e.[[symbol]], sym) is true, then return e.[[key]]. // 3. Assert: GlobalSymbolRegistry does not current contain an entry for sym. // XXX // 4. Return undefined. return _ejs_undefined; }
// ES2015, June 2015 // 19.4.3.3 Symbol.prototype.valueOf ( ) static EJS_NATIVE_FUNC(_ejs_Symbol_prototype_valueOf) { // 1. Let s be the this value. ejsval s = *_this; // 2. If Type(s) is Symbol, return s. if (EJSVAL_IS_SYMBOL(s)) return s; // 3. If Type(s) is not Object, throw a TypeError exception. if (!EJSVAL_IS_OBJECT(s)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Symbol.prototype.valueOf called with non-object this"); // 4. If s does not have a [[SymbolData]] internal slot, throw a TypeError exception. if (!EJSVAL_IS_SYMBOL_OBJECT(s)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Symbol.prototype.valueOf called with non-symbol this"); // 5. Return the value of s’s [[SymbolData]] internal slot. return EJSVAL_TO_SYMBOL_OBJECT(s)->primSymbol; }
// ECMA262: 19.4.3.2 Symbol.prototype.toString () static EJS_NATIVE_FUNC(_ejs_Symbol_prototype_toString) { // 1. Let s be the this value. ejsval s = *_this; EJSPrimSymbol* sym; // 2. If Type(s) is Symbol, then let sym be s. if (EJSVAL_IS_SYMBOL(s)) { sym = EJSVAL_TO_SYMBOL(s); } // 3. Else, else { // a. If s does not have a [[SymbolData]] internal slot, then throw a TypeError exception. if (!EJSVAL_IS_SYMBOL_OBJECT(s)) { _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Symbol.prototype.toString called with non-symbol this"); } // b. Let sym be the value of s’s [[SymbolData]] internal slot. sym = EJSVAL_TO_SYMBOL(EJSVAL_TO_SYMBOL_OBJECT(s)->primSymbol); } // 4. Let desc be the value of sym’s [[Description]] attribute. ejsval desc = sym->description; // 5. If desc is undefined, then let desc be the empty string. if (EJSVAL_IS_UNDEFINED(desc)) desc = _ejs_atom_empty; // 6. Assert: Type(desc) is String. // 7. Let result be the result of concatenating the strings "Symbol(", desc, and ")". ejsval result = _ejs_string_concatv (_ejs_atom_Symbol, _ejs_string_new_utf8("("), desc, _ejs_string_new_utf8(")"), _ejs_null); // 8. Return result. return result; }
ejsval _ejs_op_typeof (ejsval exp) { if (EJSVAL_IS_NULL(exp)) return _ejs_atom_null; else if (EJSVAL_IS_BOOLEAN(exp)) return _ejs_atom_boolean; else if (EJSVAL_IS_STRING(exp)) return _ejs_atom_string; else if (EJSVAL_IS_SYMBOL(exp)) return _ejs_atom_symbol; else if (EJSVAL_IS_NUMBER(exp)) return _ejs_atom_number; else if (EJSVAL_IS_UNDEFINED(exp)) return _ejs_atom_undefined; else if (EJSVAL_IS_OBJECT(exp)) { if (EJSVAL_IS_FUNCTION(exp)) return _ejs_atom_function; else return _ejs_atom_object; } else EJS_NOT_IMPLEMENTED(); }
ejsval _ejs_op_typeof_is_symbol(ejsval exp) { return EJSVAL_IS_SYMBOL(exp) ? _ejs_true : _ejs_false; }