From 460fc037e69145c52229ff9f1cd7c64e4fc75d05 Mon Sep 17 00:00:00 2001 From: Yui T Date: Tue, 25 Nov 2014 12:12:55 -0800 Subject: [PATCH 1/4] Refactoring emitter for emit ES6 features natively --- src/compiler/checker.ts | 2 +- src/compiler/emitter.ts | 64 ++++++++++++++++++++++++----------------- src/compiler/parser.ts | 6 ++-- src/compiler/types.ts | 2 +- 4 files changed, 42 insertions(+), 32 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5ee9fa4ab3e..321195e4fb5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8881,7 +8881,7 @@ module ts { // This is necessary as an identifier in short-hand property assignment can contains two meaning: // property name and property value. if (location && location.kind === SyntaxKind.ShorthandPropertyAssignment) { - return resolveEntityName(location, (location).name, SymbolFlags.Value); + return resolveEntityName(location, (location).name, SymbolFlags.Value); } return undefined; } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 5cdf98aa63e..8a045bd1dc2 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2197,33 +2197,28 @@ module ts { emitTrailingComments(node); } - function emitShortHandPropertyAssignment(node: ShortHandPropertyDeclaration) { - function emitAsNormalPropertyAssignment() { - emitLeadingComments(node); - // Emit identifier as an identifier - emit(node.name); - write(": "); - // Even though this is stored as identified because it is in short-hand property assignment, - // treated it as expression - emitExpressionIdentifier(node.name); - emitTrailingComments(node); - } + function emitShorthandPropertyAssignmentAsNormalPropertyAssignment(node: ShorthandPropertyDeclaration) { + emitLeadingComments(node); + // Emit identifier as an identifier + emit(node.name); + write(": "); + // Even though this is stored as identified because it is in short-hand property assignment, + // treated it as expression + emitExpressionIdentifier(node.name); + emitTrailingComments(node); + } - if (compilerOptions.target < ScriptTarget.ES6) { - emitAsNormalPropertyAssignment(); + function emitShorthandPropertyAssignment(node: ShorthandPropertyDeclaration) { + // If short-hand property has a prefix, then regardless of the target version, we will emit it as normal property assignment + var prefix = resolver.getExpressionNamePrefix(node.name); + if (prefix) { + emitShorthandPropertyAssignmentAsNormalPropertyAssignment(node); } - else if (compilerOptions.target >= ScriptTarget.ES6) { - // If short-hand property has a prefix, then regardless of the target version, we will emit it as normal property assignment - var prefix = resolver.getExpressionNamePrefix(node.name); - if (prefix) { - emitAsNormalPropertyAssignment(); - } - // If short-hand property has no prefix, emit it as short-hand. - else { - emitLeadingComments(node); - emit(node.name); - emitTrailingComments(node); - } + // If short-hand property has no prefix, emit it as short-hand. + else { + emitLeadingComments(node); + emit(node.name); + emitTrailingComments(node); } } @@ -3413,6 +3408,7 @@ module ts { return emitPinnedOrTripleSlashComments(node); } + // Check if node has SyntaxKind which can be emitted the same in both version of ES5 and ES6 switch (node.kind) { case SyntaxKind.Identifier: return emitIdentifier(node); @@ -3451,8 +3447,6 @@ module ts { return emitObjectLiteral(node); case SyntaxKind.PropertyAssignment: return emitPropertyAssignment(node); - case SyntaxKind.ShorthandPropertyAssignment: - return emitShortHandPropertyAssignment(node); case SyntaxKind.PropertyAccess: return emitPropertyAccess(node); case SyntaxKind.IndexedAccess: @@ -3539,6 +3533,22 @@ module ts { case SyntaxKind.SourceFile: return emitSourceFile(node); } + + // Emit node which needs to be emitted differently between ES5 and ES6 + if (compilerOptions.target < ScriptTarget.ES6) { + // Emit node down-leveling + switch (node.kind) { + case SyntaxKind.ShorthandPropertyAssignment: + return emitShorthandPropertyAssignmentAsNormalPropertyAssignment(node); + } + } + else if (compilerOptions.target >= ScriptTarget.ES6) { + // Emit node natively in EcmaScript6 + switch (node.kind) { + case SyntaxKind.ShorthandPropertyAssignment: + return emitShorthandPropertyAssignment(node); + } + } } function hasDetachedComments(pos: number) { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 8d7bf9e4fe7..86b847d1aeb 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2764,7 +2764,7 @@ module ts { // Parse to check if it is short-hand property assignment or normal property assignment if ((token === SyntaxKind.CommaToken || token === SyntaxKind.CloseBraceToken) && tokenIsIdentifier) { - node = createNode(SyntaxKind.ShorthandPropertyAssignment, nodePos); + node = createNode(SyntaxKind.ShorthandPropertyAssignment, nodePos); node.name = propertyName; } else { @@ -3968,7 +3968,7 @@ module ts { case SyntaxKind.ReturnStatement: return checkReturnStatement(node); case SyntaxKind.SetAccessor: return checkSetAccessor(node); case SyntaxKind.SourceFile: return checkSourceFile(node); - case SyntaxKind.ShorthandPropertyAssignment: return checkShorthandPropertyAssignment(node); + case SyntaxKind.ShorthandPropertyAssignment: return checkShorthandPropertyAssignment(node); case SyntaxKind.SwitchStatement: return checkSwitchStatement(node); case SyntaxKind.TaggedTemplateExpression: return checkTaggedTemplateExpression(node); case SyntaxKind.TupleType: return checkTupleType(node); @@ -4832,7 +4832,7 @@ module ts { return grammarErrorOnFirstToken(node, Diagnostics.A_declare_modifier_is_required_for_a_top_level_declaration_in_a_d_ts_file); } - function checkShorthandPropertyAssignment(node: ShortHandPropertyDeclaration): boolean { + function checkShorthandPropertyAssignment(node: ShorthandPropertyDeclaration): boolean { return checkForInvalidQuestionMark(node, Diagnostics.An_object_member_cannot_be_declared_optional); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 83937c24ed9..3df983f595b 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -360,7 +360,7 @@ module ts { initializer?: Expression; } - export interface ShortHandPropertyDeclaration extends Declaration { + export interface ShorthandPropertyDeclaration extends Declaration { name: Identifier; } From b55038314356215857247bb444b3d0b340c07a6a Mon Sep 17 00:00:00 2001 From: Yui T Date: Tue, 25 Nov 2014 12:12:55 -0800 Subject: [PATCH 2/4] Refactoring emitter for emit ES6 features natively --- src/compiler/checker.ts | 2 +- src/compiler/emitter.ts | 64 ++++++++++++++++++++++++----------------- src/compiler/parser.ts | 6 ++-- src/compiler/types.ts | 2 +- 4 files changed, 42 insertions(+), 32 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5ee9fa4ab3e..321195e4fb5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8881,7 +8881,7 @@ module ts { // This is necessary as an identifier in short-hand property assignment can contains two meaning: // property name and property value. if (location && location.kind === SyntaxKind.ShorthandPropertyAssignment) { - return resolveEntityName(location, (location).name, SymbolFlags.Value); + return resolveEntityName(location, (location).name, SymbolFlags.Value); } return undefined; } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 5cdf98aa63e..6b5c8d1fe39 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2197,33 +2197,28 @@ module ts { emitTrailingComments(node); } - function emitShortHandPropertyAssignment(node: ShortHandPropertyDeclaration) { - function emitAsNormalPropertyAssignment() { - emitLeadingComments(node); - // Emit identifier as an identifier - emit(node.name); - write(": "); - // Even though this is stored as identified because it is in short-hand property assignment, - // treated it as expression - emitExpressionIdentifier(node.name); - emitTrailingComments(node); - } + function emitShorthandPropertyAssignmentAsNormalPropertyAssignment(node: ShorthandPropertyDeclaration) { + emitLeadingComments(node); + // Emit identifier as an identifier + emit(node.name); + write(": "); + // Even though this is stored as identified because it is in short-hand property assignment, + // treated it as expression + emitExpressionIdentifier(node.name); + emitTrailingComments(node); + } - if (compilerOptions.target < ScriptTarget.ES6) { - emitAsNormalPropertyAssignment(); + function emitShorthandPropertyAssignment(node: ShorthandPropertyDeclaration) { + // If short-hand property has a prefix, then regardless of the target version, we will emit it as normal property assignment + var prefix = resolver.getExpressionNamePrefix(node.name); + if (prefix) { + emitShorthandPropertyAssignmentAsNormalPropertyAssignment(node); } - else if (compilerOptions.target >= ScriptTarget.ES6) { - // If short-hand property has a prefix, then regardless of the target version, we will emit it as normal property assignment - var prefix = resolver.getExpressionNamePrefix(node.name); - if (prefix) { - emitAsNormalPropertyAssignment(); - } - // If short-hand property has no prefix, emit it as short-hand. - else { - emitLeadingComments(node); - emit(node.name); - emitTrailingComments(node); - } + // If short-hand property has no prefix, emit it as short-hand. + else { + emitLeadingComments(node); + emit(node.name); + emitTrailingComments(node); } } @@ -3413,6 +3408,7 @@ module ts { return emitPinnedOrTripleSlashComments(node); } + // Check if node has SyntaxKind which can be emitted regardless of the ScriptTarget switch (node.kind) { case SyntaxKind.Identifier: return emitIdentifier(node); @@ -3451,8 +3447,6 @@ module ts { return emitObjectLiteral(node); case SyntaxKind.PropertyAssignment: return emitPropertyAssignment(node); - case SyntaxKind.ShorthandPropertyAssignment: - return emitShortHandPropertyAssignment(node); case SyntaxKind.PropertyAccess: return emitPropertyAccess(node); case SyntaxKind.IndexedAccess: @@ -3539,6 +3533,22 @@ module ts { case SyntaxKind.SourceFile: return emitSourceFile(node); } + + // Emit node which needs to be emitted differently depended on ScriptTarget + if (compilerOptions.target < ScriptTarget.ES6) { + // Emit node down-leveling + switch (node.kind) { + case SyntaxKind.ShorthandPropertyAssignment: + return emitShorthandPropertyAssignmentAsNormalPropertyAssignment(node); + } + } + else if (compilerOptions.target >= ScriptTarget.ES6) { + // Emit node natively in EcmaScript6 + switch (node.kind) { + case SyntaxKind.ShorthandPropertyAssignment: + return emitShorthandPropertyAssignment(node); + } + } } function hasDetachedComments(pos: number) { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 8d7bf9e4fe7..86b847d1aeb 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2764,7 +2764,7 @@ module ts { // Parse to check if it is short-hand property assignment or normal property assignment if ((token === SyntaxKind.CommaToken || token === SyntaxKind.CloseBraceToken) && tokenIsIdentifier) { - node = createNode(SyntaxKind.ShorthandPropertyAssignment, nodePos); + node = createNode(SyntaxKind.ShorthandPropertyAssignment, nodePos); node.name = propertyName; } else { @@ -3968,7 +3968,7 @@ module ts { case SyntaxKind.ReturnStatement: return checkReturnStatement(node); case SyntaxKind.SetAccessor: return checkSetAccessor(node); case SyntaxKind.SourceFile: return checkSourceFile(node); - case SyntaxKind.ShorthandPropertyAssignment: return checkShorthandPropertyAssignment(node); + case SyntaxKind.ShorthandPropertyAssignment: return checkShorthandPropertyAssignment(node); case SyntaxKind.SwitchStatement: return checkSwitchStatement(node); case SyntaxKind.TaggedTemplateExpression: return checkTaggedTemplateExpression(node); case SyntaxKind.TupleType: return checkTupleType(node); @@ -4832,7 +4832,7 @@ module ts { return grammarErrorOnFirstToken(node, Diagnostics.A_declare_modifier_is_required_for_a_top_level_declaration_in_a_d_ts_file); } - function checkShorthandPropertyAssignment(node: ShortHandPropertyDeclaration): boolean { + function checkShorthandPropertyAssignment(node: ShorthandPropertyDeclaration): boolean { return checkForInvalidQuestionMark(node, Diagnostics.An_object_member_cannot_be_declared_optional); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 83937c24ed9..3df983f595b 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -360,7 +360,7 @@ module ts { initializer?: Expression; } - export interface ShortHandPropertyDeclaration extends Declaration { + export interface ShorthandPropertyDeclaration extends Declaration { name: Identifier; } From a38e76b882aaf5ce15eabba2b267723a2471a6b1 Mon Sep 17 00:00:00 2001 From: Yui T Date: Tue, 2 Dec 2014 13:29:49 -0800 Subject: [PATCH 3/4] Address codereview --- src/compiler/emitter.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 303ca6264cb..e71e7920476 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2202,14 +2202,21 @@ module ts { // Emit identifier as an identifier emit(node.name); write(": "); - // Even though this is stored as identified because it is in short-hand property assignment, - // treated it as expression + // Even though this is stored as identifier treat it as an expression + // Short-hand, { x }, is equivalent of normal form { x: x } emitExpressionIdentifier(node.name); emitTrailingComments(node); } function emitShorthandPropertyAssignment(node: ShorthandPropertyDeclaration) { - // If short-hand property has a prefix, then regardless of the target version, we will emit it as normal property assignment + // If short-hand property has a prefix, then regardless of the target version, we will emit it as normal property assignment. For example: + // module m { + // export var y; + // } + // module m { + // export var obj = { y }; + // } + // The short-hand property in obj need to emit as such ... = { y : m.y } regardless of the TargetScript version var prefix = resolver.getExpressionNamePrefix(node.name); if (prefix) { emitShorthandPropertyAssignmentAsNormalPropertyAssignment(node); @@ -3408,7 +3415,7 @@ module ts { return emitPinnedOrTripleSlashComments(node); } - // Check if node has SyntaxKind which can be emitted regardless of the ScriptTarget + // Check if the node can be emitted regardless of the ScriptTarget switch (node.kind) { case SyntaxKind.Identifier: return emitIdentifier(node); @@ -3542,8 +3549,9 @@ module ts { return emitShorthandPropertyAssignmentAsNormalPropertyAssignment(node); } } - else if (compilerOptions.target >= ScriptTarget.ES6) { + else { // Emit node natively + Debug.assert(compilerOptions.target >= ScriptTarget.ES6, "Invalid ScriptTarget. We should emit as ES6 or above"); switch (node.kind) { case SyntaxKind.ShorthandPropertyAssignment: return emitShorthandPropertyAssignment(node); From ff3d64f83cf70fac24c90fc3a867330f3bb1e252 Mon Sep 17 00:00:00 2001 From: Yui T Date: Tue, 2 Dec 2014 13:29:49 -0800 Subject: [PATCH 4/4] Address codereview --- src/compiler/emitter.ts | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 303ca6264cb..0a953877866 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2197,22 +2197,29 @@ module ts { emitTrailingComments(node); } - function emitShorthandPropertyAssignmentAsNormalPropertyAssignment(node: ShorthandPropertyDeclaration) { + function emitDownlevelShorthandPropertyAssignment(node: ShorthandPropertyDeclaration) { emitLeadingComments(node); // Emit identifier as an identifier emit(node.name); write(": "); - // Even though this is stored as identified because it is in short-hand property assignment, - // treated it as expression + // Even though this is stored as identifier treat it as an expression + // Short-hand, { x }, is equivalent of normal form { x: x } emitExpressionIdentifier(node.name); emitTrailingComments(node); } function emitShorthandPropertyAssignment(node: ShorthandPropertyDeclaration) { - // If short-hand property has a prefix, then regardless of the target version, we will emit it as normal property assignment + // If short-hand property has a prefix, then regardless of the target version, we will emit it as normal property assignment. For example: + // module m { + // export var y; + // } + // module m { + // export var obj = { y }; + // } + // The short-hand property in obj need to emit as such ... = { y : m.y } regardless of the TargetScript version var prefix = resolver.getExpressionNamePrefix(node.name); if (prefix) { - emitShorthandPropertyAssignmentAsNormalPropertyAssignment(node); + emitDownlevelShorthandPropertyAssignment(node); } // If short-hand property has no prefix, emit it as short-hand. else { @@ -3408,7 +3415,7 @@ module ts { return emitPinnedOrTripleSlashComments(node); } - // Check if node has SyntaxKind which can be emitted regardless of the ScriptTarget + // Check if the node can be emitted regardless of the ScriptTarget switch (node.kind) { case SyntaxKind.Identifier: return emitIdentifier(node); @@ -3539,11 +3546,12 @@ module ts { // Emit node down-level switch (node.kind) { case SyntaxKind.ShorthandPropertyAssignment: - return emitShorthandPropertyAssignmentAsNormalPropertyAssignment(node); + return emitDownlevelShorthandPropertyAssignment(node); } } - else if (compilerOptions.target >= ScriptTarget.ES6) { + else { // Emit node natively + Debug.assert(compilerOptions.target >= ScriptTarget.ES6, "Invalid ScriptTarget. We should emit as ES6 or above"); switch (node.kind) { case SyntaxKind.ShorthandPropertyAssignment: return emitShorthandPropertyAssignment(node);