ref: 914ae72a242d91add6fbf97576723aeb31b089d7
parent: 6a592abfc410b3ba1c7c8a18ec88d327e60d3c3e
author: Tor Andersson <tor.andersson@artifex.com>
date: Thu Mar 7 08:06:47 EST 2019
Improve line number tracking in parser. Associate statements with their initial keyword, and expressions with their operator token.
--- a/jscompile.c
+++ b/jscompile.c
@@ -51,7 +51,7 @@
}
}
-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 @@
++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 @@
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 @@
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 @@
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 @@
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);
}
--- a/jsdump.c
+++ b/jsdump.c
@@ -143,6 +143,11 @@
fputs(s, stdout);
}
+static void pn(int n)
+{
+ printf("%d", n);
+}
+
static void in(int d)
{
if (minify < 1)
@@ -702,6 +707,8 @@
pc('(');
ps(astname[node->type]);
+ pc(':');
+ pn(node->line);
switch (node->type) {
default: break;
case AST_IDENTIFIER: pc(' '); ps(node->string); break;
--- a/jsi.h
+++ b/jsi.h
@@ -179,7 +179,6 @@
/* parser state */
int astdepth;
- int astline;
int lookahead;
const char *text;
double number;
--- 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 @@
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,7 +100,7 @@
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;
}
@@ -107,7 +107,7 @@
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 @@
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 *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 *propassign(js_State *J)
{
js_Ast *name, *value, *arg, *body;
+ int line = J->lexline;
name = propname(J);
@@ -278,7 +279,7 @@
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 @@
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 @@
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 *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 @@
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 *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 @@
}
if (jsP_accept(J, TK_FUNCTION))
- return funexp(J);
+ return funexp(J, line);
return primary(J);
}
@@ -386,9 +401,11 @@
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 @@
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 @@
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 *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 *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 @@
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 @@
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 @@
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 @@
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 @@
{
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 @@
{
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 @@
{
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 *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 *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 *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 *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 @@
{
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 *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 *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 *block(js_State *J)
{
js_Ast *a;
+ int line = J->lexline;
jsP_expect(J, '{');
a = statementlist(J);
jsP_expect(J, '}');
@@ -686,7 +732,7 @@
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 @@
{
js_Ast *a, *b, *c, *d;
js_Ast *stm;
+ int line = J->lexline;
INCREC();
@@ -779,7 +826,7 @@
}
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 @@
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 *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_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);