void js_call(js_State *J, int n) { js_Object *obj; int savebot; if (!js_iscallable(J, -n-2)) js_typeerror(J, "called object is not a function"); obj = js_toobject(J, -n-2); savebot = BOT; BOT = TOP - n - 1; if (obj->type == JS_CFUNCTION) { jsR_pushtrace(J, obj->u.f.function->name, obj->u.f.function->filename, obj->u.f.function->line); if (obj->u.f.function->lightweight) jsR_calllwfunction(J, n, obj->u.f.function, obj->u.f.scope); else jsR_callfunction(J, n, obj->u.f.function, obj->u.f.scope); --J->tracetop; } else if (obj->type == JS_CSCRIPT) { jsR_pushtrace(J, obj->u.f.function->name, obj->u.f.function->filename, obj->u.f.function->line); jsR_callscript(J, n, obj->u.f.function, obj->u.f.scope); --J->tracetop; } else if (obj->type == JS_CCFUNCTION) { jsR_pushtrace(J, obj->u.c.name, "[C]", 0); jsR_callcfunction(J, n, obj->u.c.length, obj->u.c.function); --J->tracetop; } BOT = savebot; }
static void Fp_toString(js_State *J) { js_Object *self = js_toobject(J, 0); char *s; unsigned int i, n; if (!js_iscallable(J, 0)) js_typeerror(J, "not a function"); if (self->type == JS_CFUNCTION || self->type == JS_CSCRIPT) { js_Function *F = self->u.f.function; n = strlen("function () { ... }"); n += strlen(F->name); for (i = 0; i < F->numparams; ++i) n += strlen(F->vartab[i]) + 1; s = js_malloc(J, n); strcpy(s, "function "); strcat(s, F->name); strcat(s, "("); for (i = 0; i < F->numparams; ++i) { if (i > 0) strcat(s, ","); strcat(s, F->vartab[i]); } strcat(s, ") { ... }"); if (js_try(J)) { js_free(J, s); js_throw(J); } js_pushstring(J, s); js_free(J, s); js_endtry(J); } else { js_pushliteral(J, "function () { ... }"); } }
static void Ap_filter(js_State *J) { int hasthis = js_gettop(J) >= 3; int k, to, len; if (!js_iscallable(J, 1)) js_typeerror(J, "callback is not a function"); js_newarray(J); to = 0; len = js_getlength(J, 0); for (k = 0; k < len; ++k) { if (js_hasindex(J, 0, k)) { js_copy(J, 1); if (hasthis) js_copy(J, 2); else js_pushundefined(J); js_copy(J, -3); js_pushnumber(J, k); js_copy(J, 0); js_call(J, 3); if (js_toboolean(J, -1)) { js_pop(J, 1); js_setindex(J, -2, to++); } else { js_pop(J, 2); } } } }
static void Ap_forEach(js_State *J) { int hasthis = js_gettop(J) >= 3; int k, len; if (!js_iscallable(J, 1)) js_typeerror(J, "callback is not a function"); len = js_getlength(J, 0); for (k = 0; k < len; ++k) { if (js_hasindex(J, 0, k)) { js_copy(J, 1); if (hasthis) js_copy(J, 2); else js_pushundefined(J); js_copy(J, -3); js_pushnumber(J, k); js_copy(J, 0); js_call(J, 3); js_pop(J, 2); } } js_pushundefined(J); }
static void Ap_sort(js_State *J) { unsigned int len, i, k; int hasx, hasy, hasfn; len = js_getlength(J, 0); hasfn = js_iscallable(J, 1); for (i = 1; i < len; ++i) { k = i; while (k > 0 && compare(J, k - 1, k, &hasx, &hasy, hasfn) > 0) { if (hasx && hasy) { js_setindex(J, 0, k - 1); js_setindex(J, 0, k); } else if (hasx) { js_delindex(J, 0, k - 1); js_setindex(J, 0, k); } else if (hasy) { js_setindex(J, 0, k - 1); js_delindex(J, 0, k); } --k; } } js_copy(J, 0); }
int js_instanceof(js_State *J) { js_Object *O, *V; if (!js_iscallable(J, -1)) js_typeerror(J, "instanceof: invalid operand"); if (!js_isobject(J, -2)) return 0; js_getproperty(J, -1, "prototype"); if (!js_isobject(J, -1)) js_typeerror(J, "instanceof: 'prototype' property is not an object"); O = js_toobject(J, -1); js_pop(J, 1); V = js_toobject(J, -2); while (V) { V = V->prototype; if (O == V) return 1; } return 0; }
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 Sp_replace_string(js_State *J) { const char *source, *needle, *s, *r; js_Buffer *sb = NULL; int n; source = js_tostring(J, 0); needle = js_tostring(J, 1); s = strstr(source, needle); if (!s) { js_copy(J, 0); return; } n = strlen(needle); if (js_iscallable(J, 2)) { js_copy(J, 2); js_pushglobal(J); js_pushlstring(J, s, n); /* arg 1: substring that matched */ js_pushnumber(J, s - source); /* arg 2: offset within search string */ js_copy(J, 0); /* arg 3: search string */ js_call(J, 3); r = js_tostring(J, -1); js_putm(J, &sb, source, s); js_puts(J, &sb, r); js_puts(J, &sb, s + n); js_putc(J, &sb, 0); js_pop(J, 1); } else { r = js_tostring(J, 2); js_putm(J, &sb, source, s); while (*r) { if (*r == '$') { switch (*(++r)) { case '$': js_putc(J, &sb, '$'); break; case '&': js_putm(J, &sb, s, s + n); break; case '`': js_putm(J, &sb, source, s); break; case '\'': js_puts(J, &sb, s + n); break; default: js_putc(J, &sb, '$'); js_putc(J, &sb, *r); break; } ++r; } else { js_putc(J, &sb, *r++); } } js_puts(J, &sb, s + n); js_putc(J, &sb, 0); } if (js_try(J)) { js_free(J, sb); js_throw(J); } js_pushstring(J, sb ? sb->s : ""); js_endtry(J); js_free(J, sb); }
static void Fp_call(js_State *J) { unsigned int i, top = js_gettop(J); if (!js_iscallable(J, 0)) js_typeerror(J, "not a function"); for (i = 0; i < top; ++i) js_copy(J, i); js_call(J, top - 2); }
void js_construct(js_State *J, int n) { js_Object *obj; js_Object *prototype; js_Object *newobj; if (!js_iscallable(J, -n-1)) js_typeerror(J, "called object is not a function"); obj = js_toobject(J, -n-1); /* built-in constructors create their own objects, give them a 'null' this */ if (obj->type == JS_CCFUNCTION && obj->u.c.constructor) { int savebot = BOT; js_pushnull(J); if (n > 0) js_rot(J, n + 1); BOT = TOP - n - 1; jsR_pushtrace(J, obj->u.c.name, "[C]", 0); jsR_callcfunction(J, n, obj->u.c.length, obj->u.c.constructor); --J->tracetop; BOT = savebot; return; } /* extract the function object's prototype property */ js_getproperty(J, -n - 1, "prototype"); if (js_isobject(J, -1)) prototype = js_toobject(J, -1); else prototype = J->Object_prototype; js_pop(J, 1); /* create a new object with above prototype, and shift it into the 'this' slot */ newobj = jsV_newobject(J, JS_COBJECT, prototype); js_pushobject(J, newobj); if (n > 0) js_rot(J, n + 1); /* call the function */ js_call(J, n); /* if result is not an object, return the original object we created */ if (!js_isobject(J, -1)) { js_pop(J, 1); js_pushobject(J, newobj); } }
/* obj.valueOf() */ static int jsV_valueOf(js_State *J, js_Object *obj) { js_pushobject(J, obj); js_getproperty(J, -1, "valueOf"); if (js_iscallable(J, -1)) { js_rot2(J); js_call(J, 0); if (js_isprimitive(J, -1)) return 1; js_pop(J, 1); return 0; } js_pop(J, 2); return 0; }
static void Fp_apply(js_State *J) { int i, n; if (!js_iscallable(J, 0)) js_typeerror(J, "not a function"); js_copy(J, 0); js_copy(J, 1); n = js_getlength(J, 2); for (i = 0; i < n; ++i) js_getindex(J, 2, i); js_call(J, n); }
static void Ap_reduceRight(js_State *J) { int hasinitial = js_gettop(J) >= 3; int k, len; if (!js_iscallable(J, 1)) js_typeerror(J, "callback is not a function"); len = js_getlength(J, 0); k = len - 1; if (len == 0 && !hasinitial) js_typeerror(J, "no initial value"); /* initial value of accumulator */ if (hasinitial) js_copy(J, 2); else { while (k >= 0) if (js_hasindex(J, 0, k--)) break; if (k < 0) js_typeerror(J, "no initial value"); } while (k >= 0) { if (js_hasindex(J, 0, k)) { js_copy(J, 1); js_pushundefined(J); js_rot(J, 4); /* accumulator on top */ js_rot(J, 4); /* property on top */ js_pushnumber(J, k); js_copy(J, 0); js_call(J, 4); /* calculate new accumulator */ } --k; } /* return accumulator */ }
static void Fp_bind(js_State *J) { unsigned int i, top = js_gettop(J); unsigned int n; if (!js_iscallable(J, 0)) js_typeerror(J, "not a function"); n = js_getlength(J, 0); if (n > top - 2) n -= top - 2; else n = 0; js_newcconstructor(J, callbound, constructbound, "[bind]", n); /* Reuse target function's prototype for HasInstance check. */ js_getproperty(J, 0, "prototype"); js_defproperty(J, -2, "prototype", JS_READONLY | JS_DONTENUM | JS_DONTCONF); /* target function */ js_copy(J, 0); js_defproperty(J, -2, "__TargetFunction__", JS_READONLY | JS_DONTENUM | JS_DONTCONF); /* bound this */ js_copy(J, 1); js_defproperty(J, -2, "__BoundThis__", JS_READONLY | JS_DONTENUM | JS_DONTCONF); /* bound arguments */ js_newarray(J); for (i = 2; i < top; ++i) { js_copy(J, i); js_setindex(J, -2, i - 2); } js_defproperty(J, -2, "__BoundArguments__", JS_READONLY | JS_DONTENUM | JS_DONTCONF); }
static void Sp_replace_regexp(js_State *J) { js_Regexp *re; const char *source, *s, *r; js_Buffer *sb = NULL; unsigned int n, x; Resub m; source = js_tostring(J, 0); re = js_toregexp(J, 1); if (js_regexec(re->prog, source, &m, 0)) { js_copy(J, 0); return; } re->last = 0; loop: s = m.sub[0].sp; n = m.sub[0].ep - m.sub[0].sp; if (js_iscallable(J, 2)) { js_copy(J, 2); js_pushglobal(J); for (x = 0; m.sub[x].sp; ++x) /* arg 0..x: substring and subexps that matched */ js_pushlstring(J, m.sub[x].sp, m.sub[x].ep - m.sub[x].sp); js_pushnumber(J, s - source); /* arg x+2: offset within search string */ js_copy(J, 0); /* arg x+3: search string */ js_call(J, 2 + x); r = js_tostring(J, -1); js_putm(J, &sb, source, s); js_puts(J, &sb, r); js_pop(J, 1); } else { r = js_tostring(J, 2); js_putm(J, &sb, source, s); while (*r) { if (*r == '$') { switch (*(++r)) { case '$': js_putc(J, &sb, '$'); break; case '`': js_putm(J, &sb, source, s); break; case '\'': js_puts(J, &sb, s + n); break; case '&': js_putm(J, &sb, s, s + n); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': x = *r - '0'; if (r[1] >= '0' && r[1] <= '9') x = x * 10 + *(++r) - '0'; if (x > 0 && x < m.nsub) { js_putm(J, &sb, m.sub[x].sp, m.sub[x].ep); } else { js_putc(J, &sb, '$'); if (x > 10) { js_putc(J, &sb, '0' + x / 10); js_putc(J, &sb, '0' + x % 10); } else { js_putc(J, &sb, '0' + x); } } break; default: js_putc(J, &sb, '$'); js_putc(J, &sb, *r); break; } ++r; } else { js_putc(J, &sb, *r++); } } } if (re->flags & JS_REGEXP_G) { source = m.sub[0].ep; if (n == 0) { if (*source) js_putc(J, &sb, *source++); else goto end; } if (!js_regexec(re->prog, source, &m, REG_NOTBOL)) goto loop; } end: js_puts(J, &sb, s + n); js_putc(J, &sb, 0); if (js_try(J)) { js_free(J, sb); js_throw(J); } js_pushstring(J, sb ? sb->s : ""); js_endtry(J); js_free(J, sb); }