Skip to content

Commit 72da291

Browse files
Merge pull request #1027 from Microsoft/separatedList
Use a flat list for separated syntax lists.
2 parents 3ed6b4f + c4d6b7c commit 72da291

14 files changed

+517
-829
lines changed

src/services/formatting/indentationTrackingWalker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ module TypeScript.Services.Formatting {
103103
if (isToken(element)) {
104104
this.visitToken(<ISyntaxToken>element);
105105
}
106-
else if (element.kind() === SyntaxKind.List || element.kind() === SyntaxKind.SeparatedList) {
106+
else if (element.kind() === SyntaxKind.List) {
107107
for (var i = 0, n = element.childCount(); i < n; i++) {
108108
this.walk(element.childAt(i));
109109
}

src/services/syntax/SyntaxGenerator.js

Lines changed: 383 additions & 563 deletions
Large diffs are not rendered by default.

src/services/syntax/incrementalParser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,7 @@ module TypeScript.IncrementalParser {
777777
function moveToFirstChildIfList(): void {
778778
var element = pieces[currentPieceIndex].element;
779779

780-
if (isList(element) || isSeparatedList(element)) {
780+
if (isList(element)) {
781781
// We cannot ever get an empty list in our piece path. Empty lists are 'shared' and
782782
// we make sure to filter that out before pushing any children.
783783
// Debug.assert(childCount(element) > 0);

src/services/syntax/parser.ts

Lines changed: 19 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ module TypeScript.Parser {
557557
// when next requested.
558558
while (true) {
559559
// Parent must be a list or a node. All of those have a 'data' element.
560-
Debug.assert(isNode(parent) || isList(parent) || isSeparatedList(parent));
560+
Debug.assert(isNode(parent) || isList(parent));
561561
var dataElement = <{ data: number }><any>parent;
562562
if (dataElement.data) {
563563
dataElement.data &= SyntaxConstants.NodeParsedInStrictModeMask
@@ -592,20 +592,6 @@ module TypeScript.Parser {
592592
}
593593
}
594594
}
595-
else if (isSeparatedList(parent)) {
596-
var list2 = <ISyntaxNodeOrToken[]>parent;
597-
for (var i = 0, n = list2.childCount(); i < n; i++) {
598-
if (list2.childAt(i) === oldToken) {
599-
if (i % 2 === 0) {
600-
list2[i / 2] = newToken;
601-
}
602-
else {
603-
list2.separators[(i - 1) / 2] = newToken;
604-
}
605-
return;
606-
}
607-
}
608-
}
609595

610596
throw Errors.invalidOperation();
611597
}
@@ -3786,7 +3772,7 @@ module TypeScript.Parser {
37863772
return result;
37873773
}
37883774

3789-
function parseSeparatedSyntaxList<T extends ISyntaxNodeOrToken>(currentListType: ListParsingState, skippedTokens: ISyntaxToken[]): T[] {
3775+
function parseSeparatedSyntaxList<T extends ISyntaxNodeOrToken>(currentListType: ListParsingState, skippedTokens: ISyntaxToken[]): ISeparatedSyntaxList<T> {
37903776
var savedListParsingState = listParsingState;
37913777
listParsingState |= (1 << currentListType);
37923778

@@ -3799,7 +3785,7 @@ module TypeScript.Parser {
37993785

38003786
// Returns true if we should abort parsing.
38013787
function abortParsingListOrMoveToNextToken<T extends ISyntaxNodeOrToken>(
3802-
currentListType: ListParsingState, nodes: T[], separators: ISyntaxToken[], skippedTokens: ISyntaxToken[]): boolean {
3788+
currentListType: ListParsingState, nodeAndSeparators: ISyntaxNodeOrToken[], skippedTokens: ISyntaxToken[]): boolean {
38033789
// Ok. We're at a token that is not a terminator for the list and wasn't the start of
38043790
// an item in the list. Definitely report an error for this token.
38053791
reportUnexpectedTokenDiagnostic(currentListType);
@@ -3819,30 +3805,27 @@ module TypeScript.Parser {
38193805

38203806
// Otherwise, if none of the lists we're in can capture this token, then we need to
38213807
// unilaterally skip it. Note: we've already reported an error above.
3822-
addSkippedTokenToList(nodes, separators, skippedTokens, consumeToken(currentToken()));
3808+
addSkippedTokenToList(nodeAndSeparators, skippedTokens, consumeToken(currentToken()));
38233809

38243810
// Continue parsing this list. Attach this token to whatever we've seen already.
38253811
return false;
38263812
}
38273813

3828-
function addSkippedTokenToList<T extends ISyntaxNodeOrToken>(
3829-
nodes: T[], separators: ISyntaxToken[], skippedTokens: ISyntaxToken[], skippedToken: ISyntaxToken): void {
3814+
function addSkippedTokenToList(
3815+
nodesAndSeparators: ISyntaxNodeOrToken[], skippedTokens: ISyntaxToken[], skippedToken: ISyntaxToken): void {
38303816
// Now, add this skipped token to the last item we successfully parsed in the list. Or
38313817
// add it to the list of skipped tokens if we haven't parsed anything. Our caller will
38323818
// have to deal with them.
38333819
//
38343820
// Note: we only bother doing this if we're creating a concrete syntax tree.
38353821
if (syntaxFactory.isConcrete) {
3836-
var length = nodes.length + (separators ? separators.length : 0);
3822+
var length = nodesAndSeparators.length;
38373823

38383824
for (var i = length - 1; i >= 0; i--) {
3839-
var array: ISyntaxNodeOrToken[] = separators && (i % 2 === 1) ? separators : nodes;
3840-
var arrayIndex = separators ? IntegerUtilities.integerDivide(i, 2) : i;
3841-
3842-
var item = array[arrayIndex];
3825+
var item = nodesAndSeparators[i];
38433826
var _lastToken = lastToken(item);
38443827
if (_lastToken && _lastToken.fullWidth() > 0) {
3845-
array[arrayIndex] = <T>addSkippedTokenAfterNodeOrToken(item, skippedToken);
3828+
nodesAndSeparators[i] = addSkippedTokenAfterNodeOrToken(item, skippedToken);
38463829
return;
38473830
}
38483831
}
@@ -3895,7 +3878,7 @@ module TypeScript.Parser {
38953878

38963879
// List wasn't complete and we didn't get an item. Figure out if we should bail out
38973880
// or skip a token and continue.
3898-
var abort = abortParsingListOrMoveToNextToken(currentListType, items, /*separators:*/ undefined, skippedTokens);
3881+
var abort = abortParsingListOrMoveToNextToken(currentListType, items, skippedTokens);
38993882
if (abort) {
39003883
break;
39013884
}
@@ -3914,9 +3897,8 @@ module TypeScript.Parser {
39143897
return result;
39153898
}
39163899

3917-
function parseSeparatedSyntaxListWorker<T extends ISyntaxNodeOrToken>(currentListType: ListParsingState, skippedTokens: ISyntaxToken[]): T[] {
3918-
var nodes: T[] = getArray();
3919-
var separators: ISyntaxToken[] = getArray();
3900+
function parseSeparatedSyntaxListWorker<T extends ISyntaxNodeOrToken>(currentListType: ListParsingState, skippedTokens: ISyntaxToken[]): ISeparatedSyntaxList<T> {
3901+
var nodesAndSeparators: ISyntaxNodeOrToken[] = getArray();
39203902

39213903
// Debug.assert(nodes.length === 0);
39223904
// Debug.assert(separators.length === 0);
@@ -3934,7 +3916,7 @@ module TypeScript.Parser {
39343916
// continue parsing.
39353917

39363918
// Debug.assert(oldItemsCount % 2 === 0);
3937-
var succeeded = tryParseExpectedListItem(currentListType, inErrorRecovery, nodes, /*processItems:*/ undefined);
3919+
var succeeded = tryParseExpectedListItem(currentListType, inErrorRecovery, nodesAndSeparators, /*processItems:*/ undefined);
39383920

39393921
if (!succeeded) {
39403922
// We weren't able to parse out a list element.
@@ -3948,7 +3930,7 @@ module TypeScript.Parser {
39483930

39493931
// List wasn't complete and we didn't get an item. Figure out if we should bail out
39503932
// or skip a token and continue.
3951-
var abort = abortParsingListOrMoveToNextToken(currentListType, nodes, separators, skippedTokens);
3933+
var abort = abortParsingListOrMoveToNextToken(currentListType, nodesAndSeparators, skippedTokens);
39523934
if (abort) {
39533935
break;
39543936
}
@@ -3973,7 +3955,7 @@ module TypeScript.Parser {
39733955
var tokenKind = _currentToken.kind();
39743956
if (tokenKind === _separatorKind || tokenKind === SyntaxKind.CommaToken) {
39753957
// Consume the last separator and continue parsing list elements.
3976-
separators.push(consumeToken(_currentToken));
3958+
nodesAndSeparators.push(consumeToken(_currentToken));
39773959
continue;
39783960
}
39793961

@@ -4001,7 +3983,7 @@ module TypeScript.Parser {
40013983

40023984
if (allowAutomaticSemicolonInsertion && canEatAutomaticSemicolon(/*allowWithoutNewline:*/ false)) {
40033985
var semicolonToken = eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false) || Syntax.emptyToken(SyntaxKind.SemicolonToken);
4004-
separators.push(semicolonToken);
3986+
nodesAndSeparators.push(semicolonToken);
40053987
// Debug.assert(items.length % 2 === 0);
40063988
continue;
40073989
}
@@ -4011,7 +3993,7 @@ module TypeScript.Parser {
40113993
// This time mark that we're in error recovery mode though.
40123994
//
40133995
// Note: trying to eat this token will emit the appropriate diagnostic.
4014-
separators.push(eatToken(_separatorKind));
3996+
nodesAndSeparators.push(eatToken(_separatorKind));
40153997

40163998
// Now that we're in 'error recovery' mode we cantweak some parsing rules as
40173999
// appropriate. For example, if we have:
@@ -4027,12 +4009,11 @@ module TypeScript.Parser {
40274009
inErrorRecovery = true;
40284010
}
40294011

4030-
var result = Syntax.separatedList<T>(nodes, separators);
4012+
var result = Syntax.separatedList<T>(nodesAndSeparators);
40314013

40324014
// Can't return if it has more then 0 elements. In that case, the list will have been
40334015
// copied into the SyntaxList.
4034-
returnZeroLengthArray(nodes);
4035-
returnZeroLengthArray(separators);
4016+
returnZeroLengthArray(nodesAndSeparators);
40364017

40374018
return result;
40384019
}

src/services/syntax/syntaxElement.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ module TypeScript {
88
// nodes don't have positions or parents.
99
export function isShared(element: ISyntaxElement): boolean {
1010
var kind = element.kind();
11-
return (kind === SyntaxKind.List || kind === SyntaxKind.SeparatedList) && (<ISyntaxNodeOrToken[]>element).length === 0;
11+
return kind === SyntaxKind.List && (<ISyntaxNodeOrToken[]>element).length === 0;
1212
}
1313

1414
export function syntaxTree(element: ISyntaxElement): SyntaxTree {
@@ -225,10 +225,6 @@ module TypeScript {
225225
return element && element.kind() === SyntaxKind.List;
226226
}
227227

228-
export function isSeparatedList(element: ISyntaxElement): boolean {
229-
return element && element.kind() === SyntaxKind.SeparatedList;
230-
}
231-
232228
export function syntaxID(element: ISyntaxElement): number {
233229
if (isShared(element)) {
234230
throw Errors.invalidOperation("Should not use shared syntax element as a key.");
@@ -350,7 +346,7 @@ module TypeScript {
350346
}
351347

352348
function data(element: ISyntaxElement): number {
353-
Debug.assert(isNode(element) || isList(element) || isSeparatedList(element));
349+
Debug.assert(isNode(element) || isList(element));
354350

355351
// Lists and nodes all have a 'data' element.
356352
var dataElement = <{ data: number }><any>element;

src/services/syntax/syntaxGenerator.ts

Lines changed: 10 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,7 +1028,7 @@ function getType(child: IMemberDefinition): string {
10281028
return "ISyntaxToken";
10291029
}
10301030
else if (child.isSeparatedList) {
1031-
return child.elementType + "[]";
1031+
return "ISeparatedSyntaxList<" + child.elementType + ">";
10321032
}
10331033
else if (child.isList) {
10341034
return child.elementType + "[]";
@@ -2180,12 +2180,12 @@ function generateRewriter(): string {
21802180
" return isToken(node) ? <ISyntaxNodeOrToken>this.visitToken(<ISyntaxToken>node) : this.visitNode(<ISyntaxNode>node);\r\n" +
21812181
" }\r\n" +
21822182
"\r\n" +
2183-
" public visitList<T extends ISyntaxNodeOrToken>(list: T[]): T[] {\r\n" +
2184-
" var newItems: T[] = undefined;\r\n" +
2183+
" public visitList<T extends ISyntaxNodeOrToken[]>(list: T): T {\r\n" +
2184+
" var newItems: T = undefined;\r\n" +
21852185
"\r\n" +
21862186
" for (var i = 0, n = list.length; i < n; i++) {\r\n" +
21872187
" var item = list[i];\r\n" +
2188-
" var newItem = <T>this.visitNodeOrToken(item);\r\n" +
2188+
" var newItem = this.visitNodeOrToken(item);\r\n" +
21892189
"\r\n" +
21902190
" if (item !== newItem && !newItems) {\r\n" +
21912191
" newItems = [];\r\n" +
@@ -2200,31 +2200,9 @@ function generateRewriter(): string {
22002200
" }\r\n" +
22012201
"\r\n" +
22022202
" // Debug.assert(!newItems || newItems.length === childCount(list));\r\n" +
2203-
" return !newItems ? list : Syntax.list<T>(newItems);\r\n" +
2203+
" return !newItems ? list : <T>Syntax.list(newItems);\r\n" +
22042204
" }\r\n" +
2205-
"\r\n" +
2206-
" public visitSeparatedList<T extends ISyntaxNodeOrToken>(list: T[]): T[] {\r\n" +
2207-
" var newItems: ISyntaxNodeOrToken[] = undefined;\r\n" +
2208-
"\r\n" +
2209-
" for (var i = 0, n = childCount(list); i < n; i++) {\r\n" +
2210-
" var item = childAt(list, i);\r\n" +
2211-
" var newItem = isToken(item) ? <ISyntaxNodeOrToken>this.visitToken(<ISyntaxToken>item) : this.visitNode(<ISyntaxNode>item);\r\n" +
2212-
"\r\n" +
2213-
" if (item !== newItem && !newItems) {\r\n" +
2214-
" newItems = [];\r\n" +
2215-
" for (var j = 0; j < i; j++) {\r\n" +
2216-
" newItems.push(childAt(list, j));\r\n" +
2217-
" }\r\n" +
2218-
" }\r\n" +
2219-
"\r\n" +
2220-
" if (newItems) {\r\n" +
2221-
" newItems.push(newItem);\r\n" +
2222-
" }\r\n" +
2223-
" }\r\n" +
2224-
"\r\n" +
2225-
" // Debug.assert(newItems === undefined || newItems.length === childCount(list));\r\n" +
2226-
" return !newItems ? list : Syntax.separatedList<T>(newItems);\r\n" +
2227-
" }\r\n";
2205+
"\r\n"
22282206

22292207
for (var i = 0; i < definitions.length; i++) {
22302208
var definition = definitions[i];
@@ -2256,12 +2234,9 @@ function generateRewriter(): string {
22562234
if (child.isToken) {
22572235
result += "this.visitToken(node." + child.name + ")";
22582236
}
2259-
else if (child.isList) {
2237+
else if (child.isList || child.isSeparatedList) {
22602238
result += "this.visitList(node." + child.name + ")";
22612239
}
2262-
else if (child.isSeparatedList) {
2263-
result += "this.visitSeparatedList(node." + child.name + ")";
2264-
}
22652240
else if (child.type === "SyntaxKind") {
22662241
result += "node.kind";
22672242
}
@@ -2318,17 +2293,7 @@ function generateWalker(): string {
23182293
" list[i].accept(this);\r\n" +
23192294
" }\r\n" +
23202295
" }\r\n" +
2321-
"\r\n" +
2322-
" public visitSeparatedList(list: ISyntaxNodeOrToken[]): void {\r\n" +
2323-
" for (var i = 0, n = separatedListChildCount(list); i < n; i++) {\r\n" +
2324-
" if (i % 2 === 0) {\r\n" +
2325-
" list[i >> 1].accept(this);\r\n" +
2326-
" }\r\n" +
2327-
" else {\r\n" +
2328-
" this.visitToken(list.separators[i >> 1]);\r\n" +
2329-
" }\r\n" +
2330-
" }\r\n" +
2331-
" }\r\n";
2296+
"\r\n";
23322297

23332298
for (var i = 0; i < definitions.length; i++) {
23342299
var definition = definitions[i];
@@ -2347,12 +2312,9 @@ function generateWalker(): string {
23472312
result += " this.visitToken(node." + child.name + ");\r\n";
23482313
}
23492314
}
2350-
else if (child.isList) {
2315+
else if (child.isList || child.isSeparatedList) {
23512316
result += " this.visitList(node." + child.name + ");\r\n";
23522317
}
2353-
else if (child.isSeparatedList) {
2354-
result += " this.visitSeparatedList(node." + child.name + ");\r\n";
2355-
}
23562318
else if (isNodeOrToken(child)) {
23572319
if (child.isOptional) {
23582320
result += " visitNodeOrToken(this, node." + child.name + ");\r\n";
@@ -2721,15 +2683,6 @@ function generateIsTypeScriptSpecific(): string {
27212683

27222684
result += "module TypeScript {\r\n";
27232685

2724-
result += " function isSeparatedListTypeScriptSpecific(list: ISyntaxNodeOrToken[]): boolean {\r\n"
2725-
result += " for (var i = 0, n = list.childCount(); i < n; i++) {\r\n";
2726-
result += " if (isTypeScriptSpecific(list.childAt(i))) {\r\n";
2727-
result += " return true;\r\n";
2728-
result += " }\r\n";
2729-
result += " }\r\n\r\n";
2730-
result += " return false;\r\n";
2731-
result += " }\r\n\r\n";
2732-
27332686
result += " function isListTypeScriptSpecific(list: ISyntaxNodeOrToken[]): boolean {\r\n"
27342687
result += " for (var i = 0, n = list.length; i < n; i++) {\r\n";
27352688
result += " if (isTypeScriptSpecific(list[i])) {\r\n";
@@ -2743,7 +2696,6 @@ function generateIsTypeScriptSpecific(): string {
27432696
result += " if (!element) { return false; }\r\n";
27442697
result += " if (isToken(element)) { return false; }\r\n";
27452698
result += " if (isList(element)) { return isListTypeScriptSpecific(<ISyntaxNodeOrToken[]>element); }\r\n";
2746-
result += " if (isSeparatedList(element)) { return isSeparatedListTypeScriptSpecific(<ISyntaxNodeOrToken[]>element); }\r\n\r\n";
27472699
result += " switch (element.kind()) {\r\n";
27482700

27492701
for (var i = 0; i < definitions.length; i++) {
@@ -2850,12 +2802,9 @@ function generateIsTypeScriptSpecificMethod(definition: ITypeDefinition): string
28502802
addedCheck = true;
28512803

28522804
if (child.isTypeScriptSpecific) {
2853-
if (child.isList) {
2805+
if (child.isList || child.isSeparatedList) {
28542806
result += getPropertyAccess(child, "node") + ".length > 0";
28552807
}
2856-
else if (child.isSeparatedList) {
2857-
result += getPropertyAccess(child, "node") + ".childCount() > 0";
2858-
}
28592808
else {
28602809
result += "!!" + getPropertyAccess(child, "node");
28612810
}

src/services/syntax/syntaxKind.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ module TypeScript {
55
// Variable width tokens, trivia and lists.
66
None,
77
List,
8-
SeparatedList,
9-
TriviaList,
108

119
// Trivia
1210
WhitespaceTrivia,

0 commit comments

Comments
 (0)