Skip to content

Commit

Permalink
Addressed CR feedback.
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielRosenwasser committed Oct 29, 2014
1 parent 7fad769 commit 4aafe1d
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 17 deletions.
12 changes: 9 additions & 3 deletions src/compiler/checker.ts
Expand Up @@ -5945,10 +5945,17 @@ module ts {
return getUnionType([type1, type2]);
}

function checkTemplateExpression(node: TemplateExpression): void {
function checkTemplateExpression(node: TemplateExpression): Type {
// We just want to check each expressions, but we are unconcerned with
// the type of each expression, as any value may be coerced into a string.
// It is worth asking whether this is what we really want though.
// A place where we actually *are* concerned with the expressions' types are
// in tagged templates.
forEach((<TemplateExpression>node).templateSpans, templateSpan => {
checkExpression(templateSpan.expression);
});

return stringType;
}

function checkExpressionWithContextualType(node: Expression, contextualType: Type, contextualMapper?: TypeMapper): Type {
Expand Down Expand Up @@ -6005,8 +6012,7 @@ module ts {
case SyntaxKind.NumericLiteral:
return numberType;
case SyntaxKind.TemplateExpression:
checkTemplateExpression(<TemplateExpression>node);
// fall through
return checkTemplateExpression(<TemplateExpression>node);
case SyntaxKind.StringLiteral:
case SyntaxKind.NoSubstitutionTemplateLiteral:
return stringType;
Expand Down
19 changes: 16 additions & 3 deletions src/compiler/emitter.ts
Expand Up @@ -806,12 +806,14 @@ module ts {
}

function getTemplateLiteralAsStringLiteral(node: LiteralExpression): string {
return "\"" + escapeString(node.text) + "\"";
return '"' + escapeString(node.text) + '"';
}

function emitTemplateExpression(node: TemplateExpression): void {
// In ES6 mode and above, we can simply emit each portion of a template in order, but in
// ES3 & ES5 we must convert the template expression into a series of string concatenations.
if (compilerOptions.target >= ScriptTarget.ES6) {
forEachChild(node, emitNode);
forEachChild(node, emit);
return;
}

Expand All @@ -825,6 +827,15 @@ module ts {
emitLiteral(node.head);

forEach(node.templateSpans, templateSpan => {
// Check if the expression has operands and binds its operands less closely than binary '+'.
// If it does, we need to wrap the expression in parentheses. Otherwise, something like
// `abc${ 1 << 2}`
// becomes
// "abc" + 1 << 2 + ""
// which is really
// ("abc" + 1) << (2 + "")
// rather than
// "abc" + (1 << 2) + ""
var needsParens = comparePrecedenceToBinaryPlus(templateSpan.expression) !== Comparison.GreaterThan;

write(" + ");
Expand Down Expand Up @@ -858,6 +869,7 @@ module ts {
//
// TODO (drosen): Note that we need to account for the upcoming 'yield' and
// spread ('...') unary operators that are anticipated for ES6.
Debug.assert(compilerOptions.target <= ScriptTarget.ES5);
switch (expression.kind) {
case SyntaxKind.BinaryExpression:
switch ((<BinaryExpression>expression).operator) {
Expand All @@ -880,7 +892,8 @@ module ts {
}

function emitTemplateSpan(span: TemplateSpan) {
forEachChild(span, emitNode);
emit(span.expression);
emit(span.literal);
}

// This function specifically handles numeric/string literals for enum and accessor 'identifiers'.
Expand Down
24 changes: 13 additions & 11 deletions src/compiler/scanner.ts
Expand Up @@ -519,10 +519,10 @@ module ts {
return +(text.substring(start, pos));
}

function scanHexDigits(count: number, useExactCount?: boolean): number {
function scanHexDigits(count: number, mustMatchCount?: boolean): number {
var digits = 0;
var value = 0;
while (digits < count || !useExactCount) {
while (digits < count || !mustMatchCount) {
var ch = text.charCodeAt(pos);
if (ch >= CharacterCodes._0 && ch <= CharacterCodes._9) {
value = value * 16 + ch - CharacterCodes._0;
Expand Down Expand Up @@ -582,18 +582,18 @@ module ts {
* a literal component of a TemplateExpression.
*/
function scanTemplateAndSetTokenValue(): SyntaxKind {
var isStartOfTemplate = text.charCodeAt(pos) === CharacterCodes.backtick;
var startedWithBacktick = text.charCodeAt(pos) === CharacterCodes.backtick;

pos++;
var start = pos;
var contents = ""
var resultingToken = SyntaxKind.Unknown;
var resultingToken: SyntaxKind;

while (true) {
if (pos >= len) {
contents += text.substring(start, pos);
error(Diagnostics.Unexpected_end_of_text);
resultingToken = isStartOfTemplate ? SyntaxKind.NoSubstitutionTemplateLiteral : SyntaxKind.TemplateTail;
resultingToken = startedWithBacktick ? SyntaxKind.NoSubstitutionTemplateLiteral : SyntaxKind.TemplateTail;
break;
}

Expand All @@ -603,15 +603,15 @@ module ts {
if (currChar === CharacterCodes.backtick) {
contents += text.substring(start, pos);
pos++;
resultingToken = isStartOfTemplate ? SyntaxKind.NoSubstitutionTemplateLiteral : SyntaxKind.TemplateTail;
resultingToken = startedWithBacktick ? SyntaxKind.NoSubstitutionTemplateLiteral : SyntaxKind.TemplateTail;
break;
}

// '${'
if (currChar === CharacterCodes.$ && pos + 1 < len && text.charCodeAt(pos + 1) === CharacterCodes.openBrace) {
contents += text.substring(start, pos);
pos += 2;
resultingToken = isStartOfTemplate ? SyntaxKind.TemplateHead : SyntaxKind.TemplateMiddle;
resultingToken = startedWithBacktick ? SyntaxKind.TemplateHead : SyntaxKind.TemplateMiddle;
break;
}

Expand Down Expand Up @@ -641,6 +641,8 @@ module ts {
pos++;
}

Debug.assert(resultingToken !== undefined);

tokenValue = contents;
return resultingToken;
}
Expand Down Expand Up @@ -673,7 +675,7 @@ module ts {
return "\"";
case CharacterCodes.x:
case CharacterCodes.u:
var ch = scanHexDigits(ch === CharacterCodes.x ? 2 : 4, /*useExactCount*/ true);
var ch = scanHexDigits(ch === CharacterCodes.x ? 2 : 4, /*mustMatchCount*/ true);
if (ch >= 0) {
return String.fromCharCode(ch);
}
Expand Down Expand Up @@ -704,7 +706,7 @@ module ts {
if (pos + 5 < len && text.charCodeAt(pos + 1) === CharacterCodes.u) {
var start = pos;
pos += 2;
var value = scanHexDigits(4, /*useExactCount*/ true);
var value = scanHexDigits(4, /*mustMatchCount*/ true);
pos = start;
return value;
}
Expand Down Expand Up @@ -922,7 +924,7 @@ module ts {
case CharacterCodes._0:
if (pos + 2 < len && (text.charCodeAt(pos + 1) === CharacterCodes.X || text.charCodeAt(pos + 1) === CharacterCodes.x)) {
pos += 2;
var value = scanHexDigits(1, /*useExactCount*/ false);
var value = scanHexDigits(1, /*mustMatchCount*/ false);
if (value < 0) {
error(Diagnostics.Hexadecimal_digit_expected);
value = 0;
Expand Down Expand Up @@ -1112,7 +1114,7 @@ module ts {
* Unconditionally back up and scan a template expression portion.
*/
function reScanTemplateToken(): SyntaxKind {
Debug.assert("'reScanTemplateToken' should only be called on a '}'");
Debug.assert(token === SyntaxKind.CloseBraceToken, "'reScanTemplateToken' should only be called on a '}'");
pos = tokenPos;
return token = scanTemplateAndSetTokenValue();
}
Expand Down

1 comment on commit 4aafe1d

@CyrusNajmabadi
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Please sign in to comment.