Consolidate Document and SoruceFile

This commit is contained in:
Mohamed Hegazy
2014-08-04 11:45:35 -07:00
parent c17a24738c
commit aa75de9c70
9 changed files with 168 additions and 198 deletions

View File

@@ -67,6 +67,13 @@ module ts {
getReturnType(): Type;
}
export interface SourceFile {
getSourceUnit(): TypeScript.SourceUnitSyntax;
getSyntaxTree(): TypeScript.SyntaxTree;
getBloomFilter(): TypeScript.BloomFilter;
update(scriptSnapshot: TypeScript.IScriptSnapshot, version: number, isOpen: boolean, textChangeRange: TypeScript.TextChangeRange): SourceFile;
}
var scanner: Scanner = createScanner(ScriptTarget.ES5);
var emptyArray: any [] = [];
@@ -81,7 +88,6 @@ module ts {
}
class NodeObject implements Node {
public kind: SyntaxKind;
public pos: number;
public end: number;
@@ -294,6 +300,130 @@ module ts {
}
}
var incrementalParse: IncrementalParse = TypeScript.IncrementalParser.parse;
class SourceFileObject extends NodeObject implements SourceFile {
public filename: string;
public text: string;
public getLineAndCharacterFromPosition(position: number): { line: number; character: number } { return null; }
public amdDependencies: string[];
public referencedFiles: FileReference[];
public syntacticErrors: Diagnostic[];
public semanticErrors: Diagnostic[];
public hasNoDefaultLib: boolean;
public externalModuleIndicator: Node; // The first node that causes this file to be an external module
public nodeCount: number;
public identifierCount: number;
public symbolCount: number;
public statements: NodeArray<Statement>;
public byteOrderMark: ByteOrderMark;
public version: number;
public isOpen: boolean;
public languageVersion: ScriptTarget;
private bloomFilter: TypeScript.BloomFilter;
private syntaxTree: TypeScript.SyntaxTree;
private scriptSnapshot: TypeScript.IScriptSnapshot;
public getSourceUnit(): TypeScript.SourceUnitSyntax {
// If we don't have a script, create one from our parse tree.
return this.getSyntaxTree().sourceUnit();
}
public getLineMap(): TypeScript.LineMap {
return this.getSyntaxTree().lineMap();
}
public getSyntaxTree(): TypeScript.SyntaxTree {
if (!this.syntaxTree) {
var start = new Date().getTime();
this.syntaxTree = TypeScript.Parser.parse(
this.filename, TypeScript.SimpleText.fromScriptSnapshot(this.scriptSnapshot), this.languageVersion, this.isDeclareFile());
var time = new Date().getTime() - start;
//TypeScript.syntaxTreeParseTime += time;
}
return this.syntaxTree;
}
private isDeclareFile(): boolean {
return TypeScript.isDTSFile(this.filename);
}
public getBloomFilter(): TypeScript.BloomFilter {
if (!this.bloomFilter) {
var identifiers = TypeScript.createIntrinsicsObject<boolean>();
var pre = function (cur: TypeScript.ISyntaxElement) {
if (TypeScript.ASTHelpers.isValidAstNode(cur)) {
if (cur.kind() === TypeScript.SyntaxKind.IdentifierName) {
var nodeText = TypeScript.tokenValueText((<TypeScript.ISyntaxToken>cur));
identifiers[nodeText] = true;
}
}
};
TypeScript.getAstWalkerFactory().simpleWalk(this.getSourceUnit(), pre, null, identifiers);
var identifierCount = 0;
for (var name in identifiers) {
if (identifiers[name]) {
identifierCount++;
}
}
this.bloomFilter = new TypeScript.BloomFilter(identifierCount);
this.bloomFilter.addKeys(identifiers);
}
return this.bloomFilter;
}
public update(scriptSnapshot: TypeScript.IScriptSnapshot, version: number, isOpen: boolean, textChangeRange: TypeScript.TextChangeRange): SourceFile {
// See if we are currently holding onto a syntax tree. We may not be because we're
// either a closed file, or we've just been lazy and haven't had to create the syntax
// tree yet. Access the field instead of the method so we don't accidently realize
// the old syntax tree.
var oldSyntaxTree = this.syntaxTree;
if (textChangeRange !== null && Debug.shouldAssert(AssertionLevel.Normal)) {
var oldText = this.scriptSnapshot;
var newText = scriptSnapshot;
TypeScript.Debug.assert((oldText.getLength() - textChangeRange.span().length() + textChangeRange.newLength()) === newText.getLength());
if (Debug.shouldAssert(AssertionLevel.VeryAggressive)) {
var oldTextPrefix = oldText.getText(0, textChangeRange.span().start());
var newTextPrefix = newText.getText(0, textChangeRange.span().start());
TypeScript.Debug.assert(oldTextPrefix === newTextPrefix);
var oldTextSuffix = oldText.getText(textChangeRange.span().end(), oldText.getLength());
var newTextSuffix = newText.getText(textChangeRange.newSpan().end(), newText.getLength());
TypeScript.Debug.assert(oldTextSuffix === newTextSuffix);
}
}
var text = TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot);
// If we don't have a text change, or we don't have an old syntax tree, then do a full
// parse. Otherwise, do an incremental parse.
var newSyntaxTree = textChangeRange === null || oldSyntaxTree === null
? TypeScript.Parser.parse(this.filename, text, this.languageVersion, TypeScript.isDTSFile(this.filename))
: TypeScript.IncrementalParser.parse(oldSyntaxTree, textChangeRange, text);
return SourceFileObject.createSourceFileObject(this.languageVersion, this.filename, scriptSnapshot, this.byteOrderMark, version, isOpen, newSyntaxTree);
}
public static createSourceFileObject(languageVersion: ScriptTarget, filename: string, scriptSnapshot: TypeScript.IScriptSnapshot, byteOrderMark: ByteOrderMark, version: number, isOpen: boolean, syntaxTree: TypeScript.SyntaxTree) {
var newSoruceFile = <SourceFileObject><any>createSourceFile(filename, scriptSnapshot.getText(0, scriptSnapshot.getLength()), languageVersion, byteOrderMark, version, isOpen);
newSoruceFile.scriptSnapshot = scriptSnapshot;
newSoruceFile.syntaxTree = syntaxTree;
return newSoruceFile;
}
}
export interface Logger {
information(): boolean;
debug(): boolean;
@@ -563,17 +693,17 @@ module ts {
byteOrderMark: ByteOrderMark,
version: number,
isOpen: boolean,
referencedFiles: string[]): Document;
referencedFiles: string[]): SourceFile;
updateDocument(
document: Document,
document: SourceFile,
filename: string,
compilationSettings: CompilerOptions,
scriptSnapshot: TypeScript.IScriptSnapshot,
version: number,
isOpen: boolean,
textChangeRange: TypeScript.TextChangeRange
): Document;
): SourceFile;
releaseDocument(filename: string, compilationSettings: CompilerOptions): void
}
@@ -665,172 +795,6 @@ module ts {
(oldSyntaxTree: TypeScript.SyntaxTree, textChangeRange: TypeScript.TextChangeRange, newText: TypeScript.ISimpleText): TypeScript.SyntaxTree
}
export interface Document {
getFilename(): string;
getByteOrderMark(): ByteOrderMark;
getVersion(): number;
isOpen(): boolean;
getSourceUnit(): TypeScript.SourceUnitSyntax;
getSyntaxTree(): TypeScript.SyntaxTree;
getSourceFile(): SourceFile;
getBloomFilter(): TypeScript.BloomFilter;
update(scriptSnapshot: TypeScript.IScriptSnapshot, version: number, isOpen: boolean, textChangeRange: TypeScript.TextChangeRange): Document;
}
class DocumentObject implements Document {
private bloomFilter: TypeScript.BloomFilter = null;
// By default, our Document class doesn't support incremental update of its conten
// However, we enable other layers (like teh services layer) to inject the capability
// into us by setting this function.
public static incrementalParse: IncrementalParse = TypeScript.IncrementalParser.parse;
constructor(private compilationSettings: CompilerOptions,
public filename: string,
public referencedFiles: string[],
private scriptSnapshot: TypeScript.IScriptSnapshot,
public byteOrderMark: ByteOrderMark,
public version: number,
public _isOpen: boolean,
private syntaxTree: TypeScript.SyntaxTree,
private soruceFile: SourceFile) {
}
public getFilename(): string {
return this.filename;
}
public getVersion(): number {
return this.version;
}
public isOpen(): boolean {
return this._isOpen;
}
public getByteOrderMark(): ByteOrderMark {
return this.byteOrderMark;
}
public isDeclareFile(): boolean {
return TypeScript.isDTSFile(this.filename);
}
public getSourceUnit(): TypeScript.SourceUnitSyntax {
// If we don't have a script, create one from our parse tree.
return this.getSyntaxTree().sourceUnit();
}
public getLineMap(): TypeScript.LineMap {
return this.getSyntaxTree().lineMap();
}
public getSyntaxTree(): TypeScript.SyntaxTree {
if (!this.syntaxTree) {
var start = new Date().getTime();
this.syntaxTree = TypeScript.Parser.parse(
this.filename, TypeScript.SimpleText.fromScriptSnapshot(this.scriptSnapshot), this.compilationSettings.target, this.isDeclareFile());
var time = new Date().getTime() - start;
//TypeScript.syntaxTreeParseTime += time;
}
return this.syntaxTree;
}
public getSourceFile(): SourceFile {
if (!this.soruceFile) {
var start = new Date().getTime();
this.soruceFile = createSourceFile(this.filename, this.scriptSnapshot.getText(0, this.scriptSnapshot.getLength()), this.compilationSettings.target);
var time = new Date().getTime() - start;
//TypeScript.astParseTime += time;
}
return this.soruceFile;
}
public getBloomFilter(): TypeScript.BloomFilter {
if (!this.bloomFilter) {
var identifiers = TypeScript.createIntrinsicsObject<boolean>();
var pre = function (cur: TypeScript.ISyntaxElement) {
if (TypeScript.ASTHelpers.isValidAstNode(cur)) {
if (cur.kind() === TypeScript.SyntaxKind.IdentifierName) {
var nodeText = TypeScript.tokenValueText((<TypeScript.ISyntaxToken>cur));
identifiers[nodeText] = true;
}
}
};
TypeScript.getAstWalkerFactory().simpleWalk(this.getSourceUnit(), pre, null, identifiers);
var identifierCount = 0;
for (var name in identifiers) {
if (identifiers[name]) {
identifierCount++;
}
}
this.bloomFilter = new TypeScript.BloomFilter(identifierCount);
this.bloomFilter.addKeys(identifiers);
}
return this.bloomFilter;
}
// Returns true if this file should get emitted into its own unique output file.
// Otherwise, it should be written into a single output file along with the rest of hte
// documents in the compilation.
public emitToOwnOutputFile(): boolean {
// If we haven't specified an output file in our settings, then we're definitely
// emitting to our own file. Also, if we're an external module, then we're
// definitely emitting to our own file.
return !this.compilationSettings.out || this.getSyntaxTree().isExternalModule();
}
public update(scriptSnapshot: TypeScript.IScriptSnapshot, version: number, isOpen: boolean, textChangeRange: TypeScript.TextChangeRange): Document {
// See if we are currently holding onto a syntax tree. We may not be because we're
// either a closed file, or we've just been lazy and haven't had to create the syntax
// tree yet. Access the field instead of the method so we don't accidently realize
// the old syntax tree.
var oldSyntaxTree = this.syntaxTree;
if (textChangeRange !== null && Debug.shouldAssert(AssertionLevel.Normal)) {
var oldText = this.scriptSnapshot;
var newText = scriptSnapshot;
TypeScript.Debug.assert((oldText.getLength() - textChangeRange.span().length() + textChangeRange.newLength()) === newText.getLength());
if (Debug.shouldAssert(AssertionLevel.VeryAggressive)) {
var oldTextPrefix = oldText.getText(0, textChangeRange.span().start());
var newTextPrefix = newText.getText(0, textChangeRange.span().start());
TypeScript.Debug.assert(oldTextPrefix === newTextPrefix);
var oldTextSuffix = oldText.getText(textChangeRange.span().end(), oldText.getLength());
var newTextSuffix = newText.getText(textChangeRange.newSpan().end(), newText.getLength());
TypeScript.Debug.assert(oldTextSuffix === newTextSuffix);
}
}
var text = TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot);
// If we don't have a text change, or we don't have an old syntax tree, then do a full
// parse. Otherwise, do an incremental parse.
var newSyntaxTree = textChangeRange === null || oldSyntaxTree === null || DocumentObject.incrementalParse === null
? TypeScript.Parser.parse(this.filename, text, this.compilationSettings.target, TypeScript.isDTSFile(this.filename))
: DocumentObject.incrementalParse(oldSyntaxTree, textChangeRange, text);
return new DocumentObject(this.compilationSettings, this.filename, this.referencedFiles, scriptSnapshot, this.byteOrderMark, version, isOpen, newSyntaxTree, /*soruceFile*/ null);
}
}
export function createDocument(compilationSettings: CompilerOptions, fileName: string, scriptSnapshot: TypeScript.IScriptSnapshot, byteOrderMark: ByteOrderMark, version: number, isOpen: boolean, referencedFiles: string[]): Document {
return new DocumentObject(compilationSettings, fileName, referencedFiles, scriptSnapshot, byteOrderMark, version, isOpen, /*syntaxTree:*/ null, /*soruceFile*/ null);
}
/// Language Service
interface CompletionSession {
@@ -859,7 +823,7 @@ module ts {
}
interface DocumentRegistryEntry {
document: Document;
document: SourceFile;
refCount: number;
owners: string[];
}
@@ -1172,13 +1136,12 @@ module ts {
scriptSnapshot: TypeScript.IScriptSnapshot,
byteOrderMark: ByteOrderMark,
version: number,
isOpen: boolean,
referencedFiles: string[]= []): Document {
isOpen: boolean): SourceFile {
var bucket = getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ true);
var entry = lookUp(bucket, filename);
if (!entry) {
var document = createDocument(compilationSettings, filename, scriptSnapshot, byteOrderMark, version, isOpen, referencedFiles);
var document = createSourceFile(filename, scriptSnapshot.getText(0, scriptSnapshot.getLength()), compilationSettings.target, byteOrderMark, version, isOpen);
bucket[filename] = entry = {
document: document,
@@ -1192,21 +1155,21 @@ module ts {
}
function updateDocument(
document: Document,
document: SourceFile,
filename: string,
compilationSettings: CompilerOptions,
scriptSnapshot: TypeScript.IScriptSnapshot,
version: number,
isOpen: boolean,
textChangeRange: TypeScript.TextChangeRange
): Document {
): SourceFile {
var bucket = getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ false);
Debug.assert(bucket);
var entry = lookUp(bucket, filename);
Debug.assert(entry);
if (entry.document.isOpen() === isOpen && entry.document.getVersion() === version) {
if (entry.document.isOpen === isOpen && entry.document.version === version) {
return entry.document;
}
@@ -1252,7 +1215,7 @@ module ts {
var program: Program;
var typeChecker: TypeChecker;
var useCaseSensitivefilenames = false;
var documentsByName: Map<Document> = {};
var documentsByName: Map<SourceFile> = {};
var documentRegistry = documentRegistry;
var cancellationToken = new CancellationTokenObject(host.getCancellationToken());
var activeCompletionSession: CompletionSession; // The current active completion session, used to get the completion entry details
@@ -1262,7 +1225,7 @@ module ts {
TypeScript.LocalizedDiagnosticMessages = host.getLocalizedDiagnosticMessages();
}
function getDocument(filename: string): Document {
function getDocument(filename: string): SourceFile {
return lookUp(documentsByName, filename);
}
@@ -1339,12 +1302,12 @@ module ts {
var isOpen = hostCache.isOpen(filename);
var scriptSnapshot = hostCache.getScriptSnapshot(filename);
var document: Document = getDocument(filename);
var document: SourceFile = getDocument(filename);
if (document) {
//
// If the document is the same, assume no update
//
if (document.getVersion() === version && document.isOpen() === isOpen) {
if (document.version === version && document.isOpen === isOpen) {
continue;
}
@@ -1356,7 +1319,7 @@ module ts {
// new text buffer).
var textChangeRange: TypeScript.TextChangeRange = null;
if (document.isOpen && isOpen) {
textChangeRange = hostCache.getScriptTextChangeRangeSinceVersion(filename, document.getVersion());
textChangeRange = hostCache.getScriptTextChangeRangeSinceVersion(filename, document.version);
}
document = documentRegistry.updateDocument(document, filename, compilationSettings, scriptSnapshot, version, isOpen, textChangeRange);
@@ -2217,7 +2180,7 @@ module ts {
getNodeConstructor: kind => {
function Node() {
}
var proto = new NodeObject();
var proto = kind === SyntaxKind.SourceFile ? new SourceFileObject() : new NodeObject();
proto.kind = kind;
proto.pos = 0;
proto.end = 0;