Implement optional trailing commas (#97)

This commit is contained in:
Alan Pierce 2018-05-06 17:16:26 -07:00 committed by Daniel Wirtz
parent 25a1f6230a
commit 00fee73022
4 changed files with 148 additions and 88 deletions

View File

@ -967,6 +967,7 @@ export class ASTBuilder {
this.serializeDecorator(decorators[i]); this.serializeDecorator(decorators[i]);
} }
} }
this.serializeExternalModifiers(node);
this.serializeAccessModifiers(node); this.serializeAccessModifiers(node);
if (node.name.text.length) { if (node.name.text.length) {
sb.push("function "); sb.push("function ");

View File

@ -819,18 +819,20 @@ export class Parser extends DiagnosticEmitter {
return null; return null;
} }
var members = new Array<EnumValueDeclaration>(); var members = new Array<EnumValueDeclaration>();
if (!tn.skip(Token.CLOSEBRACE)) { while (!tn.skip(Token.CLOSEBRACE)) {
do { let member = this.parseEnumValue(tn, CommonFlags.NONE);
let member = this.parseEnumValue(tn, CommonFlags.NONE); if (!member) return null;
if (!member) return null; members.push(<EnumValueDeclaration>member);
members.push(<EnumValueDeclaration>member); if (!tn.skip(Token.COMMA)) {
} while (tn.skip(Token.COMMA)); if (tn.skip(Token.CLOSEBRACE)) {
if (!tn.skip(Token.CLOSEBRACE)) { break;
this.error( } else {
DiagnosticCode._0_expected, this.error(
tn.range(), "}" DiagnosticCode._0_expected,
); tn.range(), "}"
return null; );
return null;
}
} }
} }
var ret = Node.createEnumDeclaration( var ret = Node.createEnumDeclaration(
@ -899,20 +901,23 @@ export class Parser extends DiagnosticEmitter {
// at '<': TypeParameter (',' TypeParameter)* '>' // at '<': TypeParameter (',' TypeParameter)* '>'
var typeParameters = new Array<TypeParameterNode>(); var typeParameters = new Array<TypeParameterNode>();
if (!tn.skip(Token.GREATERTHAN)) { while (!tn.skip(Token.GREATERTHAN)) {
do { let typeParameter = this.parseTypeParameter(tn);
let typeParameter = this.parseTypeParameter(tn); if (!typeParameter) return null;
if (!typeParameter) return null; typeParameters.push(<TypeParameterNode>typeParameter);
typeParameters.push(<TypeParameterNode>typeParameter); if (!tn.skip(Token.COMMA)) {
} while (tn.skip(Token.COMMA)); if (tn.skip(Token.GREATERTHAN)) {
if (!tn.skip(Token.GREATERTHAN)) { break;
this.error( } else {
DiagnosticCode._0_expected, this.error(
tn.range(), ">" DiagnosticCode._0_expected,
); tn.range(), ">"
return null; );
return null;
}
} }
} else { }
if (typeParameters.length === 0) {
this.error( this.error(
DiagnosticCode.Type_parameter_list_cannot_be_empty, DiagnosticCode.Type_parameter_list_cannot_be_empty,
tn.range() tn.range()
@ -971,45 +976,47 @@ export class Parser extends DiagnosticEmitter {
var seenOptional = false; var seenOptional = false;
var reportedRest = false; var reportedRest = false;
if (tn.peek() != Token.CLOSEPAREN) { while (!tn.skip(Token.CLOSEPAREN)) {
do { let param = this.parseParameter(tn, isConstructor);
let param = this.parseParameter(tn, isConstructor); if (!param) return null;
if (!param) return null; if (seenRest && !reportedRest) {
if (seenRest && !reportedRest) { this.error(
DiagnosticCode.A_rest_parameter_must_be_last_in_a_parameter_list,
seenRest.name.range
);
reportedRest = true;
}
switch (param.parameterKind) {
default: {
if (seenOptional) {
this.error(
DiagnosticCode.A_required_parameter_cannot_follow_an_optional_parameter,
param.name.range
);
}
break;
}
case ParameterKind.OPTIONAL: {
seenOptional = true;
break;
}
case ParameterKind.REST: {
seenRest = param;
break;
}
}
parameters.push(param);
if (!tn.skip(Token.COMMA)) {
if (tn.skip(Token.CLOSEPAREN)) {
break;
} else {
this.error( this.error(
DiagnosticCode.A_rest_parameter_must_be_last_in_a_parameter_list, DiagnosticCode._0_expected,
seenRest.name.range tn.range(), ")"
); );
reportedRest = true; return null;
} }
switch (param.parameterKind) { }
default: {
if (seenOptional) {
this.error(
DiagnosticCode.A_required_parameter_cannot_follow_an_optional_parameter,
param.name.range
);
}
break;
}
case ParameterKind.OPTIONAL: {
seenOptional = true;
break;
}
case ParameterKind.REST: {
seenRest = param;
break;
}
}
parameters.push(param);
} while (tn.skip(Token.COMMA));
}
if (!tn.skip(Token.CLOSEPAREN)) {
this.error(
DiagnosticCode._0_expected,
tn.range(), ")"
);
return null;
} }
return parameters; return parameters;
} }
@ -2877,23 +2884,24 @@ export class Parser extends DiagnosticEmitter {
// ArrayLiteralExpression // ArrayLiteralExpression
case Token.OPENBRACKET: { case Token.OPENBRACKET: {
let elementExpressions = new Array<Expression | null>(); let elementExpressions = new Array<Expression | null>();
if (!tn.skip(Token.CLOSEBRACKET)) { while (!tn.skip(Token.CLOSEBRACKET)) {
do { if (tn.peek() == Token.COMMA) {
if (tn.peek() == Token.COMMA) { expr = null; // omitted
expr = null; // omitted } else {
expr = this.parseExpression(tn, Precedence.COMMA + 1);
if (!expr) return null;
}
elementExpressions.push(expr);
if (!tn.skip(Token.COMMA)) {
if (tn.skip(Token.CLOSEBRACKET)) {
break;
} else { } else {
expr = this.parseExpression(tn, Precedence.COMMA + 1); this.error(
if (!expr) return null; DiagnosticCode._0_expected,
tn.range(), "]"
);
return null;
} }
elementExpressions.push(expr);
if (tn.peek() == Token.CLOSEBRACKET) break;
} while (tn.skip(Token.COMMA));
if (!tn.skip(Token.CLOSEBRACKET)) {
this.error(
DiagnosticCode._0_expected,
tn.range(), "]"
);
return null;
} }
} }
return Node.createArrayLiteralExpression(elementExpressions, tn.range(startPos, tn.pos)); return Node.createArrayLiteralExpression(elementExpressions, tn.range(startPos, tn.pos));
@ -2979,6 +2987,9 @@ export class Parser extends DiagnosticEmitter {
if (!tn.skip(Token.LESSTHAN)) return null; if (!tn.skip(Token.LESSTHAN)) return null;
var typeArguments = new Array<CommonTypeNode>(); var typeArguments = new Array<CommonTypeNode>();
do { do {
if (tn.peek() === Token.GREATERTHAN) {
break;
}
let type = this.parseType(tn, true, true); let type = this.parseType(tn, true, true);
if (!type) { if (!type) {
tn.reset(state); tn.reset(state);
@ -3000,18 +3011,20 @@ export class Parser extends DiagnosticEmitter {
// at '(': (Expression (',' Expression)*)? ')' // at '(': (Expression (',' Expression)*)? ')'
var args = new Array<Expression>(); var args = new Array<Expression>();
if (!tn.skip(Token.CLOSEPAREN)) { while (!tn.skip(Token.CLOSEPAREN)) {
do { let expr = this.parseExpression(tn, Precedence.COMMA + 1);
let expr = this.parseExpression(tn, Precedence.COMMA + 1); if (!expr) return null;
if (!expr) return null; args.push(expr);
args.push(expr); if (!tn.skip(Token.COMMA)) {
} while (tn.skip(Token.COMMA)); if (tn.skip(Token.CLOSEPAREN)) {
if (!tn.skip(Token.CLOSEPAREN)) { break;
this.error( } else {
DiagnosticCode._0_expected, this.error(
tn.range(), ")" DiagnosticCode._0_expected,
); tn.range(), ")"
return null; );
return null;
}
} }
} }
return args; return args;

View File

@ -0,0 +1,33 @@
enum Foo {
A,
B,
}
function add(
x: i32,
y: i32,
): i32 {
return x + y;
}
function parameterized<
A,
B,
>(a: A, b: B): void {
}
export function compute(): i32 {
const arr: Array<i8> = [
1,
2,
];
parameterized<
i8,
// @ts-ignore: Waiting on https://github.com/Microsoft/TypeScript/issues/21984
i32,
>(0, 0);
return add(
1,
2,
);
}

View File

@ -0,0 +1,13 @@
enum Foo {
A,
B
}
function add(x: i32, y: i32): i32 {
return x + y;
}
function parameterized<A, B>(a: A, b: B): void {}
export function compute(): i32 {
const arr: Array<i8> = [1, 2];
parameterized<i8, i32>(0, 0);
return add(1, 2);
}