diff --git a/src/diagnosticMessages.generated.ts b/src/diagnosticMessages.generated.ts index acde3a052c..ce01f9ffd6 100644 --- a/src/diagnosticMessages.generated.ts +++ b/src/diagnosticMessages.generated.ts @@ -116,6 +116,7 @@ export enum DiagnosticCode { A_definite_assignment_assertion_is_not_permitted_in_this_context = 1255, A_class_may_only_extend_another_class = 1311, A_parameter_property_cannot_be_declared_using_a_rest_parameter = 1317, + An_identifier_or_keyword_cannot_immediately_follow_a_numeric_literal = 1351, Duplicate_identifier_0 = 2300, Cannot_find_name_0 = 2304, Module_0_has_no_exported_member_1 = 2305, @@ -295,6 +296,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string { case 1255: return "A definite assignment assertion '!' is not permitted in this context."; case 1311: return "A class may only extend another class."; case 1317: return "A parameter property cannot be declared using a rest parameter."; + case 1351: return "An identifier or keyword cannot immediately follow a numeric literal."; case 2300: return "Duplicate identifier '{0}'."; case 2304: return "Cannot find name '{0}'."; case 2305: return "Module '{0}' has no exported member '{1}'."; diff --git a/src/diagnosticMessages.json b/src/diagnosticMessages.json index 7f2570ff68..2607361e6c 100644 --- a/src/diagnosticMessages.json +++ b/src/diagnosticMessages.json @@ -111,6 +111,7 @@ "A definite assignment assertion '!' is not permitted in this context.": 1255, "A class may only extend another class.": 1311, "A parameter property cannot be declared using a rest parameter.": 1317, + "An identifier or keyword cannot immediately follow a numeric literal.": 1351, "Duplicate identifier '{0}'.": 2300, "Cannot find name '{0}'.": 2304, diff --git a/src/parser.ts b/src/parser.ts index ee603404bf..d8817403fc 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -3800,10 +3800,14 @@ export class Parser extends DiagnosticEmitter { return Node.createStringLiteralExpression(tn.readString(), tn.range(startPos, tn.pos)); } case Token.INTEGERLITERAL: { - return Node.createIntegerLiteralExpression(tn.readInteger(), tn.range(startPos, tn.pos)); + let value = tn.readInteger(); + tn.checkForIdentifierStartAfterNumericLiteral(); + return Node.createIntegerLiteralExpression(value, tn.range(startPos, tn.pos)); } case Token.FLOATLITERAL: { - return Node.createFloatLiteralExpression(tn.readFloat(), tn.range(startPos, tn.pos)); + let value = tn.readFloat(); + tn.checkForIdentifierStartAfterNumericLiteral(); + return Node.createFloatLiteralExpression(value, tn.range(startPos, tn.pos)); } // RegexpLiteralExpression // note that this also continues on invalid ones so the surrounding AST remains intact @@ -4207,10 +4211,12 @@ export class Parser extends DiagnosticEmitter { } case Token.INTEGERLITERAL: { tn.readInteger(); + tn.checkForIdentifierStartAfterNumericLiteral(); break; } case Token.FLOATLITERAL: { tn.readFloat(); + tn.checkForIdentifierStartAfterNumericLiteral(); break; } case Token.OPENBRACE: { @@ -4255,10 +4261,12 @@ export class Parser extends DiagnosticEmitter { } case Token.INTEGERLITERAL: { tn.readInteger(); + tn.checkForIdentifierStartAfterNumericLiteral(); break; } case Token.FLOATLITERAL: { tn.readFloat(); + tn.checkForIdentifierStartAfterNumericLiteral(); break; } } diff --git a/src/tokenizer.ts b/src/tokenizer.ts index 7d070b1967..56813f1f21 100644 --- a/src/tokenizer.ts +++ b/src/tokenizer.ts @@ -1611,6 +1611,17 @@ export class Tokenizer extends DiagnosticEmitter { return String.fromCharCode(value); } + checkForIdentifierStartAfterNumericLiteral(): void { + // TODO: BigInt n + var pos = this.pos; + if (pos < this.end && isIdentifierStart(this.source.text.charCodeAt(pos))) { + this.error( + DiagnosticCode.An_identifier_or_keyword_cannot_immediately_follow_a_numeric_literal, + this.range(pos) + ); + } + } + readUnicodeEscape(): string { return this.readHexadecimalEscape(4); } diff --git a/tests/parser/literals.ts b/tests/parser/literals.ts index 1ea260c480..3b079c036a 100644 --- a/tests/parser/literals.ts +++ b/tests/parser/literals.ts @@ -60,3 +60,19 @@ "1\"23"; "1\"2\\3"; "\0\n\\n\r"; + +// invalid +1..; +3u8; +4b; +5-; +6=; +7_; +1.a; +2.0b; + +// technically invalid, but not handled by AS yet, TS1005: ';' expected +3 4; +5 c; +6.7 d; +a b; diff --git a/tests/parser/literals.ts.fixture.ts b/tests/parser/literals.ts.fixture.ts index dde9856d2d..8ea005ffb5 100644 --- a/tests/parser/literals.ts.fixture.ts +++ b/tests/parser/literals.ts.fixture.ts @@ -60,3 +60,25 @@ "1\"23"; "1\"2\\3"; "\0\n\\n\r"; +4; +b; +7; +1; +a; +2; +b; +3; +4; +5; +c; +6.7; +d; +a; +b; +// ERROR 1109: "Expression expected." in literals.ts(65,4+1) +// ERROR 1351: "An identifier or keyword cannot immediately follow a numeric literal." in literals.ts(66,2+0) +// ERROR 1351: "An identifier or keyword cannot immediately follow a numeric literal." in literals.ts(67,2+0) +// ERROR 1109: "Expression expected." in literals.ts(68,3+1) +// ERROR 6188: "Numeric separators are not allowed here." in literals.ts(70,2+0) +// ERROR 1351: "An identifier or keyword cannot immediately follow a numeric literal." in literals.ts(71,3+0) +// ERROR 1351: "An identifier or keyword cannot immediately follow a numeric literal." in literals.ts(72,4+0)