@@ -318,7 +318,6 @@ import {
318
318
QuestionToken,
319
319
ReadonlyKeyword,
320
320
ReadonlyPragmaMap,
321
- ReadonlyTextRange,
322
321
ResolutionMode,
323
322
RestTypeNode,
324
323
ReturnStatement,
@@ -1950,7 +1949,7 @@ namespace Parser {
1950
1949
function currentNode(position: number) {
1951
1950
const node = baseSyntaxCursor.currentNode(position);
1952
1951
if (topLevel && node && containsPossibleTopLevelAwait(node)) {
1953
- node.intersectsChange = true ;
1952
+ markAsIntersectingIncrementalChange( node) ;
1954
1953
}
1955
1954
return node;
1956
1955
}
@@ -3120,7 +3119,7 @@ namespace Parser {
3120
3119
// Can't reuse a node that intersected the change range.
3121
3120
// Can't reuse a node that contains a parse error. This is necessary so that we
3122
3121
// produce the same set of errors again.
3123
- if (nodeIsMissing(node) || node.intersectsChange || containsParseError(node)) {
3122
+ if (nodeIsMissing(node) || intersectsIncrementalChange( node) || containsParseError(node)) {
3124
3123
return undefined;
3125
3124
}
3126
3125
@@ -9844,6 +9843,25 @@ namespace Parser {
9844
9843
}
9845
9844
}
9846
9845
9846
+ const incrementallyParsedFiles = new WeakSet<SourceFile>();
9847
+
9848
+ function markAsIncrementallyParsed(sourceFile: SourceFile) {
9849
+ if (incrementallyParsedFiles.has(sourceFile)) {
9850
+ Debug.fail("Source file has already been incrementally parsed");
9851
+ }
9852
+ incrementallyParsedFiles.add(sourceFile);
9853
+ }
9854
+
9855
+ const intersectingChangeSet = new WeakSet<Node | NodeArray<Node>>();
9856
+
9857
+ function intersectsIncrementalChange(node: Node | NodeArray<Node>): boolean {
9858
+ return intersectingChangeSet.has(node);
9859
+ }
9860
+
9861
+ function markAsIntersectingIncrementalChange(node: Node | NodeArray<Node>) {
9862
+ intersectingChangeSet.add(node);
9863
+ }
9864
+
9847
9865
namespace IncrementalParser {
9848
9866
export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean): SourceFile {
9849
9867
aggressiveChecks = aggressiveChecks || Debug.shouldAssert(AssertionLevel.Aggressive);
@@ -9866,10 +9884,8 @@ namespace IncrementalParser {
9866
9884
// This is because we do incremental parsing in-place. i.e. we take nodes from the old
9867
9885
// tree and give them new positions and parents. From that point on, trusting the old
9868
9886
// tree at all is not possible as far too much of it may violate invariants.
9869
- const incrementalSourceFile = sourceFile as Node as IncrementalNode;
9870
- Debug.assert(!incrementalSourceFile.hasBeenIncrementallyParsed);
9871
- incrementalSourceFile.hasBeenIncrementallyParsed = true;
9872
- Parser.fixupParentReferences(incrementalSourceFile);
9887
+ markAsIncrementallyParsed(sourceFile);
9888
+ Parser.fixupParentReferences(sourceFile);
9873
9889
const oldText = sourceFile.text;
9874
9890
const syntaxCursor = createSyntaxCursor(sourceFile);
9875
9891
@@ -9908,7 +9924,7 @@ namespace IncrementalParser {
9908
9924
//
9909
9925
// Also, mark any syntax elements that intersect the changed span. We know, up front,
9910
9926
// that we cannot reuse these elements.
9911
- updateTokenPositionsAndMarkElements(incrementalSourceFile , changeRange.span.start, textSpanEnd(changeRange.span), textSpanEnd(textChangeRangeNewSpan(changeRange)), delta, oldText, newText, aggressiveChecks);
9927
+ updateTokenPositionsAndMarkElements(sourceFile , changeRange.span.start, textSpanEnd(changeRange.span), textSpanEnd(textChangeRangeNewSpan(changeRange)), delta, oldText, newText, aggressiveChecks);
9912
9928
9913
9929
// Now that we've set up our internal incremental state just proceed and parse the
9914
9930
// source file in the normal fashion. When possible the parser will retrieve and
@@ -9984,18 +10000,18 @@ namespace IncrementalParser {
9984
10000
}
9985
10001
}
9986
10002
9987
- function moveElementEntirelyPastChangeRange(element: IncrementalNode , isArray: false, delta: number, oldText: string, newText: string, aggressiveChecks: boolean): void;
9988
- function moveElementEntirelyPastChangeRange(element: IncrementalNodeArray , isArray: true, delta: number, oldText: string, newText: string, aggressiveChecks: boolean): void;
9989
- function moveElementEntirelyPastChangeRange(element: IncrementalNode | IncrementalNodeArray , isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) {
10003
+ function moveElementEntirelyPastChangeRange(element: Node , isArray: false, delta: number, oldText: string, newText: string, aggressiveChecks: boolean): void;
10004
+ function moveElementEntirelyPastChangeRange(element: NodeArray<Node> , isArray: true, delta: number, oldText: string, newText: string, aggressiveChecks: boolean): void;
10005
+ function moveElementEntirelyPastChangeRange(element: Node | NodeArray<Node> , isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) {
9990
10006
if (isArray) {
9991
- visitArray(element as IncrementalNodeArray );
10007
+ visitArray(element as NodeArray<Node> );
9992
10008
}
9993
10009
else {
9994
- visitNode(element as IncrementalNode );
10010
+ visitNode(element as Node );
9995
10011
}
9996
10012
return;
9997
10013
9998
- function visitNode(node: IncrementalNode ) {
10014
+ function visitNode(node: Node ) {
9999
10015
let text = "";
10000
10016
if (aggressiveChecks && shouldCheckNode(node)) {
10001
10017
text = oldText.substring(node.pos, node.end);
@@ -10014,13 +10030,13 @@ namespace IncrementalParser {
10014
10030
forEachChild(node, visitNode as (node: Node) => void, visitArray as (nodes: NodeArray<Node>) => void);
10015
10031
if (hasJSDocNodes(node)) {
10016
10032
for (const jsDocComment of node.jsDoc!) {
10017
- visitNode(jsDocComment as Node as IncrementalNode );
10033
+ visitNode(jsDocComment);
10018
10034
}
10019
10035
}
10020
10036
checkNodePositions(node, aggressiveChecks);
10021
10037
}
10022
10038
10023
- function visitArray(array: IncrementalNodeArray ) {
10039
+ function visitArray(array: NodeArray<Node> ) {
10024
10040
setTextRangePosEnd(array, array.pos + delta, array.end + delta);
10025
10041
10026
10042
for (const node of array) {
@@ -10040,7 +10056,7 @@ namespace IncrementalParser {
10040
10056
return false;
10041
10057
}
10042
10058
10043
- function adjustIntersectingElement(element: IncrementalElement , changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number) {
10059
+ function adjustIntersectingElement(element: Node | NodeArray<Node> , changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number) {
10044
10060
Debug.assert(element.end >= changeStart, "Adjusting an element that was entirely before the change range");
10045
10061
Debug.assert(element.pos <= changeRangeOldEnd, "Adjusting an element that was entirely after the change range");
10046
10062
Debug.assert(element.pos <= element.end);
@@ -10106,9 +10122,10 @@ namespace IncrementalParser {
10106
10122
Math.min(element.end, changeRangeNewEnd);
10107
10123
10108
10124
Debug.assert(pos <= end);
10109
- if (element.parent) {
10110
- Debug.assertGreaterThanOrEqual(pos, element.parent.pos);
10111
- Debug.assertLessThanOrEqual(end, element.parent.end);
10125
+ if ((element as any).parent) {
10126
+ const parent = (element as any).parent as Node;
10127
+ Debug.assertGreaterThanOrEqual(pos, parent.pos);
10128
+ Debug.assertLessThanOrEqual(end, parent.end);
10112
10129
}
10113
10130
10114
10131
setTextRangePosEnd(element, pos, end);
@@ -10132,7 +10149,7 @@ namespace IncrementalParser {
10132
10149
}
10133
10150
10134
10151
function updateTokenPositionsAndMarkElements(
10135
- sourceFile: IncrementalNode ,
10152
+ sourceFile: SourceFile ,
10136
10153
changeStart: number,
10137
10154
changeRangeOldEnd: number,
10138
10155
changeRangeNewEnd: number,
@@ -10144,7 +10161,7 @@ namespace IncrementalParser {
10144
10161
visitNode(sourceFile);
10145
10162
return;
10146
10163
10147
- function visitNode(child: IncrementalNode ) {
10164
+ function visitNode(child: Node ) {
10148
10165
Debug.assert(child.pos <= child.end);
10149
10166
if (child.pos > changeRangeOldEnd) {
10150
10167
// Node is entirely past the change range. We need to move both its pos and
@@ -10158,15 +10175,15 @@ namespace IncrementalParser {
10158
10175
// be able to use.
10159
10176
const fullEnd = child.end;
10160
10177
if (fullEnd >= changeStart) {
10161
- child.intersectsChange = true ;
10178
+ markAsIntersectingIncrementalChange( child) ;
10162
10179
unsetNodeChildren(child);
10163
10180
10164
10181
// Adjust the pos or end (or both) of the intersecting element accordingly.
10165
10182
adjustIntersectingElement(child, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta);
10166
10183
forEachChild(child, visitNode as (node: Node) => void, visitArray as (nodes: NodeArray<Node>) => void);
10167
10184
if (hasJSDocNodes(child)) {
10168
10185
for (const jsDocComment of child.jsDoc!) {
10169
- visitNode(jsDocComment as Node as IncrementalNode );
10186
+ visitNode(jsDocComment);
10170
10187
}
10171
10188
}
10172
10189
checkNodePositions(child, aggressiveChecks);
@@ -10177,7 +10194,7 @@ namespace IncrementalParser {
10177
10194
Debug.assert(fullEnd < changeStart);
10178
10195
}
10179
10196
10180
- function visitArray(array: IncrementalNodeArray ) {
10197
+ function visitArray(array: NodeArray<Node> ) {
10181
10198
Debug.assert(array.pos <= array.end);
10182
10199
if (array.pos > changeRangeOldEnd) {
10183
10200
// Array is entirely after the change range. We need to move it, and move any of
@@ -10191,7 +10208,7 @@ namespace IncrementalParser {
10191
10208
// be able to use.
10192
10209
const fullEnd = array.end;
10193
10210
if (fullEnd >= changeStart) {
10194
- array.intersectsChange = true ;
10211
+ markAsIntersectingIncrementalChange( array) ;
10195
10212
10196
10213
// Adjust the pos or end (or both) of the intersecting array accordingly.
10197
10214
adjustIntersectingElement(array, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta);
@@ -10340,25 +10357,11 @@ namespace IncrementalParser {
10340
10357
}
10341
10358
}
10342
10359
10343
- interface IncrementalElement extends ReadonlyTextRange {
10344
- readonly parent: Node;
10345
- intersectsChange: boolean;
10346
- length?: number;
10347
- }
10348
-
10349
- export interface IncrementalNode extends Node, IncrementalElement {
10350
- hasBeenIncrementallyParsed: boolean;
10351
- }
10352
-
10353
- interface IncrementalNodeArray extends NodeArray<IncrementalNode>, IncrementalElement {
10354
- length: number;
10355
- }
10356
-
10357
10360
// Allows finding nodes in the source file at a certain position in an efficient manner.
10358
10361
// The implementation takes advantage of the calling pattern it knows the parser will
10359
10362
// make in order to optimize finding nodes as quickly as possible.
10360
10363
export interface SyntaxCursor {
10361
- currentNode(position: number): IncrementalNode ;
10364
+ currentNode(position: number): Node ;
10362
10365
}
10363
10366
10364
10367
export function createSyntaxCursor(sourceFile: SourceFile): SyntaxCursor {
@@ -10400,7 +10403,7 @@ namespace IncrementalParser {
10400
10403
10401
10404
// Either we don'd have a node, or we have a node at the position being asked for.
10402
10405
Debug.assert(!current || current.pos === position);
10403
- return current as IncrementalNode ;
10406
+ return current;
10404
10407
},
10405
10408
};
10406
10409
0 commit comments