mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-16 15:45:27 -05:00
Merge pull request #1589 from ivogabe/taggedTemplates
Tagged templates ES3 & 5
This commit is contained in:
@@ -377,6 +377,7 @@ module ts {
|
||||
|
||||
function bind(node: Node) {
|
||||
node.parent = parent;
|
||||
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.TypeParameter:
|
||||
bindDeclaration(<Declaration>node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes, /*isBlockScopeContainer*/ false);
|
||||
|
||||
@@ -6759,11 +6759,6 @@ module ts {
|
||||
}
|
||||
|
||||
function checkTaggedTemplateExpression(node: TaggedTemplateExpression): Type {
|
||||
// Grammar checking
|
||||
if (languageVersion < ScriptTarget.ES6) {
|
||||
grammarErrorOnFirstToken(node.template, Diagnostics.Tagged_templates_are_only_available_when_targeting_ECMAScript_6_and_higher);
|
||||
}
|
||||
|
||||
return getReturnTypeOfSignature(getResolvedSignature(node));
|
||||
}
|
||||
|
||||
|
||||
@@ -117,7 +117,6 @@ module ts {
|
||||
const_declarations_must_be_initialized: { code: 1155, category: DiagnosticCategory.Error, key: "'const' declarations must be initialized" },
|
||||
const_declarations_can_only_be_declared_inside_a_block: { code: 1156, category: DiagnosticCategory.Error, key: "'const' declarations can only be declared inside a block." },
|
||||
let_declarations_can_only_be_declared_inside_a_block: { code: 1157, category: DiagnosticCategory.Error, key: "'let' declarations can only be declared inside a block." },
|
||||
Tagged_templates_are_only_available_when_targeting_ECMAScript_6_and_higher: { code: 1159, category: DiagnosticCategory.Error, key: "Tagged templates are only available when targeting ECMAScript 6 and higher." },
|
||||
Unterminated_template_literal: { code: 1160, category: DiagnosticCategory.Error, key: "Unterminated template literal." },
|
||||
Unterminated_regular_expression_literal: { code: 1161, category: DiagnosticCategory.Error, key: "Unterminated regular expression literal." },
|
||||
An_object_member_cannot_be_declared_optional: { code: 1162, category: DiagnosticCategory.Error, key: "An object member cannot be declared optional." },
|
||||
|
||||
@@ -459,10 +459,6 @@
|
||||
"category": "Error",
|
||||
"code": 1157
|
||||
},
|
||||
"Tagged templates are only available when targeting ECMAScript 6 and higher.": {
|
||||
"category": "Error",
|
||||
"code": 1159
|
||||
},
|
||||
"Unterminated template literal.": {
|
||||
"category": "Error",
|
||||
"code": 1160
|
||||
|
||||
@@ -2072,7 +2072,7 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function emitParenthesized(node: Node, parenthesized: boolean) {
|
||||
function emitParenthesizedIf(node: Node, parenthesized: boolean) {
|
||||
if (parenthesized) {
|
||||
write("(");
|
||||
}
|
||||
@@ -2205,6 +2205,72 @@ module ts {
|
||||
function getTemplateLiteralAsStringLiteral(node: LiteralExpression): string {
|
||||
return '"' + escapeString(node.text) + '"';
|
||||
}
|
||||
|
||||
function emitDownlevelRawTemplateLiteral(node: LiteralExpression) {
|
||||
// Find original source text, since we need to emit the raw strings of the tagged template.
|
||||
// The raw strings contain the (escaped) strings of what the user wrote.
|
||||
// Examples: `\n` is converted to "\\n", a template string with a newline to "\n".
|
||||
var text = getSourceTextOfNodeFromSourceFile(currentSourceFile, node);
|
||||
|
||||
// text contains the original source, it will also contain quotes ("`"), dolar signs and braces ("${" and "}"),
|
||||
// thus we need to remove those characters.
|
||||
// First template piece starts with "`", others with "}"
|
||||
// Last template piece ends with "`", others with "${"
|
||||
var isLast = node.kind === SyntaxKind.NoSubstitutionTemplateLiteral || node.kind === SyntaxKind.TemplateTail;
|
||||
text = text.substring(1, text.length - (isLast ? 1 : 2));
|
||||
|
||||
// Newline normalization:
|
||||
// ES6 Spec 11.8.6.1 - Static Semantics of TV's and TRV's
|
||||
// <CR><LF> and <CR> LineTerminatorSequences are normalized to <LF> for both TV and TRV.
|
||||
text = text.replace(/\r\n?/g, "\n");
|
||||
text = escapeString(text);
|
||||
|
||||
write('"' + text + '"');
|
||||
}
|
||||
|
||||
function emitDownlevelTaggedTemplateArray(node: TaggedTemplateExpression, literalEmitter: (literal: LiteralExpression) => void) {
|
||||
write("[");
|
||||
if (node.template.kind === SyntaxKind.NoSubstitutionTemplateLiteral) {
|
||||
literalEmitter(<LiteralExpression>node.template);
|
||||
}
|
||||
else {
|
||||
literalEmitter((<TemplateExpression>node.template).head);
|
||||
forEach((<TemplateExpression>node.template).templateSpans, (child) => {
|
||||
write(", ");
|
||||
literalEmitter(child.literal);
|
||||
});
|
||||
}
|
||||
write("]");
|
||||
}
|
||||
|
||||
function emitDownlevelTaggedTemplate(node: TaggedTemplateExpression) {
|
||||
var tempVariable = createAndRecordTempVariable(node);
|
||||
write("(");
|
||||
emit(tempVariable);
|
||||
write(" = ");
|
||||
emitDownlevelTaggedTemplateArray(node, emit);
|
||||
write(", ");
|
||||
|
||||
emit(tempVariable);
|
||||
write(".raw = ");
|
||||
emitDownlevelTaggedTemplateArray(node, emitDownlevelRawTemplateLiteral);
|
||||
write(", ");
|
||||
|
||||
emitParenthesizedIf(node.tag, needsParenthesisForPropertyAccessOrInvocation(node.tag));
|
||||
write("(");
|
||||
emit(tempVariable);
|
||||
|
||||
// Now we emit the expressions
|
||||
if (node.template.kind === SyntaxKind.TemplateExpression) {
|
||||
forEach((<TemplateExpression>node.template).templateSpans, templateSpan => {
|
||||
write(", ");
|
||||
var needsParens = templateSpan.expression.kind === SyntaxKind.BinaryExpression
|
||||
&& (<BinaryExpression>templateSpan.expression).operatorToken.kind === SyntaxKind.CommaToken;
|
||||
emitParenthesizedIf(templateSpan.expression, needsParens);
|
||||
});
|
||||
}
|
||||
write("))");
|
||||
}
|
||||
|
||||
function emitTemplateExpression(node: TemplateExpression): void {
|
||||
// In ES6 mode and above, we can simply emit each portion of a template in order, but in
|
||||
@@ -2249,7 +2315,8 @@ module ts {
|
||||
write(" + ");
|
||||
}
|
||||
|
||||
emitParenthesized(templateSpan.expression, needsParens);
|
||||
emitParenthesizedIf(templateSpan.expression, needsParens);
|
||||
|
||||
// Only emit if the literal is non-empty.
|
||||
// The binary '+' operator is left-associative, so the first string concatenation
|
||||
// with the head will force the result up to this point to be a string.
|
||||
@@ -2479,7 +2546,7 @@ module ts {
|
||||
emit((<SpreadElementExpression>node).expression);
|
||||
}
|
||||
|
||||
function needsParenthesisForPropertyAccess(node: Expression) {
|
||||
function needsParenthesisForPropertyAccessOrInvocation(node: Expression) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
@@ -2509,7 +2576,7 @@ module ts {
|
||||
var e = elements[pos];
|
||||
if (e.kind === SyntaxKind.SpreadElementExpression) {
|
||||
e = (<SpreadElementExpression>e).expression;
|
||||
emitParenthesized(e, /*parenthesized*/ group === 0 && needsParenthesisForPropertyAccess(e));
|
||||
emitParenthesizedIf(e, /*parenthesized*/ group === 0 && needsParenthesisForPropertyAccessOrInvocation(e));
|
||||
pos++;
|
||||
}
|
||||
else {
|
||||
@@ -2985,9 +3052,14 @@ module ts {
|
||||
}
|
||||
|
||||
function emitTaggedTemplateExpression(node: TaggedTemplateExpression): void {
|
||||
emit(node.tag);
|
||||
write(" ");
|
||||
emit(node.template);
|
||||
if (compilerOptions.target >= ScriptTarget.ES6) {
|
||||
emit(node.tag);
|
||||
write(" ");
|
||||
emit(node.template);
|
||||
}
|
||||
else {
|
||||
emitDownlevelTaggedTemplate(node);
|
||||
}
|
||||
}
|
||||
|
||||
function emitParenExpression(node: ParenthesizedExpression) {
|
||||
@@ -3157,7 +3229,7 @@ module ts {
|
||||
}
|
||||
|
||||
function emitExpressionStatement(node: ExpressionStatement) {
|
||||
emitParenthesized(node.expression, /*parenthesized*/ node.expression.kind === SyntaxKind.ArrowFunction);
|
||||
emitParenthesizedIf(node.expression, /*parenthesized*/ node.expression.kind === SyntaxKind.ArrowFunction);
|
||||
write(";");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user