Skip to content

Commit de2ac51

Browse files
committed
Change NodeArray to have a hasTrailingComma property instead of an OmittedExpression
1 parent ac88d8d commit de2ac51

16 files changed

+62
-41
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4141,8 +4141,12 @@ module ts {
41414141
// illegal, and will cause a parse error.
41424142
// Note: It may be worth keeping the upper bound check on arity, but removing
41434143
// the lower bound check if there are omitted expressions.
4144-
if (!isCorrect && forEach(node.arguments, arg => arg.kind === SyntaxKind.OmittedExpression)) {
4145-
return true;
4144+
if (!isCorrect) {
4145+
// Technically this type assertion is not safe because args could be initialized to emptyArray
4146+
// above.
4147+
if ((<NodeArray<Node>>args).hasTrailingComma || forEach(args, arg => arg.kind === SyntaxKind.OmittedExpression)) {
4148+
return true;
4149+
}
41464150
}
41474151
return isCorrect;
41484152
}

src/compiler/emitter.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,18 +824,29 @@ module ts {
824824
}
825825
}
826826

827+
function emitTrailingCommaIfPresent(nodeList: NodeArray<Node>, isMultiline: boolean): void {
828+
if (nodeList.hasTrailingComma) {
829+
write(",");
830+
if (isMultiline) {
831+
writeLine();
832+
}
833+
}
834+
}
835+
827836
function emitArrayLiteral(node: ArrayLiteral) {
828837
if (node.flags & NodeFlags.MultiLine) {
829838
write("[");
830839
increaseIndent();
831840
emitMultiLineList(node.elements);
841+
emitTrailingCommaIfPresent(node.elements, /*isMultiline*/ true);
832842
decreaseIndent();
833843
writeLine();
834844
write("]");
835845
}
836846
else {
837847
write("[");
838848
emitCommaList(node.elements);
849+
emitTrailingCommaIfPresent(node.elements, /*isMultiline*/ false);
839850
write("]");
840851
}
841852
}
@@ -848,13 +859,23 @@ module ts {
848859
write("{");
849860
increaseIndent();
850861
emitMultiLineList(node.properties);
862+
863+
if (compilerOptions.target === ScriptTarget.ES5) {
864+
emitTrailingCommaIfPresent(node.properties, /*isMultiline*/ true);
865+
}
866+
851867
decreaseIndent();
852868
writeLine();
853869
write("}");
854870
}
855871
else {
856872
write("{ ");
857873
emitCommaList(node.properties);
874+
875+
if (compilerOptions.target === ScriptTarget.ES5) {
876+
emitTrailingCommaIfPresent(node.properties, /*isMultiline*/ false);
877+
}
878+
858879
write(" }");
859880
}
860881
}

src/compiler/parser.ts

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,7 +1197,7 @@ module ts {
11971197
}
11981198

11991199
// Parses a comma-delimited list of elements
1200-
function parseDelimitedList<T extends Node>(kind: ParsingContext, parseElement: () => T, allowTrailingComma: boolean, preserveTrailingComma: boolean): NodeArray<T> {
1200+
function parseDelimitedList<T extends Node>(kind: ParsingContext, parseElement: () => T, allowTrailingComma: boolean): NodeArray<T> {
12011201
var saveParsingContext = parsingContext;
12021202
parsingContext |= 1 << kind;
12031203
var result = <NodeArray<T>>[];
@@ -1228,11 +1228,8 @@ module ts {
12281228
grammarErrorAtPos(commaStart, scanner.getStartPos() - commaStart, Diagnostics.Trailing_comma_not_allowed);
12291229
}
12301230
}
1231-
// Even if we reported an error because of a disallowed trailing comma, we still may
1232-
// need to preserve it for the checker so that signature help can work well.
1233-
if (preserveTrailingComma) {
1234-
result.push(<T>createNode(SyntaxKind.OmittedExpression));
1235-
}
1231+
// Always preserve a trailing comma by marking it on the NodeArray
1232+
result.hasTrailingComma = true;
12361233
}
12371234

12381235
break;
@@ -1267,7 +1264,7 @@ module ts {
12671264

12681265
function parseBracketedList<T extends Node>(kind: ParsingContext, parseElement: () => T, startToken: SyntaxKind, endToken: SyntaxKind): NodeArray<T> {
12691266
if (parseExpected(startToken)) {
1270-
var result = parseDelimitedList(kind, parseElement, /*allowTrailingComma*/ false, /*preserveTrailingComma*/ false);
1267+
var result = parseDelimitedList(kind, parseElement, /*allowTrailingComma*/ false);
12711268
parseExpected(endToken);
12721269
return result;
12731270
}
@@ -2307,7 +2304,7 @@ module ts {
23072304
// needs evidence of a trailing comma in order to give good results for signature help.
23082305
// That is why we do not allow a trailing comma, but we "preserve" a trailing comma.
23092306
callExpr.arguments = parseDelimitedList(ParsingContext.ArgumentExpressions,
2310-
parseArgumentExpression, /*allowTrailingComma*/ false, /*preserveTrailingComma*/ true);
2307+
parseArgumentExpression, /*allowTrailingComma*/ false);
23112308
parseExpected(SyntaxKind.CloseParenToken);
23122309
expr = finishNode(callExpr);
23132310
continue;
@@ -2402,7 +2399,7 @@ module ts {
24022399
parseExpected(SyntaxKind.OpenBracketToken);
24032400
if (scanner.hasPrecedingLineBreak()) node.flags |= NodeFlags.MultiLine;
24042401
node.elements = parseDelimitedList(ParsingContext.ArrayLiteralMembers,
2405-
parseArrayLiteralElement, /*allowTrailingComma*/ true, /*preserveTrailingComma*/ true);
2402+
parseArrayLiteralElement, /*allowTrailingComma*/ true);
24062403
parseExpected(SyntaxKind.CloseBracketToken);
24072404
return finishNode(node);
24082405
}
@@ -2444,10 +2441,7 @@ module ts {
24442441
node.flags |= NodeFlags.MultiLine;
24452442
}
24462443

2447-
// ES3 itself does not accept a trailing comma in an object literal, however, we'd like to preserve it in ES5.
2448-
var preserveTrailingComma = languageVersion !== ScriptTarget.ES3;
2449-
2450-
node.properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralMember, /*allowTrailingComma*/ true, preserveTrailingComma);
2444+
node.properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralMember, /*allowTrailingComma*/ true);
24512445
parseExpected(SyntaxKind.CloseBraceToken);
24522446

24532447
var seen: Map<SymbolFlags> = {};
@@ -2540,7 +2534,7 @@ module ts {
25402534
// needs evidence of a trailing comma in order to give good results for signature help.
25412535
// That is why we do not allow a trailing comma, but we "preserve" a trailing comma.
25422536
node.arguments = parseDelimitedList(ParsingContext.ArgumentExpressions,
2543-
parseArgumentExpression, /*allowTrailingComma*/ false, /*preserveTrailingComma*/ true);
2537+
parseArgumentExpression, /*allowTrailingComma*/ false);
25442538
parseExpected(SyntaxKind.CloseParenToken);
25452539
}
25462540
return finishNode(node);
@@ -3110,7 +3104,7 @@ module ts {
31103104

31113105
function parseVariableDeclarationList(flags: NodeFlags, noIn?: boolean): NodeArray<VariableDeclaration> {
31123106
return parseDelimitedList(ParsingContext.VariableDeclarations,
3113-
() => parseVariableDeclaration(flags, noIn), /*allowTrailingComma*/ false, /*preserveTrailingComma*/ false);
3107+
() => parseVariableDeclaration(flags, noIn), /*allowTrailingComma*/ false);
31143108
}
31153109

31163110
function parseVariableStatement(pos?: number, flags?: NodeFlags): VariableStatement {
@@ -3510,7 +3504,7 @@ module ts {
35103504
if (parseOptional(SyntaxKind.ImplementsKeyword)) {
35113505
implementsKeywordLength = scanner.getStartPos() - implementsKeywordStart;
35123506
node.implementedTypes = parseDelimitedList(ParsingContext.BaseTypeReferences,
3513-
parseTypeReference, /*allowTrailingComma*/ false, /*preserveTrailingComma*/ false);
3507+
parseTypeReference, /*allowTrailingComma*/ false);
35143508
}
35153509
var errorCountBeforeClassBody = file.syntacticErrors.length;
35163510
if (parseExpected(SyntaxKind.OpenBraceToken)) {
@@ -3539,7 +3533,7 @@ module ts {
35393533
if (parseOptional(SyntaxKind.ExtendsKeyword)) {
35403534
extendsKeywordLength = scanner.getStartPos() - extendsKeywordStart;
35413535
node.baseTypes = parseDelimitedList(ParsingContext.BaseTypeReferences,
3542-
parseTypeReference, /*allowTrailingComma*/ false, /*preserveTrailingComma*/ false);
3536+
parseTypeReference, /*allowTrailingComma*/ false);
35433537
}
35443538
var errorCountBeforeInterfaceBody = file.syntacticErrors.length;
35453539
node.members = parseTypeLiteral().members;
@@ -3604,7 +3598,7 @@ module ts {
36043598
node.name = parseIdentifier();
36053599
if (parseExpected(SyntaxKind.OpenBraceToken)) {
36063600
node.members = parseDelimitedList(ParsingContext.EnumMembers,
3607-
parseAndCheckEnumMember, /*allowTrailingComma*/ true, /*preserveTrailingComma*/ false);
3601+
parseAndCheckEnumMember, /*allowTrailingComma*/ true);
36083602
parseExpected(SyntaxKind.CloseBraceToken);
36093603
}
36103604
else {

src/compiler/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,9 @@ module ts {
259259
localSymbol?: Symbol; // Local symbol declared by node (initialized by binding only for exported nodes)
260260
}
261261

262-
export interface NodeArray<T> extends Array<T>, TextRange { }
262+
export interface NodeArray<T> extends Array<T>, TextRange {
263+
hasTrailingComma?: boolean;
264+
}
263265

264266
export interface Identifier extends Node {
265267
text: string; // Text of identifier (with escapes converted to characters)

tests/baselines/reference/castExpressionParentheses.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ new (<any>A());
4343
// parentheses should be omitted
4444
// literals
4545
{ a: 0 };
46-
[1, 3, ];
46+
[1, 3,];
4747
"string";
4848
23.0;
4949
/regexp/g;

tests/baselines/reference/emptyExpr.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
[{},]
33

44
//// [emptyExpr.js]
5-
[{}, ];
5+
[{},];

tests/baselines/reference/parserArrayLiteralExpression10.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
var v = [1,1,];
33

44
//// [parserArrayLiteralExpression10.js]
5-
var v = [1, 1, ];
5+
var v = [1, 1,];

tests/baselines/reference/parserArrayLiteralExpression15.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
var v = [,,1,1,,1,,1,1,,1,];
33

44
//// [parserArrayLiteralExpression15.js]
5-
var v = [, , 1, 1, , 1, , 1, 1, , 1, ];
5+
var v = [, , 1, 1, , 1, , 1, 1, , 1,];

tests/baselines/reference/parserArrayLiteralExpression2.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
var v = [,];
33

44
//// [parserArrayLiteralExpression2.js]
5-
var v = [, ];
5+
var v = [,];

tests/baselines/reference/parserArrayLiteralExpression3.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
var v = [,,];
33

44
//// [parserArrayLiteralExpression3.js]
5-
var v = [, , ];
5+
var v = [, ,];

0 commit comments

Comments
 (0)