Skip to content

Commit d1ba506

Browse files
Literal and Escape Sequence
1 parent 212d386 commit d1ba506

File tree

85 files changed

+6426
-225
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+6426
-225
lines changed

src/compiler/binder.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -2627,8 +2627,15 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
26272627
}
26282628
}
26292629

2630+
function checkStrictModeStringLiteral(node: StringLiteral) {
2631+
if (languageVersion >= ScriptTarget.ES5 && inStrictMode && node.rangesOfOctalSequences) {
2632+
file.bindDiagnostics.push(...node.rangesOfOctalSequences.map(
2633+
range => createFileDiagnostic(file, range.pos, range.end - range.pos, Diagnostics.Octal_escape_sequences_are_not_allowed_in_strict_mode)));
2634+
}
2635+
}
2636+
26302637
function checkStrictModeNumericLiteral(node: NumericLiteral) {
2631-
if (languageVersion < ScriptTarget.ES5 && inStrictMode && node.numericLiteralFlags & TokenFlags.Octal) {
2638+
if (languageVersion >= ScriptTarget.ES5 && inStrictMode && node.numericLiteralFlags & TokenFlags.Octal) {
26322639
file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.Octal_literals_are_not_allowed_in_strict_mode));
26332640
}
26342641
}
@@ -2875,6 +2882,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
28752882
return checkStrictModeCatchClause(node as CatchClause);
28762883
case SyntaxKind.DeleteExpression:
28772884
return checkStrictModeDeleteExpression(node as DeleteExpression);
2885+
case SyntaxKind.StringLiteral:
2886+
return checkStrictModeStringLiteral(node as StringLiteral);
28782887
case SyntaxKind.NumericLiteral:
28792888
return checkStrictModeNumericLiteral(node as NumericLiteral);
28802889
case SyntaxKind.PostfixUnaryExpression:

src/compiler/diagnosticMessages.json

+8
Original file line numberDiff line numberDiff line change
@@ -1549,6 +1549,14 @@
15491549
"category": "Message",
15501550
"code": 1483
15511551
},
1552+
"Octal escape sequences are not allowed in strict mode.": {
1553+
"category": "Error",
1554+
"code": 1484
1555+
},
1556+
"Octal escape sequences are not allowed in template strings.": {
1557+
"category": "Error",
1558+
"code": 1485
1559+
},
15521560

15531561
"The types of '{0}' are incompatible between these types.": {
15541562
"category": "Error",

src/compiler/factory/nodeFactory.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@ import {
374374
QuestionDotToken,
375375
QuestionToken,
376376
ReadonlyKeyword,
377+
ReadonlyTextRange,
377378
reduceLeft,
378379
RegularExpressionLiteral,
379380
RestTypeNode,
@@ -1292,10 +1293,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
12921293
}
12931294

12941295
// @api
1295-
function createStringLiteral(text: string, isSingleQuote?: boolean, hasExtendedUnicodeEscape?: boolean): StringLiteral {
1296+
function createStringLiteral(text: string, isSingleQuote?: boolean, hasExtendedUnicodeEscape?: boolean, rangesOfOctalSequences?: ReadonlyTextRange[]): StringLiteral {
12961297
const node = createBaseStringLiteral(text, isSingleQuote);
12971298
node.hasExtendedUnicodeEscape = hasExtendedUnicodeEscape;
12981299
if (hasExtendedUnicodeEscape) node.transformFlags |= TransformFlags.ContainsES2015;
1300+
node.rangesOfOctalSequences = rangesOfOctalSequences;
12991301
return node;
13001302
}
13011303

src/compiler/parser.ts

+8-11
Original file line numberDiff line numberDiff line change
@@ -2153,10 +2153,6 @@ namespace Parser {
21532153
return currentToken = scanner.reScanTemplateToken(isTaggedTemplate);
21542154
}
21552155

2156-
function reScanTemplateHeadOrNoSubstitutionTemplate(): SyntaxKind {
2157-
return currentToken = scanner.reScanTemplateHeadOrNoSubstitutionTemplate();
2158-
}
2159-
21602156
function reScanLessThanToken(): SyntaxKind {
21612157
return currentToken = scanner.reScanLessThanToken();
21622158
}
@@ -3606,9 +3602,7 @@ namespace Parser {
36063602
}
36073603

36083604
function parseTemplateHead(isTaggedTemplate: boolean): TemplateHead {
3609-
if (isTaggedTemplate) {
3610-
reScanTemplateHeadOrNoSubstitutionTemplate();
3611-
}
3605+
reScanTemplateToken(isTaggedTemplate);
36123606
const fragment = parseLiteralLikeNode(token());
36133607
Debug.assert(fragment.kind === SyntaxKind.TemplateHead, "Template head has wrong token kind");
36143608
return fragment as TemplateHead;
@@ -3630,14 +3624,13 @@ namespace Parser {
36303624
const pos = getNodePos();
36313625
const node =
36323626
isTemplateLiteralKind(kind) ? factory.createTemplateLiteralLikeNode(kind, scanner.getTokenValue(), getTemplateLiteralRawText(kind), scanner.getTokenFlags() & TokenFlags.TemplateLiteralLikeFlags) :
3633-
// Octal literals are not allowed in strict mode or ES5
36343627
// Note that theoretically the following condition would hold true literals like 009,
36353628
// which is not octal. But because of how the scanner separates the tokens, we would
36363629
// never get a token like this. Instead, we would get 00 and 9 as two separate tokens.
36373630
// We also do not need to check for negatives because any prefix operator would be part of a
36383631
// parent unary expression.
36393632
kind === SyntaxKind.NumericLiteral ? factory.createNumericLiteral(scanner.getTokenValue(), scanner.getNumericLiteralFlags()) :
3640-
kind === SyntaxKind.StringLiteral ? factory.createStringLiteral(scanner.getTokenValue(), /*isSingleQuote*/ undefined, scanner.hasExtendedUnicodeEscape()) :
3633+
kind === SyntaxKind.StringLiteral ? factory.createStringLiteral(scanner.getTokenValue(), /*isSingleQuote*/ undefined, scanner.hasExtendedUnicodeEscape(), scanner.getRangesOfOctalSequences()) :
36413634
isLiteralKind(kind) ? factory.createLiteralLikeNode(kind, scanner.getTokenValue()) :
36423635
Debug.fail();
36433636

@@ -6314,7 +6307,7 @@ namespace Parser {
63146307
tag,
63156308
typeArguments,
63166309
token() === SyntaxKind.NoSubstitutionTemplateLiteral ?
6317-
(reScanTemplateHeadOrNoSubstitutionTemplate(), parseLiteralNode() as NoSubstitutionTemplateLiteral) :
6310+
(reScanTemplateToken(/*isTaggedTemplate*/ true), parseLiteralNode() as NoSubstitutionTemplateLiteral) :
63186311
parseTemplateExpression(/*isTaggedTemplate*/ true)
63196312
);
63206313
if (questionDotToken || tag.flags & NodeFlags.OptionalChain) {
@@ -6414,10 +6407,14 @@ namespace Parser {
64146407

64156408
function parsePrimaryExpression(): PrimaryExpression {
64166409
switch (token()) {
6410+
case SyntaxKind.NoSubstitutionTemplateLiteral:
6411+
if (scanner.getTokenFlags() & TokenFlags.ContainsOctalOrInvalidEscape) {
6412+
reScanTemplateToken(/* isTaggedTemplate */ false);
6413+
}
6414+
// falls through
64176415
case SyntaxKind.NumericLiteral:
64186416
case SyntaxKind.BigIntLiteral:
64196417
case SyntaxKind.StringLiteral:
6420-
case SyntaxKind.NoSubstitutionTemplateLiteral:
64216418
return parseLiteralNode();
64226419
case SyntaxKind.ThisKeyword:
64236420
case SyntaxKind.SuperKeyword:

0 commit comments

Comments
 (0)