diff --git a/jscompile.c b/jscompile.c index f9ae758..615231e 100644 --- a/jscompile.c +++ b/jscompile.c @@ -286,7 +286,7 @@ static void cexp(JF, js_Ast *exp) 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 @@ static void cstm(JF, js_Ast *stm) int loop, then, end; switch (stm->type) { - case STM_FUNC: + case AST_FUNDEC: break; case STM_BLOCK: @@ -509,7 +509,7 @@ static void cfundecs(JF, js_Ast *list) { 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 @@ static void cvardecs(JF, js_Ast *node) { 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); diff --git a/jsdump.c b/jsdump.c index eaf9659..a192059 100644 --- a/jsdump.c +++ b/jsdump.c @@ -6,19 +6,19 @@ #include 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 @@ static void pexpi(int d, int i, js_Ast *exp) 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 @@ static void pstm(int d, js_Ast *stm) in(d); switch (stm->type) { - case STM_FUNC: + case AST_FUNDEC: ps("function "); pexpi(d, 1, stm->a); pc('('); @@ -533,7 +533,7 @@ static void snode(int d, js_Ast *node) 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; diff --git a/jsparse.c b/jsparse.c index bc3816f..0fd7c3d 100644 --- 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 *expression(js_State *J, int notin); 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 @@ void jsP_freeparse(js_State *J) J->ast = NULL; } +/* Lookahead */ + static inline void next(js_State *J) { J->lookahead = jsP_lex(J); @@ -215,7 +217,7 @@ static js_Ast *propassign(js_State *J) 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 @@ static js_Ast *propassign(js_State *J) expect(J, '('); arg = identifier(J); expect(J, ')'); - body = funcbody(J); + body = funbody(J); return EXP3(PROP_SET, name, arg, body); } } @@ -247,6 +249,54 @@ static js_Ast *objectliteral(js_State *J) 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 @@ static js_Ast *arguments(js_State *J) 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 @@ static js_Ast *newexp(js_State *J) 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 @@ static js_Ast *statement(js_State *J) 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 @@ static js_Ast *statement(js_State *J) } /* 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 @@ static js_Ast *statement(js_State *J) /* 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 @@ void jsP_warning(js_State *J, const char *fmt, ...) { 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 @@ js_Ast *jsP_parse(js_State *J, const char *filename, const char *source) } next(J); - return chunklist(J); + return script(J); } diff --git a/jsparse.h b/jsparse.h index 7e2e4fd..777f896 100644 --- a/jsparse.h +++ b/jsparse.h @@ -20,6 +20,8 @@ enum AST_STRING, AST_REGEXP, + AST_FUNDEC, + /* literals */ EXP_UNDEF, /* for array elisions */ EXP_NULL, @@ -27,6 +29,8 @@ enum EXP_FALSE, EXP_THIS, + EXP_FUN, + EXP_ARRAY, EXP_OBJECT, EXP_PROP_VAL, @@ -38,7 +42,6 @@ enum EXP_MEMBER, EXP_CALL, EXP_NEW, - EXP_FUNC, /* function expression */ EXP_DELETE, EXP_VOID, @@ -96,7 +99,6 @@ enum EXP_VAR, /* var initializer */ /* statements */ - STM_FUNC, /* function declaration */ STM_BLOCK, STM_NOP, STM_VAR,