Use a single scanner for all parsing tasks.

This commit is contained in:
Cyrus Najmabadi 2015-04-12 14:02:58 -07:00
parent 96995e705a
commit 61951e5d94
4 changed files with 54 additions and 27 deletions

View File

@ -1,6 +1,5 @@
// <auto-generated />
/// <reference path="types.ts" />
/* @internal */
module ts {
export var Diagnostics = {
Unterminated_string_literal: { code: 1002, category: DiagnosticCategory.Error, key: "Unterminated string literal." },

View File

@ -1006,6 +1006,10 @@ module ts {
return result;
}
// Share a single scanner across all calls to parse a source file. This helps speed things
// up by avoiding the cost of creating/compiling scanners over and over again.
let scanner = createScanner(ScriptTarget.Latest, /*skipTrivia:*/ true);
function parseSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, syntaxCursor: SyntaxCursor, setParentNodes = false): SourceFile {
const disallowInAndDecoratorContext = ParserContextFlags.DisallowIn | ParserContextFlags.Decorator;
@ -1105,7 +1109,10 @@ module ts {
let parseErrorBeforeNextFinishedNode: boolean = false;
// Create and prime the scanner before parsing the source elements.
let scanner = createScanner(languageVersion, /*skipTrivia*/ true, sourceText, scanError);
scanner.setText(sourceText);
scanner.setOnError(scanError);
scanner.setScriptTarget(languageVersion);
token = nextToken();
processReferenceComments(sourceFile);
@ -1125,6 +1132,10 @@ module ts {
}
syntaxCursor = undefined;
// Clear out the text the scanner is pointing at, so it doesn't keep anything alive unnecessarily.
scanner.setText("");
scanner.setOnError(undefined);
return sourceFile;
function setContextFlag(val: Boolean, flag: ParserContextFlags) {

View File

@ -54,6 +54,7 @@ module ts {
}
text = "";
}
return text !== undefined ? createSourceFile(fileName, text, languageVersion, setParentNodes) : undefined;
}

View File

@ -25,6 +25,8 @@ module ts {
reScanTemplateToken(): SyntaxKind;
scan(): SyntaxKind;
setText(text: string): void;
setOnError(onError: ErrorCallback): void;
setScriptTarget(scriptTarget: ScriptTarget): void;
setTextPos(textPos: number): void;
// Invokes the provided callback then unconditionally restores the scanner to the state it
// was in immediately prior to invoking the callback. The result of invoking the callback
@ -599,6 +601,7 @@ module ts {
export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean, text?: string, onError?: ErrorCallback): Scanner {
let pos: number; // Current position (end position of text of current token)
let len: number; // Length of text
let startPos: number; // Start position of whitespace before current token
let tokenPos: number; // Start position of text of current token
let token: SyntaxKind;
@ -607,6 +610,32 @@ module ts {
let hasExtendedUnicodeEscape: boolean;
let tokenIsUnterminated: boolean;
setText(text);
return {
getStartPos: () => startPos,
getTextPos: () => pos,
getToken: () => token,
getTokenPos: () => tokenPos,
getTokenText: () => text.substring(tokenPos, pos),
getTokenValue: () => tokenValue,
hasExtendedUnicodeEscape: () => hasExtendedUnicodeEscape,
hasPrecedingLineBreak: () => precedingLineBreak,
isIdentifier: () => token === SyntaxKind.Identifier || token > SyntaxKind.LastReservedWord,
isReservedWord: () => token >= SyntaxKind.FirstReservedWord && token <= SyntaxKind.LastReservedWord,
isUnterminated: () => tokenIsUnterminated,
reScanGreaterToken,
reScanSlashToken,
reScanTemplateToken,
scan,
setText,
setScriptTarget,
setOnError,
setTextPos,
tryScan,
lookAhead,
};
function error(message: DiagnosticMessage, length?: number): void {
if (onError) {
onError(message, length || 0);
@ -1450,37 +1479,24 @@ module ts {
setTextPos(0);
}
function setOnError(errorCallback: ErrorCallback) {
onError = errorCallback;
}
function setScriptTarget(scriptTarget: ScriptTarget) {
languageVersion = scriptTarget;
}
function setTextPos(textPos: number) {
pos = textPos;
startPos = textPos;
tokenPos = textPos;
token = SyntaxKind.Unknown;
precedingLineBreak = false;
tokenValue = undefined;
hasExtendedUnicodeEscape = false;
tokenIsUnterminated = false;
}
setText(text);
return {
getStartPos: () => startPos,
getTextPos: () => pos,
getToken: () => token,
getTokenPos: () => tokenPos,
getTokenText: () => text.substring(tokenPos, pos),
getTokenValue: () => tokenValue,
hasExtendedUnicodeEscape: () => hasExtendedUnicodeEscape,
hasPrecedingLineBreak: () => precedingLineBreak,
isIdentifier: () => token === SyntaxKind.Identifier || token > SyntaxKind.LastReservedWord,
isReservedWord: () => token >= SyntaxKind.FirstReservedWord && token <= SyntaxKind.LastReservedWord,
isUnterminated: () => tokenIsUnterminated,
reScanGreaterToken,
reScanSlashToken,
reScanTemplateToken,
scan,
setText,
setTextPos,
tryScan,
lookAhead,
};
}
}