Skip to content

Commit

Permalink
Literal and Escape Sequence
Browse files Browse the repository at this point in the history
  • Loading branch information
graphemecluster committed Dec 9, 2022
1 parent 212d386 commit d1ba506
Show file tree
Hide file tree
Showing 85 changed files with 6,426 additions and 225 deletions.
11 changes: 10 additions & 1 deletion src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2627,8 +2627,15 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
}
}

function checkStrictModeStringLiteral(node: StringLiteral) {
if (languageVersion >= ScriptTarget.ES5 && inStrictMode && node.rangesOfOctalSequences) {
file.bindDiagnostics.push(...node.rangesOfOctalSequences.map(
range => createFileDiagnostic(file, range.pos, range.end - range.pos, Diagnostics.Octal_escape_sequences_are_not_allowed_in_strict_mode)));
}
}

function checkStrictModeNumericLiteral(node: NumericLiteral) {
if (languageVersion < ScriptTarget.ES5 && inStrictMode && node.numericLiteralFlags & TokenFlags.Octal) {
if (languageVersion >= ScriptTarget.ES5 && inStrictMode && node.numericLiteralFlags & TokenFlags.Octal) {
file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.Octal_literals_are_not_allowed_in_strict_mode));
}
}
Expand Down Expand Up @@ -2875,6 +2882,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
return checkStrictModeCatchClause(node as CatchClause);
case SyntaxKind.DeleteExpression:
return checkStrictModeDeleteExpression(node as DeleteExpression);
case SyntaxKind.StringLiteral:
return checkStrictModeStringLiteral(node as StringLiteral);
case SyntaxKind.NumericLiteral:
return checkStrictModeNumericLiteral(node as NumericLiteral);
case SyntaxKind.PostfixUnaryExpression:
Expand Down
8 changes: 8 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1549,6 +1549,14 @@
"category": "Message",
"code": 1483
},
"Octal escape sequences are not allowed in strict mode.": {
"category": "Error",
"code": 1484
},
"Octal escape sequences are not allowed in template strings.": {
"category": "Error",
"code": 1485
},

"The types of '{0}' are incompatible between these types.": {
"category": "Error",
Expand Down
4 changes: 3 additions & 1 deletion src/compiler/factory/nodeFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ import {
QuestionDotToken,
QuestionToken,
ReadonlyKeyword,
ReadonlyTextRange,
reduceLeft,
RegularExpressionLiteral,
RestTypeNode,
Expand Down Expand Up @@ -1292,10 +1293,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
}

// @api
function createStringLiteral(text: string, isSingleQuote?: boolean, hasExtendedUnicodeEscape?: boolean): StringLiteral {
function createStringLiteral(text: string, isSingleQuote?: boolean, hasExtendedUnicodeEscape?: boolean, rangesOfOctalSequences?: ReadonlyTextRange[]): StringLiteral {
const node = createBaseStringLiteral(text, isSingleQuote);
node.hasExtendedUnicodeEscape = hasExtendedUnicodeEscape;
if (hasExtendedUnicodeEscape) node.transformFlags |= TransformFlags.ContainsES2015;
node.rangesOfOctalSequences = rangesOfOctalSequences;
return node;
}

Expand Down
19 changes: 8 additions & 11 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2153,10 +2153,6 @@ namespace Parser {
return currentToken = scanner.reScanTemplateToken(isTaggedTemplate);
}

function reScanTemplateHeadOrNoSubstitutionTemplate(): SyntaxKind {
return currentToken = scanner.reScanTemplateHeadOrNoSubstitutionTemplate();
}

function reScanLessThanToken(): SyntaxKind {
return currentToken = scanner.reScanLessThanToken();
}
Expand Down Expand Up @@ -3606,9 +3602,7 @@ namespace Parser {
}

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

Expand Down Expand Up @@ -6314,7 +6307,7 @@ namespace Parser {
tag,
typeArguments,
token() === SyntaxKind.NoSubstitutionTemplateLiteral ?
(reScanTemplateHeadOrNoSubstitutionTemplate(), parseLiteralNode() as NoSubstitutionTemplateLiteral) :
(reScanTemplateToken(/*isTaggedTemplate*/ true), parseLiteralNode() as NoSubstitutionTemplateLiteral) :
parseTemplateExpression(/*isTaggedTemplate*/ true)
);
if (questionDotToken || tag.flags & NodeFlags.OptionalChain) {
Expand Down Expand Up @@ -6414,10 +6407,14 @@ namespace Parser {

function parsePrimaryExpression(): PrimaryExpression {
switch (token()) {
case SyntaxKind.NoSubstitutionTemplateLiteral:
if (scanner.getTokenFlags() & TokenFlags.ContainsOctalOrInvalidEscape) {
reScanTemplateToken(/* isTaggedTemplate */ false);
}
// falls through
case SyntaxKind.NumericLiteral:
case SyntaxKind.BigIntLiteral:
case SyntaxKind.StringLiteral:
case SyntaxKind.NoSubstitutionTemplateLiteral:
return parseLiteralNode();
case SyntaxKind.ThisKeyword:
case SyntaxKind.SuperKeyword:
Expand Down
Loading

0 comments on commit d1ba506

Please sign in to comment.