static int sortcmp(const void *avoid, const void *bvoid) { const struct sortslot *aslot = avoid, *bslot = bvoid; const js_Value *a = &aslot->v, *b = &bslot->v; js_State *J = aslot->J; const char *sx, *sy; int c; int unx = (a->type == JS_TUNDEFINED); int uny = (b->type == JS_TUNDEFINED); if (unx) return !uny; if (uny) return -1; if (js_iscallable(J, 1)) { js_copy(J, 1); /* copy function */ js_pushundefined(J); js_pushvalue(J, *a); js_pushvalue(J, *b); js_call(J, 2); c = js_tonumber(J, -1); js_pop(J, 1); } else { js_pushvalue(J, *a); js_pushvalue(J, *b); sx = js_tostring(J, -2); sy = js_tostring(J, -1); c = strcmp(sx, sy); js_pop(J, 2); } return c; }
static void O_getOwnPropertyDescriptor(js_State *J) { js_Object *obj; js_Property *ref; if (!js_isobject(J, 1)) js_typeerror(J, "not an object"); obj = js_toobject(J, 1); ref = jsV_getproperty(J, obj, js_tostring(J, 2)); if (!ref) js_pushundefined(J); else { js_newobject(J); if (!ref->getter && !ref->setter) { js_pushvalue(J, ref->value); js_setproperty(J, -2, "value"); js_pushboolean(J, !(ref->atts & JS_READONLY)); js_setproperty(J, -2, "writable"); } else { if (ref->getter) js_pushobject(J, ref->getter); else js_pushundefined(J); js_setproperty(J, -2, "get"); if (ref->setter) js_pushobject(J, ref->setter); else js_pushundefined(J); js_setproperty(J, -2, "set"); } js_pushboolean(J, !(ref->atts & JS_DONTENUM)); js_setproperty(J, -2, "enumerable"); js_pushboolean(J, !(ref->atts & JS_DONTCONF)); js_setproperty(J, -2, "configurable"); } }
static int jsR_hasproperty(js_State *J, js_Object *obj, const char *name) { js_Property *ref; unsigned int k; if (obj->type == JS_CARRAY) { if (!strcmp(name, "length")) { js_pushnumber(J, obj->u.a.length); return 1; } } if (obj->type == JS_CSTRING) { if (!strcmp(name, "length")) { js_pushnumber(J, obj->u.s.length); return 1; } if (js_isarrayindex(J, name, &k)) { js_pushrune(J, js_runeat(J, obj->u.s.string, k)); return 1; } } if (obj->type == JS_CREGEXP) { if (!strcmp(name, "source")) { js_pushliteral(J, obj->u.r.source); return 1; } if (!strcmp(name, "global")) { js_pushboolean(J, obj->u.r.flags & JS_REGEXP_G); return 1; } if (!strcmp(name, "ignoreCase")) { js_pushboolean(J, obj->u.r.flags & JS_REGEXP_I); return 1; } if (!strcmp(name, "multiline")) { js_pushboolean(J, obj->u.r.flags & JS_REGEXP_M); return 1; } if (!strcmp(name, "lastIndex")) { js_pushnumber(J, obj->u.r.last); return 1; } } ref = jsV_getproperty(J, obj, name); if (ref) { if (ref->getter) { js_pushobject(J, ref->getter); js_pushobject(J, obj); js_call(J, 0); } else { js_pushvalue(J, ref->value); } return 1; } 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); }
static void jsR_callcfunction(js_State *J, unsigned int n, unsigned int min, js_CFunction F) { unsigned int i; js_Value v; for (i = n; i < min; ++i) js_pushundefined(J); F(J); v = *stackidx(J, -1); TOP = --BOT; /* clear stack */ js_pushvalue(J, v); }
static void jsR_callscript(js_State *J, unsigned int n, js_Function *F, js_Environment *scope) { js_Value v; if (scope) jsR_savescope(J, scope); js_pop(J, n); jsR_run(J, F); v = *stackidx(J, -1); TOP = --BOT; /* clear stack */ js_pushvalue(J, v); if (scope) jsR_restorescope(J); }
void js_throw(js_State *J) { if (J->trytop > 0) { js_Value v = *stackidx(J, -1); --J->trytop; J->E = J->trybuf[J->trytop].E; J->envtop = J->trybuf[J->trytop].envtop; J->tracetop = J->trybuf[J->trytop].tracetop; J->top = J->trybuf[J->trytop].top; J->bot = J->trybuf[J->trytop].bot; js_pushvalue(J, v); longjmp(J->trybuf[J->trytop].buf, 1); } if (J->panic) J->panic(J); abort(); }
static void O_defineProperties(js_State *J) { js_Object *props; js_Property *ref; if (!js_isobject(J, 1)) js_typeerror(J, "not an object"); if (!js_isobject(J, 2)) js_typeerror(J, "not an object"); props = js_toobject(J, 2); for (ref = props->head; ref; ref = ref->next) { if (!(ref->atts & JS_DONTENUM)) { js_pushvalue(J, ref->value); ToPropertyDescriptor(J, js_toobject(J, 1), ref->name, js_toobject(J, -1)); js_pop(J, 1); } } js_copy(J, 1); }
static void jsR_callfunction(js_State *J, unsigned int n, js_Function *F, js_Environment *scope) { js_Value v; unsigned int i; scope = jsR_newenvironment(J, jsV_newobject(J, JS_COBJECT, NULL), scope); jsR_savescope(J, scope); if (F->arguments) { js_newobject(J); if (!J->strict) { js_currentfunction(J); js_defproperty(J, -2, "callee", JS_DONTENUM); } js_pushnumber(J, n); js_defproperty(J, -2, "length", JS_DONTENUM); for (i = 0; i < n; ++i) { js_copy(J, i + 1); js_setindex(J, -2, i); } js_initvar(J, "arguments", -1); js_pop(J, 1); } for (i = 0; i < F->numparams; ++i) { if (i < n) js_initvar(J, F->vartab[i], i + 1); else { js_pushundefined(J); js_initvar(J, F->vartab[i], -1); js_pop(J, 1); } } js_pop(J, n); jsR_run(J, F); v = *stackidx(J, -1); TOP = --BOT; /* clear stack */ js_pushvalue(J, v); jsR_restorescope(J); }
static int js_hasvar(js_State *J, const char *name) { js_Environment *E = J->E; do { js_Property *ref = jsV_getproperty(J, E->variables, name); if (ref) { if (ref->getter) { js_pushobject(J, ref->getter); js_pushobject(J, E->variables); js_call(J, 0); } else { js_pushvalue(J, ref->value); } return 1; } E = E->outer; } while (E); return 0; }
static void jsR_calllwfunction(js_State *J, unsigned int n, js_Function *F, js_Environment *scope) { js_Value v; unsigned int i; jsR_savescope(J, scope); if (n > F->numparams) { js_pop(J, F->numparams - n); n = F->numparams; } for (i = n; i < F->varlen; ++i) js_pushundefined(J); jsR_run(J, F); v = *stackidx(J, -1); TOP = --BOT; /* clear stack */ js_pushvalue(J, v); jsR_restorescope(J); }
static void jsR_setproperty(js_State *J, js_Object *obj, const char *name, js_Value *value) { js_Property *ref; unsigned int k; int own; if (obj->type == JS_CARRAY) { if (!strcmp(name, "length")) { double rawlen = jsV_tonumber(J, value); unsigned int newlen = jsV_numbertouint32(rawlen); if (newlen != rawlen) js_rangeerror(J, "array length"); jsV_resizearray(J, obj, newlen); return; } if (js_isarrayindex(J, name, &k)) if (k >= obj->u.a.length) obj->u.a.length = k + 1; } if (obj->type == JS_CSTRING) { if (!strcmp(name, "length")) goto readonly; if (js_isarrayindex(J, name, &k)) if (js_runeat(J, obj->u.s.string, k)) goto readonly; } if (obj->type == JS_CREGEXP) { if (!strcmp(name, "source")) goto readonly; if (!strcmp(name, "global")) goto readonly; if (!strcmp(name, "ignoreCase")) goto readonly; if (!strcmp(name, "multiline")) goto readonly; if (!strcmp(name, "lastIndex")) { obj->u.r.last = jsV_tointeger(J, value); return; } } /* First try to find a setter in prototype chain */ ref = jsV_getpropertyx(J, obj, name, &own); if (ref && ref->setter) { js_pushobject(J, ref->setter); js_pushobject(J, obj); js_pushvalue(J, *value); js_call(J, 1); js_pop(J, 1); return; } /* Property not found on this object, so create one */ if (!ref || !own) ref = jsV_setproperty(J, obj, name); if (ref) { if (!(ref->atts & JS_READONLY)) ref->value = *value; else goto readonly; } return; readonly: if (J->strict) js_typeerror(J, "'%s' is read-only", name); }