|
|
|
|
@@ -166,10 +166,9 @@ namespace ts {
|
|
|
|
|
let enclosingVariableStatement: VariableStatement;
|
|
|
|
|
let enclosingBlockScopeContainer: Node;
|
|
|
|
|
let enclosingBlockScopeContainerParent: Node;
|
|
|
|
|
let containingNonArrowFunction: FunctionLikeDeclaration | ClassElement;
|
|
|
|
|
|
|
|
|
|
/** Tracks the container that determines whether `super.x` is a static. */
|
|
|
|
|
let superScopeContainer: FunctionLikeDeclaration | ClassElement;
|
|
|
|
|
let enclosingFunction: FunctionLikeDeclaration;
|
|
|
|
|
let enclosingNonArrowFunction: FunctionLikeDeclaration;
|
|
|
|
|
let enclosingNonAsyncFunctionBody: FunctionLikeDeclaration | ClassElement;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Used to track if we are emitting body of the converted loop
|
|
|
|
|
@@ -183,11 +182,6 @@ namespace ts {
|
|
|
|
|
*/
|
|
|
|
|
let enabledSubstitutions: ES6SubstitutionFlags;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This is used to determine whether we need to emit `_this` instead of `this`.
|
|
|
|
|
*/
|
|
|
|
|
let useCapturedThis: boolean;
|
|
|
|
|
|
|
|
|
|
return transformSourceFile;
|
|
|
|
|
|
|
|
|
|
function transformSourceFile(node: SourceFile) {
|
|
|
|
|
@@ -207,14 +201,14 @@ namespace ts {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function saveStateAndInvoke<T>(node: Node, f: (node: Node) => T): T {
|
|
|
|
|
const savedContainingNonArrowFunction = containingNonArrowFunction;
|
|
|
|
|
const savedSuperScopeContainer = superScopeContainer;
|
|
|
|
|
const savedCurrentParent = currentParent;
|
|
|
|
|
const savedCurrentNode = currentNode;
|
|
|
|
|
const savedEnclosingVariableStatement = enclosingVariableStatement;
|
|
|
|
|
const savedEnclosingFunction = enclosingFunction;
|
|
|
|
|
const savedEnclosingNonArrowFunction = enclosingNonArrowFunction;
|
|
|
|
|
const savedEnclosingNonAsyncFunctionBody = enclosingNonAsyncFunctionBody;
|
|
|
|
|
const savedEnclosingBlockScopeContainer = enclosingBlockScopeContainer;
|
|
|
|
|
const savedEnclosingBlockScopeContainerParent = enclosingBlockScopeContainerParent;
|
|
|
|
|
|
|
|
|
|
const savedEnclosingVariableStatement = enclosingVariableStatement;
|
|
|
|
|
const savedCurrentParent = currentParent;
|
|
|
|
|
const savedCurrentNode = currentNode;
|
|
|
|
|
const savedConvertedLoopState = convertedLoopState;
|
|
|
|
|
if (nodeStartsNewLexicalEnvironment(node)) {
|
|
|
|
|
// don't treat content of nodes that start new lexical environment as part of converted loop copy
|
|
|
|
|
@@ -225,13 +219,14 @@ namespace ts {
|
|
|
|
|
const visited = f(node);
|
|
|
|
|
|
|
|
|
|
convertedLoopState = savedConvertedLoopState;
|
|
|
|
|
containingNonArrowFunction = savedContainingNonArrowFunction;
|
|
|
|
|
superScopeContainer = savedSuperScopeContainer;
|
|
|
|
|
currentParent = savedCurrentParent;
|
|
|
|
|
currentNode = savedCurrentNode;
|
|
|
|
|
enclosingVariableStatement = savedEnclosingVariableStatement;
|
|
|
|
|
enclosingFunction = savedEnclosingFunction;
|
|
|
|
|
enclosingNonArrowFunction = savedEnclosingNonArrowFunction;
|
|
|
|
|
enclosingNonAsyncFunctionBody = savedEnclosingNonAsyncFunctionBody;
|
|
|
|
|
enclosingBlockScopeContainer = savedEnclosingBlockScopeContainer;
|
|
|
|
|
enclosingBlockScopeContainerParent = savedEnclosingBlockScopeContainerParent;
|
|
|
|
|
enclosingVariableStatement = savedEnclosingVariableStatement;
|
|
|
|
|
currentParent = savedCurrentParent;
|
|
|
|
|
currentNode = savedCurrentNode;
|
|
|
|
|
return visited;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -254,22 +249,13 @@ namespace ts {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function visitorForConvertedLoopWorker(node: Node): VisitResult<Node> {
|
|
|
|
|
const savedUseCapturedThis = useCapturedThis;
|
|
|
|
|
|
|
|
|
|
if (nodeStartsNewLexicalEnvironment(node)) {
|
|
|
|
|
useCapturedThis = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let result: VisitResult<Node>;
|
|
|
|
|
|
|
|
|
|
if (shouldCheckNode(node)) {
|
|
|
|
|
result = visitJavaScript(node);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
result = visitNodesInConvertedLoop(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
useCapturedThis = savedUseCapturedThis;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -412,36 +398,28 @@ namespace ts {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function onBeforeVisitNode(node: Node) {
|
|
|
|
|
const currentGrandparent = currentParent;
|
|
|
|
|
currentParent = currentNode;
|
|
|
|
|
currentNode = node;
|
|
|
|
|
|
|
|
|
|
if (currentParent) {
|
|
|
|
|
if (isBlockScope(currentParent, currentGrandparent)) {
|
|
|
|
|
enclosingBlockScopeContainer = currentParent;
|
|
|
|
|
enclosingBlockScopeContainerParent = currentGrandparent;
|
|
|
|
|
if (currentNode) {
|
|
|
|
|
if (isBlockScope(currentNode, currentParent)) {
|
|
|
|
|
enclosingBlockScopeContainer = currentNode;
|
|
|
|
|
enclosingBlockScopeContainerParent = currentParent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (currentParent.kind) {
|
|
|
|
|
case SyntaxKind.FunctionExpression:
|
|
|
|
|
case SyntaxKind.Constructor:
|
|
|
|
|
case SyntaxKind.MethodDeclaration:
|
|
|
|
|
case SyntaxKind.GetAccessor:
|
|
|
|
|
case SyntaxKind.SetAccessor:
|
|
|
|
|
case SyntaxKind.FunctionDeclaration:
|
|
|
|
|
containingNonArrowFunction = <FunctionLikeDeclaration>currentParent;
|
|
|
|
|
if (!(containingNonArrowFunction.emitFlags & NodeEmitFlags.AsyncFunctionBody)) {
|
|
|
|
|
superScopeContainer = containingNonArrowFunction;
|
|
|
|
|
if (isFunctionLike(currentNode)) {
|
|
|
|
|
enclosingFunction = currentNode;
|
|
|
|
|
if (currentNode.kind !== SyntaxKind.ArrowFunction) {
|
|
|
|
|
enclosingNonArrowFunction = currentNode;
|
|
|
|
|
if (!(currentNode.emitFlags & NodeEmitFlags.AsyncFunctionBody)) {
|
|
|
|
|
enclosingNonAsyncFunctionBody = currentNode;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// keep track of the enclosing variable statement when in the context of
|
|
|
|
|
// variable statements, variable declarations, binding elements, and binding
|
|
|
|
|
// patterns.
|
|
|
|
|
switch (currentParent.kind) {
|
|
|
|
|
switch (currentNode.kind) {
|
|
|
|
|
case SyntaxKind.VariableStatement:
|
|
|
|
|
enclosingVariableStatement = <VariableStatement>currentParent;
|
|
|
|
|
enclosingVariableStatement = <VariableStatement>currentNode;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SyntaxKind.VariableDeclarationList:
|
|
|
|
|
@@ -455,6 +433,9 @@ namespace ts {
|
|
|
|
|
enclosingVariableStatement = undefined;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
currentParent = currentNode;
|
|
|
|
|
currentNode = node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function visitSwitchStatement(node: SwitchStatement): SwitchStatement {
|
|
|
|
|
@@ -490,9 +471,8 @@ namespace ts {
|
|
|
|
|
|
|
|
|
|
function visitThisKeyword(node: Node): Node {
|
|
|
|
|
Debug.assert(convertedLoopState !== undefined);
|
|
|
|
|
|
|
|
|
|
if (useCapturedThis) {
|
|
|
|
|
// if useCapturedThis is true then 'this' keyword is contained inside an arrow function.
|
|
|
|
|
if (enclosingFunction && enclosingFunction.kind === SyntaxKind.ArrowFunction) {
|
|
|
|
|
// if the enclosing function is an ArrowFunction is then we use the captured 'this' keyword.
|
|
|
|
|
convertedLoopState.containsLexicalThis = true;
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
@@ -1328,12 +1308,7 @@ namespace ts {
|
|
|
|
|
enableSubstitutionsForCapturedThis();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const savedUseCapturedThis = useCapturedThis;
|
|
|
|
|
useCapturedThis = true;
|
|
|
|
|
|
|
|
|
|
const func = transformFunctionLikeToExpression(node, /*location*/ node, /*name*/ undefined);
|
|
|
|
|
|
|
|
|
|
useCapturedThis = savedUseCapturedThis;
|
|
|
|
|
setNodeEmitFlags(func, NodeEmitFlags.CapturesThis);
|
|
|
|
|
return func;
|
|
|
|
|
}
|
|
|
|
|
@@ -1376,9 +1351,9 @@ namespace ts {
|
|
|
|
|
* @param name The name of the new FunctionExpression.
|
|
|
|
|
*/
|
|
|
|
|
function transformFunctionLikeToExpression(node: FunctionLikeDeclaration, location: TextRange, name: Identifier): FunctionExpression {
|
|
|
|
|
const savedContainingNonArrowFunction = containingNonArrowFunction;
|
|
|
|
|
const savedContainingNonArrowFunction = enclosingNonArrowFunction;
|
|
|
|
|
if (node.kind !== SyntaxKind.ArrowFunction) {
|
|
|
|
|
containingNonArrowFunction = node;
|
|
|
|
|
enclosingNonArrowFunction = node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const expression = setOriginalNode(
|
|
|
|
|
@@ -1394,7 +1369,7 @@ namespace ts {
|
|
|
|
|
/*original*/ node
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
containingNonArrowFunction = savedContainingNonArrowFunction;
|
|
|
|
|
enclosingNonArrowFunction = savedContainingNonArrowFunction;
|
|
|
|
|
return expression;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -2091,8 +2066,8 @@ namespace ts {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const isAsyncBlockContainingAwait =
|
|
|
|
|
containingNonArrowFunction
|
|
|
|
|
&& (containingNonArrowFunction.emitFlags & NodeEmitFlags.AsyncFunctionBody) !== 0
|
|
|
|
|
enclosingNonArrowFunction
|
|
|
|
|
&& (enclosingNonArrowFunction.emitFlags & NodeEmitFlags.AsyncFunctionBody) !== 0
|
|
|
|
|
&& (node.statement.transformFlags & TransformFlags.ContainsYield) !== 0;
|
|
|
|
|
|
|
|
|
|
let loopBodyFlags: NodeEmitFlags = 0;
|
|
|
|
|
@@ -2854,9 +2829,9 @@ namespace ts {
|
|
|
|
|
* Visits the `super` keyword
|
|
|
|
|
*/
|
|
|
|
|
function visitSuperKeyword(node: PrimaryExpression): LeftHandSideExpression {
|
|
|
|
|
return superScopeContainer
|
|
|
|
|
&& isClassElement(superScopeContainer)
|
|
|
|
|
&& !hasModifier(superScopeContainer, ModifierFlags.Static)
|
|
|
|
|
return enclosingNonAsyncFunctionBody
|
|
|
|
|
&& isClassElement(enclosingNonAsyncFunctionBody)
|
|
|
|
|
&& !hasModifier(enclosingNonAsyncFunctionBody, ModifierFlags.Static)
|
|
|
|
|
&& currentParent.kind !== SyntaxKind.CallExpression
|
|
|
|
|
? createPropertyAccess(createIdentifier("_super"), "prototype")
|
|
|
|
|
: createIdentifier("_super");
|
|
|
|
|
@@ -2881,17 +2856,16 @@ namespace ts {
|
|
|
|
|
* @param node The node to be printed.
|
|
|
|
|
*/
|
|
|
|
|
function onEmitNode(node: Node, emit: (node: Node) => void) {
|
|
|
|
|
const savedUseCapturedThis = useCapturedThis;
|
|
|
|
|
const savedEnclosingFunction = enclosingFunction;
|
|
|
|
|
|
|
|
|
|
if (enabledSubstitutions & ES6SubstitutionFlags.CapturedThis && isFunctionLike(node)) {
|
|
|
|
|
// If we are tracking a captured `this`, push a bit that indicates whether the
|
|
|
|
|
// containing function is an arrow function.
|
|
|
|
|
useCapturedThis = (getNodeEmitFlags(node) & NodeEmitFlags.CapturesThis) !== 0;
|
|
|
|
|
// If we are tracking a captured `this`, keep track of the enclosing function.
|
|
|
|
|
enclosingFunction = node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
previousOnEmitNode(node, emit);
|
|
|
|
|
|
|
|
|
|
useCapturedThis = savedUseCapturedThis;
|
|
|
|
|
enclosingFunction = savedEnclosingFunction;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -3019,7 +2993,9 @@ namespace ts {
|
|
|
|
|
* @param node The ThisKeyword node.
|
|
|
|
|
*/
|
|
|
|
|
function substituteThisKeyword(node: PrimaryExpression): PrimaryExpression {
|
|
|
|
|
if (enabledSubstitutions & ES6SubstitutionFlags.CapturedThis && useCapturedThis) {
|
|
|
|
|
if (enabledSubstitutions & ES6SubstitutionFlags.CapturedThis
|
|
|
|
|
&& enclosingFunction
|
|
|
|
|
&& enclosingFunction.emitFlags & NodeEmitFlags.CapturesThis) {
|
|
|
|
|
return createIdentifier("_this", /*location*/ node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|