shithub: libmujs

Download patch

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: