8000 [Transforms] Down-level transformations for Async Functions by rbuckton · Pull Request #9175 · microsoft/TypeScript · GitHub
[go: up one dir, main page]

Skip to content

[Transforms] Down-level transformations for Async Functions #9175

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 31 commits into from
Jul 20, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
d506e92
Early support for generators.
rbuckton Feb 29, 2016
88b38f8
Merge branch 'transforms-transformer-module' into transforms-transfor…
rbuckton Mar 2, 2016
aaf3ab7
Merge branch 'transforms-transformer-module' into transforms-transfor…
rbuckton Mar 2, 2016
c267691
Fixed labels
rbuckton Mar 3, 2016
83b4cbb
merge branch 'transforms-fixMoreSourceMaps' into transforms-transform…
rbuckton May 18, 2016
4ae83fa
Fix issues after merge
rbuckton May 18, 2016
e85d3e6
Merge branch 'transforms' into transforms-generators
rbuckton Jun 13, 2016
0948f73
Cleanup, only support generators for async functions, added emit helper.
rbuckton Jun 13, 2016
8190666
Adds progress indicators to the runtests-parallel build task.
rbuckton Jun 9, 2016
3681e3c
Fixed typo
rbuckton Jun 9, 2016
4afb8c4
Fixes an issue with runtests-parallel when global mocha is not instal…
rbuckton Jun 10, 2016
aa4662e
Fixes runtests-parallel not reporting failure for failed tests.
rbuckton Jun 13, 2016
27931d5
Cleanup, fix linter errors, follow hoisted declarations.
rbuckton Jun 13, 2016
ea61f2b
Added tests and fixed related emit issues.
rbuckton Jun 15, 2016
9073572
Merge branch 'transforms' into transforms-generators
rbuckton Jun 15, 2016
5e31b25
Merge branch 'transforms' into transforms-generators
rbuckton Jun 15, 2016
4eb2a82
Merge branch 'transforms' into transforms-generators
rbuckton Jun 15, 2016
278a350
Add support for external helpers module, cleanup, and accept new base…
rbuckton Jun 15, 2016
c11b560
es6 test conformance cleanup
rbuckton Jun 27, 2016
a858db6
Remove extraneous comments.
rbuckton Jun 27, 2016
4a16f65
Removed extranous original parameter.
rbuckton Jun 27, 2016
393ee28
Move 'use strict' directive out of generator for async function.
rbuckton Jun 27, 2016
5b2e11c
Added es5 conformance tests for await in binary.
rbuckton Jun 27, 2016
48a9562
Added es5 conformance tests for async function declarations. Add abil…
rbuckton Jun 27, 2016
0c647c3
Added es5 conformance tests for awaiting a call
rbuckton Jun 27, 2016
203dab4
Added additional es5 conformance tests, better emit for functions ret…
rbuckton Jun 28, 2016
644e4da
Added es5 conformance tests for async arrow functions, add error for …
rbuckton Jun 28, 2016
9e3d6f8
Additional comments per PR feedback.
rbuckton Jun 28, 2016
252cc25
Merge branch 'transforms' into transforms-generators
rbuckton Jul 18, 2016
c832444
Accept baselines plus new linter warnings.
rbuckton Jul 18, 2016
c285767
Updated comment
rbuckton Jul 18, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
8000
Diff view
Prev Previous commit
Next Next commit
Merge branch 'transforms-transformer-module' into transforms-transfor…
…mer-es6-generators
  • Loading branch information
rbuckton committed Mar 2, 2016
commit 88b38f8b40ce4eda583ed91386fa9c1f4baa87e5
131 changes: 68 additions & 63 deletions src/compiler/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,16 +157,16 @@ namespace ts {
}

/**
* Creates a shallow, memberwise clone with no position information.
* Creates a shallow, memberwise clone of a node with no source map location.
*/
export function getSynthesizedClone<T extends Node>(node: T): T {
return cloneNode(node, /*location*/ undefined, node.flags, /*parent*/ undefined, /*original*/ node);
return nodeIsSynthesized(node) ? node : cloneNode(node, /*location*/ undefined, node.flags, /*parent*/ undefined, /*original*/ node);
}

/**
* Creates a shallow, memberwise clone with the specified position information.
* Creates a shallow, memberwise clone of a node at the specified source map location.
*/
export function getRelocatedClone<T extends Node>(node: T, location: TextRange) {
export function getRelocatedClone<T extends Node>(node: T, location: TextRange): T {
return cloneNode(node, location, node.flags, /*parent*/ undefined, /*original*/ node);
}

Expand Down Expand Up @@ -206,26 +206,32 @@ namespace ts {
return node;
}

export function createTempVariable(): Identifier {
const name = <Identifier>createNode(SyntaxKind.Identifier);
name.text = undefined;
name.tempKind = GeneratedIdentifierKind.Auto;
export function createTempVariable(location?: TextRange): Identifier {
const name = <Identifier>createNode(SyntaxKind.Identifier, location);
name.autoGenerateKind = GeneratedIdentifierKind.Auto;
getNodeId(name);
return name;
}

export function createLoopVariable(): Identifier {
const name = <Identifier>createNode(SyntaxKind.Identifier);
name.text = undefined;
name.tempKind = GeneratedIdentifierKind.Loop;
export function createLoopVariable(location?: TextRange): Identifier {
const name = <Identifier>createNode(SyntaxKind.Identifier, location);
name.autoGenerateKind = GeneratedIdentifierKind.Loop;
getNodeId(name);
return name;
}

export function createUniqueName(text: string): Identifier {
const name = <Identifier>createNode(SyntaxKind.Identifier);
export function createUniqueName(text: string, location?: TextRange): Identifier {
const name = <Identifier>createNode(SyntaxKind.Identifier, location);
name.text = text;
name.tempKind = GeneratedIdentifierKind.Unique;
name.autoGenerateKind = GeneratedIdentifierKind.Unique;
getNodeId(name);
return name;
}

export function getGeneratedNameForNode(node: Node, location?: TextRange): Identifier {
const name = <Identifier>createNode(SyntaxKind.Identifier, location);
name.autoGenerateKind = GeneratedIdentifierKind.Node;
name.original = node;
getNodeId(name);
return name;
}
Expand Down Expand Up @@ -624,7 +630,7 @@ namespace ts {
return createTryCatchFinally(tryBlock, /*catchClause*/ undefined, finallyBlock, location);
}

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);
Expand Down Expand Up @@ -1128,52 +1134,62 @@ namespace ts {
);
}

export interface CallTarget {
export interface CallBinding {
target: LeftHandSideExpression;
thisArg: Expression;
}

export function createCallBinding(expression: Expression): CallTarget {
export function createCallBinding(expression: Expression, languageVersion?: ScriptTarget): CallBinding {
const callee = skipParentheses(expression);
let thisArg: Expression;
let target: LeftHandSideExpression;
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;
}
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
);
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;
}
break;
}

default: {
// for `a()` target is `a` and thisArg is `void 0`
thisArg = createVoidZero();
target = parenthesizeForAccess(expression);
break;
default: {
// for `a()` target is `a` and thisArg is `void 0`
thisArg = createVoidZero();
target = parenthesizeForAccess(expression);
break;
}
}
}

Expand Down Expand Up @@ -1408,17 +1424,6 @@ namespace ts {
|| binaryOperator === SyntaxKind.CaretToken;
}

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
* as the expression of a NewExpression node.
Expand Down
133 changes: 81 additions & 52 deletions src/compiler/printer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,9 +313,9 @@ const _super = (function (geti, seti) {
let identifierSubstitution: (node: Identifier) => Identifier;
let onBeforeEmitNode: (node: Node) => void;
let onAfterEmitNode: (node: Node) => void;
let temporaryVariables: string[] = [];
let tempFlags: TempFlags;
let nodeToGeneratedName: string[];
let generatedNameSet: Map<string>;
let tempFlags: TempFlags;
let currentSourceFile: SourceFile;
let currentText: string;
let currentFileIdentifiers: Map<string>;
Expand All @@ -329,8 +329,8 @@ const _super = (function (geti, seti) {

function doPrint(jsFilePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) {
sourceMap.initialize(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit);
nodeToGeneratedName = [];
generatedNameSet = {};

isOwnFileEmit = !isBundledEmit;

// Emit helpers from all the files
Expand Down Expand Up @@ -376,7 +376,6 @@ const _super = (function (geti, seti) {
identifierSubstitution = undefined;
onBeforeEmitNode = undefined;
onAfterEmitNode = undefined;
temporaryVariables = undefined;
tempFlags = TempFlags.Auto;
currentSourceFile = undefined;
currentText = undefined;
Expand Down Expand Up @@ -822,46 +821,14 @@ const _super = (function (geti, seti) {
//

function emitIdentifier(node: Identifier) {
switch (node.tempKind) {
case GeneratedIdentifierKind.Auto:
return emitAutoIdentifier(node);
case GeneratedIdentifierKind.Loop:
return emitLoopIdentifier(node);
case GeneratedIdentifierKind.Unique:
return emitUniqueIdentifier(node);
}

if (nodeIsSynthesized(node) || !node.parent) {
if (getNodeEmitFlags(node) & NodeEmitFlags.UMDDefine) {
writeLines(umdHelper);
}
else {
write(node.text);
}
if (getNodeEmitFlags(node) & NodeEmitFlags.UMDDefine) {
writeLines(umdHelper);
}
else {
write(getTextOfNode(node, /*includeTrivia*/ false));
}
}

function emitAutoIdentifier(node: Identifier) {
const nodeId = getOriginalNodeId(node);
const text = temporaryVariables[nodeId] || (temporaryVariables[nodeId] = makeTempVariableName(TempFlags.Auto));
write(text);
}

function emitLoopIdentifier(node: Identifier) {
const nodeId = getOriginalNodeId(node);
const text = temporaryVariables[nodeId] || (temporaryVariables[nodeId] = makeTempVariableName(TempFlags._i));
write(text);
}

function emitUniqueIdentifier(node: Identifier) {
const nodeId = getOriginalNodeId(node);
const text = temporaryVariables[nodeId] || (temporaryVariables[nodeId] = makeUniqueName(node.text));
write(text);
}

//
// Names
//
Expand Down Expand Up @@ -2559,18 +2526,24 @@ const _super = (function (geti, seti) {
&& rangeEndIsOnSameLineAsRangeStart(block, block);
}

function tempKindToFlags(kind: GeneratedIdentifierKind) {
return kind === GeneratedIdentifierKind.Loop
? TempFlags._i
: TempFlags.Auto;
}

function isUniqueName(name: string): boolean {
return !resolver.hasGlobalName(name) &&
!hasProperty(currentFileIdentifiers, name) &&
!hasProperty(generatedNameSet, name);
}

function isUniqueLocalName(name: string, container: Node): boolean {
for (let node = container; isNodeDescendantOf(node, container); node = node.nextContainer) {
if (node.locals && hasProperty(node.locals, name)) {
// We conservatively include alias symbols to cover cases where they're emitted as locals
if (node.locals[name].flags & (SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias)) {
return false;
}
}
}
return true;
}

/**
* Return the next available name in the pattern _a ... _z, _0, _1, ...
* TempFlags._i or TempFlags._n may be used to express a preference for that dedicated name.
Expand Down Expand Up @@ -2599,28 +2572,84 @@ const _super = (function (geti, seti) {
}
}

/**
* Generate a name that is unique within the current file and doesn't conflict with any names
* in global scope. The name is formed by adding an '_n' suffix to the specified base name,
* where n is a positive integer. Note that names generated by makeTempVariableName and
* makeUniqueName are guaranteed to never conflict.
*/
// Generate a name that is unique within the current file and doesn't conflict with any names
// in global scope. The name is formed by adding an '_n' suffix to the specified base name,
// where n is a positive integer. Note that names generated by makeTempVariableName and
// makeUniqueName are guaranteed to never conflict.
function makeUniqueName(baseName: string): string {
// Find the first unique 'name_n', where n is a positive number
if (baseName.charCodeAt(baseName.length - 1) !== CharacterCodes._) {
baseName += "_";
}

let i = 1;
while (true) {
const generatedName = baseName + i;
if (isUniqueName(generatedName)) {
return generatedNameSet[generatedName] = generatedName;
}

i++;
}
}

function generateNameForModuleOrEnum(node: ModuleDeclaration | EnumDeclaration) {
const name = node.name.text;
// Use module/enum name itself if it is unique, otherwise make a unique variation
return isUniqueLocalName(name, node) ? name : makeUniqueName(name);
}

function generateNameForImportOrExportDeclaration(node: ImportDeclaration | ExportDeclaration) {
const expr = getExternalModuleName(node);
const baseName = expr.kind === SyntaxKind.StringLiteral ?
escapeIdentifier(makeIdentifierFromModuleName((<LiteralExpression>expr).text)) : "module";
return makeUniqueName(baseName);
}

function generateNameForExportDefault() {
return makeUniqueName("default");
}

function generateNameForClassExpression() {
return makeUniqueName("class");
}

function generateNameForNode(node: Node) {
switch (node.kind) {
case SyntaxKind.Identifier:
return makeUniqueName((<Identifier>node).text);
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.EnumDeclaration:
return generateNameForModuleOrEnum(<ModuleDeclaration | EnumDeclaration>node);
case SyntaxKind.ImportDeclaration:
case SyntaxKind.ExportDeclaration:
return generateNameForImportOrExportDeclaration(<ImportDeclaration | ExportDeclaration>node);
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ExportAssignment:
return generateNameForExportDefault();
case SyntaxKind.ClassExpression:
return generateNameForClassExpression();
default:
return makeTempVariableName(TempFlags.Auto);
}
}

function generateIdentifier(node: Identifier) {
switch (node.autoGenerateKind) {
case GeneratedIdentifierKind.Auto:
return makeTempVariableName(TempFlags.Auto);
case GeneratedIdentifierKind.Loop:
return makeTempVariableName(TempFlags._i);
case GeneratedIdentifierKind.Unique:
return makeUniqueName(node.text);
case GeneratedIdentifierKind.Node:
return generateNameForNode(getOriginalNode(node));
}
}

function getGeneratedIdentifier(node: Identifier) {
const id = getOriginalNodeId(node);
return nodeToGeneratedName[id] || (nodeToGeneratedName[id] = unescapeIdentifier(generateIdentifier(node)));
}
}
}

Expand Down
Loading
You are viewing a condensed version of this merge commit. You can view the full changes here.
0