/* ToPrimitive() on a value */ js_Value jsV_toprimitive(js_State *J, const js_Value *v, int preferred) { js_Value vv; js_Object *obj; if (v->type != JS_TOBJECT) return *v; obj = v->u.object; if (preferred == JS_HNONE) preferred = obj->type == JS_CDATE ? JS_HSTRING : JS_HNUMBER; if (preferred == JS_HSTRING) { if (jsV_toString(J, obj) || jsV_valueOf(J, obj)) { vv = js_tovalue(J, -1); js_pop(J, 1); return vv; } } else { if (jsV_valueOf(J, obj) || jsV_toString(J, obj)) { vv = js_tovalue(J, -1); js_pop(J, 1); return vv; } } js_typeerror(J, "cannot convert object to primitive"); }
/* ToPrimitive() on a value */ void jsV_toprimitive(js_State *J, js_Value *v, int preferred) { js_Object *obj; if (v->type != JS_TOBJECT) return; obj = v->u.object; if (preferred == JS_HNONE) preferred = obj->type == JS_CDATE ? JS_HSTRING : JS_HNUMBER; if (preferred == JS_HSTRING) { if (jsV_toString(J, obj) || jsV_valueOf(J, obj)) { *v = *js_tovalue(J, -1); js_pop(J, 1); return; } } else { if (jsV_valueOf(J, obj) || jsV_toString(J, obj)) { *v = *js_tovalue(J, -1); js_pop(J, 1); return; } } v->type = JS_TLITSTR; v->u.litstr = "[object]"; return; }
int js_strictequal(js_State *J) { js_Value va = js_tovalue(J, -2); js_Value vb = js_tovalue(J, -1); if (va.type != vb.type) return 0; if (va.type == JS_TUNDEFINED) return 1; if (va.type == JS_TNULL) return 1; if (va.type == JS_TNUMBER) return va.u.number == vb.u.number; if (va.type == JS_TBOOLEAN) return va.u.boolean == vb.u.boolean; if (va.type == JS_TSTRING) return !strcmp(va.u.string, vb.u.string); if (va.type == JS_TOBJECT) return va.u.object == vb.u.object; return 0; }
int js_strictequal(js_State *J) { js_Value *x = js_tovalue(J, -2); js_Value *y = js_tovalue(J, -1); if (JSV_ISSTRING(x) && JSV_ISSTRING(y)) return !strcmp(JSV_TOSTRING(x), JSV_TOSTRING(y)); if (x->type != y->type) return 0; if (x->type == JS_TUNDEFINED) return 1; if (x->type == JS_TNULL) return 1; if (x->type == JS_TNUMBER) return x->u.number == y->u.number; if (x->type == JS_TBOOLEAN) return x->u.boolean == y->u.boolean; if (x->type == JS_TOBJECT) return x->u.object == y->u.object; return 0; }
int js_equal(js_State *J) { js_Value *x = js_tovalue(J, -2); js_Value *y = js_tovalue(J, -1); retry: if (JSV_ISSTRING(x) && JSV_ISSTRING(y)) return !strcmp(JSV_TOSTRING(x), JSV_TOSTRING(y)); if (x->type == y->type) { if (x->type == JS_TUNDEFINED) return 1; if (x->type == JS_TNULL) return 1; if (x->type == JS_TNUMBER) return x->u.number == y->u.number; if (x->type == JS_TBOOLEAN) return x->u.boolean == y->u.boolean; if (x->type == JS_TOBJECT) return x->u.object == y->u.object; return 0; } if (x->type == JS_TNULL && y->type == JS_TUNDEFINED) return 1; if (x->type == JS_TUNDEFINED && y->type == JS_TNULL) return 1; if (x->type == JS_TNUMBER && JSV_ISSTRING(y)) return x->u.number == jsV_tonumber(J, y); if (JSV_ISSTRING(x) && y->type == JS_TNUMBER) return jsV_tonumber(J, x) == y->u.number; if (x->type == JS_TBOOLEAN) { x->type = JS_TNUMBER; x->u.number = x->u.boolean; goto retry; } if (y->type == JS_TBOOLEAN) { y->type = JS_TNUMBER; y->u.number = y->u.boolean; goto retry; } if ((JSV_ISSTRING(x) || x->type == JS_TNUMBER) && y->type == JS_TOBJECT) { jsV_toprimitive(J, y, JS_HNONE); goto retry; } if (x->type == JS_TOBJECT && (JSV_ISSTRING(y) || y->type == JS_TNUMBER)) { jsV_toprimitive(J, x, JS_HNONE); goto retry; } return 0; }
int js_equal(js_State *J) { js_Value x = js_tovalue(J, -2); js_Value y = js_tovalue(J, -1); retry: if (x.type == y.type) { if (x.type == JS_TUNDEFINED) return 1; if (x.type == JS_TNULL) return 1; if (x.type == JS_TNUMBER) return x.u.number == y.u.number; if (x.type == JS_TBOOLEAN) return x.u.boolean == y.u.boolean; if (x.type == JS_TSTRING) return !strcmp(x.u.string, y.u.string); if (x.type == JS_TOBJECT) return x.u.object == y.u.object; return 0; } if (x.type == JS_TNULL && y.type == JS_TUNDEFINED) return 1; if (x.type == JS_TUNDEFINED && y.type == JS_TNULL) return 1; if (x.type == JS_TNUMBER && y.type == JS_TSTRING) return x.u.number == jsV_tonumber(J, &y); if (x.type == JS_TSTRING && y.type == JS_TNUMBER) return jsV_tonumber(J, &x) == y.u.number; if (x.type == JS_TBOOLEAN) { x.type = JS_TNUMBER; x.u.number = x.u.boolean; goto retry; } if (y.type == JS_TBOOLEAN) { y.type = JS_TNUMBER; y.u.number = y.u.boolean; goto retry; } if ((x.type == JS_TSTRING || x.type == JS_TNUMBER) && y.type == JS_TOBJECT) { y = jsV_toprimitive(J, &y, JS_HNONE); goto retry; } if (x.type == JS_TOBJECT && (y.type == JS_TSTRING || y.type == JS_TNUMBER)) { x = jsV_toprimitive(J, &x, JS_HNONE); goto retry; } return 0; }
static void Ap_sort(js_State *J) { struct sortslot *array = NULL; int i, n, len; len = js_getlength(J, 0); if (len <= 0) { js_copy(J, 0); return; } if (len >= INT_MAX / (int)sizeof(*array)) js_rangeerror(J, "array is too large to sort"); array = js_malloc(J, len * sizeof *array); /* Holding objects where the GC cannot see them is illegal, but if we * don't allow the GC to run we can use qsort() on a temporary array of * js_Values for fast sorting. */ ++J->gcpause; if (js_try(J)) { --J->gcpause; js_free(J, array); js_throw(J); } n = 0; for (i = 0; i < len; ++i) { if (js_hasindex(J, 0, i)) { array[n].v = *js_tovalue(J, -1); array[n].J = J; js_pop(J, 1); ++n; } } qsort(array, n, sizeof *array, sortcmp); for (i = 0; i < n; ++i) { js_pushvalue(J, array[i].v); js_setindex(J, 0, i); } for (i = n; i < len; ++i) { js_delindex(J, 0, i); } --J->gcpause; js_endtry(J); js_free(J, array); js_copy(J, 0); }