From 370e15971660c29957699e7b167f72bf910f554f Mon Sep 17 00:00:00 2001 From: Mike Pennisi Date: Mon, 11 May 2020 00:08:54 -0400 Subject: [PATCH] [[FIX]] Improve numeric literal warnings/errors Previously, JSHint issued the warning W045 in response to invalid numeric literals and numeric literals which could not be represented with the JavaScript "number" type. (The existing code comment which claims otherwise is erroneous.) While the warning's message was generic enough to describe both cases ("Bad number"), the dual usage undermined JSHint's distinction between "errors" and "warnings." Create a new error to describe the invalid syntax and emit it as appropriate. Reword the existing warning to more precisely describe the likely programming error it reflects. --- src/lex.js | 16 +++++++++++----- src/messages.js | 6 ++++-- tests/test262/expectations.txt | 8 -------- tests/unit/parser.js | 4 ++-- tests/unit/unstable/bigint.js | 6 +++--- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/lex.js b/src/lex.js index c5431649a1..9a078ea79a 100644 --- a/src/lex.js +++ b/src/lex.js @@ -966,11 +966,19 @@ Lexer.prototype = { } } + // TODO: Extend this check to other numeric literals + this.triggerAsync("warning", { + code: "W045", + line: this.line, + character: this.char + value.length, + data: [ value ] + }, checks, function() { return !isFinite(value); }); + return { type: Token.NumericLiteral, value: value, base: base, - isMalformed: !isFinite(value) + isMalformed: false }; }, @@ -2143,10 +2151,8 @@ Lexer.prototype = { case Token.NumericLiteral: if (token.isMalformed) { - // This condition unequivocally describes a syntax error. - // TODO: Re-factor as an "error" (not a "warning"). - this.trigger("warning", { - code: "W045", + this.trigger("error", { + code: "E067", line: this.line, character: this.char, data: [ token.value ] diff --git a/src/messages.js b/src/messages.js index cce95ff773..e541cdeb19 100644 --- a/src/messages.js +++ b/src/messages.js @@ -82,7 +82,8 @@ var errors = { E064: "Super call may only be used within class method bodies.", E065: "Functions defined outside of strict mode with non-simple parameter lists may not " + "enable strict mode.", - E066: "Asynchronous iteration is only available with for-of loops." + E066: "Asynchronous iteration is only available with for-of loops.", + E067: "Malformed numeric literal: '{a}'." }; var warnings = { @@ -131,7 +132,8 @@ var warnings = { W042: "Avoid EOL escaping.", W043: "Bad escaping of EOL. Use option multistr if needed.", W044: "Bad or unnecessary escaping.", /* TODO(caitp): remove W044 */ - W045: "Bad number '{a}'.", + W045: "Value described by numeric literal cannot be accurately " + + "represented with a number value: '{a}'.", W046: "Don't use extra leading zeros '{a}'.", W047: "A trailing decimal point can be confused with a dot: '{a}'.", W048: "Unexpected control character in regular expression.", diff --git a/tests/test262/expectations.txt b/tests/test262/expectations.txt index d90d2ea097..c8836ca755 100644 --- a/tests/test262/expectations.txt +++ b/tests/test262/expectations.txt @@ -150,15 +150,7 @@ test/language/rest-parameters/object-pattern.js(strict mode) test/language/arguments-object/10.6-13-c-1-s.js(strict mode) test/language/arguments-object/10.6-1gs.js(strict mode) test/language/arguments-object/10.6-2gs.js(strict mode) -test/language/literals/numeric/S7.8.3_A6.1_T1.js(default) -test/language/literals/numeric/S7.8.3_A6.1_T1.js(strict mode) -test/language/literals/numeric/S7.8.3_A6.1_T2.js(default) -test/language/literals/numeric/S7.8.3_A6.1_T2.js(strict mode) -test/language/literals/numeric/binary-invalid-truncated.js(default) -test/language/literals/numeric/binary-invalid-truncated.js(strict mode) test/language/literals/numeric/non-octal-decimal-integer-strict.js(strict mode) -test/language/literals/numeric/octal-invalid-truncated.js(default) -test/language/literals/numeric/octal-invalid-truncated.js(strict mode) test/language/block-scope/syntax/function-declarations/in-statement-position-if-expression-statement-else-statement.js(strict mode) test/language/block-scope/syntax/function-declarations/in-statement-position-if-expression-statement.js(strict mode) test/language/destructuring/binding/syntax/array-elements-with-initializer.js(default) diff --git a/tests/unit/parser.js b/tests/unit/parser.js index 034a186c6c..c1c8159237 100644 --- a/tests/unit/parser.js +++ b/tests/unit/parser.js @@ -537,7 +537,7 @@ exports.numbers = function (test) { ]; TestRun(test) - .addError(2, 15, "Bad number '10e308'.") + .addError(2, 15, "Value described by numeric literal cannot be accurately represented with a number value: '10e308'.") .addError(5, 11, "A leading decimal point can be confused with a dot: '.3'.") .addError(6, 9, "Unexpected '0'.") .addError(7, 1, "Expected an identifier and instead saw 'var'.") @@ -547,7 +547,7 @@ exports.numbers = function (test) { .addError(9, 9, "A dot following a number can be confused with a decimal point.") .addError(11, 9, "'Octal integer literal' is only available in ES6 (use 'esversion: 6').") .addError(12, 9, "'Binary integer literal' is only available in ES6 (use 'esversion: 6').") - .addError(13, 11, "Bad number '0x'.") + .addError(13, 11, "Malformed numeric literal: '0x'.") .addError(15, 9, "Unexpected '1'.") .addError(16, 11, "Expected an identifier and instead saw ';'.") .addError(16, 1, "Expected an identifier and instead saw 'var'.") diff --git a/tests/unit/unstable/bigint.js b/tests/unit/unstable/bigint.js index 174505bc96..a299cca847 100644 --- a/tests/unit/unstable/bigint.js +++ b/tests/unit/unstable/bigint.js @@ -75,19 +75,19 @@ exports.invalid = function (test) { .test("void 1e3n;", {esversion: 6, unstable: {bigint: true}}); TestRun(test, "invalid hex digit") - .addError(1, 8, "Bad number '0x'.") + .addError(1, 8, "Malformed numeric literal: '0x'.") .addError(1, 8, "Missing semicolon.") .addError(1, 8, "Expected an assignment or function call and instead saw an expression.") .test("void 0xgn;", {esversion: 6, unstable: {bigint: true}}); TestRun(test, "invalid binary digit") - .addError(1, 8, "Bad number '0b'.") + .addError(1, 8, "Malformed numeric literal: '0b'.") .addError(1, 8, "Missing semicolon.") .addError(1, 8, "Expected an assignment or function call and instead saw an expression.") .test("void 0b2n;", {esversion: 6, unstable: {bigint: true}}); TestRun(test, "invalid octal digit") - .addError(1, 8, "Bad number '0o'.") + .addError(1, 8, "Malformed numeric literal: '0o'.") .addError(1, 8, "Missing semicolon.") .addError(1, 8, "Expected an assignment or function call and instead saw an expression.") .test("void 0o8n;", {esversion: 6, unstable: {bigint: true}});