shithub: libmujs

Download patch

ref: 4b981faad7f0ea14ceb0af14ebfae4859fb9debb
parent: d3d073195c861b52964670b69db407429a93dd89
author: Tor Andersson <tor@ccxvii.net>
date: Mon Jan 13 09:56:17 EST 2014

Clean up handling of function declarations / statements / expressions.

--- a/jscompile.c
+++ b/jscompile.c
@@ -286,7 +286,7 @@
 		emit(J, F, n);
 		break;
 
-	case EXP_FUNC:
+	case EXP_FUN:
 		emitfunction(J, F, OP_CLOSURE, newfun(J, exp->a, exp->b, exp->c));
 		break;
 
@@ -412,7 +412,7 @@
 	int loop, then, end;
 
 	switch (stm->type) {
-	case STM_FUNC:
+	case AST_FUNDEC:
 		break;
 
 	case STM_BLOCK:
@@ -509,7 +509,7 @@
 {
 	while (list) {
 		js_Ast *stm = list->a;
-		if (stm->type == STM_FUNC) {
+		if (stm->type == AST_FUNDEC) {
 			emitfunction(J, F, OP_CLOSURE, newfun(J, stm->a, stm->b, stm->c));
 			emitname(J, F, OP_FUNDEC, stm->a->string);
 		}
@@ -521,7 +521,7 @@
 {
 	if (node->type == EXP_VAR) {
 		emitname(J, F, OP_VARDEC, node->a->string);
-	} else if (node->type != EXP_FUNC && node->type != STM_FUNC) {
+	} else if (node->type != EXP_FUN && node->type != AST_FUNDEC) {
 		if (node->a) cvardecs(J, F, node->a);
 		if (node->b) cvardecs(J, F, node->b);
 		if (node->c) cvardecs(J, F, node->c);
--- a/jsdump.c
+++ b/jsdump.c
@@ -6,19 +6,19 @@
 #include <assert.h>
 
 static const char *astname[] = {
-	"list", "ident", "number", "string", "regexp", "undef", "null", "true",
-	"false", "this", "array", "object", "prop_val", "prop_get", "prop_set",
-	"index", "member", "call", "new", "funexp", "delete", "void", "typeof",
-	"preinc", "predec", "postinc", "postdec", "pos", "neg", "bitnot",
-	"lognot", "logor", "logand", "bitor", "bitxor", "bitand", "eq", "ne",
-	"eq3", "ne3", "lt", "gt", "le", "ge", "instanceof", "in", "shl", "shr",
-	"ushr", "add", "sub", "mul", "div", "mod", "cond", "ass", "ass_mul",
-	"ass_div", "ass_mod", "ass_add", "ass_sub", "ass_shl", "ass_shr",
-	"ass_ushr", "ass_bitand", "ass_bitxor", "ass_bitor", "comma",
-	"var-init", "fundec", "block", "nop", "var", "if", "do-while", "while",
-	"for", "for-var", "for-in", "for-in-var", "continue", "break",
-	"return", "with", "switch", "throw", "try", "debugger", "label",
-	"case", "default",
+	"list", "ident", "number", "string", "regexp", "fundec", "undef",
+	"null", "true", "false", "this", "fun", "array", "object", "prop_val",
+	"prop_get", "prop_set", "index", "member", "call", "new", "delete",
+	"void", "typeof", "preinc", "predec", "postinc", "postdec", "pos",
+	"neg", "bitnot", "lognot", "logor", "logand", "bitor", "bitxor",
+	"bitand", "eq", "ne", "eq3", "ne3", "lt", "gt", "le", "ge",
+	"instanceof", "in", "shl", "shr", "ushr", "add", "sub", "mul", "div",
+	"mod", "cond", "ass", "ass_mul", "ass_div", "ass_mod", "ass_add",
+	"ass_sub", "ass_shl", "ass_shr", "ass_ushr", "ass_bitand",
+	"ass_bitxor", "ass_bitor", "comma", "var_init", "block", "nop", "var",
+	"if", "do_while", "while", "for", "for_var", "for_in", "for_in_var",
+	"continue", "break", "return", "with", "switch", "throw", "try",
+	"debugger", "label", "case", "default",
 };
 
 static const char *opname[] = {
@@ -268,7 +268,7 @@
 		if (i) pc(')');
 		break;
 
-	case EXP_FUNC:
+	case EXP_FUN:
 		ps("(function ");
 		if (exp->a) pexpi(d, 1, exp->a);
 		pc('(');
@@ -352,7 +352,7 @@
 	in(d);
 
 	switch (stm->type) {
-	case STM_FUNC:
+	case AST_FUNDEC:
 		ps("function ");
 		pexpi(d, 1, stm->a);
 		pc('(');
@@ -533,7 +533,7 @@
 	case AST_REGEXP: pc(' '); pregexp(node->string, node->number); break;
 	case AST_NUMBER: printf(" %.9g", node->number); break;
 	case STM_BLOCK: afun = sblock; break;
-	case STM_FUNC: case EXP_FUNC: cfun = sblock; break;
+	case AST_FUNDEC: case EXP_FUN: cfun = sblock; break;
 	case STM_SWITCH: bfun = sblock; break;
 	case STM_CASE: bfun = sblock; break;
 	case STM_DEFAULT: afun = sblock; break;
--- a/jsparse.c
+++ b/jsparse.c
@@ -5,7 +5,7 @@
 
 #define nelem(a) (sizeof (a) / sizeof (a)[0])
 
-#define LIST(h)		jsP_newnode(J, AST_LIST, h, 0, 0, 0);
+#define LIST(h)		jsP_newnode(J, AST_LIST, h, 0, 0, 0)
 
 #define EXP0(x)		jsP_newnode(J, EXP_ ## x, 0, 0, 0, 0)
 #define EXP1(x,a)	jsP_newnode(J, EXP_ ## x, a, 0, 0, 0)
@@ -24,7 +24,7 @@
 static js_Ast *assignment(js_State *J, int notin);
 static js_Ast *memberexp(js_State *J);
 static js_Ast *statement(js_State *J);
-static js_Ast *funcbody(js_State *J);
+static js_Ast *funbody(js_State *J);
 
 js_Ast *jsP_newnode(js_State *J, int type, js_Ast *a, js_Ast *b, js_Ast *c, js_Ast *d)
 {
@@ -70,6 +70,8 @@
 	J->ast = NULL;
 }
 
+/* Lookahead */
+
 static inline void next(js_State *J)
 {
 	J->lookahead = jsP_lex(J);
@@ -215,7 +217,7 @@
 			name = propname(J);
 			expect(J, '(');
 			expect(J, ')');
-			body = funcbody(J);
+			body = funbody(J);
 			return EXP2(PROP_GET, name, body);
 		}
 		if (!strcmp(name->string, "set")) {
@@ -223,7 +225,7 @@
 			expect(J, '(');
 			arg = identifier(J);
 			expect(J, ')');
-			body = funcbody(J);
+			body = funbody(J);
 			return EXP3(PROP_SET, name, arg, body);
 		}
 	}
@@ -247,6 +249,54 @@
 	return head;
 }
 
+/* Functions */
+
+static js_Ast *parameters(js_State *J)
+{
+	js_Ast *head, *tail;
+	if (J->lookahead == ')')
+		return NULL;
+	head = tail = LIST(identifier(J));
+	while (accept(J, ',')) {
+		tail = tail->b = LIST(identifier(J));
+	}
+	return head;
+}
+
+static js_Ast *fundec(js_State *J)
+{
+	js_Ast *a, *b, *c;
+	a = identifier(J);
+	expect(J, '(');
+	b = parameters(J);
+	expect(J, ')');
+	c = funbody(J);
+	return jsP_newnode(J, AST_FUNDEC, a, b, c, 0);
+}
+
+static js_Ast *funstm(js_State *J)
+{
+	js_Ast *a, *b, *c;
+	a = identifier(J);
+	expect(J, '(');
+	b = parameters(J);
+	expect(J, ')');
+	c = funbody(J);
+	/* rewrite function statement as "var X = function X() {}" */
+	return STM1(VAR, LIST(EXP2(VAR, a, EXP3(FUN, a, b, c))));
+}
+
+static js_Ast *funexp(js_State *J)
+{
+	js_Ast *a, *b, *c;
+	a = identifieropt(J);
+	expect(J, '(');
+	b = parameters(J);
+	expect(J, ')');
+	c = funbody(J);
+	return EXP3(FUN, a, b, c);
+}
+
 /* Expressions */
 
 static js_Ast *primary(js_State *J)
@@ -299,21 +349,9 @@
 	return head;
 }
 
-static js_Ast *parameters(js_State *J)
-{
-	js_Ast *head, *tail;
-	if (J->lookahead == ')')
-		return NULL;
-	head = tail = LIST(identifier(J));
-	while (accept(J, ',')) {
-		tail = tail->b = LIST(identifier(J));
-	}
-	return head;
-}
-
 static js_Ast *newexp(js_State *J)
 {
-	js_Ast *a, *b, *c;
+	js_Ast *a, *b;
 
 	if (accept(J, TK_NEW)) {
 		a = memberexp(J);
@@ -325,14 +363,8 @@
 		return EXP1(NEW, a);
 	}
 
-	if (accept(J, TK_FUNCTION)) {
-		a = identifieropt(J);
-		expect(J, '(');
-		b = parameters(J);
-		expect(J, ')');
-		c = funcbody(J);
-		return EXP3(FUNC, a, b, c);
-	}
+	if (accept(J, TK_FUNCTION))
+		return funexp(J);
 
 	return primary(J);
 }
@@ -752,6 +784,11 @@
 		return STM0(DEBUGGER);
 	}
 
+	if (accept(J, TK_FUNCTION)) {
+		jsP_warning(J, "function statements are not standard");
+		return funstm(J);
+	}
+
 	/* labelled statement or expression statement */
 	if (J->lookahead == TK_IDENTIFIER) {
 		a = expression(J, 0);
@@ -764,9 +801,6 @@
 	}
 
 	/* expression statement */
-	if (J->lookahead == TK_FUNCTION)
-		jsP_warning(J, "naked function expression");
-
 	a = expression(J, 0);
 	semicolon(J);
 	return a;
@@ -777,36 +811,29 @@
 
 /* Program */
 
-static js_Ast *chunkelement(js_State *J)
+static js_Ast *scriptelement(js_State *J)
 {
-	js_Ast *a, *b, *c;
-	if (accept(J, TK_FUNCTION)) {
-		a = identifier(J);
-		expect(J, '(');
-		b = parameters(J);
-		expect(J, ')');
-		c = funcbody(J);
-		return STM3(FUNC, a, b, c);
-	}
+	if (accept(J, TK_FUNCTION))
+		return fundec(J);
 	return statement(J);
 }
 
-static js_Ast *chunklist(js_State *J)
+static js_Ast *script(js_State *J)
 {
 	js_Ast *head, *tail;
 	if (J->lookahead == '}' || J->lookahead == 0)
 		return NULL;
-	head = tail = LIST(chunkelement(J));
+	head = tail = LIST(scriptelement(J));
 	while (J->lookahead != '}' && J->lookahead != 0)
-		tail = tail->b = LIST(chunkelement(J));
+		tail = tail->b = LIST(scriptelement(J));
 	return head;
 }
 
-static js_Ast *funcbody(js_State *J)
+static js_Ast *funbody(js_State *J)
 {
 	js_Ast *a;
 	expect(J, '{');
-	a = chunklist(J);
+	a = script(J);
 	expect(J, '}');
 	return a;
 }
@@ -815,7 +842,7 @@
 {
 	va_list ap;
 
-	fprintf(stderr, "%s:%d: warning:", J->filename, J->line);
+	fprintf(stderr, "%s:%d: warning: ", J->filename, J->line);
 	va_start(ap, fmt);
 	vfprintf(stderr, fmt, ap);
 	va_end(ap);
@@ -846,5 +873,5 @@
 	}
 
 	next(J);
-	return chunklist(J);
+	return script(J);
 }
--- a/jsparse.h
+++ b/jsparse.h
@@ -20,6 +20,8 @@
 	AST_STRING,
 	AST_REGEXP,
 
+	AST_FUNDEC,
+
 	/* literals */
 	EXP_UNDEF, /* for array elisions */
 	EXP_NULL,
@@ -27,6 +29,8 @@
 	EXP_FALSE,
 	EXP_THIS,
 
+	EXP_FUN,
+
 	EXP_ARRAY,
 	EXP_OBJECT,
 	EXP_PROP_VAL,
@@ -38,7 +42,6 @@
 	EXP_MEMBER,
 	EXP_CALL,
 	EXP_NEW,
-	EXP_FUNC, /* function expression */
 
 	EXP_DELETE,
 	EXP_VOID,
@@ -96,7 +99,6 @@
 	EXP_VAR, /* var initializer */
 
 	/* statements */
-	STM_FUNC, /* function declaration */
 	STM_BLOCK,
 	STM_NOP,
 	STM_VAR,