From 8b7caedbec33bc442b98764ba981903a8da97993 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 2 Jun 2015 10:45:50 -0700 Subject: [PATCH] Remove EmitResolver.getExpressionNameSubstitution Add EmitResolver.getReferencedExportContainer Add EmitResolver.getReferencedImportDeclaration Clean up getGeneratedNameForNode in emitter.ts Switch isNotExpressionIdentifier to isExpressionIdentifier in emitter.ts Revise emitExpressionIdentifier in emitter.ts --- src/compiler/checker.ts | 110 ++++++++------------ src/compiler/emitter.ts | 216 +++++++++++++++++++++------------------- src/compiler/types.ts | 3 +- 3 files changed, 155 insertions(+), 174 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 759b235ad0a..6257031afbd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11784,76 +11784,39 @@ module ts { // Emitter support - function isExternalModuleSymbol(symbol: Symbol): boolean { - return symbol.flags & SymbolFlags.ValueModule && symbol.declarations.length === 1 && symbol.declarations[0].kind === SyntaxKind.SourceFile; - } - - function getAliasNameSubstitution(symbol: Symbol, getGeneratedNameForNode: (node: Node) => string): string { - // If this is es6 or higher, just use the name of the export - // no need to qualify it. - if (languageVersion >= ScriptTarget.ES6) { - return undefined; - } - - let node = getDeclarationOfAliasSymbol(symbol); - if (node) { - if (node.kind === SyntaxKind.ImportClause) { - let defaultKeyword: string; - - if (languageVersion === ScriptTarget.ES3) { - defaultKeyword = "[\"default\"]"; - } else { - defaultKeyword = ".default"; - } - return getGeneratedNameForNode(node.parent) + defaultKeyword; - } - if (node.kind === SyntaxKind.ImportSpecifier) { - let moduleName = getGeneratedNameForNode(node.parent.parent.parent); - let propertyName = (node).propertyName || (node).name; - return moduleName + "." + unescapeIdentifier(propertyName.text); - } - } - } - - function getExportNameSubstitution(symbol: Symbol, location: Node, getGeneratedNameForNode: (Node: Node) => string): string { - if (isExternalModuleSymbol(symbol.parent)) { - // 1. If this is es6 or higher, just use the name of the export - // no need to qualify it. - // 2. export mechanism for System modules is different from CJS\AMD - // and it does not need qualifications for exports - if (languageVersion >= ScriptTarget.ES6 || compilerOptions.module === ModuleKind.System) { - return undefined; - } - return "exports." + unescapeIdentifier(symbol.name); - } - let node = location; - let containerSymbol = getParentOfSymbol(symbol); - while (node) { - if ((node.kind === SyntaxKind.ModuleDeclaration || node.kind === SyntaxKind.EnumDeclaration) && getSymbolOfNode(node) === containerSymbol) { - return getGeneratedNameForNode(node) + "." + unescapeIdentifier(symbol.name); - } - node = node.parent; - } - } - - function getExpressionNameSubstitution(node: Identifier, getGeneratedNameForNode: (Node: Node) => string): string { - let symbol = getNodeLinks(node).resolvedSymbol || (isDeclarationName(node) ? getSymbolOfNode(node.parent) : undefined); + // When resolved as an expression identifier, if the given node references an exported entity, return the declaration + // node of the exported entity's container. Otherwise, return undefined. + function getReferencedExportContainer(node: Identifier): SourceFile | ModuleDeclaration | EnumDeclaration { + let symbol = getReferencedValueSymbol(node); if (symbol) { - // Whan an identifier resolves to a parented symbol, it references an exported entity from - // another declaration of the same internal module. - if (symbol.parent) { - return getExportNameSubstitution(symbol, node.parent, getGeneratedNameForNode); + if (symbol.flags & SymbolFlags.ExportValue) { + let exportSymbol = getMergedSymbol(symbol.exportSymbol); + if (!(exportSymbol.flags & SymbolFlags.ExportHasLocal)) { + symbol = exportSymbol; + } } - // If we reference an exported entity within the same module declaration, then whether - // we prefix depends on the kind of entity. SymbolFlags.ExportHasLocal encompasses all the - // kinds that we do NOT prefix. - let exportSymbol = getExportSymbolOfValueSymbolIfExported(symbol); - if (symbol !== exportSymbol && !(exportSymbol.flags & SymbolFlags.ExportHasLocal)) { - return getExportNameSubstitution(exportSymbol, node.parent, getGeneratedNameForNode); + let parentSymbol = getParentOfSymbol(symbol); + if (parentSymbol) { + if (parentSymbol.flags & SymbolFlags.ValueModule && parentSymbol.valueDeclaration.kind === SyntaxKind.SourceFile) { + return parentSymbol.valueDeclaration; + } + for (let n = node.parent; n; n = n.parent) { + if ((n.kind === SyntaxKind.ModuleDeclaration || n.kind === SyntaxKind.EnumDeclaration) && getSymbolOfNode(n) === parentSymbol) { + return n; + } + } } - // Named imports from ES6 import declarations are rewritten - if (symbol.flags & SymbolFlags.Alias) { - return getAliasNameSubstitution(symbol, getGeneratedNameForNode); + } + } + + // When resolved as an expression identifier, if the given node references a default import or a named import, return + // the declaration node of that import. Otherwise, return undefined. + function getReferencedImportDeclaration(node: Identifier): ImportClause | ImportSpecifier { + let symbol = getReferencedValueSymbol(node); + if (symbol && symbol.flags & SymbolFlags.Alias) { + let declaration = getDeclarationOfAliasSymbol(symbol); + if (declaration.kind === SyntaxKind.ImportClause || declaration.kind === SyntaxKind.ImportSpecifier) { + return declaration; } } } @@ -12182,12 +12145,15 @@ module ts { return !!resolveName(location, name, SymbolFlags.Value, /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined); } + function getReferencedValueSymbol(reference: Identifier): Symbol { + return getNodeLinks(reference).resolvedSymbol || + resolveName(reference, reference.text, SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias, + /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined); + } + function getReferencedValueDeclaration(reference: Identifier): Declaration { Debug.assert(!nodeIsSynthesized(reference)); - let symbol = - getNodeLinks(reference).resolvedSymbol || - resolveName(reference, reference.text, SymbolFlags.Value | SymbolFlags.Alias, /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined); - + let symbol = getReferencedValueSymbol(reference); return symbol && getExportSymbolOfValueSymbolIfExported(symbol).valueDeclaration; } @@ -12233,6 +12199,8 @@ module ts { function createResolver(): EmitResolver { return { getExpressionNameSubstitution, + getReferencedExportContainer, + getReferencedImportDeclaration, isValueAliasDeclaration, hasGlobalName, isReferencedAliasDeclaration, diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 32ebeaec08f..2414c88a7a9 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -249,81 +249,42 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } } - function assignGeneratedName(node: Node, name: string) { - nodeToGeneratedName[getNodeId(node)] = unescapeIdentifier(name); - } - - function generateNameForFunctionOrClassDeclaration(node: Declaration) { - if (!node.name) { - assignGeneratedName(node, makeUniqueName("default")); - } - } - function generateNameForModuleOrEnum(node: ModuleDeclaration | EnumDeclaration) { - if (node.name.kind === SyntaxKind.Identifier) { - let name = node.name.text; - // Use module/enum name itself if it is unique, otherwise make a unique variation - assignGeneratedName(node, isUniqueLocalName(name, node) ? name : makeUniqueName(name)); - } + let 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) { let expr = getExternalModuleName(node); let baseName = expr.kind === SyntaxKind.StringLiteral ? escapeIdentifier(makeIdentifierFromModuleName((expr).text)) : "module"; - assignGeneratedName(node, makeUniqueName(baseName)); + return makeUniqueName(baseName); } - function generateNameForImportDeclaration(node: ImportDeclaration) { - if (node.importClause) { - generateNameForImportOrExportDeclaration(node); - } - } - - function generateNameForExportDeclaration(node: ExportDeclaration) { - if (node.moduleSpecifier) { - generateNameForImportOrExportDeclaration(node); - } - } - - function generateNameForExportAssignment(node: ExportAssignment) { - if (node.expression && node.expression.kind !== SyntaxKind.Identifier) { - assignGeneratedName(node, makeUniqueName("default")); - } + function generateNameForExportDefault() { + return makeUniqueName("default"); } function generateNameForNode(node: Node) { switch (node.kind) { + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.EnumDeclaration: + return generateNameForModuleOrEnum(node); + case SyntaxKind.ImportDeclaration: + case SyntaxKind.ExportDeclaration: + return generateNameForImportOrExportDeclaration(node); case SyntaxKind.FunctionDeclaration: case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: - generateNameForFunctionOrClassDeclaration(node); - break; - case SyntaxKind.ModuleDeclaration: - generateNameForModuleOrEnum(node); - generateNameForNode((node).body); - break; - case SyntaxKind.EnumDeclaration: - generateNameForModuleOrEnum(node); - break; - case SyntaxKind.ImportDeclaration: - generateNameForImportDeclaration(node); - break; - case SyntaxKind.ExportDeclaration: - generateNameForExportDeclaration(node); - break; case SyntaxKind.ExportAssignment: - generateNameForExportAssignment(node); - break; + return generateNameForExportDefault(); } } function getGeneratedNameForNode(node: Node) { - let nodeId = getNodeId(node); - if (!nodeToGeneratedName[nodeId]) { - generateNameForNode(node); - } - return nodeToGeneratedName[nodeId]; + let id = getNodeId(node); + return nodeToGeneratedName[id] || (nodeToGeneratedName[id] = unescapeIdentifier(generateNameForNode(node))); } function initializeEmitterWithSourceMaps() { @@ -1201,51 +1162,96 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } } - function isNotExpressionIdentifier(node: Identifier) { + function isExpressionIdentifier(node: Node): boolean { let parent = node.parent; switch (parent.kind) { - case SyntaxKind.Parameter: - case SyntaxKind.VariableDeclaration: - case SyntaxKind.BindingElement: - case SyntaxKind.PropertyDeclaration: - case SyntaxKind.PropertySignature: - case SyntaxKind.PropertyAssignment: - case SyntaxKind.ShorthandPropertyAssignment: - case SyntaxKind.EnumMember: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.MethodSignature: - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - case SyntaxKind.FunctionExpression: - case SyntaxKind.ClassDeclaration: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.EnumDeclaration: - case SyntaxKind.ModuleDeclaration: - case SyntaxKind.ImportEqualsDeclaration: - case SyntaxKind.ImportClause: - case SyntaxKind.NamespaceImport: - return (parent).name === node; - case SyntaxKind.ImportSpecifier: - case SyntaxKind.ExportSpecifier: - return (parent).name === node || (parent).propertyName === node; - case SyntaxKind.BreakStatement: - case SyntaxKind.ContinueStatement: + case SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.BinaryExpression: + case SyntaxKind.CallExpression: + case SyntaxKind.CaseClause: + case SyntaxKind.ComputedPropertyName: + case SyntaxKind.ConditionalExpression: + case SyntaxKind.Decorator: + case SyntaxKind.DeleteExpression: + case SyntaxKind.DoStatement: + case SyntaxKind.ElementAccessExpression: case SyntaxKind.ExportAssignment: - return false; - case SyntaxKind.LabeledStatement: - return (node.parent).label === node; + case SyntaxKind.ExpressionStatement: + case SyntaxKind.ExpressionWithTypeArguments: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + case SyntaxKind.IfStatement: + case SyntaxKind.NewExpression: + case SyntaxKind.ParenthesizedExpression: + case SyntaxKind.PostfixUnaryExpression: + case SyntaxKind.PrefixUnaryExpression: + case SyntaxKind.ReturnStatement: + case SyntaxKind.SpreadElementExpression: + case SyntaxKind.SwitchStatement: + case SyntaxKind.TaggedTemplateExpression: + case SyntaxKind.TemplateSpan: + case SyntaxKind.ThrowStatement: + case SyntaxKind.TypeAssertionExpression: + case SyntaxKind.TypeOfExpression: + case SyntaxKind.VoidExpression: + case SyntaxKind.WhileStatement: + case SyntaxKind.WithStatement: + case SyntaxKind.YieldExpression: + return true; + case SyntaxKind.BindingElement: + case SyntaxKind.EnumMember: + case SyntaxKind.Parameter: + case SyntaxKind.PropertyAssignment: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.VariableDeclaration: + return (parent).initializer === node; + case SyntaxKind.PropertyAccessExpression: + return (parent).expression === node; + case SyntaxKind.ArrowFunction: + case SyntaxKind.FunctionExpression: + return (parent).body === node; + case SyntaxKind.ImportEqualsDeclaration: + return (parent).moduleReference === node; + case SyntaxKind.QualifiedName: + return (parent).left === node; } + return false; } function emitExpressionIdentifier(node: Identifier) { - let substitution = resolver.getExpressionNameSubstitution(node, getGeneratedNameForNode); - if (substitution) { - write(substitution); + let container = resolver.getReferencedExportContainer(node); + if (container) { + if (container.kind === SyntaxKind.SourceFile) { + // Identifier references module export + if (languageVersion < ScriptTarget.ES6 && compilerOptions.module !== ModuleKind.System) { + write("exports."); + } + } + else { + // Identifier references namespace export + write(getGeneratedNameForNode(container)); + write("."); + } } - else { - writeTextOfNode(currentSourceFile, node); + else if (languageVersion < ScriptTarget.ES6) { + let declaration = resolver.getReferencedImportDeclaration(node); + if (declaration) { + if (declaration.kind === SyntaxKind.ImportClause) { + // Identifier references default import + write(getGeneratedNameForNode(declaration.parent)); + write(languageVersion === ScriptTarget.ES3 ? '["default"]' : ".default"); + } + else { + // Identifier references named import + write(getGeneratedNameForNode(declaration.parent.parent.parent)); + write("."); + writeTextOfNode(currentSourceFile, (declaration).propertyName || (declaration).name); + } + return; + } } + writeTextOfNode(currentSourceFile, node); } function getGeneratedNameForIdentifier(node: Identifier): string { @@ -1272,7 +1278,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { if (!node.parent) { write(node.text); } - else if (!isNotExpressionIdentifier(node)) { + else if (isExpressionIdentifier(node)) { emitExpressionIdentifier(node); } else { @@ -1709,12 +1715,15 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { emitExpressionIdentifier(node.name); } } - else if (resolver.getExpressionNameSubstitution(node.name, getGeneratedNameForNode)) { - // Emit identifier as an identifier - write(": "); - // 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); + else { + let container = resolver.getReferencedExportContainer(node.name); + if (container && container.kind !== SyntaxKind.SourceFile) { + // Emit identifier as an identifier + write(": "); + // 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); + } } } @@ -4983,13 +4992,16 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } } - function getLocalNameForExternalImport(importNode: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration): string { - let namespaceDeclaration = getNamespaceDeclarationNode(importNode); - if (namespaceDeclaration && !isDefaultImport(importNode)) { + function getLocalNameForExternalImport(node: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration): string { + let namespaceDeclaration = getNamespaceDeclarationNode(node); + if (namespaceDeclaration && !isDefaultImport(node)) { return getSourceTextOfNodeFromSourceFile(currentSourceFile, namespaceDeclaration.name); } - else { - return getGeneratedNameForNode(importNode); + if (node.kind === SyntaxKind.ImportDeclaration && (node).importClause) { + return getGeneratedNameForNode(node); + } + if (node.kind === SyntaxKind.ExportDeclaration && (node).moduleSpecifier) { + return getGeneratedNameForNode(node); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 14e53ee8f72..e64d6afad8e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1396,7 +1396,8 @@ module ts { /* @internal */ export interface EmitResolver { hasGlobalName(name: string): boolean; - getExpressionNameSubstitution(node: Identifier, getGeneratedNameForNode: (node: Node) => string): string; + getReferencedExportContainer(node: Identifier): SourceFile | ModuleDeclaration | EnumDeclaration; + getReferencedImportDeclaration(node: Identifier): ImportClause | ImportSpecifier; isValueAliasDeclaration(node: Node): boolean; isReferencedAliasDeclaration(node: Node, checkChildren?: boolean): boolean; isTopLevelValueImportEqualsWithEntityName(node: ImportEqualsDeclaration): boolean;