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,