Skip to content

Commit 00fee73

Browse files
alangpiercedcodeIO
authored andcommitted
Implement optional trailing commas (AssemblyScript#97)
1 parent 25a1f62 commit 00fee73

File tree

4 files changed

+148
-88
lines changed

4 files changed

+148
-88
lines changed

src/extra/ast.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -967,6 +967,7 @@ export class ASTBuilder {
967967
this.serializeDecorator(decorators[i]);
968968
}
969969
}
970+
this.serializeExternalModifiers(node);
970971
this.serializeAccessModifiers(node);
971972
if (node.name.text.length) {
972973
sb.push("function ");

src/parser.ts

Lines changed: 101 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -819,18 +819,20 @@ export class Parser extends DiagnosticEmitter {
819819
return null;
820820
}
821821
var members = new Array<EnumValueDeclaration>();
822-
if (!tn.skip(Token.CLOSEBRACE)) {
823-
do {
824-
let member = this.parseEnumValue(tn, CommonFlags.NONE);
825-
if (!member) return null;
826-
members.push(<EnumValueDeclaration>member);
827-
} while (tn.skip(Token.COMMA));
828-
if (!tn.skip(Token.CLOSEBRACE)) {
829-
this.error(
830-
DiagnosticCode._0_expected,
831-
tn.range(), "}"
832-
);
833-
return null;
822+
while (!tn.skip(Token.CLOSEBRACE)) {
823+
let member = this.parseEnumValue(tn, CommonFlags.NONE);
824+
if (!member) return null;
825+
members.push(<EnumValueDeclaration>member);
826+
if (!tn.skip(Token.COMMA)) {
827+
if (tn.skip(Token.CLOSEBRACE)) {
828+
break;
829+
} else {
830+
this.error(
831+
DiagnosticCode._0_expected,
832+
tn.range(), "}"
833+
);
834+
return null;
835+
}
834836
}
835837
}
836838
var ret = Node.createEnumDeclaration(
@@ -899,20 +901,23 @@ export class Parser extends DiagnosticEmitter {
899901
// at '<': TypeParameter (',' TypeParameter)* '>'
900902

901903
var typeParameters = new Array<TypeParameterNode>();
902-
if (!tn.skip(Token.GREATERTHAN)) {
903-
do {
904-
let typeParameter = this.parseTypeParameter(tn);
905-
if (!typeParameter) return null;
906-
typeParameters.push(<TypeParameterNode>typeParameter);
907-
} while (tn.skip(Token.COMMA));
908-
if (!tn.skip(Token.GREATERTHAN)) {
909-
this.error(
910-
DiagnosticCode._0_expected,
911-
tn.range(), ">"
912-
);
913-
return null;
904+
while (!tn.skip(Token.GREATERTHAN)) {
905+
let typeParameter = this.parseTypeParameter(tn);
906+
if (!typeParameter) return null;
907+
typeParameters.push(<TypeParameterNode>typeParameter);
908+
if (!tn.skip(Token.COMMA)) {
909+
if (tn.skip(Token.GREATERTHAN)) {
910+
break;
911+
} else {
912+
this.error(
913+
DiagnosticCode._0_expected,
914+
tn.range(), ">"
915+
);
916+
return null;
917+
}
914918
}
915-
} else {
919+
}
920+
if (typeParameters.length === 0) {
916921
this.error(
917922
DiagnosticCode.Type_parameter_list_cannot_be_empty,
918923
tn.range()
@@ -971,45 +976,47 @@ export class Parser extends DiagnosticEmitter {
971976
var seenOptional = false;
972977
var reportedRest = false;
973978

974-
if (tn.peek() != Token.CLOSEPAREN) {
975-
do {
976-
let param = this.parseParameter(tn, isConstructor);
977-
if (!param) return null;
978-
if (seenRest && !reportedRest) {
979+
while (!tn.skip(Token.CLOSEPAREN)) {
980+
let param = this.parseParameter(tn, isConstructor);
981+
if (!param) return null;
982+
if (seenRest && !reportedRest) {
983+
this.error(
984+
DiagnosticCode.A_rest_parameter_must_be_last_in_a_parameter_list,
985+
seenRest.name.range
986+
);
987+
reportedRest = true;
988+
}
989+
switch (param.parameterKind) {
990+
default: {
991+
if (seenOptional) {
992+
this.error(
993+
DiagnosticCode.A_required_parameter_cannot_follow_an_optional_parameter,
994+
param.name.range
995+
);
996+
}
997+
break;
998+
}
999+
case ParameterKind.OPTIONAL: {
1000+
seenOptional = true;
1001+
break;
1002+
}
1003+
case ParameterKind.REST: {
1004+
seenRest = param;
1005+
break;
1006+
}
1007+
}
1008+
parameters.push(param);
1009+
if (!tn.skip(Token.COMMA)) {
1010+
if (tn.skip(Token.CLOSEPAREN)) {
1011+
break;
1012+
} else {
9791013
this.error(
980-
DiagnosticCode.A_rest_parameter_must_be_last_in_a_parameter_list,
981-
seenRest.name.range
1014+
DiagnosticCode._0_expected,
1015+
tn.range(), ")"
9821016
);
983-
reportedRest = true;
984-
}
985-
switch (param.parameterKind) {
986-
default: {
987-
if (seenOptional) {
988-
this.error(
989-
DiagnosticCode.A_required_parameter_cannot_follow_an_optional_parameter,
990-
param.name.range
991-
);
992-
}
993-
break;
994-
}
995-
case ParameterKind.OPTIONAL: {
996-
seenOptional = true;
997-
break;
998-
}
999-
case ParameterKind.REST: {
1000-
seenRest = param;
1001-
break;
1002-
}
1017+
return null;
10031018
}
1004-
parameters.push(param);
1005-
} while (tn.skip(Token.COMMA));
1006-
}
1007-
if (!tn.skip(Token.CLOSEPAREN)) {
1008-
this.error(
1009-
DiagnosticCode._0_expected,
1010-
tn.range(), ")"
1011-
);
1012-
return null;
1019+
}
10131020
}
10141021
return parameters;
10151022
}
@@ -2877,23 +2884,24 @@ export class Parser extends DiagnosticEmitter {
28772884
// ArrayLiteralExpression
28782885
case Token.OPENBRACKET: {
28792886
let elementExpressions = new Array<Expression | null>();
2880-
if (!tn.skip(Token.CLOSEBRACKET)) {
2881-
do {
2882-
if (tn.peek() == Token.COMMA) {
2883-
expr = null; // omitted
2887+
while (!tn.skip(Token.CLOSEBRACKET)) {
2888+
if (tn.peek() == Token.COMMA) {
2889+
expr = null; // omitted
2890+
} else {
2891+
expr = this.parseExpression(tn, Precedence.COMMA + 1);
2892+
if (!expr) return null;
2893+
}
2894+
elementExpressions.push(expr);
2895+
if (!tn.skip(Token.COMMA)) {
2896+
if (tn.skip(Token.CLOSEBRACKET)) {
2897+
break;
28842898
} else {
2885-
expr = this.parseExpression(tn, Precedence.COMMA + 1);
2886-
if (!expr) return null;
2899+
this.error(
2900+
DiagnosticCode._0_expected,
2901+
tn.range(), "]"
2902+
);
2903+
return null;
28872904
}
2888-
elementExpressions.push(expr);
2889-
if (tn.peek() == Token.CLOSEBRACKET) break;
2890-
} while (tn.skip(Token.COMMA));
2891-
if (!tn.skip(Token.CLOSEBRACKET)) {
2892-
this.error(
2893-
DiagnosticCode._0_expected,
2894-
tn.range(), "]"
2895-
);
2896-
return null;
28972905
}
28982906
}
28992907
return Node.createArrayLiteralExpression(elementExpressions, tn.range(startPos, tn.pos));
@@ -2979,6 +2987,9 @@ export class Parser extends DiagnosticEmitter {
29792987
if (!tn.skip(Token.LESSTHAN)) return null;
29802988
var typeArguments = new Array<CommonTypeNode>();
29812989
do {
2990+
if (tn.peek() === Token.GREATERTHAN) {
2991+
break;
2992+
}
29822993
let type = this.parseType(tn, true, true);
29832994
if (!type) {
29842995
tn.reset(state);
@@ -3000,18 +3011,20 @@ export class Parser extends DiagnosticEmitter {
30003011
// at '(': (Expression (',' Expression)*)? ')'
30013012

30023013
var args = new Array<Expression>();
3003-
if (!tn.skip(Token.CLOSEPAREN)) {
3004-
do {
3005-
let expr = this.parseExpression(tn, Precedence.COMMA + 1);
3006-
if (!expr) return null;
3007-
args.push(expr);
3008-
} while (tn.skip(Token.COMMA));
3009-
if (!tn.skip(Token.CLOSEPAREN)) {
3010-
this.error(
3011-
DiagnosticCode._0_expected,
3012-
tn.range(), ")"
3013-
);
3014-
return null;
3014+
while (!tn.skip(Token.CLOSEPAREN)) {
3015+
let expr = this.parseExpression(tn, Precedence.COMMA + 1);
3016+
if (!expr) return null;
3017+
args.push(expr);
3018+
if (!tn.skip(Token.COMMA)) {
3019+
if (tn.skip(Token.CLOSEPAREN)) {
3020+
break;
3021+
} else {
3022+
this.error(
3023+
DiagnosticCode._0_expected,
3024+
tn.range(), ")"
3025+
);
3026+
return null;
3027+
}
30153028
}
30163029
}
30173030
return args;

tests/parser/trailing-commas.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
enum Foo {
2+
A,
3+
B,
4+
}
5+
6+
function add(
7+
x: i32,
8+
y: i32,
9+
): i32 {
10+
return x + y;
11+
}
12+
13+
function parameterized<
14+
A,
15+
B,
16+
>(a: A, b: B): void {
17+
}
18+
19+
export function compute(): i32 {
20+
const arr: Array<i8> = [
21+
1,
22+
2,
23+
];
24+
parameterized<
25+
i8,
26+
// @ts-ignore: Waiting on https://github.com/Microsoft/TypeScript/issues/21984
27+
i32,
28+
>(0, 0);
29+
return add(
30+
1,
31+
2,
32+
);
33+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
enum Foo {
2+
A,
3+
B
4+
}
5+
function add(x: i32, y: i32): i32 {
6+
return x + y;
7+
}
8+
function parameterized<A, B>(a: A, b: B): void {}
9+
export function compute(): i32 {
10+
const arr: Array<i8> = [1, 2];
11+
parameterized<i8, i32>(0, 0);
12+
return add(1, 2);
13+
}

0 commit comments

Comments
 (0)