#include "jsi.h"#include "jscompile.h"#include "jsvalue.h"#include "jsrun.h" #include "utf.h" static void jsR_run(js_State *J, js_Function *F); /* Push values on stack */ #define STACK (J->stack)#define TOP (J->top)#define BOT (J->bot) static void js_stackoverflow(js_State *J){ STACK[TOP].type = JS_TLITSTR; STACK[TOP].u.litstr = "stack overflow"; ++TOP; js_throw(J);} static void js_outofmemory(js_State *J){ STACK[TOP].type = JS_TLITSTR; STACK[TOP].u.litstr = "out of memory"; ++TOP; js_throw(J);} void *js_malloc(js_State *J, int size){ void *ptr = J->alloc(J->actx, NULL, size); if (!ptr) js_outofmemory(J); return ptr;} void *js_realloc(js_State *J, void *ptr, int size){ ptr = J->alloc(J->actx, ptr, size); if (!ptr) js_outofmemory(J); return ptr;} char *js_strdup(js_State *J, const char *s){ int n = strlen(s) + 1; char *p = js_malloc(J, n); memcpy(p, s, n); return p;} void js_free(js_State *J, void *ptr){ J->alloc(J->actx, ptr, 0);} js_String *jsV_newmemstring(js_State *J, const char *s, int n){ js_String *v = js_malloc(J, soffsetof(js_String, p) + n + 1); memcpy(v->p, s, n); v->p[n] = 0; v->gcmark = 0; v->gcnext = J->gcstr; J->gcstr = v; ++J->gccounter; return v;} #define CHECKSTACK(n) if (TOP + n >= JS_STACKSIZE) js_stackoverflow(J) void js_pushvalue(js_State *J, js_Value v){ CHECKSTACK(1); STACK[TOP] = v; ++TOP;} void js_pushundefined(js_State *J){ CHECKSTACK(1); STACK[TOP].type = JS_TUNDEFINED; ++TOP;} void js_pushnull(js_State *J){ CHECKSTACK(1); STACK[TOP].type = JS_TNULL; ++TOP;} void js_pushboolean(js_State *J, int v){ CHECKSTACK(1); STACK[TOP].type = JS_TBOOLEAN; STACK[TOP].u.boolean = !!v; ++TOP;} void js_pushnumber(js_State *J, double v){ CHECKSTACK(1); STACK[TOP].type = JS_TNUMBER; STACK[TOP].u.number = v; ++TOP;} void js_pushstring(js_State *J, const char *v){ int n = strlen(v); CHECKSTACK(1); if (n <= soffsetof(js_Value, type)) { char *s = STACK[TOP].u.shrstr; while (n--) *s++ = *v++; *s = 0; STACK[TOP].type = JS_TSHRSTR; } else { STACK[TOP].type = JS_TMEMSTR; STACK[TOP].u.memstr = jsV_newmemstring(J, v, n); } ++TOP;} void js_pushlstring(js_State *J, const char *v, int n){ CHECKSTACK(1); if (n <= soffsetof(js_Value, type)) { char *s = STACK[TOP].u.shrstr; while (n--) *s++ = *v++; *s = 0; STACK[TOP].type = JS_TSHRSTR; } else { STACK[TOP].type = JS_TMEMSTR; STACK[TOP].u.memstr = jsV_newmemstring(J, v, n); } ++TOP;} void js_pushliteral(js_State *J, const char *v){ CHECKSTACK(1); STACK[TOP].type = JS_TLITSTR; STACK[TOP].u.litstr = v; ++TOP;} void js_pushobject(js_State *J, js_Object *v){ CHECKSTACK(1); STACK[TOP].type = JS_TOBJECT; STACK[TOP].u.object = v; ++TOP;} void js_pushglobal(js_State *J){ js_pushobject(J, J->G);} void js_currentfunction(js_State *J){ CHECKSTACK(1); STACK[TOP] = STACK[BOT-1]; ++TOP;} /* Read values from stack */ static js_Value *stackidx(js_State *J, int idx){ static js_Value undefined = { {0}, {0}, JS_TUNDEFINED }; idx = idx < 0 ? TOP + idx : BOT + idx; if (idx < 0 || idx >= TOP) return &undefined; return STACK + idx;} js_Value *js_tovalue(js_State *J, int idx){ return stackidx(J, idx);} int js_isdefined(js_State *J, int idx) { return stackidx(J, idx)->type != JS_TUNDEFINED; }int js_isundefined(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TUNDEFINED; }int js_isnull(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TNULL; }int js_isboolean(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TBOOLEAN; }int js_isnumber(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TNUMBER; }int js_isstring(js_State *J, int idx) { enum js_Type t = stackidx(J, idx)->type; return t == JS_TSHRSTR || t == JS_TLITSTR || t == JS_TMEMSTR; }int js_isprimitive(js_State *J, int idx) { return stackidx(J, idx)->type != JS_TOBJECT; }int js_isobject(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TOBJECT; }int js_iscoercible(js_State *J, int idx) { js_Value *v = stackidx(J, idx); return v->type != JS_TUNDEFINED && v->type != JS_TNULL; } int js_iscallable(js_State *J, int idx){ js_Value *v = stackidx(J, idx); if (v->type == JS_TOBJECT) return v->u.object->type == JS_CFUNCTION || v->u.object->type == JS_CSCRIPT || v->u.object->type == JS_CCFUNCTION; return 0;} int js_isarray(js_State *J, int idx){ js_Value *v = stackidx(J, idx); return v->type == JS_TOBJECT && v->u.object->type == JS_CARRAY;} int js_isregexp(js_State *J, int idx){ js_Value *v = stackidx(J, idx); return v->type == JS_TOBJECT && v->u.object->type == JS_CREGEXP;} int js_isuserdata(js_State *J, int idx, const char *tag){ js_Value *v = stackidx(J, idx); if (v->type == JS_TOBJECT && v->u.object->type == JS_CUSERDATA) return !strcmp(tag, v->u.object->u.user.tag); return 0;} int js_iserror(js_State *J, int idx){ js_Value *v = stackidx(J, idx); return v->type == JS_TOBJECT && v->u.object->type == JS_CERROR;} const char *js_typeof(js_State *J, int idx){ js_Value *v = stackidx(J, idx); switch (v->type) { default: case JS_TSHRSTR: return "string"; case JS_TUNDEFINED: return "undefined"; case JS_TNULL: return "object"; case JS_TBOOLEAN: return "boolean"; case JS_TNUMBER: return "number"; case JS_TLITSTR: return "string"; case JS_TMEMSTR: return "string"; case JS_TOBJECT: if (v->u.object->type == JS_CFUNCTION || v->u.object->type == JS_CCFUNCTION) return "function"; return "object"; }} int js_type(js_State *J, int idx){ js_Value *v = stackidx(J, idx); switch (v->type) { default: case JS_TSHRSTR: return JS_ISSTRING; case JS_TUNDEFINED: return JS_ISUNDEFINED; case JS_TNULL: return JS_ISNULL; case JS_TBOOLEAN: return JS_ISBOOLEAN; case JS_TNUMBER: return JS_ISNUMBER; case JS_TLITSTR: return JS_ISSTRING; case JS_TMEMSTR: return JS_ISSTRING; case JS_TOBJECT: if (v->u.object->type == JS_CFUNCTION || v->u.object->type == JS_CCFUNCTION) return JS_ISFUNCTION; return JS_ISOBJECT; }} int js_toboolean(js_State *J, int idx){ return jsV_toboolean(J, stackidx(J, idx));} double js_tonumber(js_State *J, int idx){ return jsV_tonumber(J, stackidx(J, idx));} int js_tointeger(js_State *J, int idx){ return jsV_numbertointeger(jsV_tonumber(J, stackidx(J, idx)));} int js_toint32(js_State *J, int idx){ return jsV_numbertoint32(jsV_tonumber(J, stackidx(J, idx)));} unsigned int js_touint32(js_State *J, int idx){ return jsV_numbertouint32(jsV_tonumber(J, stackidx(J, idx)));} short js_toint16(js_State *J, int idx){ return jsV_numbertoint16(jsV_tonumber(J, stackidx(J, idx)));} unsigned short js_touint16(js_State *J, int idx){ return jsV_numbertouint16(jsV_tonumber(J, stackidx(J, idx)));} const char *js_tostring(js_State *J, int idx){ return jsV_tostring(J, stackidx(J, idx));} js_Object *js_toobject(js_State *J, int idx){ return jsV_toobject(J, stackidx(J, idx));} void js_toprimitive(js_State *J, int idx, int hint){ jsV_toprimitive(J, stackidx(J, idx), hint);} js_Regexp *js_toregexp(js_State *J, int idx){ js_Value *v = stackidx(J, idx); if (v->type == JS_TOBJECT && v->u.object->type == JS_CREGEXP) return &v->u.object->u.r; return js_typeerror(J, "not a regexp");} void *js_touserdata(js_State *J, int idx, const char *tag){ js_Value *v = stackidx(J, idx); if (v->type == JS_TOBJECT && v->u.object->type == JS_CUSERDATA) if (!strcmp(tag, v->u.object->u.user.tag)) return v->u.object->u.user.data; return js_typeerror(J, "not a %s", tag);} static js_Object *jsR_tofunction(js_State *J, int idx){ js_Value *v = stackidx(J, idx); if (v->type == JS_TUNDEFINED || v->type == JS_TNULL) return NULL; if (v->type == JS_TOBJECT) if (v->u.object->type == JS_CFUNCTION || v->u.object->type == JS_CCFUNCTION) return v->u.object; return js_typeerror(J, "not a function");} /* Stack manipulation */ int js_gettop(js_State *J){ return TOP - BOT;} void js_pop(js_State *J, int n){ TOP -= n; if (TOP < BOT) { TOP = BOT; js_error(J, "stack underflow!"); }} void js_remove(js_State *J, int idx){ idx = idx < 0 ? TOP + idx : BOT + idx; if (idx < BOT || idx >= TOP) js_error(J, "stack error!"); for (;idx < TOP - 1; ++idx) STACK[idx] = STACK[idx+1]; --TOP;} void js_insert(js_State *J, int idx){ js_error(J, "not implemented yet");} void js_replace(js_State* J, int idx){ idx = idx < 0 ? TOP + idx : BOT + idx; if (idx < BOT || idx >= TOP) js_error(J, "stack error!"); STACK[idx] = STACK[--TOP];} void js_copy(js_State *J, int idx){ CHECKSTACK(1); STACK[TOP] = *stackidx(J, idx); ++TOP;} void js_dup(js_State *J){ CHECKSTACK(1); STACK[TOP] = STACK[TOP-1]; ++TOP;} void js_dup2(js_State *J){ CHECKSTACK(2); STACK[TOP] = STACK[TOP-2]; STACK[TOP+1] = STACK[TOP-1]; TOP += 2;} void js_rot2(js_State *J){ /* A B -> B A */ js_Value tmp = STACK[TOP-1]; /* A B (B) */ STACK[TOP-1] = STACK[TOP-2]; /* A A */ STACK[TOP-2] = tmp; /* B A */} void js_rot3(js_State *J){ /* A B C -> C A B */ js_Value tmp = STACK[TOP-1]; /* A B C (C) */ STACK[TOP-1] = STACK[TOP-2]; /* A B B */ STACK[TOP-2] = STACK[TOP-3]; /* A A B */ STACK[TOP-3] = tmp; /* C A B */} void js_rot4(js_State *J){ /* A B C D -> D A B C */ js_Value tmp = STACK[TOP-1]; /* A B C D (D) */ STACK[TOP-1] = STACK[TOP-2]; /* A B C C */ STACK[TOP-2] = STACK[TOP-3]; /* A B B C */ STACK[TOP-3] = STACK[TOP-4]; /* A A B C */ STACK[TOP-4] = tmp; /* D A B C */} void js_rot2pop1(js_State *J){ /* A B -> B */ STACK[TOP-2] = STACK[TOP-1]; --TOP;} void js_rot3pop2(js_State *J){ /* A B C -> C */ STACK[TOP-3] = STACK[TOP-1]; TOP -= 2;} void js_rot(js_State *J, int n){ int i; js_Value tmp = STACK[TOP-1]; for (i = 1; i < n; ++i) STACK[TOP-i] = STACK[TOP-i-1]; STACK[TOP-i] = tmp;} /* Property access that takes care of attributes and getters/setters */ int js_isarrayindex(js_State *J, const char *p, int *idx){ int n = 0; /* check for empty string */ if (p[0] == 0) return 0; /* check for '0' and integers with leading zero */ if (p[0] == '0') return (p[1] == 0) ? *idx = 0, 1 : 0; while (*p) { int c = *p++; if (c >= '0' && c <= '9') { if (n >= INT_MAX / 10) return 0; n = n * 10 + (c - '0'); } else { return 0; } } return *idx = n, 1;} static void js_pushrune(js_State *J, Rune rune){ char buf[UTFmax + 1]; if (rune >= 0) { buf[runetochar(buf, &rune)] = 0; js_pushstring(J, buf); } else { js_pushundefined(J); }} static int jsR_hasproperty(js_State *J, js_Object *obj, const char *name){ js_Property *ref;Lines 1–500 of 1835. Load more
#include "jsi.h" #include "jscompile.h" #include "jsvalue.h" #include "jsrun.h" #include "utf.h" static void jsR_run(js_State *J, js_Function *F); /* Push values on stack */ #define STACK (J->stack) #define TOP (J->top) #define BOT (J->bot) static void js_stackoverflow(js_State *J) { STACK[TOP].type = JS_TLITSTR; STACK[TOP].u.litstr = "stack overflow"; ++TOP; js_throw(J); } static void js_outofmemory(js_State *J) { STACK[TOP].type = JS_TLITSTR; STACK[TOP].u.litstr = "out of memory"; ++TOP; js_throw(J); } void *js_malloc(js_State *J, int size) { void *ptr = J->alloc(J->actx, NULL, size); if (!ptr) js_outofmemory(J); return ptr; } void *js_realloc(js_State *J, void *ptr, int size) { ptr = J->alloc(J->actx, ptr, size); if (!ptr) js_outofmemory(J); return ptr; } char *js_strdup(js_State *J, const char *s) { int n = strlen(s) + 1; char *p = js_malloc(J, n); memcpy(p, s, n); return p; } void js_free(js_State *J, void *ptr) { J->alloc(J->actx, ptr, 0); } js_String *jsV_newmemstring(js_State *J, const char *s, int n) { js_String *v = js_malloc(J, soffsetof(js_String, p) + n + 1); memcpy(v->p, s, n); v->p[n] = 0; v->gcmark = 0; v->gcnext = J->gcstr; J->gcstr = v; ++J->gccounter; return v; } #define CHECKSTACK(n) if (TOP + n >= JS_STACKSIZE) js_stackoverflow(J) void js_pushvalue(js_State *J, js_Value v) { CHECKSTACK(1); STACK[TOP] = v; ++TOP; } void js_pushundefined(js_State *J) { CHECKSTACK(1); STACK[TOP].type = JS_TUNDEFINED; ++TOP; } void js_pushnull(js_State *J) { CHECKSTACK(1); STACK[TOP].type = JS_TNULL; ++TOP; } void js_pushboolean(js_State *J, int v) { CHECKSTACK(1); STACK[TOP].type = JS_TBOOLEAN; STACK[TOP].u.boolean = !!v; ++TOP; } void js_pushnumber(js_State *J, double v) { CHECKSTACK(1); STACK[TOP].type = JS_TNUMBER; STACK[TOP].u.number = v; ++TOP; } void js_pushstring(js_State *J, const char *v) { int n = strlen(v); CHECKSTACK(1); if (n <= soffsetof(js_Value, type)) { char *s = STACK[TOP].u.shrstr; while (n--) *s++ = *v++; *s = 0; STACK[TOP].type = JS_TSHRSTR; } else { STACK[TOP].type = JS_TMEMSTR; STACK[TOP].u.memstr = jsV_newmemstring(J, v, n); } ++TOP; } void js_pushlstring(js_State *J, const char *v, int n) { CHECKSTACK(1); if (n <= soffsetof(js_Value, type)) { char *s = STACK[TOP].u.shrstr; while (n--) *s++ = *v++; *s = 0; STACK[TOP].type = JS_TSHRSTR; } else { STACK[TOP].type = JS_TMEMSTR; STACK[TOP].u.memstr = jsV_newmemstring(J, v, n); } ++TOP; } void js_pushliteral(js_State *J, const char *v) { CHECKSTACK(1); STACK[TOP].type = JS_TLITSTR; STACK[TOP].u.litstr = v; ++TOP; } void js_pushobject(js_State *J, js_Object *v) { CHECKSTACK(1); STACK[TOP].type = JS_TOBJECT; STACK[TOP].u.object = v; ++TOP; } void js_pushglobal(js_State *J) { js_pushobject(J, J->G); } void js_currentfunction(js_State *J) { CHECKSTACK(1); STACK[TOP] = STACK[BOT-1]; ++TOP; } /* Read values from stack */ static js_Value *stackidx(js_State *J, int idx) { static js_Value undefined = { {0}, {0}, JS_TUNDEFINED }; idx = idx < 0 ? TOP + idx : BOT + idx; if (idx < 0 || idx >= TOP) return &undefined; return STACK + idx; } js_Value *js_tovalue(js_State *J, int idx) { return stackidx(J, idx); } int js_isdefined(js_State *J, int idx) { return stackidx(J, idx)->type != JS_TUNDEFINED; } int js_isundefined(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TUNDEFINED; } int js_isnull(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TNULL; } int js_isboolean(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TBOOLEAN; } int js_isnumber(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TNUMBER; } int js_isstring(js_State *J, int idx) { enum js_Type t = stackidx(J, idx)->type; return t == JS_TSHRSTR || t == JS_TLITSTR || t == JS_TMEMSTR; } int js_isprimitive(js_State *J, int idx) { return stackidx(J, idx)->type != JS_TOBJECT; } int js_isobject(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TOBJECT; } int js_iscoercible(js_State *J, int idx) { js_Value *v = stackidx(J, idx); return v->type != JS_TUNDEFINED && v->type != JS_TNULL; } int js_iscallable(js_State *J, int idx) { js_Value *v = stackidx(J, idx); if (v->type == JS_TOBJECT) return v->u.object->type == JS_CFUNCTION || v->u.object->type == JS_CSCRIPT || v->u.object->type == JS_CCFUNCTION; return 0; } int js_isarray(js_State *J, int idx) { js_Value *v = stackidx(J, idx); return v->type == JS_TOBJECT && v->u.object->type == JS_CARRAY; } int js_isregexp(js_State *J, int idx) { js_Value *v = stackidx(J, idx); return v->type == JS_TOBJECT && v->u.object->type == JS_CREGEXP; } int js_isuserdata(js_State *J, int idx, const char *tag) { js_Value *v = stackidx(J, idx); if (v->type == JS_TOBJECT && v->u.object->type == JS_CUSERDATA) return !strcmp(tag, v->u.object->u.user.tag); return 0; } int js_iserror(js_State *J, int idx) { js_Value *v = stackidx(J, idx); return v->type == JS_TOBJECT && v->u.object->type == JS_CERROR; } const char *js_typeof(js_State *J, int idx) { js_Value *v = stackidx(J, idx); switch (v->type) { default: case JS_TSHRSTR: return "string"; case JS_TUNDEFINED: return "undefined"; case JS_TNULL: return "object"; case JS_TBOOLEAN: return "boolean"; case JS_TNUMBER: return "number"; case JS_TLITSTR: return "string"; case JS_TMEMSTR: return "string"; case JS_TOBJECT: if (v->u.object->type == JS_CFUNCTION || v->u.object->type == JS_CCFUNCTION) return "function"; return "object"; } } int js_type(js_State *J, int idx) { js_Value *v = stackidx(J, idx); switch (v->type) { default: case JS_TSHRSTR: return JS_ISSTRING; case JS_TUNDEFINED: return JS_ISUNDEFINED; case JS_TNULL: return JS_ISNULL; case JS_TBOOLEAN: return JS_ISBOOLEAN; case JS_TNUMBER: return JS_ISNUMBER; case JS_TLITSTR: return JS_ISSTRING; case JS_TMEMSTR: return JS_ISSTRING; case JS_TOBJECT: if (v->u.object->type == JS_CFUNCTION || v->u.object->type == JS_CCFUNCTION) return JS_ISFUNCTION; return JS_ISOBJECT; } } int js_toboolean(js_State *J, int idx) { return jsV_toboolean(J, stackidx(J, idx)); } double js_tonumber(js_State *J, int idx) { return jsV_tonumber(J, stackidx(J, idx)); } int js_tointeger(js_State *J, int idx) { return jsV_numbertointeger(jsV_tonumber(J, stackidx(J, idx))); } int js_toint32(js_State *J, int idx) { return jsV_numbertoint32(jsV_tonumber(J, stackidx(J, idx))); } unsigned int js_touint32(js_State *J, int idx) { return jsV_numbertouint32(jsV_tonumber(J, stackidx(J, idx))); } short js_toint16(js_State *J, int idx) { return jsV_numbertoint16(jsV_tonumber(J, stackidx(J, idx))); } unsigned short js_touint16(js_State *J, int idx) { return jsV_numbertouint16(jsV_tonumber(J, stackidx(J, idx))); } const char *js_tostring(js_State *J, int idx) { return jsV_tostring(J, stackidx(J, idx)); } js_Object *js_toobject(js_State *J, int idx) { return jsV_toobject(J, stackidx(J, idx)); } void js_toprimitive(js_State *J, int idx, int hint) { jsV_toprimitive(J, stackidx(J, idx), hint); } js_Regexp *js_toregexp(js_State *J, int idx) { js_Value *v = stackidx(J, idx); if (v->type == JS_TOBJECT && v->u.object->type == JS_CREGEXP) return &v->u.object->u.r; return js_typeerror(J, "not a regexp"); } void *js_touserdata(js_State *J, int idx, const char *tag) { js_Value *v = stackidx(J, idx); if (v->type == JS_TOBJECT && v->u.object->type == JS_CUSERDATA) if (!strcmp(tag, v->u.object->u.user.tag)) return v->u.object->u.user.data; return js_typeerror(J, "not a %s", tag); } static js_Object *jsR_tofunction(js_State *J, int idx) { js_Value *v = stackidx(J, idx); if (v->type == JS_TUNDEFINED || v->type == JS_TNULL) return NULL; if (v->type == JS_TOBJECT) if (v->u.object->type == JS_CFUNCTION || v->u.object->type == JS_CCFUNCTION) return v->u.object; return js_typeerror(J, "not a function"); } /* Stack manipulation */ int js_gettop(js_State *J) { return TOP - BOT; } void js_pop(js_State *J, int n) { TOP -= n; if (TOP < BOT) { TOP = BOT; js_error(J, "stack underflow!"); } } void js_remove(js_State *J, int idx) { idx = idx < 0 ? TOP + idx : BOT + idx; if (idx < BOT || idx >= TOP) js_error(J, "stack error!"); for (;idx < TOP - 1; ++idx) STACK[idx] = STACK[idx+1]; --TOP; } void js_insert(js_State *J, int idx) { js_error(J, "not implemented yet"); } void js_replace(js_State* J, int idx) { idx = idx < 0 ? TOP + idx : BOT + idx; if (idx < BOT || idx >= TOP) js_error(J, "stack error!"); STACK[idx] = STACK[--TOP]; } void js_copy(js_State *J, int idx) { CHECKSTACK(1); STACK[TOP] = *stackidx(J, idx); ++TOP; } void js_dup(js_State *J) { CHECKSTACK(1); STACK[TOP] = STACK[TOP-1]; ++TOP; } void js_dup2(js_State *J) { CHECKSTACK(2); STACK[TOP] = STACK[TOP-2]; STACK[TOP+1] = STACK[TOP-1]; TOP += 2; } void js_rot2(js_State *J) { /* A B -> B A */ js_Value tmp = STACK[TOP-1]; /* A B (B) */ STACK[TOP-1] = STACK[TOP-2]; /* A A */ STACK[TOP-2] = tmp; /* B A */ } void js_rot3(js_State *J) { /* A B C -> C A B */ js_Value tmp = STACK[TOP-1]; /* A B C (C) */ STACK[TOP-1] = STACK[TOP-2]; /* A B B */ STACK[TOP-2] = STACK[TOP-3]; /* A A B */ STACK[TOP-3] = tmp; /* C A B */ } void js_rot4(js_State *J) { /* A B C D -> D A B C */ js_Value tmp = STACK[TOP-1]; /* A B C D (D) */ STACK[TOP-1] = STACK[TOP-2]; /* A B C C */ STACK[TOP-2] = STACK[TOP-3]; /* A B B C */ STACK[TOP-3] = STACK[TOP-4]; /* A A B C */ STACK[TOP-4] = tmp; /* D A B C */ } void js_rot2pop1(js_State *J) { /* A B -> B */ STACK[TOP-2] = STACK[TOP-1]; --TOP; } void js_rot3pop2(js_State *J) { /* A B C -> C */ STACK[TOP-3] = STACK[TOP-1]; TOP -= 2; } void js_rot(js_State *J, int n) { int i; js_Value tmp = STACK[TOP-1]; for (i = 1; i < n; ++i) STACK[TOP-i] = STACK[TOP-i-1]; STACK[TOP-i] = tmp; } /* Property access that takes care of attributes and getters/setters */ int js_isarrayindex(js_State *J, const char *p, int *idx) { int n = 0; /* check for empty string */ if (p[0] == 0) return 0; /* check for '0' and integers with leading zero */ if (p[0] == '0') return (p[1] == 0) ? *idx = 0, 1 : 0; while (*p) { int c = *p++; if (c >= '0' && c <= '9') { if (n >= INT_MAX / 10) return 0; n = n * 10 + (c - '0'); } else { return 0; } } return *idx = n, 1; } static void js_pushrune(js_State *J, Rune rune) { char buf[UTFmax + 1]; if (rune >= 0) { buf[runetochar(buf, &rune)] = 0; js_pushstring(J, buf); } else { js_pushundefined(J); } } static int jsR_hasproperty(js_State *J, js_Object *obj, const char *name) { js_Property *ref;