shithub: libmujs

Download patch

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);