static void js_setvar(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->setter) { js_pushobject(J, ref->setter); js_pushobject(J, E->variables); js_copy(J, -3); js_call(J, 1); js_pop(J, 1); return; } if (!(ref->atts & JS_READONLY)) ref->value = *stackidx(J, -1); else if (J->strict) js_typeerror(J, "'%s' is read-only", name); return; } E = E->outer; } while (E); if (J->strict) js_referenceerror(J, "assignment to undeclared variable '%s'", name); jsR_setproperty(J, J->G, name, stackidx(J, -1)); }
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; }
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; 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; js_typeerror(J, "not a %s", tag); }
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; }
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; js_typeerror(J, "not a function"); }
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 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"; } }
/* ** Double the size of the stack */ static Stack *doublestack (lua_State *L, Stack **stacklimit, int ptop) { Stack *stack = getstackbase(L, ptop); Stack *newstack; int n = *stacklimit - stack; /* current stack size */ int max, newn; lua_getfield(L, LUA_REGISTRYINDEX, MAXSTACKIDX); max = lua_tointeger(L, -1); /* maximum allowed size */ lua_pop(L, 1); if (n >= max) /* already at maximum size? */ luaL_error(L, "too many pending calls/choices"); newn = 2 * n; /* new size */ if (newn > max) newn = max; newstack = (Stack *)lua_newuserdata(L, newn * sizeof(Stack)); memcpy(newstack, stack, n * sizeof(Stack)); lua_replace(L, stackidx(ptop)); *stacklimit = newstack + newn; return newstack + n; /* return next position */ }
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 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); }
const char *js_ref(js_State *J) { js_Value *v = stackidx(J, -1); const char *s; char buf[32]; switch (v->type) { case JS_TUNDEFINED: s = "_Undefined"; break; case JS_TNULL: s = "_Null"; break; case JS_TBOOLEAN: s = v->u.boolean ? "_True" : "_False"; break; case JS_TOBJECT: sprintf(buf, "%p", (void*)v->u.object); s = js_intern(J, buf); break; default: sprintf(buf, "%d", J->nextref++); s = js_intern(J, buf); break; } js_setregistry(J, s); return s; }
double js_tointeger(js_State *J, int idx) { return jsV_numbertointeger(jsV_tonumber(J, stackidx(J, idx))); }
static void js_initvar(js_State *J, const char *name, int idx) { jsR_defproperty(J, J->E->variables, name, JS_DONTENUM | JS_DONTCONF, stackidx(J, idx), NULL, NULL); }
void js_defproperty(js_State *J, int idx, const char *name, int atts) { jsR_defproperty(J, js_toobject(J, idx), name, atts, stackidx(J, -1), NULL, NULL); js_pop(J, 1); }
js_Object *js_toobject(js_State *J, int idx) { return jsV_toobject(J, stackidx(J, idx)); }
/* ** Opcode interpreter */ const char *match (lua_State *L, const char *o, const char *s, const char *e, Instruction *op, Capture *capture, int ptop) { Stack stackbase[INITBACK]; Stack *stacklimit = stackbase + INITBACK; Stack *stack = stackbase; /* point to first empty slot in stack */ int capsize = INITCAPSIZE; int captop = 0; /* point to first empty slot in captures */ int ndyncap = 0; /* number of dynamic captures (in Lua stack) */ const Instruction *p = op; /* current instruction */ stack->p = &giveup; stack->s = s; stack->caplevel = 0; stack++; lua_pushlightuserdata(L, stackbase); for (;;) { //#if defined(DEBUG) // printf("s: |%s| stck:%d, dyncaps:%d, caps:%d ", // s, stack - getstackbase(L, ptop), ndyncap, captop); /*printinst(op, p); printcaplist(capture, capture + captop);*/ //#endif assert(stackidx(ptop) + ndyncap == lua_gettop(L) && ndyncap <= captop); switch ((Opcode)p->i.code) { case IEnd: { assert(stack == getstackbase(L, ptop) + 1); capture[captop].kind = Cclose; capture[captop].s = NULL; return s; } case IGiveup: { assert(stack == getstackbase(L, ptop)); return NULL; } case IRet: { assert(stack > getstackbase(L, ptop) && (stack - 1)->s == NULL); p = (--stack)->p; continue; } case IAny: { if (s < e) { p++; s++; } else goto fail; continue; } case ITestAny: { if (s < e) p += 2; else p += getoffset(p); continue; } case IChar: { if ((byte)*s == p->i.aux && s < e) { p++; s++; } else goto fail; continue; } case ITestChar: { if ((byte)*s == p->i.aux && s < e) p += 2; else p += getoffset(p); continue; } case ISet: { int c = (byte)*s; if (testchar((p+1)->buff, c) && s < e) { p += CHARSETINSTSIZE; s++; } else goto fail; continue; } case ITestSet: { int c = (byte)*s; if (testchar((p + 2)->buff, c) && s < e) p += 1 + CHARSETINSTSIZE; else p += getoffset(p); continue; } case IBehind: { int n = p->i.aux; if (n > s - o) goto fail; s -= n; p++; continue; } case ISpan: { for (; s < e; s++) { int c = (byte)*s; if (!testchar((p+1)->buff, c)) break; } p += CHARSETINSTSIZE; continue; } case IJmp: { p += getoffset(p); continue; } case IChoice: { if (stack == stacklimit) stack = doublestack(L, &stacklimit, ptop); stack->p = p + getoffset(p); stack->s = s; stack->caplevel = captop; stack++; p += 2; continue; } case ICall: { if (stack == stacklimit) stack = doublestack(L, &stacklimit, ptop); stack->s = NULL; stack->p = p + 2; /* save return address */ stack++; p += getoffset(p); continue; } case ICommit: { assert(stack > getstackbase(L, ptop) && (stack - 1)->s != NULL); stack--; p += getoffset(p); continue; } case IPartialCommit: { assert(stack > getstackbase(L, ptop) && (stack - 1)->s != NULL); (stack - 1)->s = s; (stack - 1)->caplevel = captop; p += getoffset(p); continue; } case IBackCommit: { assert(stack > getstackbase(L, ptop) && (stack - 1)->s != NULL); s = (--stack)->s; captop = stack->caplevel; p += getoffset(p); continue; } case IFailTwice: assert(stack > getstackbase(L, ptop)); stack--; /* go through */ case IFail: fail: { /* pattern failed: try to backtrack */ do { /* remove pending calls */ assert(stack > getstackbase(L, ptop)); s = (--stack)->s; } while (s == NULL); if (ndyncap > 0) /* is there matchtime captures? */ ndyncap -= removedyncap(L, capture, stack->caplevel, captop); captop = stack->caplevel; p = stack->p; continue; } case ICloseRunTime: { CapState cs; int rem, res, n; int fr = lua_gettop(L) + 1; /* stack index of first result */ cs.s = o; cs.L = L; cs.ocap = capture; cs.ptop = ptop; n = runtimecap(&cs, capture + captop, s, &rem); /* call function */ captop -= n; /* remove nested captures */ fr -= rem; /* 'rem' items were popped from Lua stack */ res = resdyncaptures(L, fr, s - o, e - o); /* get result */ if (res == -1) /* fail? */ goto fail; s = o + res; /* else update current position */ n = lua_gettop(L) - fr + 1; /* number of new captures */ ndyncap += n - rem; /* update number of dynamic captures */ if (n > 0) { /* any new capture? */ if ((captop += n + 2) >= capsize) { capture = doublecap(L, capture, captop, ptop); capsize = 2 * captop; } /* add new captures to 'capture' list */ adddyncaptures(s, capture + captop - n - 2, n, fr); } p++; continue; } case ICloseCapture: { const char *s1 = s; assert(captop > 0); /* if possible, turn capture into a full capture */ if (capture[captop - 1].siz == 0 && s1 - capture[captop - 1].s < UCHAR_MAX) { capture[captop - 1].siz = s1 - capture[captop - 1].s + 1; p++; continue; } else { capture[captop].siz = 1; /* mark entry as closed */ capture[captop].s = s; goto pushcapture; } } case IOpenCapture: capture[captop].siz = 0; /* mark entry as open */ capture[captop].s = s; goto pushcapture; case IFullCapture: capture[captop].siz = getoff(p) + 1; /* save capture size */ capture[captop].s = s - getoff(p); /* goto pushcapture; */ pushcapture: { capture[captop].idx = p->i.key; capture[captop].kind = getkind(p); if (++captop >= capsize) { capture = doublecap(L, capture, captop, ptop); capsize = 2 * captop; } p++; continue; } default: assert(0); return NULL; } } }
void js_setglobal(js_State *J, const char *name) { jsR_setproperty(J, J->G, name, stackidx(J, -1)); js_pop(J, 1); }
void js_setregistry(js_State *J, const char *name) { jsR_setproperty(J, J->R, name, stackidx(J, -1)); js_pop(J, 1); }
int js_toint32(js_State *J, int idx) { return jsV_numbertoint32(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)); }
int js_toboolean(js_State *J, int idx) { return jsV_toboolean(J, stackidx(J, idx)); }
void js_defglobal(js_State *J, const char *name, int atts) { jsR_defproperty(J, J->G, name, atts, stackidx(J, -1), NULL, NULL); js_pop(J, 1); }
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; }
void js_setproperty(js_State *J, int idx, const char *name) { jsR_setproperty(J, js_toobject(J, idx), name, stackidx(J, -1)); js_pop(J, 1); }
void js_copy(js_State *J, int idx) { CHECKSTACK(1); STACK[TOP] = *stackidx(J, idx); ++TOP; }
void js_toprimitive(js_State *J, int idx, int hint) { jsV_toprimitive(J, stackidx(J, idx), hint); }