Skip to content

Commit

Permalink
Add support for trailing commas in more places
Browse files Browse the repository at this point in the history
This lets the parser understand trailing commas in method calls, method
definitions, enum variants, and type parameters.

Closes rust-lang#14240.
Closes rust-lang#15887.
  • Loading branch information
ftxqxd committed Aug 22, 2014
1 parent eaf810a commit fde41a3
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 20 deletions.
43 changes: 25 additions & 18 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ use std::collections::HashSet;
use std::mem::replace;
use std::rc::Rc;
use std::gc::{Gc, GC};
use std::iter;

#[allow(non_camel_case_types)]
#[deriving(PartialEq)]
Expand Down Expand Up @@ -762,20 +763,26 @@ impl<'a> Parser<'a> {
sep: Option<token::Token>,
f: |&mut Parser| -> T)
-> OwnedSlice<T> {
let mut first = true;
let mut v = Vec::new();
while self.token != token::GT
&& self.token != token::BINOP(token::SHR)
&& self.token != token::GE
&& self.token != token::BINOPEQ(token::SHR) {
match sep {
Some(ref t) => {
if first { first = false; }
else { self.expect(t); }
}
_ => ()
// This loop works by alternating back and forth between parsing types
// and commas. For example, given a string `A, B,>`, the parser would
// first parse `A`, then a comma, then `B`, then a comma. After that it
// would encounter a `>` and stop. This lets the parser handle trailing
// commas in generic parameters, because it can stop either after
// parsing a type or after parsing a comma.
for i in iter::count(0u, 1) {
if self.token == token::GT
|| self.token == token::BINOP(token::SHR)
|| self.token == token::GE
|| self.token == token::BINOPEQ(token::SHR) {
break;
}

if i % 2 == 0 {
v.push(f(self));
} else {
sep.as_ref().map(|t| self.expect(t));
}
v.push(f(self));
}
return OwnedSlice::from_vec(v);
}
Expand Down Expand Up @@ -2266,7 +2273,7 @@ impl<'a> Parser<'a> {
let mut es = self.parse_unspanned_seq(
&token::LPAREN,
&token::RPAREN,
seq_sep_trailing_disallowed(token::COMMA),
seq_sep_trailing_allowed(token::COMMA),
|p| p.parse_expr()
);
hi = self.last_span.hi;
Expand Down Expand Up @@ -3196,7 +3203,7 @@ impl<'a> Parser<'a> {
args = self.parse_enum_variant_seq(
&token::LPAREN,
&token::RPAREN,
seq_sep_trailing_disallowed(token::COMMA),
seq_sep_trailing_allowed(token::COMMA),
|p| p.parse_pat()
);
pat = PatEnum(enum_path, Some(args));
Expand Down Expand Up @@ -4068,7 +4075,7 @@ impl<'a> Parser<'a> {
match self.token {
token::COMMA => {
self.bump();
let sep = seq_sep_trailing_disallowed(token::COMMA);
let sep = seq_sep_trailing_allowed(token::COMMA);
let mut fn_inputs = self.parse_seq_to_before_end(
&token::RPAREN,
sep,
Expand All @@ -4091,7 +4098,7 @@ impl<'a> Parser<'a> {

let fn_inputs = match explicit_self {
SelfStatic => {
let sep = seq_sep_trailing_disallowed(token::COMMA);
let sep = seq_sep_trailing_allowed(token::COMMA);
self.parse_seq_to_before_end(&token::RPAREN, sep, parse_arg_fn)
}
SelfValue(id) => parse_remaining_arguments!(id),
Expand Down Expand Up @@ -4128,7 +4135,7 @@ impl<'a> Parser<'a> {
self.parse_optional_unboxed_closure_kind();
let args = self.parse_seq_to_before_end(
&token::BINOP(token::OR),
seq_sep_trailing_disallowed(token::COMMA),
seq_sep_trailing_allowed(token::COMMA),
|p| p.parse_fn_block_arg()
);
self.bump();
Expand Down Expand Up @@ -4950,7 +4957,7 @@ impl<'a> Parser<'a> {
let arg_tys = self.parse_enum_variant_seq(
&token::LPAREN,
&token::RPAREN,
seq_sep_trailing_disallowed(token::COMMA),
seq_sep_trailing_allowed(token::COMMA),
|p| p.parse_ty(true)
);
for ty in arg_tys.move_iter() {
Expand Down
26 changes: 24 additions & 2 deletions src/test/run-pass/trailing-comma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,31 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn f(_: int,) {}
fn f<T,>(_: T,) {}

struct Foo<T,>;

struct Bar;

impl Bar {
fn f(_: int,) {}
fn g(self, _: int,) {}
fn h(self,) {}
}

enum Baz {
Qux(int,),
}

pub fn main() {
f(0i,);
f::<int,>(0i,);
let (_, _,) = (1i, 1i,);

let x: Foo<int,> = Foo::<int,>;

Bar::f(0i,);
Bar.g(0i,);
Bar.h();

let x = Qux(1,);
}

1 comment on commit fde41a3

@alexcrichton
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r+, thanks!

Please sign in to comment.