Added support for tagged template strings, updated baselines.

Still need to implement some error recovery and add tests.
This commit is contained in:
Daniel Rosenwasser
2014-10-23 16:54:11 -07:00
parent b704f19502
commit e7096280b4
15 changed files with 101 additions and 36 deletions
+13
View File
@@ -5422,6 +5422,13 @@ module ts {
return getReturnTypeOfSignature(signature);
}
function checkTaggedTemplateExpression(node: TaggedTemplateExpression): Type {
// TODO (drosen): Make sure substitutions are assignable to the tag's arguments.
checkExpression(node.tag);
checkExpression(node.template);
return anyType;
}
function checkTypeAssertion(node: TypeAssertion): Type {
var exprType = checkExpression(node.operand);
var targetType = getTypeFromTypeNode(node.type);
@@ -6012,6 +6019,8 @@ module ts {
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
return checkCallExpression(<CallExpression>node);
case SyntaxKind.TaggedTemplateExpression:
return checkTaggedTemplateExpression(<TaggedTemplateExpression>node);
case SyntaxKind.TypeAssertion:
return checkTypeAssertion(<TypeAssertion>node);
case SyntaxKind.ParenExpression:
@@ -7744,6 +7753,7 @@ module ts {
case SyntaxKind.IndexedAccess:
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
case SyntaxKind.TaggedTemplateExpression:
case SyntaxKind.TypeAssertion:
case SyntaxKind.ParenExpression:
case SyntaxKind.PrefixOperator:
@@ -8020,6 +8030,9 @@ module ts {
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
return (<CallExpression>parent).typeArguments && (<CallExpression>parent).typeArguments.indexOf(node) >= 0;
case SyntaxKind.TaggedTemplateExpression:
// TODO (drosen): TaggedTemplateExpressions may eventually support type arguments.
return false;
}
}
@@ -121,6 +121,7 @@ module ts {
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." },
Invalid_template_literal_expected: { code: 1158, category: DiagnosticCategory.Error, key: "Invalid template literal; expected '}'" },
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." },
Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." },
Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." },
Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." },
+4
View File
@@ -475,6 +475,10 @@
"category": "Error",
"code": 1158
},
"Tagged templates are only available when targeting ECMAScript 6 and higher.": {
"category": "Error",
"code": 1159
},
"Duplicate identifier '{0}'.": {
"category": "Error",
+9
View File
@@ -1064,6 +1064,13 @@ module ts {
}
}
function emitTaggedTemplateExpression(node: TaggedTemplateExpression): void {
Debug.assert(compilerOptions.target >= ScriptTarget.ES6, "Trying to emit a tagged template in pre-ES6 mode.");
emit(node.tag);
write(" ");
emit(node.template);
}
function emitParenExpression(node: ParenExpression) {
if (node.expression.kind === SyntaxKind.TypeAssertion) {
var operand = (<TypeAssertion>node.expression).operand;
@@ -2197,6 +2204,8 @@ module ts {
return emitCallExpression(<CallExpression>node);
case SyntaxKind.NewExpression:
return emitNewExpression(<NewExpression>node);
case SyntaxKind.TaggedTemplateExpression:
return emitTaggedTemplateExpression(<TaggedTemplateExpression>node);
case SyntaxKind.TypeAssertion:
return emit((<TypeAssertion>node).operand);
case SyntaxKind.ParenExpression:
+24 -4
View File
@@ -244,6 +244,9 @@ module ts {
return child((<CallExpression>node).func) ||
children((<CallExpression>node).typeArguments) ||
children((<CallExpression>node).arguments);
case SyntaxKind.TaggedTemplateExpression:
return child((<TaggedTemplateExpression>node).tag) ||
child((<TaggedTemplateExpression>node).template);
case SyntaxKind.TypeAssertion:
return child((<TypeAssertion>node).type) ||
child((<TypeAssertion>node).operand);
@@ -470,6 +473,7 @@ module ts {
case SyntaxKind.IndexedAccess:
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
case SyntaxKind.TaggedTemplateExpression:
case SyntaxKind.TypeAssertion:
case SyntaxKind.ParenExpression:
case SyntaxKind.FunctionExpression:
@@ -2074,6 +2078,7 @@ module ts {
case SyntaxKind.IndexedAccess:
case SyntaxKind.NewExpression:
case SyntaxKind.CallExpression:
case SyntaxKind.TaggedTemplateExpression:
case SyntaxKind.ArrayLiteral:
case SyntaxKind.ParenExpression:
case SyntaxKind.ObjectLiteral:
@@ -2440,7 +2445,7 @@ module ts {
function parseCallAndAccess(expr: Expression, inNewExpression: boolean): Expression {
while (true) {
var dotStart = scanner.getTokenPos();
var dotOrBracketStart = scanner.getTokenPos();
if (parseOptional(SyntaxKind.DotToken)) {
var propertyAccess = <PropertyAccess>createNode(SyntaxKind.PropertyAccess, expr.pos);
// Technically a keyword is valid here as all keywords are identifier names.
@@ -2463,7 +2468,7 @@ module ts {
// In the first case though, ASI will not take effect because there is not a
// line terminator after the keyword.
if (scanner.hasPrecedingLineBreak() && scanner.isReservedWord() && lookAhead(() => scanner.isReservedWord())) {
grammarErrorAtPos(dotStart, scanner.getStartPos() - dotStart, Diagnostics.Identifier_expected);
grammarErrorAtPos(dotOrBracketStart, scanner.getStartPos() - dotOrBracketStart, Diagnostics.Identifier_expected);
var id = <Identifier>createMissingNode();
}
else {
@@ -2476,7 +2481,6 @@ module ts {
continue;
}
var bracketStart = scanner.getTokenPos();
if (parseOptional(SyntaxKind.OpenBracketToken)) {
var indexedAccess = <IndexedAccess>createNode(SyntaxKind.IndexedAccess, expr.pos);
@@ -2486,7 +2490,7 @@ module ts {
// Check for that common pattern and report a better error message.
if (inNewExpression && parseOptional(SyntaxKind.CloseBracketToken)) {
indexedAccess.index = createMissingNode();
grammarErrorAtPos(bracketStart, scanner.getStartPos() - bracketStart, Diagnostics.new_T_cannot_be_used_to_create_an_array_Use_new_Array_T_instead);
grammarErrorAtPos(dotOrBracketStart, scanner.getStartPos() - dotOrBracketStart, Diagnostics.new_T_cannot_be_used_to_create_an_array_Use_new_Array_T_instead);
}
else {
indexedAccess.index = parseExpression();
@@ -2519,6 +2523,22 @@ module ts {
expr = finishNode(callExpr);
continue;
}
if (token === SyntaxKind.NoSubstitutionTemplateLiteral || token === SyntaxKind.TemplateHead) {
var tagExpression = <TaggedTemplateExpression>createNode(SyntaxKind.TaggedTemplateExpression, expr.pos);
tagExpression.tag = expr;
tagExpression.template = token === SyntaxKind.NoSubstitutionTemplateLiteral
? parseLiteralNode()
: parseTemplateExpression();
expr = finishNode(tagExpression);
if (languageVersion < ScriptTarget.ES6) {
grammarErrorOnNode(expr, Diagnostics.Tagged_templates_are_only_available_when_targeting_ECMAScript_6_and_higher);
}
continue;
}
return expr;
}
}
+9 -1
View File
@@ -169,6 +169,7 @@ module ts {
IndexedAccess,
CallExpression,
NewExpression,
TaggedTemplateExpression,
TypeAssertion,
ParenExpression,
FunctionExpression,
@@ -437,6 +438,12 @@ module ts {
export interface NewExpression extends CallExpression { }
export interface TaggedTemplateExpression extends Expression {
tag: Expression;
// Either a LiteralExpression of kind NoSubstitutionTemplateLiteral, or a TemplateExpression
template: Expression;
}
export interface TypeAssertion extends Expression {
type: TypeNode;
operand: Expression;
@@ -819,10 +826,11 @@ module ts {
Prototype = 0x04000000, // Prototype property (no source representation)
UnionProperty = 0x08000000, // Property in union type
BlockScopedVariable = 0x10000000, // A block-scoped variable (let ot const)
BlockScopedVariable = 0x10000000, // A block-scoped variable (let or const)
Variable = FunctionScopedVariable | BlockScopedVariable,
Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor,
Type = Class | Interface | Enum | TypeLiteral | ObjectLiteral | TypeParameter,
Namespace = ValueModule | NamespaceModule,
Module = ValueModule | NamespaceModule,
@@ -1,8 +1,8 @@
tests/cases/conformance/es6/templates/templateStringInModuleName.ts(1,9): error TS1005: ';' expected.
tests/cases/conformance/es6/templates/templateStringInModuleName.ts(1,16): error TS1005: ';' expected.
tests/cases/conformance/es6/templates/templateStringInModuleName.ts(1,9): error TS1159: Tagged templates are only available when targeting ECMAScript 6 and higher.
tests/cases/conformance/es6/templates/templateStringInModuleName.ts(1,21): error TS1005: ';' expected.
tests/cases/conformance/es6/templates/templateStringInModuleName.ts(4,9): error TS1005: ';' expected.
tests/cases/conformance/es6/templates/templateStringInModuleName.ts(4,16): error TS1005: ';' expected.
tests/cases/conformance/es6/templates/templateStringInModuleName.ts(4,9): error TS1159: Tagged templates are only available when targeting ECMAScript 6 and higher.
tests/cases/conformance/es6/templates/templateStringInModuleName.ts(4,24): error TS1005: ';' expected.
tests/cases/conformance/es6/templates/templateStringInModuleName.ts(1,1): error TS2304: Cannot find name 'declare'.
tests/cases/conformance/es6/templates/templateStringInModuleName.ts(1,9): error TS2304: Cannot find name 'module'.
@@ -14,8 +14,8 @@ tests/cases/conformance/es6/templates/templateStringInModuleName.ts(4,9): error
declare module `M1` {
~~~~~~
!!! error TS1005: ';' expected.
~~~~
!!! error TS1005: ';' expected.
~~~~~~~~~~~
!!! error TS1159: Tagged templates are only available when targeting ECMAScript 6 and higher.
~
!!! error TS1005: ';' expected.
~~~~~~~
@@ -27,8 +27,8 @@ tests/cases/conformance/es6/templates/templateStringInModuleName.ts(4,9): error
declare module `M${2}` {
~~~~~~
!!! error TS1005: ';' expected.
~~~~
!!! error TS1005: ';' expected.
~~~~~~~~~~~~~~
!!! error TS1159: Tagged templates are only available when targeting ECMAScript 6 and higher.
~
!!! error TS1005: ';' expected.
~~~~~~~
@@ -1,8 +1,6 @@
tests/cases/conformance/es6/templates/templateStringInModuleNameES6.ts(1,9): error TS1005: ';' expected.
tests/cases/conformance/es6/templates/templateStringInModuleNameES6.ts(1,16): error TS1005: ';' expected.
tests/cases/conformance/es6/templates/templateStringInModuleNameES6.ts(1,21): error TS1005: ';' expected.
tests/cases/conformance/es6/templates/templateStringInModuleNameES6.ts(4,9): error TS1005: ';' expected.
tests/cases/conformance/es6/templates/templateStringInModuleNameES6.ts(4,16): error TS1005: ';' expected.
tests/cases/conformance/es6/templates/templateStringInModuleNameES6.ts(4,24): error TS1005: ';' expected.
tests/cases/conformance/es6/templates/templateStringInModuleNameES6.ts(1,1): error TS2304: Cannot find name 'declare'.
tests/cases/conformance/es6/templates/templateStringInModuleNameES6.ts(1,9): error TS2304: Cannot find name 'module'.
@@ -10,11 +8,9 @@ tests/cases/conformance/es6/templates/templateStringInModuleNameES6.ts(4,1): err
tests/cases/conformance/es6/templates/templateStringInModuleNameES6.ts(4,9): error TS2304: Cannot find name 'module'.
==== tests/cases/conformance/es6/templates/templateStringInModuleNameES6.ts (10 errors) ====
==== tests/cases/conformance/es6/templates/templateStringInModuleNameES6.ts (8 errors) ====
declare module `M1` {
~~~~~~
!!! error TS1005: ';' expected.
~~~~
!!! error TS1005: ';' expected.
~
!!! error TS1005: ';' expected.
@@ -26,8 +22,6 @@ tests/cases/conformance/es6/templates/templateStringInModuleNameES6.ts(4,9): err
declare module `M${2}` {
~~~~~~
!!! error TS1005: ';' expected.
~~~~
!!! error TS1005: ';' expected.
~
!!! error TS1005: ';' expected.
@@ -1,16 +1,24 @@
tests/cases/conformance/es6/templates/templateStringInObjectLiteral.ts(1,9): error TS1159: Tagged templates are only available when targeting ECMAScript 6 and higher.
tests/cases/conformance/es6/templates/templateStringInObjectLiteral.ts(3,5): error TS1136: Property assignment expected.
tests/cases/conformance/es6/templates/templateStringInObjectLiteral.ts(3,8): error TS1005: ';' expected.
tests/cases/conformance/es6/templates/templateStringInObjectLiteral.ts(3,8): error TS1005: ',' expected.
tests/cases/conformance/es6/templates/templateStringInObjectLiteral.ts(3,10): error TS1134: Variable declaration expected.
tests/cases/conformance/es6/templates/templateStringInObjectLiteral.ts(4,1): error TS1128: Declaration or statement expected.
==== tests/cases/conformance/es6/templates/templateStringInObjectLiteral.ts (3 errors) ====
==== tests/cases/conformance/es6/templates/templateStringInObjectLiteral.ts (5 errors) ====
var x = {
~
a: `abc${ 123 }def`,
~~~~~~~~~~~~~~~~~~~~~~~~
`b`: 321
~~~~~~~
!!! error TS1159: Tagged templates are only available when targeting ECMAScript 6 and higher.
~~~
!!! error TS1136: Property assignment expected.
~
!!! error TS1005: ';' expected.
!!! error TS1005: ',' expected.
~~~
!!! error TS1134: Variable declaration expected.
}
~
!!! error TS1128: Declaration or statement expected.
@@ -1,16 +1,19 @@
tests/cases/conformance/es6/templates/templateStringInObjectLiteralES6.ts(3,5): error TS1136: Property assignment expected.
tests/cases/conformance/es6/templates/templateStringInObjectLiteralES6.ts(3,8): error TS1005: ';' expected.
tests/cases/conformance/es6/templates/templateStringInObjectLiteralES6.ts(3,8): error TS1005: ',' expected.
tests/cases/conformance/es6/templates/templateStringInObjectLiteralES6.ts(3,10): error TS1134: Variable declaration expected.
tests/cases/conformance/es6/templates/templateStringInObjectLiteralES6.ts(4,1): error TS1128: Declaration or statement expected.
==== tests/cases/conformance/es6/templates/templateStringInObjectLiteralES6.ts (3 errors) ====
==== tests/cases/conformance/es6/templates/templateStringInObjectLiteralES6.ts (4 errors) ====
var x = {
a: `abc${ 123 }def`,
`b`: 321
~~~
!!! error TS1136: Property assignment expected.
~
!!! error TS1005: ';' expected.
!!! error TS1005: ',' expected.
~~~
!!! error TS1134: Variable declaration expected.
}
~
!!! error TS1128: Declaration or statement expected.
@@ -1,6 +1,6 @@
tests/cases/conformance/es6/templates/templateStringInYieldKeyword.ts(1,9): error TS1003: Identifier expected.
tests/cases/conformance/es6/templates/templateStringInYieldKeyword.ts(1,15): error TS1005: ';' expected.
tests/cases/conformance/es6/templates/templateStringInYieldKeyword.ts(3,19): error TS1005: ',' expected.
tests/cases/conformance/es6/templates/templateStringInYieldKeyword.ts(3,13): error TS1159: Tagged templates are only available when targeting ECMAScript 6 and higher.
tests/cases/conformance/es6/templates/templateStringInYieldKeyword.ts(1,11): error TS2304: Cannot find name 'gen'.
tests/cases/conformance/es6/templates/templateStringInYieldKeyword.ts(3,13): error TS2304: Cannot find name 'yield'.
@@ -15,8 +15,8 @@ tests/cases/conformance/es6/templates/templateStringInYieldKeyword.ts(3,13): err
!!! error TS2304: Cannot find name 'gen'.
// Once this is supported, the inner expression does not need to be parenthesized.
var x = yield `abc${ x }def`;
~~~~~~
!!! error TS1005: ',' expected.
~~~~~~~~~~~~~~~~~~~~
!!! error TS1159: Tagged templates are only available when targeting ECMAScript 6 and higher.
~~~~~
!!! error TS2304: Cannot find name 'yield'.
}
@@ -0,0 +1,5 @@
=== tests/cases/conformance/es6/templates/templateStringWithEmbeddedConditional.ts ===
var x = `abc${ true ? false : " " }def`;
>x : string
>true ? false : " " : string | boolean
@@ -0,0 +1,5 @@
=== tests/cases/conformance/es6/templates/templateStringWithEmbeddedConditionalES6.ts ===
var x = `abc${ true ? false : " " }def`;
>x : string
>true ? false : " " : string | boolean
@@ -1,7 +1,7 @@
tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeyword.ts(1,9): error TS1003: Identifier expected.
tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeyword.ts(1,15): error TS1005: ';' expected.
tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeyword.ts(3,26): error TS1158: Invalid template literal; expected '}'
tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeyword.ts(3,33): error TS1005: ';' expected.
tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeyword.ts(3,30): error TS1159: Tagged templates are only available when targeting ECMAScript 6 and higher.
tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeyword.ts(5,1): error TS1126: Unexpected end of text.
tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeyword.ts(1,11): error TS2304: Cannot find name 'gen'.
tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeyword.ts(3,20): error TS2304: Cannot find name 'yield'.
@@ -20,7 +20,7 @@ tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeyword.ts(
var x = `abc${ yield 10 }def`;
~~
!!! error TS1158: Invalid template literal; expected '}'
~~
~~~~~
~~~~~
!!! error TS2304: Cannot find name 'yield'.
~~~
@@ -29,6 +29,6 @@ tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeyword.ts(
~
!!! error TS1005: ';' expected.
!!! error TS1159: Tagged templates are only available when targeting ECMAScript 6 and higher.
!!! error TS1126: Unexpected end of text.
@@ -1,14 +1,13 @@
tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeywordES6.ts(1,9): error TS1003: Identifier expected.
tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeywordES6.ts(1,17): error TS1005: ';' expected.
tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeywordES6.ts(3,26): error TS1158: Invalid template literal; expected '}'
tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeywordES6.ts(3,33): error TS1005: ';' expected.
tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeywordES6.ts(5,1): error TS1126: Unexpected end of text.
tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeywordES6.ts(1,11): error TS2304: Cannot find name 'gen'.
tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeywordES6.ts(3,20): error TS2304: Cannot find name 'yield'.
tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeywordES6.ts(3,30): error TS2304: Cannot find name 'def'.
==== tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeywordES6.ts (8 errors) ====
==== tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeywordES6.ts (7 errors) ====
function* gen() {
~
!!! error TS1003: Identifier expected.
@@ -20,15 +19,11 @@ tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeywordES6.
var x = `abc${ yield 10 }def`;
~~
!!! error TS1158: Invalid template literal; expected '}'
~~
~~~~~
!!! error TS2304: Cannot find name 'yield'.
~~~
!!! error TS2304: Cannot find name 'def'.
}
~
!!! error TS1005: ';' expected.
!!! error TS1126: Unexpected end of text.