shithub: libmujs

Download patch

ref: 294a803552de8874390bedd5e3ce1ead703394c1
parent: 11730a96aa72ab0fb6e019605f5ab7aa4f24eaed
author: Tor Andersson <tor@ccxvii.net>
date: Fri Dec 27 10:41:59 EST 2013

Print error message with line number on lexical errors.

--- a/js-lex.c
+++ b/js-lex.c
@@ -118,6 +118,17 @@
 #define NEXTPEEK() (NEXT(), PEEK())
 #define LOOK(x) (PEEK() == x ? (NEXT(), 1) : 0)
 
+js_Token js_syntaxerror(js_State *J, const char *fmt, ...)
+{
+	va_list ap;
+	fprintf(stderr, "syntax error: line %d: ", J->yyline);
+	va_start(ap, fmt);
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+	return JS_ERROR;
+}
+
 static void textinit(js_State *J)
 {
 	if (!J->yytext) {
@@ -260,13 +271,13 @@
 	if ((*sp)[0] == '0' && ((*sp)[1] == 'x' || (*sp)[1] == 'X')) {
 		*sp += 2;
 		if (!ishex(PEEK()))
-			return JS_ERROR;
+			return js_syntaxerror(J, "0x not followed by hexademical digit");
 		J->yynumber = lexhex(sp);
 		return JS_NUMBER;
 	}
 
-	if ((*sp)[0] == '0' && (*sp)[1] == '0')
-		return JS_ERROR;
+	if ((*sp)[0] == '0' && isdec((*sp)[1]))
+		return js_syntaxerror(J, "number with leading zero");
 
 	n = lexinteger(sp);
 	if (LOOK('.'))
@@ -274,7 +285,7 @@
 	n *= pow(10, lexexponent(sp));
 
 	if (isidentifierstart(PEEK()))
-		return JS_ERROR;
+		return js_syntaxerror(J, "number with letter suffix");
 
 	J->yynumber = n;
 	return JS_NUMBER;
@@ -318,7 +329,7 @@
 
 	while (c != q) {
 		if (c == 0 || isnewline(c))
-			return JS_ERROR;
+			return js_syntaxerror(J, "string not terminated");
 
 		if (c == '\\')
 			c = lexescape(sp);
@@ -363,12 +374,12 @@
 	c = GET();
 	while (c != '/') {
 		if (c == 0 || isnewline(c)) {
-			return JS_ERROR;
+			return js_syntaxerror(J, "regular expression not terminated");
 		} else if (c == '\\') {
 			textpush(J, c);
 			c = GET();
 			if (c == 0 || isnewline(c))
-				return JS_ERROR;
+				return js_syntaxerror(J, "regular expression not terminated");
 			textpush(J, c);
 			c = GET();
 		} else {
@@ -387,12 +398,12 @@
 		if (c == 'g') J->yyflags.g ++;
 		else if (c == 'i') J->yyflags.i ++;
 		else if (c == 'm') J->yyflags.m ++;
-		else return JS_ERROR;
+		else return js_syntaxerror(J, "illegal flag in regular expression: %c", c);
 		c = NEXTPEEK();
 	}
 
 	if (J->yyflags.g > 1 || J->yyflags.i > 1 || J->yyflags.m > 1)
-		return JS_ERROR;
+		return js_syntaxerror(J, "duplicated flag in regular expression");
 
 	return JS_REGEXP;
 }
@@ -404,8 +415,13 @@
 		while (iswhite(c))
 			c = GET();
 
-		if (isnewline(c))
+		if (isnewline(c)) {
+			/* consume CR LF as one unit */
+			if (c == '\r' && PEEK() == '\n')
+				NEXT();
+			J->yyline++;
 			return JS_NEWLINE;
+		}
 
 		if (c == '/') {
 			if (LOOK('/')) {
@@ -412,7 +428,7 @@
 				lexlinecomment(sp);
 			} else if (LOOK('*')) {
 				if (lexcomment(sp))
-					return JS_ERROR;
+					return js_syntaxerror(J, "multi-line comment not terminated");
 			} else if (isregexpcontext(J->lasttoken)) {
 				return lexregexp(J, sp);
 			} else if (LOOK('=')) {
@@ -564,4 +580,10 @@
 	js_Token t = js_leximp(J, sp);
 	J->lasttoken = t;
 	return t;
+}
+
+void js_initlex(js_State *J)
+{
+	J->yyline = 1;
+	J->lasttoken = JS_ERROR;
 }
--- a/js-load.c
+++ b/js-load.c
@@ -4,6 +4,8 @@
 {
 	js_Token t;
 
+	js_initlex(J);
+
 	do {
 		t = js_lex(J, &source);
 
--- a/js.h
+++ b/js.h
@@ -156,10 +156,13 @@
 	size_t yylen, yycap;
 	double yynumber;
 	struct { int g, i, m; } yyflags;
+	int yyline;
 	js_Token lasttoken;
 };
 
+void js_initlex(js_State *J);
 js_Token js_lex(js_State *J, const char **sp);
+js_Token js_syntaxerror(js_State *J, const char *fmt, ...);
 const char *js_tokentostring(js_Token t);
 
 #endif