Skip to content

Commit 0982adf

Browse files
committed
Reject identifier or keyword immediately following a numeric literal
1 parent 4dc6567 commit 0982adf

File tree

6 files changed

+62
-2
lines changed

6 files changed

+62
-2
lines changed

src/diagnosticMessages.generated.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ export enum DiagnosticCode {
116116
A_definite_assignment_assertion_is_not_permitted_in_this_context = 1255,
117117
A_class_may_only_extend_another_class = 1311,
118118
A_parameter_property_cannot_be_declared_using_a_rest_parameter = 1317,
119+
An_identifier_or_keyword_cannot_immediately_follow_a_numeric_literal = 1351,
119120
Duplicate_identifier_0 = 2300,
120121
Cannot_find_name_0 = 2304,
121122
Module_0_has_no_exported_member_1 = 2305,
@@ -295,6 +296,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
295296
case 1255: return "A definite assignment assertion '!' is not permitted in this context.";
296297
case 1311: return "A class may only extend another class.";
297298
case 1317: return "A parameter property cannot be declared using a rest parameter.";
299+
case 1351: return "An identifier or keyword cannot immediately follow a numeric literal.";
298300
case 2300: return "Duplicate identifier '{0}'.";
299301
case 2304: return "Cannot find name '{0}'.";
300302
case 2305: return "Module '{0}' has no exported member '{1}'.";

src/diagnosticMessages.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
"A definite assignment assertion '!' is not permitted in this context.": 1255,
112112
"A class may only extend another class.": 1311,
113113
"A parameter property cannot be declared using a rest parameter.": 1317,
114+
"An identifier or keyword cannot immediately follow a numeric literal.": 1351,
114115

115116
"Duplicate identifier '{0}'.": 2300,
116117
"Cannot find name '{0}'.": 2304,

src/parser.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3800,10 +3800,14 @@ export class Parser extends DiagnosticEmitter {
38003800
return Node.createStringLiteralExpression(tn.readString(), tn.range(startPos, tn.pos));
38013801
}
38023802
case Token.INTEGERLITERAL: {
3803-
return Node.createIntegerLiteralExpression(tn.readInteger(), tn.range(startPos, tn.pos));
3803+
let value = tn.readInteger();
3804+
tn.checkForIdentifierStartAfterNumericLiteral();
3805+
return Node.createIntegerLiteralExpression(value, tn.range(startPos, tn.pos));
38043806
}
38053807
case Token.FLOATLITERAL: {
3806-
return Node.createFloatLiteralExpression(tn.readFloat(), tn.range(startPos, tn.pos));
3808+
let value = tn.readFloat();
3809+
tn.checkForIdentifierStartAfterNumericLiteral();
3810+
return Node.createFloatLiteralExpression(value, tn.range(startPos, tn.pos));
38073811
}
38083812
// RegexpLiteralExpression
38093813
// note that this also continues on invalid ones so the surrounding AST remains intact
@@ -4207,10 +4211,12 @@ export class Parser extends DiagnosticEmitter {
42074211
}
42084212
case Token.INTEGERLITERAL: {
42094213
tn.readInteger();
4214+
tn.checkForIdentifierStartAfterNumericLiteral();
42104215
break;
42114216
}
42124217
case Token.FLOATLITERAL: {
42134218
tn.readFloat();
4219+
tn.checkForIdentifierStartAfterNumericLiteral();
42144220
break;
42154221
}
42164222
case Token.OPENBRACE: {
@@ -4255,10 +4261,12 @@ export class Parser extends DiagnosticEmitter {
42554261
}
42564262
case Token.INTEGERLITERAL: {
42574263
tn.readInteger();
4264+
tn.checkForIdentifierStartAfterNumericLiteral();
42584265
break;
42594266
}
42604267
case Token.FLOATLITERAL: {
42614268
tn.readFloat();
4269+
tn.checkForIdentifierStartAfterNumericLiteral();
42624270
break;
42634271
}
42644272
}

src/tokenizer.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,6 +1611,17 @@ export class Tokenizer extends DiagnosticEmitter {
16111611
return String.fromCharCode(value);
16121612
}
16131613

1614+
checkForIdentifierStartAfterNumericLiteral(): void {
1615+
// TODO: BigInt n
1616+
var pos = this.pos;
1617+
if (pos < this.end && isIdentifierStart(this.source.text.charCodeAt(pos))) {
1618+
this.error(
1619+
DiagnosticCode.An_identifier_or_keyword_cannot_immediately_follow_a_numeric_literal,
1620+
this.range(pos)
1621+
);
1622+
}
1623+
}
1624+
16141625
readUnicodeEscape(): string {
16151626
return this.readHexadecimalEscape(4);
16161627
}

tests/parser/literals.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,19 @@
6060
"1\"23";
6161
"1\"2\\3";
6262
"\0\n\\n\r";
63+
64+
// invalid
65+
1..;
66+
3u8;
67+
4b;
68+
5-;
69+
6=;
70+
7_;
71+
1.a;
72+
2.0b;
73+
74+
// technically invalid, but not handled by AS yet, TS1005: ';' expected
75+
3 4;
76+
5 c;
77+
6.7 d;
78+
a b;

tests/parser/literals.ts.fixture.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,25 @@
6060
"1\"23";
6161
"1\"2\\3";
6262
"\0\n\\n\r";
63+
4;
64+
b;
65+
7;
66+
1;
67+
a;
68+
2;
69+
b;
70+
3;
71+
4;
72+
5;
73+
c;
74+
6.7;
75+
d;
76+
a;
77+
b;
78+
// ERROR 1109: "Expression expected." in literals.ts(65,4+1)
79+
// ERROR 1351: "An identifier or keyword cannot immediately follow a numeric literal." in literals.ts(66,2+0)
80+
// ERROR 1351: "An identifier or keyword cannot immediately follow a numeric literal." in literals.ts(67,2+0)
81+
// ERROR 1109: "Expression expected." in literals.ts(68,3+1)
82+
// ERROR 6188: "Numeric separators are not allowed here." in literals.ts(70,2+0)
83+
// ERROR 1351: "An identifier or keyword cannot immediately follow a numeric literal." in literals.ts(71,3+0)
84+
// ERROR 1351: "An identifier or keyword cannot immediately follow a numeric literal." in literals.ts(72,4+0)

0 commit comments

Comments
 (0)