Skip to content

Commit

Permalink
auto merge of #16646 : P1start/rust/trailing-commas, r=alexcrichton
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 #14240.
Closes #15887.
  • Loading branch information
bors committed Aug 24, 2014
2 parents 9e8c30c + fde41a3 commit 6d9b219
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,);
}

0 comments on commit 6d9b219

Please sign in to comment.