ES6 cleanup

This commit is contained in:
Ron Buckton 2016-03-02 11:38:30 -08:00
parent 88e17728d6
commit 30433c2c67
10 changed files with 1053 additions and 507 deletions

View file

@ -1930,7 +1930,8 @@ namespace ts {
case SyntaxKind.CallExpression:
excludeFlags = TransformFlags.ArrayLiteralOrCallOrNewExcludes;
if (subtreeFlags & TransformFlags.ContainsSpreadElementExpression
|| isSuperCall(node)) {
|| isSuperCall(node)
|| isSuperPropertyCall(node)) {
// If the this node contains a SpreadElementExpression, or is a super call, then it is an ES6
// node.
transformFlags |= TransformFlags.AssertES6;
@ -1969,12 +1970,18 @@ namespace ts {
}
}
// If the expression of a ParenthesizedExpression is a destructuring assignment,
// then the ParenthesizedExpression is a destructuring assignment.
if ((<ParenthesizedExpression>node).expression.transformFlags & TransformFlags.DestructuringAssignment) {
transformFlags |= TransformFlags.DestructuringAssignment;
}
break;
case SyntaxKind.BinaryExpression:
if (isDestructuringAssignment(node)) {
// Destructuring assignments are ES6 syntax.
transformFlags |= TransformFlags.AssertES6;
transformFlags |= TransformFlags.AssertES6 | TransformFlags.DestructuringAssignment;
}
else if ((<BinaryExpression>node).operatorToken.kind === SyntaxKind.AsteriskAsteriskToken
|| (<BinaryExpression>node).operatorToken.kind === SyntaxKind.AsteriskAsteriskEqualsToken) {
@ -1984,6 +1991,16 @@ namespace ts {
break;
case SyntaxKind.ExpressionStatement:
// If the expression of an expression statement is a destructuring assignment,
// then we treat the statement as ES6 so that we can indicate that we do not
// need to hold on to the right-hand side.
if ((<ExpressionStatement>node).expression.transformFlags & TransformFlags.DestructuringAssignment) {
transformFlags |= TransformFlags.AssertES6;
}
break;
case SyntaxKind.Parameter:
// If the parameter has a question token, then it is TypeScript syntax.
if ((<ParameterDeclaration>node).questionToken) {

View file

@ -7495,7 +7495,7 @@ namespace ts {
// This is required for destructuring assignments, as a call expression cannot be used as the target of a destructuring assignment
// while a property access can.
if (container.kind === SyntaxKind.MethodDeclaration && container.flags & NodeFlags.Async) {
if (isSuperPropertyOrElementAccess(node.parent) && isAssignmentTarget(node.parent)) {
if (isSuperProperty(node.parent) && isAssignmentTarget(node.parent)) {
getNodeLinks(container).flags |= NodeCheckFlags.AsyncMethodWithSuperBinding;
}
else {

View file

@ -220,6 +220,23 @@ namespace ts {
return result;
}
/**
* Computes the first matching span of elements and returns a tuple of the first span
* and the remaining elements.
*/
export function span<T>(array: T[], f: (x: T, i: number) => boolean): [T[], T[]] {
if (array) {
for (let i = 0; i < array.length; i++) {
if (!f(array[i], i)) {
return [array.slice(0, i), array.slice(i)];
}
}
return [array.slice(0), []];
}
return undefined;
}
/**
* Maps contiguous spans of values with the same key.
*

View file

@ -2339,7 +2339,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
superCall = true;
}
else {
superCall = isSuperPropertyOrElementAccess(expression);
superCall = isSuperProperty(expression);
isAsyncMethodWithSuper = superCall && isInAsyncMethodWithSuperInES6(node);
emit(expression);
}

View file

@ -152,7 +152,7 @@ namespace ts {
/**
* Creates a shallow, memberwise clone of a node for mutation.
*/
export function getMutableNode<T extends Node>(node: T): T {
export function getMutableClone<T extends Node>(node: T): T {
return cloneNode(node, /*location*/ node, node.flags, /*parent*/ undefined, /*original*/ node);
}
@ -320,15 +320,21 @@ namespace ts {
// Expression
export function createArrayLiteral(elements?: Expression[]) {
const node = <ArrayLiteralExpression>createNode(SyntaxKind.ArrayLiteralExpression);
export function createArrayLiteral(elements?: Expression[], location?: TextRange, multiLine?: boolean) {
const node = <ArrayLiteralExpression>createNode(SyntaxKind.ArrayLiteralExpression, location);
node.elements = parenthesizeListElements(createNodeArray(elements));
if (multiLine) {
node.multiLine = multiLine;
}
return node;
}
export function createObjectLiteral(properties?: ObjectLiteralElement[], location?: TextRange) {
export function createObjectLiteral(properties?: ObjectLiteralElement[], location?: TextRange, multiLine?: boolean) {
const node = <ObjectLiteralExpression>createNode(SyntaxKind.ObjectLiteralExpression, location);
node.properties = createNodeArray(properties);
if (multiLine) {
node.multiLine = multiLine;
}
return node;
}
@ -356,7 +362,7 @@ namespace ts {
export function createNew(expression: Expression, argumentsArray: Expression[], location?: TextRange) {
const node = <NewExpression>createNode(SyntaxKind.NewExpression, location);
node.expression = parenthesizeForAccess(expression);
node.expression = parenthesizeForNew(expression);
node.arguments = argumentsArray
? parenthesizeListElements(createNodeArray(argumentsArray))
: undefined;
@ -369,7 +375,7 @@ namespace ts {
return node;
}
export function createFunctionExpression(asteriskToken: Node, name: string | Identifier, parameters: ParameterDeclaration[], body: Block, location?: TextRange) {
export function createFunctionExpression(asteriskToken: Node, name: string | Identifier, parameters: ParameterDeclaration[], body: Block, location?: TextRange, original?: Node) {
const node = <FunctionExpression>createNode(SyntaxKind.FunctionExpression, location);
node.modifiers = undefined;
node.asteriskToken = asteriskToken;
@ -378,6 +384,10 @@ namespace ts {
node.parameters = createNodeArray(parameters);
node.type = undefined;
node.body = body;
if (original) {
node.original = original;
}
return node;
}
@ -468,9 +478,12 @@ namespace ts {
// Element
export function createBlock(statements: Statement[], location?: TextRange): Block {
export function createBlock(statements: Statement[], location?: TextRange, multiLine?: boolean): Block {
const block = <Block>createNode(SyntaxKind.Block, location);
block.statements = createNodeArray(statements);
if (multiLine) {
block.multiLine = true;
}
return block;
}
@ -573,7 +586,7 @@ namespace ts {
return node;
}
export function createFunctionDeclaration(modifiers: Modifier[], asteriskToken: Node, name: string | Identifier, parameters: ParameterDeclaration[], body: Block, location?: TextRange) {
export function createFunctionDeclaration(modifiers: Modifier[], asteriskToken: Node, name: string | Identifier, parameters: ParameterDeclaration[], body: Block, location?: TextRange, original?: Node) {
const node = <FunctionDeclaration>createNode(SyntaxKind.FunctionDeclaration, location);
node.decorators = undefined;
setModifiers(node, modifiers);
@ -583,6 +596,9 @@ namespace ts {
node.parameters = createNodeArray(parameters);
node.type = undefined;
node.body = body;
if (original) {
node.original = original;
}
return node;
}
@ -1068,6 +1084,68 @@ namespace ts {
);
}
export interface CallBinding {
target: LeftHandSideExpression;
thisArg: Expression;
}
export function createCallBinding(expression: Expression, languageVersion?: ScriptTarget): CallBinding {
const callee = skipParentheses(expression);
let thisArg: Expression;
let target: LeftHandSideExpression;
if (isSuperProperty(callee)) {
thisArg = createThis(/*location*/ callee.expression);
target = callee;
}
else if (isSuperCall(callee)) {
thisArg = createThis(/*location*/ callee);
target = languageVersion < ScriptTarget.ES6 ? createIdentifier("_super", /*location*/ callee) : callee;
}
else {
switch (callee.kind) {
case SyntaxKind.PropertyAccessExpression: {
// for `a.b()` target is `(_a = a).b` and thisArg is `_a`
thisArg = createTempVariable();
target = createPropertyAccess(
createAssignment(
thisArg,
(<PropertyAccessExpression>callee).expression,
/*location*/ (<PropertyAccessExpression>callee).expression
),
(<PropertyAccessExpression>callee).name,
/*location*/ callee
);
break;
}
case SyntaxKind.ElementAccessExpression: {
// for `a[b]()` target is `(_a = a)[b]` and thisArg is `_a`
thisArg = createTempVariable();
target = createElementAccess(
createAssignment(
thisArg,
(<ElementAccessExpression>callee).expression,
/*location*/ (<ElementAccessExpression>callee).expression
),
(<ElementAccessExpression>callee).argumentExpression,
/*location*/ callee
);
break;
}
default: {
// for `a()` target is `a` and thisArg is `void 0`
thisArg = createVoidZero();
target = parenthesizeForAccess(expression);
break;
}
}
}
return { target, thisArg };
}
export function inlineExpressions(expressions: Expression[]) {
return reduceLeft(expressions, createComma);
}
@ -1206,6 +1284,23 @@ namespace ts {
|| binaryOperator === SyntaxKind.CaretToken;
}
/**
* Wraps an expression in parentheses if it is needed in order to use the expression
* as the expression of a NewExpression node.
*
* @param expression The Expression node.
*/
export function parenthesizeForNew(expression: Expression): LeftHandSideExpression {
const lhs = parenthesizeForAccess(expression);
switch (lhs.kind) {
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
return createParen(lhs);
}
return lhs;
}
/**
* Wraps an expression in parentheses if it is needed in order to use the expression for
* property or element access.

File diff suppressed because it is too large Load diff

View file

@ -44,7 +44,6 @@ namespace ts {
let currentScope: SourceFile | Block | ModuleBlock | CaseBlock;
let currentParent: Node;
let currentNode: Node;
let combinedNodeFlags: NodeFlags;
/**
* Keeps track of whether expression substitution has been enabled for specific edge cases.
@ -104,7 +103,6 @@ namespace ts {
const savedCurrentScope = currentScope;
const savedCurrentParent = currentParent;
const savedCurrentNode = currentNode;
const savedCombinedNodeFlags = combinedNodeFlags;
// Handle state changes before visiting a node.
onBeforeVisitNode(node);
@ -116,7 +114,6 @@ namespace ts {
currentScope = savedCurrentScope;
currentParent = savedCurrentParent;
currentNode = savedCurrentNode;
combinedNodeFlags = savedCombinedNodeFlags;
return node;
}
@ -392,8 +389,6 @@ namespace ts {
currentParent = currentNode;
currentNode = node;
combinedNodeFlags = combineNodeFlags(currentNode, currentParent, combinedNodeFlags);
switch (node.kind) {
case SyntaxKind.SourceFile:
case SyntaxKind.CaseBlock:
@ -2758,7 +2753,7 @@ namespace ts {
function substituteCallExpression(node: CallExpression): Expression {
const expression = node.expression;
if (isSuperPropertyOrElementAccess(expression)) {
if (isSuperProperty(expression)) {
const flags = getSuperContainerAsyncMethodFlags();
if (flags) {
const argumentExpression = isPropertyAccessExpression(expression)

View file

@ -2761,18 +2761,19 @@ namespace ts {
ContainsES7 = 1 << 5,
ES6 = 1 << 6,
ContainsES6 = 1 << 7,
DestructuringAssignment = 1 << 8,
// Markers
// - Flags used to indicate that a subtree contains a specific transformation.
ContainsDecorators = 1 << 8,
ContainsPropertyInitializer = 1 << 9,
ContainsLexicalThis = 1 << 10,
ContainsCapturedLexicalThis = 1 << 11,
ContainsDefaultValueAssignments = 1 << 12,
ContainsParameterPropertyAssignments = 1 << 13,
ContainsSpreadElementExpression = 1 << 14,
ContainsComputedPropertyName = 1 << 15,
ContainsBlockScopedBinding = 1 << 16,
ContainsDecorators = 1 << 9,
ContainsPropertyInitializer = 1 << 10,
ContainsLexicalThis = 1 << 11,
ContainsCapturedLexicalThis = 1 << 12,
ContainsDefaultValueAssignments = 1 << 13,
ContainsParameterPropertyAssignments = 1 << 14,
ContainsSpreadElementExpression = 1 << 15,
ContainsComputedPropertyName = 1 << 16,
ContainsBlockScopedBinding = 1 << 17,
// Assertions
// - Bitmasks that are used to assert facts about the syntax of a node and its subtree.
@ -2784,7 +2785,7 @@ namespace ts {
// Scope Exclusions
// - Bitmasks that exclude flags from propagating out of a specific context
// into the subtree flags of their container.
NodeExcludes = TypeScript | Jsx | ES7 | ES6,
NodeExcludes = TypeScript | Jsx | ES7 | ES6 | DestructuringAssignment,
ArrowFunctionExcludes = ContainsDecorators | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding,
FunctionExcludes = ContainsDecorators | ContainsDefaultValueAssignments | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding,
ConstructorExcludes = ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding,

View file

@ -491,19 +491,6 @@ namespace ts {
return node;
}
/**
* Combines the flags of a node with the combined flags of its parent if they can be combined.
*/
export function combineNodeFlags(node: Node, parentNode: Node, previousNodeFlags: NodeFlags) {
if ((node.kind === SyntaxKind.VariableDeclarationList && parentNode.kind === SyntaxKind.VariableStatement) ||
(node.kind === SyntaxKind.VariableDeclaration && parentNode.kind === SyntaxKind.VariableDeclarationList) ||
(node.kind === SyntaxKind.BindingElement)) {
return node.flags | previousNodeFlags;
}
return node.flags;
}
// Returns the node flags for this node and all relevant parent nodes. This is done so that
// nodes like variable declarations and binding elements can returned a view of their flags
// that includes the modifiers from their container. i.e. flags like export/declare aren't
@ -948,19 +935,20 @@ namespace ts {
/**
* Determines whether a node is a property or element access expression for super.
*/
export function isSuperPropertyOrElementAccess(node: Node): node is (PropertyAccessExpression | ElementAccessExpression) {
export function isSuperProperty(node: Node): node is (PropertyAccessExpression | ElementAccessExpression) {
return (node.kind === SyntaxKind.PropertyAccessExpression
|| node.kind === SyntaxKind.ElementAccessExpression)
&& (<PropertyAccessExpression | ElementAccessExpression>node).expression.kind === SyntaxKind.SuperKeyword;
}
/**
* Determines whether a node is a call to either `super`, or a super property or element access.
*/
export function isSuperPropertyCall(node: Node): node is CallExpression {
return node.kind === SyntaxKind.CallExpression
&& <boolean>isSuperProperty((<CallExpression>node).expression);
}
export function isSuperCall(node: Node): node is CallExpression {
return node.kind === SyntaxKind.CallExpression
&& ((<CallExpression>node).expression.kind === SyntaxKind.SuperKeyword
|| isSuperPropertyOrElementAccess((<CallExpression>node).expression));
&& (<CallExpression>node).expression.kind === SyntaxKind.SuperKeyword;
}
export function getEntityNameFromTypeNode(node: TypeNode): EntityName | Expression {

View file

@ -134,7 +134,7 @@ namespace ts {
{ name: "arguments", test: isExpression },
],
[SyntaxKind.NewExpression]: [
{ name: "expression", test: isLeftHandSideExpression, parenthesize: parenthesizeForAccess },
{ name: "expression", test: isLeftHandSideExpression, parenthesize: parenthesizeForNew },
{ name: "typeArguments", test: isTypeNode },
{ name: "arguments", test: isExpression },
],
@ -630,7 +630,7 @@ namespace ts {
if (updated !== undefined || visited !== value) {
if (updated === undefined) {
updated = getMutableNode(node);
updated = getMutableClone(node);
updated.flags &= ~NodeFlags.Modifier;
}