Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for Lift Template Literal Restriction #23801

Merged
merged 34 commits into from
Feb 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
344d505
add support for Lift Template Literal Restriction
Kingwl May 1, 2018
6ef797f
rename file and improve comment and tests
Kingwl May 1, 2018
3932d20
fix NoSubstitutionTemplateLiteral support
Kingwl May 2, 2018
dbbcdae
Merge branch 'master' into Lift-Template-Literal-Restriction
Kingwl May 24, 2018
c642abe
Merge branch 'Lift-Template-Literal-Restriction' of https://github.co…
Kingwl May 25, 2018
e92b6bc
extract tagged template and add more test
Kingwl May 26, 2018
9bfb15b
Merge branch 'master' into Lift-Template-Literal-Restriction
Kingwl Jun 8, 2018
2c973b1
avoid useless parameter
Kingwl Jun 8, 2018
c2580ed
fix incorrect return node if cannot transform
Kingwl Jun 8, 2018
21c91d6
accept baseline
Kingwl Jun 8, 2018
cd46d9f
Merge branch 'master' into Lift-Template-Literal-Restriction
Kingwl Jun 30, 2018
472223b
correctly baseline
Kingwl Jun 30, 2018
789cbed
Merge branch 'master' of https://github.com/kingwl/typescript into Li…
Kingwl Aug 28, 2018
4fa33a1
Merge branch 'master' into Lift-Template-Literal-Restriction
Kingwl Aug 28, 2018
2b97fca
Merge branch 'master' into Lift-Template-Literal-Restriction
Kingwl Aug 29, 2018
78355db
accept baseline
Kingwl Aug 29, 2018
3da97e2
Merge branch 'master' into Lift-Template-Literal-Restriction
Kingwl Jan 19, 2019
dde0b37
fix merge break
Kingwl Jan 20, 2019
8bf6c64
Merge branch 'master' into Lift-Template-Literal-Restriction
Kingwl Apr 10, 2019
c4ccddf
fix merge break
Kingwl Apr 10, 2019
3e87998
inline rescan template head or no subsititution template
Kingwl Apr 10, 2019
826802f
update scan error
Kingwl Apr 10, 2019
7b67e5d
add comment and fix lint
Kingwl Apr 10, 2019
8671a24
refactor and fix lint
Kingwl Apr 12, 2019
6237adf
avoid blank
Kingwl Apr 12, 2019
12a1252
Merge branch 'master' of https://github.com/microsoft/TypeScript into…
Kingwl Aug 19, 2019
8b65fdc
fix merge conflict
Kingwl Aug 19, 2019
c4cb21d
Merge branch 'master' into Lift-Template-Literal-Restriction
Kingwl Aug 27, 2019
36c3bb3
fix again
Kingwl Aug 27, 2019
b7f5c77
fix again
Kingwl Aug 27, 2019
fd47863
Merge branch 'master' into Lift-Template-Literal-Restriction
Kingwl Jan 9, 2020
569b35e
use multiple target
Kingwl Jan 9, 2020
45406d4
Merge branch 'master' into Lift-Template-Literal-Restriction
sandersn Feb 5, 2020
f8b9bbb
fix space lint
sandersn Feb 5, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4124,8 +4124,18 @@ namespace ts {
case SyntaxKind.TemplateHead:
case SyntaxKind.TemplateMiddle:
case SyntaxKind.TemplateTail:
case SyntaxKind.TemplateExpression:
if ((<NoSubstitutionTemplateLiteral | TemplateHead | TemplateMiddle | TemplateTail>node).templateFlags) {
transformFlags |= TransformFlags.AssertES2018;
break;
}
// falls through
case SyntaxKind.TaggedTemplateExpression:
if (hasInvalidEscape((<TaggedTemplateExpression>node).template)) {
transformFlags |= TransformFlags.AssertES2018;
break;
}
// falls through
case SyntaxKind.TemplateExpression:
case SyntaxKind.ShorthandPropertyAssignment:
case SyntaxKind.StaticKeyword:
case SyntaxKind.MetaProperty:
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/factoryPublic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1486,7 +1486,7 @@ namespace ts {

let token = rawTextScanner.scan();
if (token === SyntaxKind.CloseBracketToken) {
token = rawTextScanner.reScanTemplateToken();
token = rawTextScanner.reScanTemplateToken(/* isTaggedTemplate */ false);
}

if (rawTextScanner.isUnterminated()) {
Expand Down
33 changes: 22 additions & 11 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1137,8 +1137,12 @@ namespace ts {
return currentToken = scanner.reScanSlashToken();
}

function reScanTemplateToken(): SyntaxKind {
return currentToken = scanner.reScanTemplateToken();
function reScanTemplateToken(isTaggedTemplate: boolean): SyntaxKind {
return currentToken = scanner.reScanTemplateToken(isTaggedTemplate);
}

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

function reScanLessThanToken(): SyntaxKind {
Expand Down Expand Up @@ -2329,17 +2333,17 @@ namespace ts {
return allowIdentifierNames ? parseIdentifierName() : parseIdentifier();
}

function parseTemplateExpression(): TemplateExpression {
function parseTemplateExpression(isTaggedTemplate: boolean): TemplateExpression {
const template = <TemplateExpression>createNode(SyntaxKind.TemplateExpression);

template.head = parseTemplateHead();
template.head = parseTemplateHead(isTaggedTemplate);
Debug.assert(template.head.kind === SyntaxKind.TemplateHead, "Template head has wrong token kind");

const list = [];
const listPos = getNodePos();

do {
list.push(parseTemplateSpan());
list.push(parseTemplateSpan(isTaggedTemplate));
}
while (last(list).literal.kind === SyntaxKind.TemplateMiddle);

Expand All @@ -2348,13 +2352,13 @@ namespace ts {
return finishNode(template);
}

function parseTemplateSpan(): TemplateSpan {
function parseTemplateSpan(isTaggedTemplate: boolean): TemplateSpan {
const span = <TemplateSpan>createNode(SyntaxKind.TemplateSpan);
span.expression = allowInAnd(parseExpression);

let literal: TemplateMiddle | TemplateTail;
if (token() === SyntaxKind.CloseBraceToken) {
reScanTemplateToken();
reScanTemplateToken(isTaggedTemplate);
literal = parseTemplateMiddleOrTemplateTail();
}
else {
Expand All @@ -2369,7 +2373,10 @@ namespace ts {
return <LiteralExpression>parseLiteralLikeNode(token());
}

function parseTemplateHead(): TemplateHead {
function parseTemplateHead(isTaggedTemplate: boolean): TemplateHead {
if (isTaggedTemplate) {
reScanTemplateHeadOrNoSubstitutionTemplate();
}
const fragment = parseLiteralLikeNode(token());
Debug.assert(fragment.kind === SyntaxKind.TemplateHead, "Template head has wrong token kind");
return <TemplateHead>fragment;
Expand Down Expand Up @@ -2413,6 +2420,10 @@ namespace ts {
(<NumericLiteral>node).numericLiteralFlags = scanner.getTokenFlags() & TokenFlags.NumericLiteralFlags;
}

if (isTemplateLiteralKind(node.kind)) {
(<TemplateHead | TemplateMiddle | TemplateTail | NoSubstitutionTemplateLiteral>node).templateFlags = scanner.getTokenFlags() & TokenFlags.ContainsInvalidEscape;
}

nextToken();
finishNode(node);

Expand Down Expand Up @@ -4772,8 +4783,8 @@ namespace ts {
tagExpression.questionDotToken = questionDotToken;
tagExpression.typeArguments = typeArguments;
tagExpression.template = token() === SyntaxKind.NoSubstitutionTemplateLiteral
? <NoSubstitutionTemplateLiteral>parseLiteralNode()
: parseTemplateExpression();
? (reScanTemplateHeadOrNoSubstitutionTemplate(), <NoSubstitutionTemplateLiteral>parseLiteralNode())
: parseTemplateExpression(/*isTaggedTemplate*/ true);
if (questionDotToken || tag.flags & NodeFlags.OptionalChain) {
tagExpression.flags |= NodeFlags.OptionalChain;
}
Expand Down Expand Up @@ -4945,7 +4956,7 @@ namespace ts {
}
break;
case SyntaxKind.TemplateHead:
return parseTemplateExpression();
return parseTemplateExpression(/* isTaggedTemplate */ false);
}

return parseIdentifier(Diagnostics.Expression_expected);
Expand Down
80 changes: 72 additions & 8 deletions src/compiler/scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ namespace ts {
getTokenFlags(): TokenFlags;
reScanGreaterToken(): SyntaxKind;
reScanSlashToken(): SyntaxKind;
reScanTemplateToken(): SyntaxKind;
reScanTemplateToken(isTaggedTemplate: boolean): SyntaxKind;
reScanTemplateHeadOrNoSubstitutionTemplate(): SyntaxKind;
scanJsxIdentifier(): SyntaxKind;
scanJsxAttributeValue(): SyntaxKind;
reScanJsxAttributeValue(): SyntaxKind;
Expand Down Expand Up @@ -468,6 +469,14 @@ namespace ts {
return ch >= CharacterCodes._0 && ch <= CharacterCodes._9;
}

function isHexDigit(ch: number): boolean {
return isDigit(ch) || ch >= CharacterCodes.A && ch <= CharacterCodes.F || ch >= CharacterCodes.a && ch <= CharacterCodes.f;
}

function isCodePoint(code: number): boolean {
return code <= 0x10FFFF;
}

/* @internal */
export function isOctalDigit(ch: number): boolean {
return ch >= CharacterCodes._0 && ch <= CharacterCodes._7;
Expand Down Expand Up @@ -901,6 +910,7 @@ namespace ts {
reScanGreaterToken,
reScanSlashToken,
reScanTemplateToken,
reScanTemplateHeadOrNoSubstitutionTemplate,
scanJsxIdentifier,
scanJsxAttributeValue,
reScanJsxAttributeValue,
Expand Down Expand Up @@ -1164,7 +1174,7 @@ namespace ts {
* Sets the current 'tokenValue' and returns a NoSubstitutionTemplateLiteral or
* a literal component of a TemplateExpression.
*/
function scanTemplateAndSetTokenValue(): SyntaxKind {
function scanTemplateAndSetTokenValue(isTaggedTemplate: boolean): SyntaxKind {
const startedWithBacktick = text.charCodeAt(pos) === CharacterCodes.backtick;

pos++;
Expand Down Expand Up @@ -1202,7 +1212,7 @@ namespace ts {
// Escape character
if (currChar === CharacterCodes.backslash) {
contents += text.substring(start, pos);
contents += scanEscapeSequence();
contents += scanEscapeSequence(isTaggedTemplate);
start = pos;
continue;
}
Expand Down Expand Up @@ -1231,7 +1241,8 @@ namespace ts {
return resultingToken;
}

function scanEscapeSequence(): string {
function scanEscapeSequence(isTaggedTemplate?: boolean): string {
const start = pos;
pos++;
if (pos >= end) {
error(Diagnostics.Unexpected_end_of_text);
Expand All @@ -1241,6 +1252,12 @@ namespace ts {
pos++;
switch (ch) {
case CharacterCodes._0:
// '\01'
if (isTaggedTemplate && pos < end && isDigit(text.charCodeAt(pos))) {
pos++;
tokenFlags |= TokenFlags.ContainsInvalidEscape;
return text.substring(start, pos);
}
return "\0";
case CharacterCodes.b:
return "\b";
Expand All @@ -1259,10 +1276,41 @@ namespace ts {
case CharacterCodes.doubleQuote:
return "\"";
case CharacterCodes.u:
if (isTaggedTemplate) {
// '\u' or '\u0' or '\u00' or '\u000'
for (let escapePos = pos; escapePos < pos + 4; escapePos++) {
if (escapePos < end && !isHexDigit(text.charCodeAt(escapePos)) && text.charCodeAt(escapePos) !== CharacterCodes.openBrace) {
pos = escapePos;
tokenFlags |= TokenFlags.ContainsInvalidEscape;
return text.substring(start, pos);
}
}
}
// '\u{DDDDDDDD}'
if (pos < end && text.charCodeAt(pos) === CharacterCodes.openBrace) {
tokenFlags |= TokenFlags.ExtendedUnicodeEscape;
pos++;

// '\u{'
if (isTaggedTemplate && !isHexDigit(text.charCodeAt(pos))) {
tokenFlags |= TokenFlags.ContainsInvalidEscape;
return text.substring(start, pos);
}

if (isTaggedTemplate) {
const savePos = pos;
const escapedValueString = scanMinimumNumberOfHexDigits(1, /*canHaveSeparators*/ false);
const escapedValue = escapedValueString ? parseInt(escapedValueString, 16) : -1;

// '\u{Not Code Point' or '\u{CodePoint'
if (!isCodePoint(escapedValue) || text.charCodeAt(pos) !== CharacterCodes.closeBrace) {
tokenFlags |= TokenFlags.ContainsInvalidEscape;
return text.substring(start, pos);
}
else {
pos = savePos;
}
}
tokenFlags |= TokenFlags.ExtendedUnicodeEscape;
return scanExtendedUnicodeEscape();
}

Expand All @@ -1271,6 +1319,17 @@ namespace ts {
return scanHexadecimalEscape(/*numDigits*/ 4);

case CharacterCodes.x:
if (isTaggedTemplate) {
if (!isHexDigit(text.charCodeAt(pos))) {
tokenFlags |= TokenFlags.ContainsInvalidEscape;
return text.substring(start, pos);
}
else if (!isHexDigit(text.charCodeAt(pos + 1))) {
pos++;
tokenFlags |= TokenFlags.ContainsInvalidEscape;
return text.substring(start, pos);
}
}
// '\xDD'
return scanHexadecimalEscape(/*numDigits*/ 2);

Expand Down Expand Up @@ -1561,7 +1620,7 @@ namespace ts {
tokenValue = scanString();
return token = SyntaxKind.StringLiteral;
case CharacterCodes.backtick:
return token = scanTemplateAndSetTokenValue();
return token = scanTemplateAndSetTokenValue(/* isTaggedTemplate */ false);
case CharacterCodes.percent:
if (text.charCodeAt(pos + 1) === CharacterCodes.equals) {
return pos += 2, token = SyntaxKind.PercentEqualsToken;
Expand Down Expand Up @@ -2019,10 +2078,15 @@ namespace ts {
/**
* Unconditionally back up and scan a template expression portion.
*/
function reScanTemplateToken(): SyntaxKind {
function reScanTemplateToken(isTaggedTemplate: boolean): SyntaxKind {
Debug.assert(token === SyntaxKind.CloseBraceToken, "'reScanTemplateToken' should only be called on a '}'");
pos = tokenPos;
return token = scanTemplateAndSetTokenValue();
return token = scanTemplateAndSetTokenValue(isTaggedTemplate);
}

function reScanTemplateHeadOrNoSubstitutionTemplate(): SyntaxKind {
pos = tokenPos;
return token = scanTemplateAndSetTokenValue(/* isTaggedTemplate */ true);
}

function reScanJsxToken(): JsxTokenSyntaxKind {
Expand Down
Loading