Bug 1339895 - Improve error message for unexpected token. r=arai
authorIshigaki <sigmaths.scientia@gmail.com>
Thu, 02 Nov 2017 13:15:27 +0900
changeset 390501 53ce0e7d27e7
parent 390500 bbfe61dcf41a
child 390502 0d5c2d176a45
push id97056
push userryanvm@gmail.com
push dateTue, 07 Nov 2017 13:57:43 +0000
treeherdermozilla-inbound@53ce0e7d27e7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersarai
bugs1339895
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1339895 - Improve error message for unexpected token. r=arai
devtools/client/debugger/test/mochitest/browser_dbg_parser-02.js
devtools/client/debugger/test/mochitest/browser_dbg_parser-04.js
devtools/server/actors/errordocs.js
js/src/frontend/Parser.cpp
js/src/js.msg
js/src/tests/ecma_3/LexicalConventions/7.9.1.js
js/src/tests/js1_5/LexicalConventions/regress-469940.js
js/src/tests/js1_8/regress/regress-384758.js
toolkit/modules/tests/xpcshell/test_Log.js
--- a/devtools/client/debugger/test/mochitest/browser_dbg_parser-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_parser-02.js
@@ -18,13 +18,13 @@ function test() {
 
   ok(parsed,
     "An object should be returned even though the source had a syntax error.");
 
   is(parser.errors.length, 1,
     "There should be one error logged when parsing.");
   is(parser.errors[0].name, "SyntaxError",
     "The correct exception was caught.");
-  is(parser.errors[0].message, "missing ; before statement",
+  is(parser.errors[0].message, "unexpected token: \'+\'",
     "The correct exception was caught.");
 
   finish();
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_parser-04.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_parser-04.js
@@ -31,22 +31,22 @@ function test() {
 
   ok(parsed,
     "HTML code should be parsed correctly.");
   is(parser.errors.length, 2,
     "There should be two errors logged when parsing.");
 
   is(parser.errors[0].name, "SyntaxError",
     "The correct first exception was caught.");
-  is(parser.errors[0].message, "missing ; before statement",
+  is(parser.errors[0].message, "unexpected token: \'+\'",
     "The correct first exception was caught.");
 
   is(parser.errors[1].name, "SyntaxError",
     "The correct second exception was caught.");
-  is(parser.errors[1].message, "missing ; before statement",
+  is(parser.errors[1].message, "unexpected token: \'+\'",
     "The correct second exception was caught.");
 
   is(parsed.scriptCount, 1,
     "There should be 1 script parsed in the parent HTML source.");
 
   is(parsed.getScriptInfo(source.indexOf("let a")).toSource(), "({start:-1, length:-1, index:-1})",
     "The first script shouldn't be considered valid.");
   is(parsed.getScriptInfo(source.indexOf("let b")).toSource(), "({start:85, length:13, index:0})",
--- a/devtools/server/actors/errordocs.js
+++ b/devtools/server/actors/errordocs.js
@@ -34,17 +34,17 @@ const ErrorDocs = {
   JSMSG_JSON_BAD_PARSE: "JSON_bad_parse",
   JSMSG_UNDECLARED_VAR: "Undeclared_var",
   JSMSG_UNEXPECTED_TOKEN: "Unexpected_token",
   JSMSG_BAD_OCTAL: "Bad_octal",
   JSMSG_PROPERTY_ACCESS_DENIED: "Property_access_denied",
   JSMSG_NO_PROPERTIES: "No_properties",
   JSMSG_ALREADY_HAS_PRAGMA: "Already_has_pragma",
   JSMSG_BAD_RETURN_OR_YIELD: "Bad_return_or_yield",
-  JSMSG_SEMI_BEFORE_STMNT: "Missing_semicolon_before_statement",
+  JSMSG_UNEXPECTED_TOKEN_NO_EXPECT: "Missing_semicolon_before_statement",
   JSMSG_OVER_RECURSED: "Too_much_recursion",
   JSMSG_BRACKET_AFTER_LIST: "Missing_bracket_after_list",
   JSMSG_PAREN_AFTER_ARGS: "Missing_parenthesis_after_argument_list",
   JSMSG_MORE_ARGS_NEEDED: "More_arguments_needed",
   JSMSG_BAD_LEFTSIDE_OF_ASS: "Invalid_assignment_left-hand_side",
   JSMSG_UNTERMINATED_STRING: "Unterminated_string_literal",
   JSMSG_NOT_CONSTRUCTOR: "Not_a_constructor",
   JSMSG_CURLY_AFTER_LIST: "Missing_curly_after_property_list",
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -2867,30 +2867,30 @@ Parser<ParseHandler, CharT>::matchOrInse
          * it's possibly intended to be an await expression.
          *
          *   await f();
          *        ^
          *        |
          *        tried to insert semicolon here
          *
          * Detect this situation and throw an understandable error.  Otherwise
-         * we'd throw a confusing "missing ; before statement" error.
+         * we'd throw a confusing "unexpected token: (unexpected token)" error.
          */
         if (!pc->isAsync() && tokenStream.currentToken().type == TOK_AWAIT) {
             error(JSMSG_AWAIT_OUTSIDE_ASYNC);
             return false;
         }
         if (!yieldExpressionsSupported() && tokenStream.currentToken().type == TOK_YIELD) {
             error(JSMSG_YIELD_OUTSIDE_GENERATOR);
             return false;
         }
 
         /* Advance the scanner for proper error location reporting. */
         tokenStream.consumeKnownToken(tt, TokenStream::Operand);
-        error(JSMSG_SEMI_BEFORE_STMNT);
+        error(JSMSG_UNEXPECTED_TOKEN_NO_EXPECT, TokenKindToDesc(tt));
         return false;
     }
     bool matched;
     return tokenStream.matchToken(&matched, TOK_SEMI, TokenStream::Operand);
 }
 
 template <class ParseHandler, typename CharT>
 bool
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -315,32 +315,32 @@ MSG_DEF(JSMSG_REDECLARED_CATCH_IDENTIFIE
 MSG_DEF(JSMSG_RESERVED_ID,             1, JSEXN_SYNTAXERR, "{0} is a reserved identifier")
 MSG_DEF(JSMSG_REST_WITH_COMMA,         0, JSEXN_SYNTAXERR, "rest element may not have a trailing comma")
 MSG_DEF(JSMSG_REST_WITH_DEFAULT,       0, JSEXN_SYNTAXERR, "rest parameter may not have a default")
 MSG_DEF(JSMSG_SELFHOSTED_TOP_LEVEL_LEXICAL, 1, JSEXN_SYNTAXERR, "self-hosted code cannot contain top-level {0} declarations")
 MSG_DEF(JSMSG_SELFHOSTED_METHOD_CALL,  0, JSEXN_SYNTAXERR, "self-hosted code may not contain direct method calls. Use callFunction() or callContentFunction()")
 MSG_DEF(JSMSG_SELFHOSTED_UNBOUND_NAME, 0, JSEXN_TYPEERR, "self-hosted code may not contain unbound name lookups")
 MSG_DEF(JSMSG_SEMI_AFTER_FOR_COND,     0, JSEXN_SYNTAXERR, "missing ; after for-loop condition")
 MSG_DEF(JSMSG_SEMI_AFTER_FOR_INIT,     0, JSEXN_SYNTAXERR, "missing ; after for-loop initializer")
-MSG_DEF(JSMSG_SEMI_BEFORE_STMNT,       0, JSEXN_SYNTAXERR, "missing ; before statement")
 MSG_DEF(JSMSG_SOURCE_TOO_LONG,         0, JSEXN_RANGEERR, "source is too long")
 MSG_DEF(JSMSG_STMT_AFTER_RETURN,       0, JSEXN_WARN, "unreachable code after return statement")
 MSG_DEF(JSMSG_STRICT_CODE_WITH,        0, JSEXN_SYNTAXERR, "strict mode code may not contain 'with' statements")
 MSG_DEF(JSMSG_STRICT_NON_SIMPLE_PARAMS, 1, JSEXN_SYNTAXERR, "\"use strict\" not allowed in function with {0} parameter")
 MSG_DEF(JSMSG_TEMPLSTR_UNTERM_EXPR,    0, JSEXN_SYNTAXERR, "missing } in template string")
 MSG_DEF(JSMSG_SIMD_NOT_A_VECTOR,       2, JSEXN_TYPEERR, "expecting a SIMD {0} object as argument {1}")
 MSG_DEF(JSMSG_TOO_MANY_CASES,          0, JSEXN_INTERNALERR, "too many switch cases")
 MSG_DEF(JSMSG_TOO_MANY_CATCH_VARS,     0, JSEXN_SYNTAXERR, "too many catch variables")
 MSG_DEF(JSMSG_TOO_MANY_CON_ARGS,       0, JSEXN_SYNTAXERR, "too many constructor arguments")
 MSG_DEF(JSMSG_TOO_MANY_DEFAULTS,       0, JSEXN_SYNTAXERR, "more than one switch default")
 MSG_DEF(JSMSG_TOO_MANY_FUN_ARGS,       0, JSEXN_SYNTAXERR, "too many function arguments")
 MSG_DEF(JSMSG_TOO_MANY_LOCALS,         0, JSEXN_SYNTAXERR, "too many local variables")
 MSG_DEF(JSMSG_TOO_MANY_YIELDS,         0, JSEXN_SYNTAXERR, "too many yield expressions")
 MSG_DEF(JSMSG_TOUGH_BREAK,             0, JSEXN_SYNTAXERR, "unlabeled break must be inside loop or switch")
 MSG_DEF(JSMSG_UNEXPECTED_TOKEN,        2, JSEXN_SYNTAXERR, "expected {0}, got {1}")
+MSG_DEF(JSMSG_UNEXPECTED_TOKEN_NO_EXPECT,  1, JSEXN_SYNTAXERR, "unexpected token: {0}")
 MSG_DEF(JSMSG_UNEXPECTED_PARAMLIST_END,0, JSEXN_SYNTAXERR, "unexpected end of function parameter list")
 MSG_DEF(JSMSG_UNNAMED_CLASS_STMT,      0, JSEXN_SYNTAXERR, "class statement requires a name")
 MSG_DEF(JSMSG_UNNAMED_FUNCTION_STMT,   0, JSEXN_SYNTAXERR, "function statement requires a name")
 MSG_DEF(JSMSG_UNTERMINATED_COMMENT,    0, JSEXN_SYNTAXERR, "unterminated comment")
 MSG_DEF(JSMSG_UNTERMINATED_REGEXP,     0, JSEXN_SYNTAXERR, "unterminated regular expression literal")
 MSG_DEF(JSMSG_UNTERMINATED_STRING,     0, JSEXN_SYNTAXERR, "unterminated string literal")
 MSG_DEF(JSMSG_USELESS_EXPR,            0, JSEXN_TYPEERR, "useless expression")
 MSG_DEF(JSMSG_USE_ASM_DIRECTIVE_FAIL,  0, JSEXN_SYNTAXERR, "\"use asm\" is only meaningful in the Directive Prologue of a function body")
--- a/js/src/tests/ecma_3/LexicalConventions/7.9.1.js
+++ b/js/src/tests/ecma_3/LexicalConventions/7.9.1.js
@@ -86,31 +86,31 @@ function test()
   }
   reportCompare(expect, actual, summary + ': ' + code);
 
   //
 
   var x = 1;
   var y = 1;
   code   = '(x\n)-- y';
-  expect = 'SyntaxError: missing ; before statement';
+  expect = 'SyntaxError: unexpected token: identifier';
 
   try
   {
     eval(code);
     actual = expr;
   }
   catch(ex)
   {
     actual = ex + '';
   }
   reportCompare(expect, actual, summary + ': ' + code);
 
   code   = '(x)-- y';
-  expect = 'SyntaxError: missing ; before statement';
+  expect = 'SyntaxError: unexpected token: identifier';
 
   try
   {
     eval(code);
     actual = expr;
   }
   catch(ex)
   {
--- a/js/src/tests/js1_5/LexicalConventions/regress-469940.js
+++ b/js/src/tests/js1_5/LexicalConventions/regress-469940.js
@@ -14,17 +14,17 @@ var expect = '';
 test();
 //-----------------------------------------------------------------------------
 
 function test()
 {
   printBugNumber(BUGNUMBER);
   printStatus (summary);
  
-  expect = 'SyntaxError: missing ; before statement';
+  expect = 'SyntaxError: unexpected token: identifier';
 
   var s = 'var x = function f() { \n return 42; } print(x);';
 
   try
   {
     eval(s);
   }
   catch(ex)
--- a/js/src/tests/js1_8/regress/regress-384758.js
+++ b/js/src/tests/js1_8/regress/regress-384758.js
@@ -14,17 +14,17 @@ var expect = '';
 test();
 //-----------------------------------------------------------------------------
 
 function test()
 {
   printBugNumber(BUGNUMBER);
   printStatus (summary);
 
-  expect = 'SyntaxError: missing ; before statement';
+  expect = 'SyntaxError: unexpected token: identifier';
   try
   {
     eval('(function() { if(t) function x() foo() bar(); })');
   }
   catch(ex)
   {
     actual = ex + '';
   }
--- a/toolkit/modules/tests/xpcshell/test_Log.js
+++ b/toolkit/modules/tests/xpcshell/test_Log.js
@@ -572,17 +572,17 @@ add_task(function* format_errors() {
 
   // Test that JS-generated Errors are recognized and formatted.
   try {
     yield Promise.resolve(); // Scrambles the stack
     // eslint-disable-next-line no-eval
     eval("javascript syntax error");
   } catch (e) {
     str = pFormat.format(e);
-    do_check_true(str.includes("SyntaxError: missing ;"));
+    do_check_true(str.includes("SyntaxError: unexpected token"));
     // Make sure we identified it as an Error and formatted the error location as
     // lineNumber:columnNumber.
     do_check_true(str.includes(":1:11)"));
     // Make sure that we use human-readable stack traces
     // Check that the error doesn't contain any reference to "Promise.jsm" or "Task.jsm"
     do_check_false(str.includes("Promise.jsm"));
     do_check_false(str.includes("Task.jsm"));
     do_check_true(str.includes("format_errors"));