Use sparse arrays for number-keyed maps

This commit is contained in:
Andy Hanson
2016-12-27 11:17:33 -08:00
parent b53b5cf4ab
commit 8386d491ab
17 changed files with 240 additions and 221 deletions

View File

@@ -4054,16 +4054,15 @@ namespace ts {
enumType.symbol = symbol;
if (enumHasLiteralMembers(symbol)) {
const memberTypeList: Type[] = [];
const memberTypes = createMap<EnumLiteralType>();
const memberTypes = sparseArray<EnumLiteralType>();
for (const declaration of enumType.symbol.declarations) {
if (declaration.kind === SyntaxKind.EnumDeclaration) {
computeEnumMemberValues(<EnumDeclaration>declaration);
for (const member of (<EnumDeclaration>declaration).members) {
const memberSymbol = getSymbolOfNode(member);
const value = getEnumMemberValue(member);
if (!memberTypes.has(value)) {
const memberType = createEnumLiteralType(memberSymbol, enumType, "" + value);
memberTypes.set(value, memberType);
if (!memberTypes[value]) {
const memberType = memberTypes[value] = createEnumLiteralType(memberSymbol, enumType, "" + value);
memberTypeList.push(memberType);
}
}
@@ -4085,7 +4084,7 @@ namespace ts {
if (!links.declaredType) {
const enumType = <EnumType>getDeclaredTypeOfEnum(getParentOfSymbol(symbol));
links.declaredType = enumType.flags & TypeFlags.Union ?
enumType.memberTypes.get(getEnumMemberValue(<EnumMember>symbol.valueDeclaration)) :
enumType.memberTypes[getEnumMemberValue(<EnumMember>symbol.valueDeclaration)] :
enumType;
}
return links.declaredType;

View File

@@ -39,6 +39,8 @@ namespace ts {
return map;
}
export const sparseArray: <T>() => SparseArray<T> = createMapLike;
/** Create a new map. If a template object is provided, the map will copy entries from it. */
export function createMap<T>(template?: MapLike<T>): Map<T> {
const map: Map<T> = new MapCtr<T>();
@@ -52,17 +54,6 @@ namespace ts {
return map;
}
/** Create a map from [key, value] pairs. This avoids casting keys to strings. */
export function createMapFromPairs<T>(...pairs: [number, T][]): Map<T> {
const map: Map<T> = new MapCtr<T>();
for (const [key, value] of pairs) {
map.set(key, value);
}
return map;
}
/** Methods on native maps but not on shim maps. Only used in this file. */
interface ES6Map<T> extends Map<T> {
entries(): Iterator<[string, T]>;
@@ -92,21 +83,21 @@ namespace ts {
return class<T> implements ShimMap<T> {
private data = createMapLike<T>();
get(key: MapKey): T {
get(key: string): T {
return this.data[key];
}
set(key: MapKey, value: T): this {
set(key: string, value: T): this {
this.data[key] = value;
return this;
}
has(key: MapKey): boolean {
has(key: string): boolean {
// tslint:disable-next-line:no-in-operator
return key in this.data;
}
delete(key: MapKey): boolean {
delete(key: string): boolean {
const had = this.has(key);
if (had) {
delete this.data[key];
@@ -890,7 +881,7 @@ namespace ts {
* Array of every key in a map.
* May not actually return string[] if numbers were put into the map.
*/
export function keysOfMap<T>(map: Map<T>): string[] {
export function keysOfMap(map: Map<{}>): string[] {
const keys: string[] = [];
forEachKeyInMap(map, key => {
keys.push(key);
@@ -1040,7 +1031,7 @@ namespace ts {
* Adds the value to an array of values associated with the key, and returns the array.
* Creates the array if it does not already exist.
*/
export function multiMapAdd<V>(map: Map<V[]>, key: string | number, value: V): V[] {
export function multiMapAdd<V>(map: Map<V[]>, key: string, value: V): V[] {
let values = map.get(key);
if (values) {
values.push(value);
@@ -1051,6 +1042,17 @@ namespace ts {
return values;
}
export function multiMapSparseArrayAdd<V>(map: SparseArray<V[]>, key: number, value: V): V[] {
let values = map[key];
if (values) {
values.push(value);
}
else {
map[key] = values = [value];
}
return values;
}
/**
* Removes a value from an array of values associated with the key.
* Does not preserve the order of those values.

View File

@@ -1,4 +1,4 @@
/// <reference path="core.ts"/>
/// <reference path="core.ts"/>
/// <reference path="utilities.ts"/>
/* @internal */
@@ -2641,9 +2641,11 @@ namespace ts {
return destEmitNode;
}
function mergeTokenSourceMapRanges(sourceRanges: Map<TextRange>, destRanges: Map<TextRange>) {
if (!destRanges) destRanges = createMap<TextRange>();
copyMapEntries(sourceRanges, destRanges);
function mergeTokenSourceMapRanges(sourceRanges: SparseArray<TextRange>, destRanges: SparseArray<TextRange>) {
if (!destRanges) destRanges = [];
for (const key in sourceRanges) {
destRanges[key] = sourceRanges[key];
}
return destRanges;
}
@@ -2745,7 +2747,7 @@ namespace ts {
export function getTokenSourceMapRange(node: Node, token: SyntaxKind) {
const emitNode = node.emitNode;
const tokenSourceMapRanges = emitNode && emitNode.tokenSourceMapRanges;
return tokenSourceMapRanges && tokenSourceMapRanges.get(token);
return tokenSourceMapRanges && tokenSourceMapRanges[token];
}
/**
@@ -2757,8 +2759,8 @@ namespace ts {
*/
export function setTokenSourceMapRange<T extends Node>(node: T, token: SyntaxKind, range: TextRange) {
const emitNode = getOrCreateEmitNode(node);
const tokenSourceMapRanges = emitNode.tokenSourceMapRanges || (emitNode.tokenSourceMapRanges = createMap<TextRange>());
tokenSourceMapRanges.set(token, range);
const tokenSourceMapRanges = emitNode.tokenSourceMapRanges || (emitNode.tokenSourceMapRanges = []);
tokenSourceMapRanges[token] = range;
return node;
}
@@ -3270,7 +3272,7 @@ namespace ts {
externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[]; // imports of other external modules
externalHelpersImportDeclaration: ImportDeclaration | undefined; // import of external helpers
exportSpecifiers: Map<ExportSpecifier[]>; // export specifiers by name
exportedBindings: Map<Identifier[]>; // exported names of local declarations
exportedBindings: SparseArray<Identifier[]>; // exported names of local declarations
exportedNames: Identifier[]; // all exported names local to module
exportEquals: ExportAssignment | undefined; // an export= declaration if one was present
hasExportStarsToExportValues: boolean; // whether this module contains export*
@@ -3279,7 +3281,7 @@ namespace ts {
export function collectExternalModuleInfo(sourceFile: SourceFile, resolver: EmitResolver, compilerOptions: CompilerOptions): ExternalModuleInfo {
const externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[] = [];
const exportSpecifiers = createMap<ExportSpecifier[]>();
const exportedBindings = createMap<Identifier[]>();
const exportedBindings = sparseArray<Identifier[]>();
const uniqueExports = createMap<boolean>();
let exportedNames: Identifier[];
let hasExportDefault = false;
@@ -3338,7 +3340,7 @@ namespace ts {
|| resolver.getReferencedValueDeclaration(name);
if (decl) {
multiMapAdd(exportedBindings, getOriginalNodeId(decl), specifier.name);
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(decl), specifier.name);
}
uniqueExports.set(specifier.name.text, true);
@@ -3368,7 +3370,7 @@ namespace ts {
if (hasModifier(node, ModifierFlags.Default)) {
// export default function() { }
if (!hasExportDefault) {
multiMapAdd(exportedBindings, getOriginalNodeId(node), getDeclarationName(<FunctionDeclaration>node));
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), getDeclarationName(<FunctionDeclaration>node));
hasExportDefault = true;
}
}
@@ -3376,7 +3378,7 @@ namespace ts {
// export function x() { }
const name = (<FunctionDeclaration>node).name;
if (!uniqueExports.get(name.text)) {
multiMapAdd(exportedBindings, getOriginalNodeId(node), name);
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), name);
uniqueExports.set(name.text, true);
exportedNames = append(exportedNames, name);
}
@@ -3389,7 +3391,7 @@ namespace ts {
if (hasModifier(node, ModifierFlags.Default)) {
// export default class { }
if (!hasExportDefault) {
multiMapAdd(exportedBindings, getOriginalNodeId(node), getDeclarationName(<ClassDeclaration>node));
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), getDeclarationName(<ClassDeclaration>node));
hasExportDefault = true;
}
}
@@ -3397,7 +3399,7 @@ namespace ts {
// export class x { }
const name = (<ClassDeclaration>node).name;
if (!uniqueExports.get(name.text)) {
multiMapAdd(exportedBindings, getOriginalNodeId(node), name);
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), name);
uniqueExports.set(name.text, true);
exportedNames = append(exportedNames, name);
}

View File

@@ -362,7 +362,7 @@ namespace ts {
const emitNode = node && node.emitNode;
const emitFlags = emitNode && emitNode.flags;
const range = emitNode && emitNode.tokenSourceMapRanges && emitNode.tokenSourceMapRanges.get(token);
const range = emitNode && emitNode.tokenSourceMapRanges && emitNode.tokenSourceMapRanges[token];
tokenPos = skipTrivia(currentSourceText, range ? range.pos : tokenPos);
if ((emitFlags & EmitFlags.NoTokenLeadingSourceMaps) === 0 && tokenPos >= 0) {

View File

@@ -1,4 +1,4 @@
/// <reference path="visitor.ts" />
/// <reference path="visitor.ts" />
/// <reference path="transformers/ts.ts" />
/// <reference path="transformers/jsx.ts" />
/// <reference path="transformers/esnext.ts" />
@@ -13,14 +13,16 @@
/* @internal */
namespace ts {
const moduleTransformerMap = createMapFromPairs<Transformer>(
[ModuleKind.ES2015, transformES2015Module],
[ModuleKind.System, transformSystemModule],
[ModuleKind.AMD, transformModule],
[ModuleKind.CommonJS, transformModule],
[ModuleKind.UMD, transformModule],
[ModuleKind.None, transformModule],
);
function getModuleTransformer(moduleKind: ModuleKind): Transformer {
switch (moduleKind) {
case ModuleKind.ES2015:
return transformES2015Module;
case ModuleKind.System:
return transformSystemModule;
default:
return transformModule;
}
}
const enum SyntaxKindFeatureFlags {
Substitution = 1 << 0,
@@ -56,7 +58,7 @@ namespace ts {
transformers.push(transformGenerators);
}
transformers.push(moduleTransformerMap.get(moduleKind) || moduleTransformerMap.get(ModuleKind.None));
transformers.push(getModuleTransformer(moduleKind));
// The ES5 transformer is last so that it can substitute expressions like `exports.default`
// for ES3.

View File

@@ -1,4 +1,4 @@
/// <reference path="../factory.ts" />
/// <reference path="../factory.ts" />
/// <reference path="../visitor.ts" />
// Transforms generator functions into a compatible ES5 representation with similar runtime
@@ -217,13 +217,15 @@ namespace ts {
Endfinally = 7,
}
const instructionNames = createMapFromPairs<string>(
[Instruction.Return, "return"],
[Instruction.Break, "break"],
[Instruction.Yield, "yield"],
[Instruction.YieldStar, "yield*"],
[Instruction.Endfinally, "endfinally"],
);
function getInstructionName(instruction: Instruction): string {
switch (instruction) {
case Instruction.Return: return "return";
case Instruction.Break: return "break";
case Instruction.Yield: return "yield";
case Instruction.YieldStar: return "yield*";
case Instruction.Endfinally: return "endfinally";
}
}
export function transformGenerators(context: TransformationContext) {
const {
@@ -241,7 +243,7 @@ namespace ts {
let currentSourceFile: SourceFile;
let renamedCatchVariables: Map<boolean>;
let renamedCatchVariableDeclarations: Map<Identifier>;
let renamedCatchVariableDeclarations: SparseArray<Identifier>;
let inGeneratorFunctionBody: boolean;
let inStatementContainingYield: boolean;
@@ -1926,7 +1928,7 @@ namespace ts {
if (isIdentifier(original) && original.parent) {
const declaration = resolver.getReferencedValueDeclaration(original);
if (declaration) {
const name = renamedCatchVariableDeclarations.get(getOriginalNodeId(declaration));
const name = renamedCatchVariableDeclarations[getOriginalNodeId(declaration)];
if (name) {
const clone = getMutableClone(name);
setSourceMapRange(clone, node);
@@ -2092,12 +2094,12 @@ namespace ts {
if (!renamedCatchVariables) {
renamedCatchVariables = createMap<boolean>();
renamedCatchVariableDeclarations = createMap<Identifier>();
renamedCatchVariableDeclarations = sparseArray<Identifier>();
context.enableSubstitution(SyntaxKind.Identifier);
}
renamedCatchVariables.set(text, true);
renamedCatchVariableDeclarations.set(getOriginalNodeId(variable), name);
renamedCatchVariableDeclarations[getOriginalNodeId(variable)] = name;
const exception = <ExceptionBlock>peekBlock();
Debug.assert(exception.state < ExceptionBlockState.Catch);
@@ -2401,7 +2403,7 @@ namespace ts {
*/
function createInstruction(instruction: Instruction): NumericLiteral {
const literal = createLiteral(instruction);
literal.trailingComment = instructionNames.get(instruction);
literal.trailingComment = getInstructionName(instruction);
return literal;
}

View File

@@ -1,4 +1,4 @@
/// <reference path="../../factory.ts" />
/// <reference path="../../factory.ts" />
/// <reference path="../../visitor.ts" />
/*@internal*/
@@ -10,12 +10,13 @@ namespace ts {
importAliasNames: ParameterDeclaration[];
}
const transformModuleDelegates = createMapFromPairs<(node: SourceFile) => SourceFile>(
[ModuleKind.None, transformCommonJSModule],
[ModuleKind.CommonJS, transformCommonJSModule],
[ModuleKind.AMD, transformAMDModule],
[ModuleKind.UMD, transformUMDModule],
);
function getTransformModuleDelegate(moduleKind: ModuleKind): (node: SourceFile) => SourceFile {
switch (moduleKind) {
case ModuleKind.AMD: return transformAMDModule;
case ModuleKind.UMD: return transformUMDModule;
default: return transformCommonJSModule;
}
}
const {
startLexicalEnvironment,
@@ -38,12 +39,12 @@ namespace ts {
context.enableSubstitution(SyntaxKind.ShorthandPropertyAssignment); // Substitutes shorthand property assignments for imported/exported symbols.
context.enableEmitNotification(SyntaxKind.SourceFile); // Restore state when substituting nodes in a file.
const moduleInfoMap = createMap<ExternalModuleInfo>(); // The ExternalModuleInfo for each file.
const deferredExports = createMap<Statement[]>(); // Exports to defer until an EndOfDeclarationMarker is found.
const moduleInfoMap = sparseArray<ExternalModuleInfo>(); // The ExternalModuleInfo for each file.
const deferredExports = sparseArray<Statement[]>(); // Exports to defer until an EndOfDeclarationMarker is found.
let currentSourceFile: SourceFile; // The current file.
let currentModuleInfo: ExternalModuleInfo; // The ExternalModuleInfo for the current file.
let noSubstitution: Map<boolean>; // Set of nodes for which substitution rules should be ignored.
let noSubstitution: SparseArray<boolean>; // Set of nodes for which substitution rules should be ignored.
return transformSourceFile;
@@ -61,10 +62,10 @@ namespace ts {
currentSourceFile = node;
currentModuleInfo = collectExternalModuleInfo(node, resolver, compilerOptions);
moduleInfoMap.set(getOriginalNodeId(node), currentModuleInfo);
moduleInfoMap[getOriginalNodeId(node)] = currentModuleInfo;
// Perform the transformation.
const transformModule = transformModuleDelegates.get(moduleKind) || transformModuleDelegates.get(ModuleKind.None);
const transformModule = getTransformModuleDelegate(moduleKind);
const updated = transformModule(node);
currentSourceFile = undefined;
@@ -445,7 +446,7 @@ namespace ts {
if (hasAssociatedEndOfDeclarationMarker(node)) {
// Defer exports until we encounter an EndOfDeclarationMarker node
const id = getOriginalNodeId(node);
deferredExports.set(id, appendExportsOfImportDeclaration(deferredExports.get(id), node));
deferredExports[id] = appendExportsOfImportDeclaration(deferredExports[id], node);
}
else {
statements = appendExportsOfImportDeclaration(statements, node);
@@ -524,7 +525,7 @@ namespace ts {
if (hasAssociatedEndOfDeclarationMarker(node)) {
// Defer exports until we encounter an EndOfDeclarationMarker node
const id = getOriginalNodeId(node);
deferredExports.set(id, appendExportsOfImportEqualsDeclaration(deferredExports.get(id), node));
deferredExports[id] = appendExportsOfImportEqualsDeclaration(deferredExports[id], node);
}
else {
statements = appendExportsOfImportEqualsDeclaration(statements, node);
@@ -611,7 +612,7 @@ namespace ts {
if (original && hasAssociatedEndOfDeclarationMarker(original)) {
// Defer exports until we encounter an EndOfDeclarationMarker node
const id = getOriginalNodeId(node);
deferredExports.set(id, appendExportStatement(deferredExports.get(id), createIdentifier("default"), node.expression, /*location*/ node, /*allowComments*/ true));
deferredExports[id] = appendExportStatement(deferredExports[id], createIdentifier("default"), node.expression, /*location*/ node, /*allowComments*/ true);
}
else {
statements = appendExportStatement(statements, createIdentifier("default"), node.expression, /*location*/ node, /*allowComments*/ true);
@@ -652,7 +653,7 @@ namespace ts {
if (hasAssociatedEndOfDeclarationMarker(node)) {
// Defer exports until we encounter an EndOfDeclarationMarker node
const id = getOriginalNodeId(node);
deferredExports.set(id, appendExportsOfHoistedDeclaration(deferredExports.get(id), node));
deferredExports[id] = appendExportsOfHoistedDeclaration(deferredExports[id], node);
}
else {
statements = appendExportsOfHoistedDeclaration(statements, node);
@@ -691,7 +692,7 @@ namespace ts {
if (hasAssociatedEndOfDeclarationMarker(node)) {
// Defer exports until we encounter an EndOfDeclarationMarker node
const id = getOriginalNodeId(node);
deferredExports.set(id, appendExportsOfHoistedDeclaration(deferredExports.get(id), node));
deferredExports[id] = appendExportsOfHoistedDeclaration(deferredExports[id], node);
}
else {
statements = appendExportsOfHoistedDeclaration(statements, node);
@@ -742,7 +743,7 @@ namespace ts {
if (hasAssociatedEndOfDeclarationMarker(node)) {
// Defer exports until we encounter an EndOfDeclarationMarker node
const id = getOriginalNodeId(node);
deferredExports.set(id, appendExportsOfVariableStatement(deferredExports.get(id), node));
deferredExports[id] = appendExportsOfVariableStatement(deferredExports[id], node);
}
else {
statements = appendExportsOfVariableStatement(statements, node);
@@ -795,7 +796,7 @@ namespace ts {
// statement.
if (hasAssociatedEndOfDeclarationMarker(node) && node.original.kind === SyntaxKind.VariableStatement) {
const id = getOriginalNodeId(node);
deferredExports.set(id, appendExportsOfVariableStatement(deferredExports.get(id), <VariableStatement>node.original));
deferredExports[id] = appendExportsOfVariableStatement(deferredExports[id], <VariableStatement>node.original);
}
return node;
@@ -821,9 +822,9 @@ namespace ts {
// end of the transformed declaration. We use this marker to emit any deferred exports
// of the declaration.
const id = getOriginalNodeId(node);
const statements = deferredExports.get(id);
const statements = deferredExports[id];
if (statements) {
deferredExports.delete(id);
delete deferredExports[id];
return append(statements, node);
}
@@ -1103,8 +1104,8 @@ namespace ts {
function onEmitNode(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void {
if (node.kind === SyntaxKind.SourceFile) {
currentSourceFile = <SourceFile>node;
currentModuleInfo = moduleInfoMap.get(getOriginalNodeId(currentSourceFile));
noSubstitution = createMap<boolean>();
currentModuleInfo = moduleInfoMap[getOriginalNodeId(currentSourceFile)];
noSubstitution = sparseArray<boolean>();
previousOnEmitNode(emitContext, node, emitCallback);
@@ -1129,7 +1130,7 @@ namespace ts {
*/
function onSubstituteNode(emitContext: EmitContext, node: Node) {
node = previousOnSubstituteNode(emitContext, node);
if (node.id && noSubstitution.get(node.id)) {
if (node.id && noSubstitution[node.id]) {
return node;
}
@@ -1255,7 +1256,7 @@ namespace ts {
let expression: Expression = node;
for (const exportName of exportedNames) {
// Mark the node to prevent triggering this rule again.
noSubstitution.set(getNodeId(expression), true);
noSubstitution[getNodeId(expression)] = true;
expression = createExportExpression(exportName, expression, /*location*/ node);
}
@@ -1297,7 +1298,7 @@ namespace ts {
: node;
for (const exportName of exportedNames) {
// Mark the node to prevent triggering this rule again.
noSubstitution.set(getNodeId(expression), true);
noSubstitution[getNodeId(expression)] = true;
expression = createExportExpression(exportName, expression);
}
@@ -1319,7 +1320,7 @@ namespace ts {
|| resolver.getReferencedValueDeclaration(name);
if (valueDeclaration) {
return currentModuleInfo
&& currentModuleInfo.exportedBindings.get(getOriginalNodeId(valueDeclaration));
&& currentModuleInfo.exportedBindings[getOriginalNodeId(valueDeclaration)];
}
}
}

View File

@@ -1,4 +1,4 @@
/// <reference path="../../factory.ts" />
/// <reference path="../../factory.ts" />
/// <reference path="../../visitor.ts" />
/*@internal*/
@@ -28,10 +28,10 @@ namespace ts {
context.enableSubstitution(SyntaxKind.PostfixUnaryExpression); // Substitutes updates to exported symbols.
context.enableEmitNotification(SyntaxKind.SourceFile); // Restore state when substituting nodes in a file.
const moduleInfoMap = createMap<ExternalModuleInfo>(); // The ExternalModuleInfo for each file.
const deferredExports = createMap<Statement[]>(); // Exports to defer until an EndOfDeclarationMarker is found.
const exportFunctionsMap = createMap<Identifier>(); // The export function associated with a source file.
const noSubstitutionMap = createMap<Map<boolean>>(); // Set of nodes for which substitution rules should be ignored for each file.
const moduleInfoMap = sparseArray<ExternalModuleInfo>(); // The ExternalModuleInfo for each file.
const deferredExports = sparseArray<Statement[]>(); // Exports to defer until an EndOfDeclarationMarker is found.
const exportFunctionsMap = sparseArray<Identifier>(); // The export function associated with a source file.
const noSubstitutionMap = sparseArray<SparseArray<boolean>>(); // Set of nodes for which substitution rules should be ignored for each file.
let currentSourceFile: SourceFile; // The current file.
let moduleInfo: ExternalModuleInfo; // ExternalModuleInfo for the current file.
@@ -39,7 +39,7 @@ namespace ts {
let contextObject: Identifier; // The context object for the current file.
let hoistedStatements: Statement[];
let enclosingBlockScopedContainer: Node;
let noSubstitution: Map<boolean>; // Set of nodes for which substitution rules should be ignored.
let noSubstitution: SparseArray<boolean>; // Set of nodes for which substitution rules should be ignored.
return transformSourceFile;
@@ -73,13 +73,12 @@ namespace ts {
// see comment to 'substitutePostfixUnaryExpression' for more details
// Collect information about the external module and dependency groups.
moduleInfo = collectExternalModuleInfo(node, resolver, compilerOptions);
moduleInfoMap.set(id, moduleInfo);
moduleInfo = moduleInfoMap[id] = collectExternalModuleInfo(node, resolver, compilerOptions);
// Make sure that the name of the 'exports' function does not conflict with
// existing identifiers.
exportFunction = createUniqueName("exports");
exportFunctionsMap.set(id, exportFunction);
exportFunctionsMap[id] = exportFunction;
contextObject = createUniqueName("context");
// Add the body of the module.
@@ -123,7 +122,7 @@ namespace ts {
}
if (noSubstitution) {
noSubstitutionMap.set(id, noSubstitution);
noSubstitutionMap[id] = noSubstitution;
noSubstitution = undefined;
}
@@ -610,7 +609,7 @@ namespace ts {
if (hasAssociatedEndOfDeclarationMarker(node)) {
// Defer exports until we encounter an EndOfDeclarationMarker node
const id = getOriginalNodeId(node);
deferredExports.set(id, appendExportsOfImportDeclaration(deferredExports.get(id), node));
deferredExports[id] = appendExportsOfImportDeclaration(deferredExports[id], node);
}
else {
statements = appendExportsOfImportDeclaration(statements, node);
@@ -633,7 +632,7 @@ namespace ts {
if (hasAssociatedEndOfDeclarationMarker(node)) {
// Defer exports until we encounter an EndOfDeclarationMarker node
const id = getOriginalNodeId(node);
deferredExports.set(id, appendExportsOfImportEqualsDeclaration(deferredExports.get(id), node));
deferredExports[id] = appendExportsOfImportEqualsDeclaration(deferredExports[id], node);
}
else {
statements = appendExportsOfImportEqualsDeclaration(statements, node);
@@ -658,7 +657,7 @@ namespace ts {
if (original && hasAssociatedEndOfDeclarationMarker(original)) {
// Defer exports until we encounter an EndOfDeclarationMarker node
const id = getOriginalNodeId(node);
deferredExports.set(id, appendExportStatement(deferredExports.get(id), createIdentifier("default"), expression, /*allowComments*/ true));
deferredExports[id] = appendExportStatement(deferredExports[id], createIdentifier("default"), expression, /*allowComments*/ true);
}
else {
return createExportStatement(createIdentifier("default"), expression, /*allowComments*/ true);
@@ -690,7 +689,7 @@ namespace ts {
if (hasAssociatedEndOfDeclarationMarker(node)) {
// Defer exports until we encounter an EndOfDeclarationMarker node
const id = getOriginalNodeId(node);
deferredExports.set(id, appendExportsOfHoistedDeclaration(deferredExports.get(id), node));
deferredExports[id] = appendExportsOfHoistedDeclaration(deferredExports[id], node);
}
else {
hoistedStatements = appendExportsOfHoistedDeclaration(hoistedStatements, node);
@@ -732,7 +731,7 @@ namespace ts {
if (hasAssociatedEndOfDeclarationMarker(node)) {
// Defer exports until we encounter an EndOfDeclarationMarker node
const id = getOriginalNodeId(node);
deferredExports.set(id, appendExportsOfHoistedDeclaration(deferredExports.get(id), node));
deferredExports[id] = appendExportsOfHoistedDeclaration(deferredExports[id], node);
}
else {
statements = appendExportsOfHoistedDeclaration(statements, node);
@@ -772,7 +771,7 @@ namespace ts {
if (isMarkedDeclaration) {
// Defer exports until we encounter an EndOfDeclarationMarker node
const id = getOriginalNodeId(node);
deferredExports.set(id, appendExportsOfVariableStatement(deferredExports.get(id), node, isExportedDeclaration));
deferredExports[id] = appendExportsOfVariableStatement(deferredExports[id], node, isExportedDeclaration);
}
else {
statements = appendExportsOfVariableStatement(statements, node, /*exportSelf*/ false);
@@ -885,7 +884,7 @@ namespace ts {
if (hasAssociatedEndOfDeclarationMarker(node) && node.original.kind === SyntaxKind.VariableStatement) {
const id = getOriginalNodeId(node);
const isExportedDeclaration = hasModifier(node.original, ModifierFlags.Export);
deferredExports.set(id, appendExportsOfVariableStatement(deferredExports.get(id), <VariableStatement>node.original, isExportedDeclaration));
deferredExports[id] = appendExportsOfVariableStatement(deferredExports[id], <VariableStatement>node.original, isExportedDeclaration);
}
return node;
@@ -911,9 +910,9 @@ namespace ts {
// end of the transformed declaration. We use this marker to emit any deferred exports
// of the declaration.
const id = getOriginalNodeId(node);
const statements = deferredExports.get(id);
const statements = deferredExports[id];
if (statements) {
deferredExports.delete(id);
delete deferredExports[id];
return append(statements, node);
}
@@ -1556,12 +1555,12 @@ namespace ts {
if (node.kind === SyntaxKind.SourceFile) {
const id = getOriginalNodeId(node);
currentSourceFile = <SourceFile>node;
moduleInfo = moduleInfoMap.get(id);
exportFunction = exportFunctionsMap.get(id);
noSubstitution = noSubstitutionMap.get(id);
moduleInfo = moduleInfoMap[id];
exportFunction = exportFunctionsMap[id];
noSubstitution = noSubstitutionMap[id];
if (noSubstitution) {
noSubstitutionMap.delete(id);
delete noSubstitutionMap[id];
}
previousOnEmitNode(emitContext, node, emitCallback);
@@ -1758,7 +1757,7 @@ namespace ts {
exportedNames = append(exportedNames, getDeclarationName(valueDeclaration));
}
exportedNames = addRange(exportedNames, moduleInfo && moduleInfo.exportedBindings.get(getOriginalNodeId(valueDeclaration)));
exportedNames = addRange(exportedNames, moduleInfo && moduleInfo.exportedBindings[getOriginalNodeId(valueDeclaration)]);
}
}
@@ -1771,8 +1770,8 @@ namespace ts {
* @param node The node which should not be substituted.
*/
function preventSubstitution<T extends Node>(node: T): T {
if (noSubstitution === undefined) noSubstitution = createMap<boolean>();
noSubstitution.set(getNodeId(node), true);
if (noSubstitution === undefined) noSubstitution = sparseArray<boolean>();
noSubstitution[getNodeId(node)] = true;
return node;
}
@@ -1782,7 +1781,7 @@ namespace ts {
* @param node The node to test.
*/
function isSubstitutionPrevented(node: Node) {
return noSubstitution && node.id && noSubstitution.get(node.id);
return noSubstitution && node.id && noSubstitution[node.id];
}
}
}

View File

@@ -1,4 +1,4 @@
/// <reference path="../factory.ts" />
/// <reference path="../factory.ts" />
/// <reference path="../visitor.ts" />
/// <reference path="./destructuring.ts" />
@@ -60,7 +60,7 @@ namespace ts {
* A map that keeps track of aliases created for classes with decorators to avoid issues
* with the double-binding behavior of classes.
*/
let classAliases: Map<Identifier>;
let classAliases: SparseArray<Identifier>;
/**
* Keeps track of whether we are within any containing namespaces when performing
@@ -752,7 +752,7 @@ namespace ts {
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference) {
// record an alias as the class name is not in scope for statics.
enableSubstitutionForClassAliases();
classAliases.set(getOriginalNodeId(node), getSynthesizedClone(temp));
classAliases[getOriginalNodeId(node)] = getSynthesizedClone(temp);
}
// To preserve the behavior of the old emitter, we explicitly indent
@@ -1420,7 +1420,7 @@ namespace ts {
return undefined;
}
const classAlias = classAliases && classAliases.get(getOriginalNodeId(node));
const classAlias = classAliases && classAliases[getOriginalNodeId(node)];
const localName = getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true);
const decorate = createDecorateHelper(context, decoratorExpressions, localName);
const expression = createAssignment(localName, classAlias ? createAssignment(classAlias, decorate) : decorate);
@@ -3085,7 +3085,7 @@ namespace ts {
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference) {
enableSubstitutionForClassAliases();
const classAlias = createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? node.name.text : "default");
classAliases.set(getOriginalNodeId(node), classAlias);
classAliases[getOriginalNodeId(node)] = classAlias;
hoistVariableDeclaration(classAlias);
return classAlias;
}
@@ -3117,7 +3117,7 @@ namespace ts {
context.enableSubstitution(SyntaxKind.Identifier);
// Keep track of class aliases.
classAliases = createMap<Identifier>();
classAliases = sparseArray<Identifier>();
}
}
@@ -3230,7 +3230,7 @@ namespace ts {
// constructor references in static property initializers.
const declaration = resolver.getReferencedValueDeclaration(node);
if (declaration) {
const classAlias = classAliases.get(declaration.id);
const classAlias = classAliases[declaration.id];
if (classAlias) {
const clone = getSynthesizedClone(classAlias);
setSourceMapRange(clone, node);

View File

@@ -1,4 +1,4 @@
/// <reference path="program.ts"/>
/// <reference path="program.ts"/>
/// <reference path="commandLineParser.ts"/>
namespace ts {
@@ -67,11 +67,13 @@ namespace ts {
const gutterSeparator = " ";
const resetEscapeSequence = "\u001b[0m";
const ellipsis = "...";
const categoryFormatMap = createMapFromPairs<string>(
[DiagnosticCategory.Warning, yellowForegroundEscapeSequence],
[DiagnosticCategory.Error, redForegroundEscapeSequence],
[DiagnosticCategory.Message, blueForegroundEscapeSequence],
);
function getCategoryFormat(category: DiagnosticCategory): string {
switch (category) {
case DiagnosticCategory.Warning: return yellowForegroundEscapeSequence;
case DiagnosticCategory.Error: return redForegroundEscapeSequence;
case DiagnosticCategory.Message: return blueForegroundEscapeSequence;
}
}
function formatAndReset(text: string, formatStyle: string) {
return formatStyle + text + resetEscapeSequence;
@@ -139,7 +141,7 @@ namespace ts {
output += `${ relativeFileName }(${ firstLine + 1 },${ firstLineChar + 1 }): `;
}
const categoryColor = categoryFormatMap.get(diagnostic.category);
const categoryColor = getCategoryFormat(diagnostic.category);
const category = DiagnosticCategory[diagnostic.category].toLowerCase();
output += `${ formatAndReset(category, categoryColor) } TS${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine) }`;
output += sys.newLine + sys.newLine;

View File

@@ -1,4 +1,4 @@
namespace ts {
namespace ts {
/**
* Type of objects whose values are all of the same type.
* The `in` and `for-in` operators can *not* be safely used,
@@ -8,15 +8,19 @@ namespace ts {
[index: string]: T;
}
/** It's allowed to get/set into a map with numbers. However, when iterating, you may get strings back due to the shim being an ordinary object (which only allows string keys). */
export type MapKey = string | number;
/**
* Like MapLike, but keys must be numbers.
*/
export interface SparseArray<T> {
[key: number]: T;
}
/** Minimal ES6 Map interface. Does not include iterators as those are hard to shim performantly. */
export interface Map<T> {
get(key: MapKey): T;
has(key: MapKey): boolean;
set(key: MapKey, value: T): this;
delete(key: MapKey): boolean;
get(key: string): T;
has(key: string): boolean;
set(key: string, value: T): this;
delete(key: string): boolean;
clear(): void;
/** `key` may *not* be a string if it was set with a number and we are not using the shim. */
forEach(action: (value: T, key: string) => void): void;
@@ -2853,7 +2857,7 @@ namespace ts {
// Enum types (TypeFlags.Enum)
export interface EnumType extends Type {
memberTypes: Map<EnumLiteralType>;
memberTypes: SparseArray<EnumLiteralType>;
}
// Enum types (TypeFlags.EnumLiteral)
@@ -3682,7 +3686,7 @@ namespace ts {
flags?: EmitFlags; // Flags that customize emit
commentRange?: TextRange; // The text range to use when emitting leading or trailing comments
sourceMapRange?: TextRange; // The text range to use when emitting leading or trailing source mappings
tokenSourceMapRanges?: Map<TextRange>; // The text range to use when emitting source mappings for tokens
tokenSourceMapRanges?: SparseArray<TextRange>; // The text range to use when emitting source mappings for tokens
constantValue?: number; // The constant value of an expression
externalHelpersModuleName?: Identifier; // The local name for an imported helpers module
helpers?: EmitHelper[]; // Emit helpers for the node

View File

@@ -3311,12 +3311,12 @@ namespace ts {
return false;
}
const syntaxKindCache = createMap<string>();
const syntaxKindCache = sparseArray<string>();
export function formatSyntaxKind(kind: SyntaxKind): string {
const syntaxKindEnum = (<any>ts).SyntaxKind;
if (syntaxKindEnum) {
const cached = syntaxKindCache.get(kind);
const cached = syntaxKindCache[kind];
if (cached !== undefined) {
return cached;
}
@@ -3324,7 +3324,7 @@ namespace ts {
for (const name in syntaxKindEnum) {
if (syntaxKindEnum[name] === kind) {
const result = `${kind} (${name})`;
syntaxKindCache.set(kind, result);
syntaxKindCache[kind] = result;
return result;
}
}

View File

@@ -1,4 +1,4 @@
/// <reference path="checker.ts" />
/// <reference path="checker.ts" />
/// <reference path="factory.ts" />
/// <reference path="utilities.ts" />
@@ -46,54 +46,56 @@ namespace ts {
* supplant the existing `forEachChild` implementation if performance is not
* significantly impacted.
*/
const nodeEdgeTraversalMap = createMapFromPairs<NodeTraversalPath>(
[SyntaxKind.QualifiedName, [
{ name: "left", test: isEntityName },
{ name: "right", test: isIdentifier }
]],
[SyntaxKind.Decorator, [
{ name: "expression", test: isLeftHandSideExpression }
]],
[SyntaxKind.TypeAssertionExpression, [
{ name: "type", test: isTypeNode },
{ name: "expression", test: isUnaryExpression }
]],
[SyntaxKind.AsExpression, [
{ name: "expression", test: isExpression },
{ name: "type", test: isTypeNode }
]],
[SyntaxKind.NonNullExpression, [
{ name: "expression", test: isLeftHandSideExpression }
]],
[SyntaxKind.EnumDeclaration, [
{ name: "decorators", test: isDecorator },
{ name: "modifiers", test: isModifier },
{ name: "name", test: isIdentifier },
{ name: "members", test: isEnumMember }
]],
[SyntaxKind.ModuleDeclaration, [
{ name: "decorators", test: isDecorator },
{ name: "modifiers", test: isModifier },
{ name: "name", test: isModuleName },
{ name: "body", test: isModuleBody }
]],
[SyntaxKind.ModuleBlock, [
{ name: "statements", test: isStatement }
]],
[SyntaxKind.ImportEqualsDeclaration, [
{ name: "decorators", test: isDecorator },
{ name: "modifiers", test: isModifier },
{ name: "name", test: isIdentifier },
{ name: "moduleReference", test: isModuleReference }
]],
[SyntaxKind.ExternalModuleReference, [
{ name: "expression", test: isExpression, optional: true }
]],
[SyntaxKind.EnumMember, [
{ name: "name", test: isPropertyName },
{ name: "initializer", test: isExpression, optional: true, parenthesize: parenthesizeExpressionForList }
]]
);
function getNodeEdgeTraversal(kind: SyntaxKind): NodeTraversalPath {
switch (kind) {
case SyntaxKind.QualifiedName: return [
{ name: "left", test: isEntityName },
{ name: "right", test: isIdentifier }
];
case SyntaxKind.Decorator: return [
{ name: "expression", test: isLeftHandSideExpression }
];
case SyntaxKind.TypeAssertionExpression: return [
{ name: "type", test: isTypeNode },
{ name: "expression", test: isUnaryExpression }
];
case SyntaxKind.AsExpression: return [
{ name: "expression", test: isExpression },
{ name: "type", test: isTypeNode }
];
case SyntaxKind.NonNullExpression: return [
{ name: "expression", test: isLeftHandSideExpression }
];
case SyntaxKind.EnumDeclaration: return [
{ name: "decorators", test: isDecorator },
{ name: "modifiers", test: isModifier },
{ name: "name", test: isIdentifier },
{ name: "members", test: isEnumMember }
];
case SyntaxKind.ModuleDeclaration: return [
{ name: "decorators", test: isDecorator },
{ name: "modifiers", test: isModifier },
{ name: "name", test: isModuleName },
{ name: "body", test: isModuleBody }
];
case SyntaxKind.ModuleBlock: return [
{ name: "statements", test: isStatement }
];
case SyntaxKind.ImportEqualsDeclaration: return [
{ name: "decorators", test: isDecorator },
{ name: "modifiers", test: isModifier },
{ name: "name", test: isIdentifier },
{ name: "moduleReference", test: isModuleReference }
];
case SyntaxKind.ExternalModuleReference: return [
{ name: "expression", test: isExpression, optional: true }
];
case SyntaxKind.EnumMember: return [
{ name: "name", test: isPropertyName },
{ name: "initializer", test: isExpression, optional: true, parenthesize: parenthesizeExpressionForList }
];
}
}
function reduceNode<T>(node: Node, f: (memo: T, node: Node) => T, initial: T) {
return node ? f(initial, node) : initial;
@@ -530,7 +532,7 @@ namespace ts {
break;
default:
const edgeTraversalPath = nodeEdgeTraversalMap.get(kind);
const edgeTraversalPath = getNodeEdgeTraversal(kind);
if (edgeTraversalPath) {
for (const edge of edgeTraversalPath) {
const value = (<MapLike<any>>node)[edge.name];
@@ -1188,7 +1190,7 @@ namespace ts {
default:
let updated: Node & MapLike<any>;
const edgeTraversalPath = nodeEdgeTraversalMap.get(kind);
const edgeTraversalPath = getNodeEdgeTraversal(kind);
if (edgeTraversalPath) {
for (const edge of edgeTraversalPath) {
const value = <Node | NodeArray<Node>>(<Node & MapLike<any>>node)[edge.name];

View File

@@ -1,4 +1,4 @@
/// <reference path="..\harness.ts" />
/// <reference path="..\harness.ts" />
const expect: typeof _chai.expect = _chai.expect;
@@ -416,16 +416,16 @@ namespace ts.server {
class InProcClient {
private server: InProcSession;
private seq = 0;
private callbacks = createMap<(resp: protocol.Response) => void>();
private callbacks = sparseArray<(resp: protocol.Response) => void>();
private eventHandlers = createMap<(args: any) => void>();
handle(msg: protocol.Message): void {
if (msg.type === "response") {
const response = <protocol.Response>msg;
const handler = this.callbacks.get(response.request_seq);
const handler = this.callbacks[response.request_seq];
if (handler) {
handler(response);
this.callbacks.delete(response.request_seq);
delete this.callbacks[response.request_seq];
}
}
else if (msg.type === "event") {
@@ -460,7 +460,7 @@ namespace ts.server {
command,
arguments: args
});
this.callbacks.set(this.seq, callback);
this.callbacks[this.seq] = callback;
}
};

View File

@@ -1,4 +1,4 @@
/// <reference path="..\harness.ts" />
/// <reference path="..\harness.ts" />
/// <reference path="../../server/typingsInstaller/typingsInstaller.ts" />
namespace ts.projectSystem {
@@ -290,30 +290,34 @@ namespace ts.projectSystem {
}
export class Callbacks {
private map = createMap<TimeOutCallback>();
private map = sparseArray<TimeOutCallback>();
private nextId = 1;
register(cb: (...args: any[]) => void, args: any[]) {
const timeoutId = this.nextId;
this.nextId++;
this.map.set(timeoutId, cb.bind(undefined, ...args));
this.map[timeoutId] = cb.bind(undefined, ...args);
return timeoutId;
}
unregister(id: any) {
if (typeof id === "number") {
this.map.delete(id);
delete this.map[id];
}
}
count() {
return this.map.size;
let n = 0;
for (const _ in this.map) {
n++;
}
return n;
}
invoke() {
this.map.forEach(cb => {
cb();
});
this.map.clear();
for (const key in this.map) {
this.map[key]();
}
this.map = sparseArray<TimeOutCallback>();
}
}

View File

@@ -16,25 +16,25 @@ namespace ts {
}
export namespace codefix {
const codeFixes = createMap<CodeFix[]>();
const codeFixes = sparseArray<CodeFix[]>();
export function registerCodeFix(action: CodeFix) {
forEach(action.errorCodes, error => {
let fixes = codeFixes.get(error);
let fixes = codeFixes[error];
if (!fixes) {
fixes = [];
codeFixes.set(error, fixes);
codeFixes[error] = fixes;
}
fixes.push(action);
});
}
export function getSupportedErrorCodes() {
return keysOfMap(codeFixes);
return keysOfSparseArray(codeFixes);
}
export function getFixes(context: CodeFixContext): CodeAction[] {
const fixes = codeFixes.get(context.errorCode);
const fixes = codeFixes[context.errorCode];
let allActions: CodeAction[] = [];
forEach(fixes, f => {

View File

@@ -14,16 +14,16 @@ namespace ts.codefix {
}
class ImportCodeActionMap {
private symbolIdToActionMap = createMap<ImportCodeAction[]>();
private symbolIdToActionMap = sparseArray<ImportCodeAction[]>();
addAction(symbolId: number, newAction: ImportCodeAction) {
if (!newAction) {
return;
}
const actions = this.symbolIdToActionMap.get(symbolId);
const actions = this.symbolIdToActionMap[symbolId];
if (!actions) {
this.symbolIdToActionMap.set(symbolId, [newAction]);
this.symbolIdToActionMap[symbolId] = [newAction];
return;
}
@@ -33,7 +33,7 @@ namespace ts.codefix {
}
const updatedNewImports: ImportCodeAction[] = [];
for (const existingAction of this.symbolIdToActionMap.get(symbolId)) {
for (const existingAction of this.symbolIdToActionMap[symbolId]) {
if (existingAction.kind === "CodeChange") {
// only import actions should compare
updatedNewImports.push(existingAction);
@@ -63,7 +63,7 @@ namespace ts.codefix {
}
// if we reach here, it means the new one is better or equal to all of the existing ones.
updatedNewImports.push(newAction);
this.symbolIdToActionMap.set(symbolId, updatedNewImports);
this.symbolIdToActionMap[symbolId] = updatedNewImports;
}
addActions(symbolId: number, newActions: ImportCodeAction[]) {
@@ -74,9 +74,9 @@ namespace ts.codefix {
getAllActions() {
let result: ImportCodeAction[] = [];
this.symbolIdToActionMap.forEach(actions => {
result = concatenate(result, actions);
});
for (const key in this.symbolIdToActionMap) {
result = concatenate(result, this.symbolIdToActionMap[key])
}
return result;
}
@@ -125,7 +125,7 @@ namespace ts.codefix {
const symbolIdActionMap = new ImportCodeActionMap();
// this is a module id -> module import declaration map
const cachedImportDeclarations = createMap<(ImportDeclaration | ImportEqualsDeclaration)[]>();
const cachedImportDeclarations = sparseArray<(ImportDeclaration | ImportEqualsDeclaration)[]>();
let cachedNewImportInsertPosition: number;
const allPotentialModules = checker.getAmbientModules();
@@ -163,7 +163,7 @@ namespace ts.codefix {
function getImportDeclarations(moduleSymbol: Symbol) {
const moduleSymbolId = getUniqueSymbolId(moduleSymbol);
const cached = cachedImportDeclarations.get(moduleSymbolId);
const cached = cachedImportDeclarations[moduleSymbolId];
if (cached) {
return cached;
}
@@ -175,7 +175,7 @@ namespace ts.codefix {
existingDeclarations.push(getImportDeclaration(importModuleSpecifier));
}
}
cachedImportDeclarations.set(moduleSymbolId, existingDeclarations);
cachedImportDeclarations[moduleSymbolId] = existingDeclarations;
return existingDeclarations;
function getImportDeclaration(moduleSpecifier: LiteralExpression) {