Skip to content

Commit 5bd49fe

Browse files
Initial entrypoint in SourceFile for the LS to call to peform incremental parsing.
Right now the entrypoint just causes a full parse to happen. But the LS code is cleaned up to take advantage of it appropriately.
1 parent aea499e commit 5bd49fe

14 files changed

Lines changed: 202 additions & 155 deletions

File tree

src/compiler/parser.ts

Lines changed: 62 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,10 +1034,13 @@ module ts {
10341034

10351035
export function createSourceFile(filename: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes = false): SourceFile {
10361036
var parsingContext: ParsingContext;
1037-
var identifiers: Map<string> = {};
1037+
var identifiers: Map<string>;
10381038
var identifierCount = 0;
10391039
var nodeCount = 0;
10401040
var lineStarts: number[];
1041+
var syntacticDiagnostics: Diagnostic[];
1042+
var scanner: Scanner;
1043+
var token: SyntaxKind;
10411044

10421045
// Flags that dictate what parsing context we're in. For example:
10431046
// Whether or not we are in strict parsing mode. All that changes in strict parsing mode is
@@ -1085,7 +1088,7 @@ module ts {
10851088
// Note: it should not be necessary to save/restore these flags during speculative/lookahead
10861089
// parsing. These context flags are naturally stored and restored through normal recursive
10871090
// descent parsing and unwinding.
1088-
var contextFlags: ParserContextFlags = 0;
1091+
var contextFlags: ParserContextFlags;
10891092

10901093
// Whether or not we've had a parse error since creating the last AST node. If we have
10911094
// encountered an error, it will be stored on the next AST node we create. Parse errors
@@ -1114,48 +1117,69 @@ module ts {
11141117
//
11151118
// Note: any errors at the end of the file that do not precede a regular node, should get
11161119
// attached to the EOF token.
1117-
var parseErrorBeforeNextFinishedNode = false;
1120+
var parseErrorBeforeNextFinishedNode: boolean;
11181121

1119-
var sourceFile = <SourceFile>createNode(SyntaxKind.SourceFile, 0);
1120-
if (fileExtensionIs(filename, ".d.ts")) {
1121-
sourceFile.flags = NodeFlags.DeclarationFile;
1122-
}
1123-
sourceFile.end = sourceText.length;
1124-
sourceFile.filename = normalizePath(filename);
1125-
sourceFile.text = sourceText;
1122+
var sourceFile: SourceFile;
1123+
1124+
return parseSourceFile(sourceText, /*textChangeRange:*/ undefined, setParentNodes);
1125+
1126+
function parseSourceFile(text: string, textChangeRange: TextChangeRange, setParentNodes: boolean): SourceFile {
1127+
// Set our initial state before parsing.
1128+
sourceText = text;
1129+
parsingContext = 0;
1130+
identifiers = {};
1131+
lineStarts = undefined;
1132+
syntacticDiagnostics = undefined;
1133+
contextFlags = 0;
1134+
parseErrorBeforeNextFinishedNode = false;
1135+
1136+
sourceFile = <SourceFile>createNode(SyntaxKind.SourceFile, 0);
1137+
sourceFile.referenceDiagnostics = [];
1138+
sourceFile.parseDiagnostics = [];
1139+
sourceFile.grammarDiagnostics = [];
1140+
sourceFile.semanticDiagnostics = [];
11261141

1127-
sourceFile.getLineAndCharacterFromPosition = getLineAndCharacterFromSourcePosition;
1128-
sourceFile.getPositionFromLineAndCharacter = getPositionFromSourceLineAndCharacter;
1129-
sourceFile.getLineStarts = getLineStarts;
1130-
sourceFile.getSyntacticDiagnostics = getSyntacticDiagnostics;
1142+
// Create and prime the scanner before parsing the source elements.
1143+
scanner = createScanner(languageVersion, /*skipTrivia*/ true, sourceText, scanError);
1144+
token = nextToken();
11311145

1132-
sourceFile.referenceDiagnostics = [];
1133-
sourceFile.parseDiagnostics = [];
1134-
sourceFile.grammarDiagnostics = [];
1135-
sourceFile.semanticDiagnostics = [];
1146+
sourceFile.flags = fileExtensionIs(filename, ".d.ts") ? NodeFlags.DeclarationFile : 0;
1147+
sourceFile.end = sourceText.length;
1148+
sourceFile.filename = normalizePath(filename);
1149+
sourceFile.text = sourceText;
11361150

1137-
processReferenceComments();
1151+
sourceFile.getLineAndCharacterFromPosition = getLineAndCharacterFromSourcePosition;
1152+
sourceFile.getPositionFromLineAndCharacter = getPositionFromSourceLineAndCharacter;
1153+
sourceFile.getLineStarts = getLineStarts;
1154+
sourceFile.getSyntacticDiagnostics = getSyntacticDiagnostics;
1155+
sourceFile.update = update;
11381156

1139-
// Create and prime the scanner before parsing the source elements.
1140-
var scanner = createScanner(languageVersion, /*skipTrivia*/ true, sourceText, scanError);
1141-
var token = nextToken();
1157+
processReferenceComments(sourceFile);
11421158

1143-
sourceFile.statements = parseList(ParsingContext.SourceElements, /*checkForStrictMode*/ true, parseSourceElement);
1144-
Debug.assert(token === SyntaxKind.EndOfFileToken);
1145-
sourceFile.endOfFileToken = parseTokenNode();
1159+
sourceFile.statements = parseList(ParsingContext.SourceElements, /*checkForStrictMode*/ true, parseSourceElement);
1160+
Debug.assert(token === SyntaxKind.EndOfFileToken);
1161+
sourceFile.endOfFileToken = parseTokenNode();
11461162

1147-
sourceFile.externalModuleIndicator = getExternalModuleIndicator();
1163+
setExternalModuleIndicator(sourceFile);
11481164

1149-
sourceFile.nodeCount = nodeCount;
1150-
sourceFile.identifierCount = identifierCount;
1151-
sourceFile.languageVersion = languageVersion;
1152-
sourceFile.identifiers = identifiers;
1165+
sourceFile.nodeCount = nodeCount;
1166+
sourceFile.identifierCount = identifierCount;
1167+
sourceFile.languageVersion = languageVersion;
1168+
sourceFile.identifiers = identifiers;
11531169

1154-
if (setParentNodes) {
1155-
fixupParentReferences(sourceFile);
1170+
if (setParentNodes) {
1171+
fixupParentReferences(sourceFile);
1172+
}
1173+
1174+
return sourceFile;
1175+
}
1176+
1177+
function update(newText: string, textChangeRange: TextChangeRange) {
1178+
// Don't pass along the text change range for now. We'll pass it along once incremental
1179+
// parsing is enabled.
1180+
return parseSourceFile(newText, /*textChangeRange:*/ undefined, /*setNodeParents*/ true);
11561181
}
11571182

1158-
return sourceFile;
11591183

11601184
function setContextFlag(val: Boolean, flag: ParserContextFlags) {
11611185
if (val) {
@@ -4467,7 +4491,7 @@ module ts {
44674491
: parseStatement();
44684492
}
44694493

4470-
function processReferenceComments(): void {
4494+
function processReferenceComments(sourceFile: SourceFile): void {
44714495
var triviaScanner = createScanner(languageVersion, /*skipTrivia*/false, sourceText);
44724496
var referencedFiles: FileReference[] = [];
44734497
var amdDependencies: string[] = [];
@@ -4523,16 +4547,15 @@ module ts {
45234547
sourceFile.amdModuleName = amdModuleName;
45244548
}
45254549

4526-
function getExternalModuleIndicator() {
4527-
return forEach(sourceFile.statements, node =>
4550+
function setExternalModuleIndicator(sourceFile: SourceFile) {
4551+
sourceFile.externalModuleIndicator = forEach(sourceFile.statements, node =>
45284552
node.flags & NodeFlags.Export
45294553
|| node.kind === SyntaxKind.ImportDeclaration && (<ImportDeclaration>node).moduleReference.kind === SyntaxKind.ExternalModuleReference
45304554
|| node.kind === SyntaxKind.ExportAssignment
4531-
? node
4532-
: undefined);
4555+
? node
4556+
: undefined);
45334557
}
45344558

4535-
var syntacticDiagnostics: Diagnostic[];
45364559
function getSyntacticDiagnostics() {
45374560
if (syntacticDiagnostics === undefined) {
45384561
if (sourceFile.parseDiagnostics.length > 0) {

src/compiler/types.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -866,9 +866,20 @@ module ts {
866866

867867
filename: string;
868868
text: string;
869+
869870
getLineAndCharacterFromPosition(position: number): LineAndCharacter;
870871
getPositionFromLineAndCharacter(line: number, character: number): number;
871872
getLineStarts(): number[];
873+
874+
// Updates this source file to represent the 'newText' passed in. The 'textChangeRange'
875+
// parameter indicates what changed between the 'text' that this SourceFile has and the
876+
// 'newText'.
877+
//
878+
// Note: this function mutates nodes from this SourceFile. That means any existing nodes
879+
// from this SourceFile that are being held onto may change as a result (including
880+
// becoming detached from any SourceFile).
881+
update(newText: string, textChangeRange: TextChangeRange): SourceFile;
882+
872883
amdDependencies: string[];
873884
amdModuleName: string;
874885
referencedFiles: FileReference[];
@@ -1435,7 +1446,6 @@ module ts {
14351446
character: number;
14361447
}
14371448

1438-
14391449
export const enum ScriptTarget {
14401450
ES3,
14411451
ES5,
@@ -1607,4 +1617,26 @@ module ts {
16071617
useCaseSensitiveFileNames(): boolean;
16081618
getNewLine(): string;
16091619
}
1620+
1621+
export interface TextChangeRange {
1622+
span(): TextSpan;
1623+
newLength(): number;
1624+
newSpan(): TextSpan;
1625+
isUnchanged(): boolean;
1626+
}
1627+
1628+
export interface TextSpan {
1629+
start(): number;
1630+
length(): number;
1631+
end(): number;
1632+
isEmpty(): boolean;
1633+
containsPosition(position: number): boolean;
1634+
containsTextSpan(span: TextSpan): boolean;
1635+
overlapsWith(span: TextSpan): boolean;
1636+
overlap(span: TextSpan): TextSpan;
1637+
intersectsWithTextSpan(span: TextSpan): boolean;
1638+
intersectsWith(start: number, length: number): boolean;
1639+
intersectsWithPosition(position: number): boolean;
1640+
intersection(span: TextSpan): TextSpan;
1641+
}
16101642
}

src/harness/fourslash.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1755,14 +1755,14 @@ module FourSlash {
17551755

17561756
public verifySemanticClassifications(expected: { classificationType: string; text: string }[]) {
17571757
var actual = this.languageService.getSemanticClassifications(this.activeFile.fileName,
1758-
new ts.TextSpan(0, this.activeFile.content.length));
1758+
new ts.TextSpanObject(0, this.activeFile.content.length));
17591759

17601760
this.verifyClassifications(expected, actual);
17611761
}
17621762

17631763
public verifySyntacticClassifications(expected: { classificationType: string; text: string }[]) {
17641764
var actual = this.languageService.getSyntacticClassifications(this.activeFile.fileName,
1765-
new ts.TextSpan(0, this.activeFile.content.length));
1765+
new ts.TextSpanObject(0, this.activeFile.content.length));
17661766

17671767
this.verifyClassifications(expected, actual);
17681768
}
@@ -1796,7 +1796,7 @@ module FourSlash {
17961796
for (var i = 0; i < spans.length; i++) {
17971797
var expectedSpan = spans[i];
17981798
var actualComment = actual[i];
1799-
var actualCommentSpan = new ts.TextSpan(actualComment.position, actualComment.message.length);
1799+
var actualCommentSpan = new ts.TextSpanObject(actualComment.position, actualComment.message.length);
18001800

18011801
if (expectedSpan.start !== actualCommentSpan.start() || expectedSpan.end !== actualCommentSpan.end()) {
18021802
this.raiseError('verifyOutliningSpans failed - span ' + (i + 1) + ' expected: (' + expectedSpan.start + ',' + expectedSpan.end + '), actual: (' + actualCommentSpan.start() + ',' + actualCommentSpan.end() + ')');

src/harness/harnessLanguageService.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ module Harness.LanguageService {
3232
// Store edit range + new length of script
3333
this.editRanges.push({
3434
length: this.content.length,
35-
textChangeRange: new ts.TextChangeRange(
36-
ts.TextSpan.fromBounds(minChar, limChar), newText.length)
35+
textChangeRange: new ts.TextChangeRangeObject(
36+
ts.TextSpanObject.fromBounds(minChar, limChar), newText.length)
3737
});
3838

3939
// Update version #
@@ -43,14 +43,14 @@ module Harness.LanguageService {
4343
public getTextChangeRangeBetweenVersions(startVersion: number, endVersion: number): ts.TextChangeRange {
4444
if (startVersion === endVersion) {
4545
// No edits!
46-
return ts.TextChangeRange.unchanged;
46+
return ts.TextChangeRangeObject.unchanged;
4747
}
4848

4949
var initialEditRangeIndex = this.editRanges.length - (this.version - startVersion);
5050
var lastEditRangeIndex = this.editRanges.length - (this.version - endVersion);
5151

5252
var entries = this.editRanges.slice(initialEditRangeIndex, lastEditRangeIndex);
53-
return ts.TextChangeRange.collapseChangesAcrossMultipleVersions(entries.map(e => e.textChangeRange));
53+
return ts.TextChangeRangeObject.collapseChangesAcrossMultipleVersions(entries.map(e => e.textChangeRange));
5454
}
5555
}
5656

@@ -126,7 +126,7 @@ module Harness.LanguageService {
126126
isOpen: boolean,
127127
textChangeRange: ts.TextChangeRange
128128
): ts.SourceFile {
129-
return document.update(scriptSnapshot, version, isOpen, textChangeRange);
129+
return ts.updateLanguageServiceSourceFile(document, scriptSnapshot, version, isOpen, textChangeRange);
130130
}
131131

132132
public releaseDocument(fileName: string, compilationSettings: ts.CompilerOptions): void {

src/services/breakpoints.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ module ts.BreakpointResolver {
3838
return spanInNode(tokenAtLocation);
3939

4040
function textSpan(startNode: Node, endNode?: Node) {
41-
return TextSpan.fromBounds(startNode.getStart(), (endNode || startNode).getEnd());
41+
return TextSpanObject.fromBounds(startNode.getStart(), (endNode || startNode).getEnd());
4242
}
4343

4444
function spanInNodeIfStartsOnSameLine(node: Node, otherwiseOnNode?: Node): TextSpan {

src/services/formatting.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,7 @@ module ts.formatting {
868868
}
869869

870870
function newTextChange(start: number, len: number, newText: string): TextChange {
871-
return { span: new TextSpan(start, len), newText }
871+
return { span: new TextSpanObject(start, len), newText }
872872
}
873873

874874
function recordDelete(start: number, len: number) {

src/services/formatting/tokenSpan.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
///<reference path='references.ts' />
1717

1818
module ts.formatting {
19-
export class TokenSpan extends TextSpan {
19+
export class TokenSpan extends TextSpanObject {
2020
constructor(public kind: SyntaxKind, start: number, length: number) {
2121
super(start, length);
2222
}

src/services/navigationBar.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -462,8 +462,8 @@ module ts.NavigationBar {
462462

463463
function getNodeSpan(node: Node) {
464464
return node.kind === SyntaxKind.SourceFile
465-
? TextSpan.fromBounds(node.getFullStart(), node.getEnd())
466-
: TextSpan.fromBounds(node.getStart(), node.getEnd());
465+
? TextSpanObject.fromBounds(node.getFullStart(), node.getEnd())
466+
: TextSpanObject.fromBounds(node.getStart(), node.getEnd());
467467
}
468468

469469
function getTextOfNode(node: Node): string {

src/services/outliningElementsCollector.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ module ts {
3838
function addOutliningSpan(hintSpanNode: Node, startElement: Node, endElement: Node, autoCollapse: boolean) {
3939
if (hintSpanNode && startElement && endElement) {
4040
var span: OutliningSpan = {
41-
textSpan: TextSpan.fromBounds(startElement.pos, endElement.end),
42-
hintSpan: TextSpan.fromBounds(hintSpanNode.getStart(), hintSpanNode.end),
41+
textSpan: TextSpanObject.fromBounds(startElement.pos, endElement.end),
42+
hintSpan: TextSpanObject.fromBounds(hintSpanNode.getStart(), hintSpanNode.end),
4343
bannerText: collapseText,
4444
autoCollapse: autoCollapse
4545
};
@@ -88,7 +88,7 @@ module ts {
8888
else {
8989
// Block was a standalone block. In this case we want to only collapse
9090
// the span of the block, independent of any parent span.
91-
var span = TextSpan.fromBounds(n.getStart(), n.end);
91+
var span = TextSpanObject.fromBounds(n.getStart(), n.end);
9292
elements.push({
9393
textSpan: span,
9494
hintSpan: span,

0 commit comments

Comments
 (0)