diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 4ab8d9d1d5..a1dc0ef7b1 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -371,8 +371,8 @@ module ts { return false; } - function moveElementEntirelyPastChangeRange(element: IncrementalElement, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) { - if (element.length) { + function moveElementEntirelyPastChangeRange(element: IncrementalElement, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) { + if (isArray) { visitArray(element); } else { @@ -400,6 +400,7 @@ module ts { } function visitArray(array: IncrementalNodeArray) { + array._children = undefined; array.pos += delta; array.end += delta; @@ -412,6 +413,7 @@ module ts { function adjustIntersectingElement(element: IncrementalElement, changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number) { Debug.assert(element.end >= changeStart, "Adjusting an element that was entirely before the change range"); Debug.assert(element.pos <= changeRangeOldEnd, "Adjusting an element that was entirely after the change range"); + Debug.assert(element.pos <= element.end); // We have an element that intersects the change range in some way. It may have its // start, or its end (or both) in the changed range. We want to adjust any part @@ -508,10 +510,11 @@ module ts { return; function visitNode(child: IncrementalNode) { + Debug.assert(child.pos <= child.end); if (child.pos > changeRangeOldEnd) { // Node is entirely past the change range. We need to move both its pos and // end, forward or backward appropriately. - moveElementEntirelyPastChangeRange(child, delta, oldText, newText, aggressiveChecks); + moveElementEntirelyPastChangeRange(child, /*isArray:*/ false, delta, oldText, newText, aggressiveChecks); return; } @@ -521,6 +524,7 @@ module ts { var fullEnd = child.end; if (fullEnd >= changeStart) { child.intersectsChange = true; + child._children = undefined; // Adjust the pos or end (or both) of the intersecting element accordingly. adjustIntersectingElement(child, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); @@ -531,32 +535,36 @@ module ts { } // Otherwise, the node is entirely before the change range. No need to do anything with it. + Debug.assert(fullEnd < changeStart); } function visitArray(array: IncrementalNodeArray) { + Debug.assert(array.pos <= array.end); if (array.pos > changeRangeOldEnd) { // Array is entirely after the change range. We need to move it, and move any of // its children. - moveElementEntirelyPastChangeRange(array, delta, oldText, newText, aggressiveChecks); + moveElementEntirelyPastChangeRange(array, /*isArray:*/ true, delta, oldText, newText, aggressiveChecks); + return; } - else { - // Check if the element intersects the change range. If it does, then it is not - // reusable. Also, we'll need to recurse to see what constituent portions we may - // be able to use. - var fullEnd = array.end; - if (fullEnd >= changeStart) { - array.intersectsChange = true; - // Adjust the pos or end (or both) of the intersecting array accordingly. - adjustIntersectingElement(array, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); - for (var i = 0, n = array.length; i < n; i++) { - visitNode(array[i]); - } + // Check if the element intersects the change range. If it does, then it is not + // reusable. Also, we'll need to recurse to see what constituent portions we may + // be able to use. + var fullEnd = array.end; + if (fullEnd >= changeStart) { + array.intersectsChange = true; + array._children = undefined; + + // Adjust the pos or end (or both) of the intersecting array accordingly. + adjustIntersectingElement(array, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); + for (var i = 0, n = array.length; i < n; i++) { + visitNode(array[i]); } - // else { - // Otherwise, the array is entirely before the change range. No need to do anything with it. - // } + return; } + + // Otherwise, the array is entirely before the change range. No need to do anything with it. + Debug.assert(fullEnd < changeStart); } } @@ -842,7 +850,7 @@ module ts { // Much of the time the parser will need the very next node in the array that // we just returned a node from.So just simply check for that case and move // forward in the array instead of searching for the node again. - if (current && current.end === position && currentArrayIndex < currentArray.length) { + if (current && current.end === position && currentArrayIndex < (currentArray.length - 1)) { currentArrayIndex++; current = currentArray[currentArrayIndex]; } @@ -878,6 +886,7 @@ module ts { // Recurse into the source file to find the highest node at this position. forEachChild(sourceFile, visitNode, visitArray); + return; function visitNode(node: Node) { if (position >= node.pos && position < node.end) { @@ -1649,8 +1658,8 @@ module ts { return result; } - function parseListElement(kind: ParsingContext, parseElement: () => T): T { - var node = currentNode(kind); + function parseListElement(parsingContext: ParsingContext, parseElement: () => T): T { + var node = currentNode(parsingContext); if (node) { return consumeNode(node); } @@ -1807,29 +1816,10 @@ module ts { case SyntaxKind.InterfaceDeclaration: case SyntaxKind.ModuleDeclaration: case SyntaxKind.EnumDeclaration: - - // Keep in sync with isStatement: - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.VariableStatement: - case SyntaxKind.Block: - case SyntaxKind.IfStatement: - case SyntaxKind.ExpressionStatement: - case SyntaxKind.ThrowStatement: - case SyntaxKind.ReturnStatement: - case SyntaxKind.SwitchStatement: - case SyntaxKind.BreakStatement: - case SyntaxKind.ContinueStatement: - case SyntaxKind.ForInStatement: - case SyntaxKind.ForStatement: - case SyntaxKind.WhileStatement: - case SyntaxKind.WithStatement: - case SyntaxKind.EmptyStatement: - case SyntaxKind.TryStatement: - case SyntaxKind.LabeledStatement: - case SyntaxKind.DoStatement: - case SyntaxKind.DebuggerStatement: return true; } + + return isReusableStatement(node); } return false; @@ -1935,9 +1925,13 @@ module ts { } function isReusableParameter(node: Node) { - // TODO: this most likely needs the same initializer check that - // isReusableVariableDeclaration has. - return node.kind === SyntaxKind.Parameter; + if (node.kind !== SyntaxKind.Parameter) { + return false; + } + + // See the comment in isReusableVariableDeclaration for why we do this. + var parameter = node; + return parameter.initializer === undefined; } // Returns true if we should abort parsing.