mirror of
https://github.com/ccxvii/mujs.git
synced 2026-09-21 06:33:35 +08:00
Handle variable shadowing.
This commit is contained in:
+38
-33
@@ -42,6 +42,7 @@ static js_Function *newfun(js_State *J, js_Ast *name, js_Ast *params, js_Ast *bo
|
||||
F->filename = js_intern(J, J->filename);
|
||||
F->line = name ? name->line : params ? params->line : body ? body->line : 1;
|
||||
F->script = script;
|
||||
F->name = name ? name->string : "";
|
||||
|
||||
cfunbody(J, F, name, params, body);
|
||||
|
||||
@@ -102,8 +103,14 @@ static int addstring(JF, const char *value)
|
||||
return F->strlen++;
|
||||
}
|
||||
|
||||
static void addlocal(JF, const char *name)
|
||||
static void addlocal(JF, const char *name, int reuse)
|
||||
{
|
||||
if (reuse) {
|
||||
int i;
|
||||
for (i = 0; i < F->varlen; ++i)
|
||||
if (!strcmp(F->vartab[i], name))
|
||||
return;
|
||||
}
|
||||
if (F->varlen >= F->varcap) {
|
||||
F->varcap = F->varcap ? F->varcap * 2 : 16;
|
||||
F->vartab = realloc(F->vartab, F->varcap * sizeof *F->vartab);
|
||||
@@ -114,9 +121,9 @@ static void addlocal(JF, const char *name)
|
||||
static int findlocal(JF, const char *name)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < F->varlen; ++i)
|
||||
for (i = F->varlen - 1; i >= 0; --i)
|
||||
if (!strcmp(F->vartab[i], name))
|
||||
return i;
|
||||
return i + 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -154,7 +161,7 @@ static void emitlocal(JF, int oploc, int opvar, const char *name)
|
||||
i = findlocal(J, F, name);
|
||||
if (i >= 0) {
|
||||
emit(J, F, oploc);
|
||||
emitraw(J, F, i + 1);
|
||||
emitraw(J, F, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1093,9 +1100,6 @@ static void analyze(JF, js_Ast *node)
|
||||
}
|
||||
}
|
||||
|
||||
if (node->type == EXP_VAR)
|
||||
addlocal(J, F, node->a->string);
|
||||
|
||||
if (node->a) analyze(J, F, node->a);
|
||||
if (node->b) analyze(J, F, node->b);
|
||||
if (node->c) analyze(J, F, node->c);
|
||||
@@ -1115,18 +1119,27 @@ static void cparams(JF, js_Ast *list)
|
||||
{
|
||||
F->numparams = listlength(list);
|
||||
while (list) {
|
||||
addlocal(J, F, list->a->string);
|
||||
addlocal(J, F, list->a->string, 0);
|
||||
list = list->b;
|
||||
}
|
||||
}
|
||||
|
||||
static void cvardecs(JF)
|
||||
static void cvardecs(JF, js_Ast *node)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < F->varlen; ++i) {
|
||||
emit(J, F, OP_UNDEF);
|
||||
emitstring(J, F, OP_INITVAR, F->vartab[i]);
|
||||
if (isfun(node->type))
|
||||
return; /* stop at inner functions */
|
||||
|
||||
if (node->type == EXP_VAR) {
|
||||
if (F->lightweight)
|
||||
addlocal(J, F, node->a->string, 1);
|
||||
else
|
||||
emitstring(J, F, OP_DEFVAR, node->a->string);
|
||||
}
|
||||
|
||||
if (node->a) cvardecs(J, F, node->a);
|
||||
if (node->b) cvardecs(J, F, node->b);
|
||||
if (node->c) cvardecs(J, F, node->c);
|
||||
if (node->d) cvardecs(J, F, node->d);
|
||||
}
|
||||
|
||||
static void cfundecs(JF, js_Ast *list)
|
||||
@@ -1134,7 +1147,6 @@ static void cfundecs(JF, js_Ast *list)
|
||||
while (list) {
|
||||
js_Ast *stm = list->a;
|
||||
if (stm->type == AST_FUNDEC) {
|
||||
addlocal(J, F, stm->a->string);
|
||||
emitfunction(J, F, newfun(J, stm->a, stm->b, stm->c, 0));
|
||||
emitstring(J, F, OP_INITVAR, stm->a->string);
|
||||
}
|
||||
@@ -1147,32 +1159,25 @@ static void cfunbody(JF, js_Ast *name, js_Ast *params, js_Ast *body)
|
||||
F->lightweight = 1;
|
||||
F->arguments = 0;
|
||||
|
||||
cparams(J, F, params);
|
||||
|
||||
if (name) {
|
||||
F->name = name->string;
|
||||
addlocal(J, F, name->string);
|
||||
} else {
|
||||
F->name = "";
|
||||
}
|
||||
|
||||
if (body)
|
||||
analyze(J, F, body);
|
||||
|
||||
if (!F->lightweight) {
|
||||
cvardecs(J, F);
|
||||
cfundecs(J, F, body);
|
||||
}
|
||||
cparams(J, F, params);
|
||||
|
||||
if (name) {
|
||||
if (F->lightweight)
|
||||
emit(J, F, OP_CURRENT);
|
||||
else
|
||||
emitfunction(J, F, F);
|
||||
emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, name->string);
|
||||
emit(J, F, OP_POP);
|
||||
emit(J, F, OP_CURRENT);
|
||||
if (F->lightweight) {
|
||||
addlocal(J, F, name->string, 0);
|
||||
emit(J, F, OP_INITLOCAL);
|
||||
emitraw(J, F, findlocal(J, F, name->string));
|
||||
} else {
|
||||
emitstring(J, F, OP_INITVAR, name->string);
|
||||
}
|
||||
}
|
||||
|
||||
cvardecs(J, F, body);
|
||||
cfundecs(J, F, body);
|
||||
|
||||
if (F->script) {
|
||||
emit(J, F, OP_UNDEF);
|
||||
cstmlist(J, F, body);
|
||||
|
||||
@@ -42,6 +42,7 @@ enum js_OpCode
|
||||
OP_DELLOCAL, /* -N- false */
|
||||
|
||||
OP_INITVAR, /* <value> -S- */
|
||||
OP_DEFVAR, /* -S- */
|
||||
OP_GETVAR, /* -S- <value> */
|
||||
OP_SETVAR, /* <value> -S- <value> */
|
||||
OP_DELVAR, /* -S- <success> */
|
||||
|
||||
@@ -756,6 +756,7 @@ void jsC_dumpfunction(js_State *J, js_Function *F)
|
||||
break;
|
||||
|
||||
case OP_INITVAR:
|
||||
case OP_DEFVAR:
|
||||
case OP_GETVAR:
|
||||
case OP_SETVAR:
|
||||
case OP_DELVAR:
|
||||
@@ -772,6 +773,10 @@ void jsC_dumpfunction(js_State *J, js_Function *F)
|
||||
case OP_GETLOCAL:
|
||||
case OP_SETLOCAL:
|
||||
case OP_DELLOCAL:
|
||||
printf(" %d (%s)", *p, F->vartab[*p-1]);
|
||||
++p;
|
||||
break;
|
||||
|
||||
case OP_NUMBER_N:
|
||||
case OP_INITPROP_N:
|
||||
case OP_CALL:
|
||||
|
||||
@@ -687,11 +687,16 @@ js_Environment *jsR_newenvironment(js_State *J, js_Object *vars, js_Environment
|
||||
return E;
|
||||
}
|
||||
|
||||
static void js_decvar(js_State *J, const char *name, int 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);
|
||||
}
|
||||
|
||||
static void js_defvar(js_State *J, const char *name)
|
||||
{
|
||||
jsR_defproperty(J, J->E->variables, name, JS_DONTENUM | JS_DONTCONF, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void js_getvar(js_State *J, const char *name)
|
||||
{
|
||||
js_Environment *E = J->E;
|
||||
@@ -787,12 +792,27 @@ static void jsR_callfunction(js_State *J, int n, js_Function *F, js_Environment
|
||||
saveE = J->E;
|
||||
|
||||
J->E = jsR_newenvironment(J, jsV_newobject(J, JS_COBJECT, NULL), scope);
|
||||
|
||||
if (F->arguments) {
|
||||
js_newobject(J);
|
||||
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_decvar(J, F->vartab[i], i + 1);
|
||||
js_initvar(J, F->vartab[i], i + 1);
|
||||
else {
|
||||
js_pushundefined(J);
|
||||
js_decvar(J, F->vartab[i], -1);
|
||||
js_initvar(J, F->vartab[i], -1);
|
||||
js_pop(J, 1);
|
||||
}
|
||||
}
|
||||
@@ -1041,10 +1061,14 @@ static void jsR_run(js_State *J, js_Function *F)
|
||||
break;
|
||||
|
||||
case OP_INITVAR:
|
||||
js_decvar(J, ST[*pc++], -1);
|
||||
js_initvar(J, ST[*pc++], -1);
|
||||
js_pop(J, 1);
|
||||
break;
|
||||
|
||||
case OP_DEFVAR:
|
||||
js_defvar(J, ST[*pc++]);
|
||||
break;
|
||||
|
||||
case OP_GETVAR:
|
||||
js_getvar(J, ST[*pc++]);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user