From 914ae72a242d91add6fbf97576723aeb31b089d7 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Thu, 7 Mar 2019 13:06:47 +0100 Subject: [PATCH] Improve line number tracking in parser. Associate statements with their initial keyword, and expressions with their operator token. --- jscompile.c | 16 ++++---- jsdump.c | 7 ++++ jsi.h | 1 - jsparse.c | 103 ++++++++++++++++++++++++++++++++++++++-------------- 4 files changed, 91 insertions(+), 36 deletions(-) diff --git a/jscompile.c b/jscompile.c index 7672e4e..34cf843 100644 --- a/jscompile.c +++ b/jscompile.c @@ -51,7 +51,7 @@ static void checkfutureword(JF, js_Ast *exp) } } -static js_Function *newfun(js_State *J, js_Ast *name, js_Ast *params, js_Ast *body, int script, int default_strict) +static js_Function *newfun(js_State *J, int line, js_Ast *name, js_Ast *params, js_Ast *body, int script, int default_strict) { js_Function *F = js_malloc(J, sizeof *F); memset(F, 0, sizeof *F); @@ -61,7 +61,7 @@ static js_Function *newfun(js_State *J, js_Ast *name, js_Ast *params, js_Ast *bo ++J->gccounter; F->filename = js_intern(J, J->filename); - F->line = name ? name->line : params ? params->line : body ? body->line : 1; + F->line = line; F->script = script; F->strict = default_strict; F->name = name ? name->string : ""; @@ -354,11 +354,11 @@ static void cobject(JF, js_Ast *list) emit(J, F, OP_INITPROP); break; case EXP_PROP_GET: - emitfunction(J, F, newfun(J, NULL, NULL, kv->c, 0, F->strict)); + emitfunction(J, F, newfun(J, prop->line, NULL, NULL, kv->c, 0, F->strict)); emit(J, F, OP_INITGETTER); break; case EXP_PROP_SET: - emitfunction(J, F, newfun(J, NULL, kv->b, kv->c, 0, F->strict)); + emitfunction(J, F, newfun(J, prop->line, NULL, kv->b, kv->c, 0, F->strict)); emit(J, F, OP_INITSETTER); break; } @@ -586,7 +586,7 @@ static void cexp(JF, js_Ast *exp) break; case EXP_FUN: - emitfunction(J, F, newfun(J, exp->a, exp->b, exp->c, 0, F->strict)); + emitfunction(J, F, newfun(J, exp->line, exp->a, exp->b, exp->c, 0, F->strict)); break; case EXP_IDENTIFIER: @@ -1321,7 +1321,7 @@ static void cfundecs(JF, js_Ast *list) while (list) { js_Ast *stm = list->a; if (stm->type == AST_FUNDEC) { - emitfunction(J, F, newfun(J, stm->a, stm->b, stm->c, 0, F->strict)); + emitfunction(J, F, newfun(J, stm->line, stm->a, stm->b, stm->c, 0, F->strict)); emitstring(J, F, OP_INITVAR, stm->a->string); } list = list->b; @@ -1378,10 +1378,10 @@ static void cfunbody(JF, js_Ast *name, js_Ast *params, js_Ast *body) js_Function *jsC_compilefunction(js_State *J, js_Ast *prog) { - return newfun(J, prog->a, prog->b, prog->c, 0, J->default_strict); + return newfun(J, prog->line, prog->a, prog->b, prog->c, 0, J->default_strict); } js_Function *jsC_compilescript(js_State *J, js_Ast *prog, int default_strict) { - return newfun(J, NULL, NULL, prog, 1, default_strict); + return newfun(J, prog->line, NULL, NULL, prog, 1, default_strict); } diff --git a/jsdump.c b/jsdump.c index d3f089d..47b96b1 100644 --- a/jsdump.c +++ b/jsdump.c @@ -143,6 +143,11 @@ static void ps(const char *s) fputs(s, stdout); } +static void pn(int n) +{ + printf("%d", n); +} + static void in(int d) { if (minify < 1) @@ -702,6 +707,8 @@ static void snode(int d, js_Ast *node) pc('('); ps(astname[node->type]); + pc(':'); + pn(node->line); switch (node->type) { default: break; case AST_IDENTIFIER: pc(' '); ps(node->string); break; diff --git a/jsi.h b/jsi.h index ea70daa..b739fc7 100644 --- a/jsi.h +++ b/jsi.h @@ -179,7 +179,6 @@ struct js_State /* parser state */ int astdepth; - int astline; int lookahead; const char *text; double number; diff --git a/jsparse.c b/jsparse.c index 4182885..f91f491 100644 --- a/jsparse.c +++ b/jsparse.c @@ -2,18 +2,18 @@ #include "jslex.h" #include "jsparse.h" -#define LIST(h) jsP_newnode(J, AST_LIST, h, 0, 0, 0) +#define LIST(h) jsP_newnode(J, AST_LIST, 0, 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) -#define EXP2(x,a,b) jsP_newnode(J, EXP_ ## x, a, b, 0, 0) -#define EXP3(x,a,b,c) jsP_newnode(J, EXP_ ## x, a, b, c, 0) +#define EXP0(x) jsP_newnode(J, EXP_ ## x, line, 0, 0, 0, 0) +#define EXP1(x,a) jsP_newnode(J, EXP_ ## x, line, a, 0, 0, 0) +#define EXP2(x,a,b) jsP_newnode(J, EXP_ ## x, line, a, b, 0, 0) +#define EXP3(x,a,b,c) jsP_newnode(J, EXP_ ## x, line, a, b, c, 0) -#define STM0(x) jsP_newnode(J, STM_ ## x, 0, 0, 0, 0) -#define STM1(x,a) jsP_newnode(J, STM_ ## x, a, 0, 0, 0) -#define STM2(x,a,b) jsP_newnode(J, STM_ ## x, a, b, 0, 0) -#define STM3(x,a,b,c) jsP_newnode(J, STM_ ## x, a, b, c, 0) -#define STM4(x,a,b,c,d) jsP_newnode(J, STM_ ## x, a, b, c, d) +#define STM0(x) jsP_newnode(J, STM_ ## x, line, 0, 0, 0, 0) +#define STM1(x,a) jsP_newnode(J, STM_ ## x, line, a, 0, 0, 0) +#define STM2(x,a,b) jsP_newnode(J, STM_ ## x, line, a, b, 0, 0) +#define STM3(x,a,b,c) jsP_newnode(J, STM_ ## x, line, a, b, c, 0) +#define STM4(x,a,b,c,d) jsP_newnode(J, STM_ ## x, line, a, b, c, d) static js_Ast *expression(js_State *J, int notin); static js_Ast *assignment(js_State *J, int notin); @@ -59,12 +59,12 @@ static void jsP_warning(js_State *J, const char *fmt, ...) js_report(J, buf); } -static js_Ast *jsP_newnode(js_State *J, enum js_AstType type, js_Ast *a, js_Ast *b, js_Ast *c, js_Ast *d) +static js_Ast *jsP_newnode(js_State *J, enum js_AstType type, int line, js_Ast *a, js_Ast *b, js_Ast *c, js_Ast *d) { js_Ast *node = js_malloc(J, sizeof *node); node->type = type; - node->line = J->astline; + node->line = line; node->a = a; node->b = b; node->c = c; @@ -100,14 +100,14 @@ static js_Ast *jsP_list(js_Ast *head) static js_Ast *jsP_newstrnode(js_State *J, enum js_AstType type, const char *s) { - js_Ast *node = jsP_newnode(J, type, 0, 0, 0, 0); + js_Ast *node = jsP_newnode(J, type, J->lexline, 0, 0, 0, 0); node->string = s; return node; } static js_Ast *jsP_newnumnode(js_State *J, enum js_AstType type, double n) { - js_Ast *node = jsP_newnode(J, type, 0, 0, 0, 0); + js_Ast *node = jsP_newnode(J, type, J->lexline, 0, 0, 0, 0); node->number = n; return node; } @@ -138,7 +138,6 @@ void jsP_freeparse(js_State *J) static void jsP_next(js_State *J) { J->lookahead = jsY_lex(J); - J->astline = J->lexline; } #define jsP_accept(J,x) (J->lookahead == x ? (jsP_next(J), 1) : 0) @@ -188,6 +187,7 @@ static js_Ast *identifiername(js_State *J) static js_Ast *arrayelement(js_State *J) { + int line = J->lexline; if (J->lookahead == ',') return EXP0(UNDEF); return assignment(J, 0); @@ -224,6 +224,7 @@ static js_Ast *propname(js_State *J) static js_Ast *propassign(js_State *J) { js_Ast *name, *value, *arg, *body; + int line = J->lexline; name = propname(J); @@ -278,7 +279,7 @@ static js_Ast *parameters(js_State *J) return jsP_list(head); } -static js_Ast *fundec(js_State *J) +static js_Ast *fundec(js_State *J, int line) { js_Ast *a, *b, *c; a = identifier(J); @@ -286,10 +287,10 @@ static js_Ast *fundec(js_State *J) b = parameters(J); jsP_expect(J, ')'); c = funbody(J); - return jsP_newnode(J, AST_FUNDEC, a, b, c, 0); + return jsP_newnode(J, AST_FUNDEC, line, a, b, c, 0); } -static js_Ast *funstm(js_State *J) +static js_Ast *funstm(js_State *J, int line) { js_Ast *a, *b, *c; a = identifier(J); @@ -301,7 +302,7 @@ static js_Ast *funstm(js_State *J) return STM1(VAR, LIST(EXP2(VAR, a, EXP3(FUN, a, b, c)))); } -static js_Ast *funexp(js_State *J) +static js_Ast *funexp(js_State *J, int line) { js_Ast *a, *b, *c; a = identifieropt(J); @@ -317,6 +318,7 @@ static js_Ast *funexp(js_State *J) static js_Ast *primary(js_State *J) { js_Ast *a; + int line = J->lexline; if (J->lookahead == TK_IDENTIFIER) { a = jsP_newstrnode(J, EXP_IDENTIFIER, J->text); @@ -344,9 +346,21 @@ static js_Ast *primary(js_State *J) if (jsP_accept(J, TK_NULL)) return EXP0(NULL); if (jsP_accept(J, TK_TRUE)) return EXP0(TRUE); if (jsP_accept(J, TK_FALSE)) return EXP0(FALSE); - if (jsP_accept(J, '{')) { a = EXP1(OBJECT, objectliteral(J)); jsP_expect(J, '}'); return a; } - if (jsP_accept(J, '[')) { a = EXP1(ARRAY, arrayliteral(J)); jsP_expect(J, ']'); return a; } - if (jsP_accept(J, '(')) { a = expression(J, 0); jsP_expect(J, ')'); return a; } + if (jsP_accept(J, '{')) { + a = EXP1(OBJECT, objectliteral(J)); + jsP_expect(J, '}'); + return a; + } + if (jsP_accept(J, '[')) { + a = EXP1(ARRAY, arrayliteral(J)); + jsP_expect(J, ']'); + return a; + } + if (jsP_accept(J, '(')) { + a = expression(J, 0); + jsP_expect(J, ')'); + return a; + } jsP_error(J, "unexpected token in expression: %s", jsY_tokenstring(J->lookahead)); } @@ -366,6 +380,7 @@ static js_Ast *arguments(js_State *J) static js_Ast *newexp(js_State *J) { js_Ast *a, *b; + int line = J->lexline; if (jsP_accept(J, TK_NEW)) { a = memberexp(J); @@ -378,7 +393,7 @@ static js_Ast *newexp(js_State *J) } if (jsP_accept(J, TK_FUNCTION)) - return funexp(J); + return funexp(J, line); return primary(J); } @@ -386,9 +401,11 @@ static js_Ast *newexp(js_State *J) static js_Ast *memberexp(js_State *J) { js_Ast *a = newexp(J); + int line; SAVEREC(); loop: INCREC(); + line = J->lexline; if (jsP_accept(J, '.')) { a = EXP2(MEMBER, a, identifiername(J)); goto loop; } if (jsP_accept(J, '[')) { a = EXP2(INDEX, a, expression(J, 0)); jsP_expect(J, ']'); goto loop; } POPREC(); @@ -398,9 +415,11 @@ loop: static js_Ast *callexp(js_State *J) { js_Ast *a = newexp(J); + int line; SAVEREC(); loop: INCREC(); + line = J->lexline; if (jsP_accept(J, '.')) { a = EXP2(MEMBER, a, identifiername(J)); goto loop; } if (jsP_accept(J, '[')) { a = EXP2(INDEX, a, expression(J, 0)); jsP_expect(J, ']'); goto loop; } if (jsP_accept(J, '(')) { a = EXP2(CALL, a, arguments(J)); jsP_expect(J, ')'); goto loop; } @@ -411,6 +430,7 @@ loop: static js_Ast *postfix(js_State *J) { js_Ast *a = callexp(J); + int line = J->lexline; if (!J->newline && jsP_accept(J, TK_INC)) return EXP1(POSTINC, a); if (!J->newline && jsP_accept(J, TK_DEC)) return EXP1(POSTDEC, a); return a; @@ -419,6 +439,7 @@ static js_Ast *postfix(js_State *J) static js_Ast *unary(js_State *J) { js_Ast *a; + int line = J->lexline; INCREC(); if (jsP_accept(J, TK_DELETE)) a = EXP1(DELETE, unary(J)); else if (jsP_accept(J, TK_VOID)) a = EXP1(VOID, unary(J)); @@ -437,9 +458,11 @@ static js_Ast *unary(js_State *J) static js_Ast *multiplicative(js_State *J) { js_Ast *a = unary(J); + int line; SAVEREC(); loop: INCREC(); + line = J->lexline; if (jsP_accept(J, '*')) { a = EXP2(MUL, a, unary(J)); goto loop; } if (jsP_accept(J, '/')) { a = EXP2(DIV, a, unary(J)); goto loop; } if (jsP_accept(J, '%')) { a = EXP2(MOD, a, unary(J)); goto loop; } @@ -450,9 +473,11 @@ loop: static js_Ast *additive(js_State *J) { js_Ast *a = multiplicative(J); + int line; SAVEREC(); loop: INCREC(); + line = J->lexline; if (jsP_accept(J, '+')) { a = EXP2(ADD, a, multiplicative(J)); goto loop; } if (jsP_accept(J, '-')) { a = EXP2(SUB, a, multiplicative(J)); goto loop; } POPREC(); @@ -462,9 +487,11 @@ loop: static js_Ast *shift(js_State *J) { js_Ast *a = additive(J); + int line; SAVEREC(); loop: INCREC(); + line = J->lexline; if (jsP_accept(J, TK_SHL)) { a = EXP2(SHL, a, additive(J)); goto loop; } if (jsP_accept(J, TK_SHR)) { a = EXP2(SHR, a, additive(J)); goto loop; } if (jsP_accept(J, TK_USHR)) { a = EXP2(USHR, a, additive(J)); goto loop; } @@ -475,9 +502,11 @@ loop: static js_Ast *relational(js_State *J, int notin) { js_Ast *a = shift(J); + int line; SAVEREC(); loop: INCREC(); + line = J->lexline; if (jsP_accept(J, '<')) { a = EXP2(LT, a, shift(J)); goto loop; } if (jsP_accept(J, '>')) { a = EXP2(GT, a, shift(J)); goto loop; } if (jsP_accept(J, TK_LE)) { a = EXP2(LE, a, shift(J)); goto loop; } @@ -491,9 +520,11 @@ loop: static js_Ast *equality(js_State *J, int notin) { js_Ast *a = relational(J, notin); + int line; SAVEREC(); loop: INCREC(); + line = J->lexline; if (jsP_accept(J, TK_EQ)) { a = EXP2(EQ, a, relational(J, notin)); goto loop; } if (jsP_accept(J, TK_NE)) { a = EXP2(NE, a, relational(J, notin)); goto loop; } if (jsP_accept(J, TK_STRICTEQ)) { a = EXP2(STRICTEQ, a, relational(J, notin)); goto loop; } @@ -506,9 +537,11 @@ static js_Ast *bitand(js_State *J, int notin) { js_Ast *a = equality(J, notin); SAVEREC(); + int line = J->lexline; while (jsP_accept(J, '&')) { INCREC(); a = EXP2(BITAND, a, equality(J, notin)); + line = J->lexline; } POPREC(); return a; @@ -518,9 +551,11 @@ static js_Ast *bitxor(js_State *J, int notin) { js_Ast *a = bitand(J, notin); SAVEREC(); + int line = J->lexline; while (jsP_accept(J, '^')) { INCREC(); a = EXP2(BITXOR, a, bitand(J, notin)); + line = J->lexline; } POPREC(); return a; @@ -530,9 +565,11 @@ static js_Ast *bitor(js_State *J, int notin) { js_Ast *a = bitxor(J, notin); SAVEREC(); + int line = J->lexline; while (jsP_accept(J, '|')) { INCREC(); a = EXP2(BITOR, a, bitxor(J, notin)); + line = J->lexline; } POPREC(); return a; @@ -541,6 +578,7 @@ static js_Ast *bitor(js_State *J, int notin) static js_Ast *logand(js_State *J, int notin) { js_Ast *a = bitor(J, notin); + int line = J->lexline; if (jsP_accept(J, TK_AND)) { INCREC(); a = EXP2(LOGAND, a, logand(J, notin)); @@ -552,6 +590,7 @@ static js_Ast *logand(js_State *J, int notin) static js_Ast *logor(js_State *J, int notin) { js_Ast *a = logand(J, notin); + int line = J->lexline; if (jsP_accept(J, TK_OR)) { INCREC(); a = EXP2(LOGOR, a, logor(J, notin)); @@ -563,6 +602,7 @@ static js_Ast *logor(js_State *J, int notin) static js_Ast *conditional(js_State *J, int notin) { js_Ast *a = logor(J, notin); + int line = J->lexline; if (jsP_accept(J, '?')) { js_Ast *b, *c; INCREC(); @@ -578,6 +618,7 @@ static js_Ast *conditional(js_State *J, int notin) static js_Ast *assignment(js_State *J, int notin) { js_Ast *a = conditional(J, notin); + int line = J->lexline; INCREC(); if (jsP_accept(J, '=')) a = EXP2(ASS, a, assignment(J, notin)); else if (jsP_accept(J, TK_MUL_ASS)) a = EXP2(ASS_MUL, a, assignment(J, notin)); @@ -599,9 +640,11 @@ static js_Ast *expression(js_State *J, int notin) { js_Ast *a = assignment(J, notin); SAVEREC(); + int line = J->lexline; while (jsP_accept(J, ',')) { INCREC(); a = EXP2(COMMA, a, assignment(J, notin)); + line = J->lexline; } POPREC(); return a; @@ -612,6 +655,7 @@ static js_Ast *expression(js_State *J, int notin) static js_Ast *vardec(js_State *J, int notin) { js_Ast *a = identifier(J); + int line = J->lexline; if (jsP_accept(J, '=')) return EXP2(VAR, a, assignment(J, notin)); return EXP1(VAR, a); @@ -640,6 +684,7 @@ static js_Ast *statementlist(js_State *J) static js_Ast *caseclause(js_State *J) { js_Ast *a, *b; + int line = J->lexline; if (jsP_accept(J, TK_CASE)) { a = expression(J, 0); @@ -671,6 +716,7 @@ static js_Ast *caselist(js_State *J) static js_Ast *block(js_State *J) { js_Ast *a; + int line = J->lexline; jsP_expect(J, '{'); a = statementlist(J); jsP_expect(J, '}'); @@ -686,7 +732,7 @@ static js_Ast *forexpression(js_State *J, int end) return a; } -static js_Ast *forstatement(js_State *J) +static js_Ast *forstatement(js_State *J, int line) { js_Ast *a, *b, *c, *d; jsP_expect(J, '('); @@ -730,6 +776,7 @@ static js_Ast *statement(js_State *J) { js_Ast *a, *b, *c, *d; js_Ast *stm; + int line = J->lexline; INCREC(); @@ -779,7 +826,7 @@ static js_Ast *statement(js_State *J) } else if (jsP_accept(J, TK_FOR)) { - stm = forstatement(J); + stm = forstatement(J, line); } else if (jsP_accept(J, TK_CONTINUE)) { @@ -851,7 +898,7 @@ static js_Ast *statement(js_State *J) else if (jsP_accept(J, TK_FUNCTION)) { jsP_warning(J, "function statements are not standard"); - stm = funstm(J); + stm = funstm(J, line); } /* labelled statement or expression statement */ @@ -881,8 +928,9 @@ static js_Ast *statement(js_State *J) static js_Ast *scriptelement(js_State *J) { + int line = J->lexline; if (jsP_accept(J, TK_FUNCTION)) - return fundec(J); + return fundec(J, line); return statement(J); } @@ -1008,6 +1056,7 @@ js_Ast *jsP_parse(js_State *J, const char *filename, const char *source) js_Ast *jsP_parsefunction(js_State *J, const char *filename, const char *params, const char *body) { js_Ast *p = NULL; + int line = 0; if (params) { jsY_initlex(J, filename, params); jsP_next(J);