ref: e45115faeee4928b5fa103eaff55b6ed804899a8
parent: 68862386d80d02e24bbae650f11be0ec07e11195
author: Tor Andersson <tor@ccxvii.net>
date: Mon Feb 10 13:54:52 EST 2014
Handle variable shadowing.
--- a/jscompile.c
+++ b/jscompile.c
@@ -42,6 +42,7 @@
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 @@
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 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 @@
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 @@
}
}
- 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 @@
{
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 @@
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,31 +1159,24 @@
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);
--- a/jscompile.h
+++ b/jscompile.h
@@ -42,6 +42,7 @@
OP_DELLOCAL, /* -N- false */
OP_INITVAR, /* <value> -S- */
+ OP_DEFVAR, /* -S- */
OP_GETVAR, /* -S- <value> */
OP_SETVAR, /* <value> -S- <value> */
OP_DELVAR, /* -S- <success> */
--- a/jsdump.c
+++ b/jsdump.c
@@ -756,6 +756,7 @@
break;
case OP_INITVAR:
+ case OP_DEFVAR:
case OP_GETVAR:
case OP_SETVAR:
case OP_DELVAR:
@@ -772,6 +773,10 @@
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:
--- a/jsrun.c
+++ b/jsrun.c
@@ -687,11 +687,16 @@
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 @@
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,8 +1061,12 @@
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: