ret spanned(lo, t.span.hi, {mode: mode, ty: t});
}
let inputs =
- parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA),
+ parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
parse_fn_input_ty, p);
// FIXME: there's no syntax for this right now anyway
// auto constrs = parse_constrs(~[], p);
}
}
let meths =
- parse_seq(token::LBRACE, token::RBRACE, none, parse_method_sig, p);
+ parse_seq(token::LBRACE, token::RBRACE, seq_sep_none(),
+ parse_method_sig, p);
ret ast::ty_obj(meths.node);
}
let lo = p.get_lo_pos();
let path = parse_path(p);
let args: {node: [@ast::constr_arg], span: span} =
- parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA),
+ parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
{|p| parse_constr_arg(fn_args, p)}, p);
ret @spanned(lo, args.span.hi,
{path: path, args: args.node, id: p.get_id()});
let lo = p.get_lo_pos();
let path = parse_path(p);
let args: [@ast::ty_constr_arg] =
- parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA),
+ parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
parse_type_constr_arg, p).node;
let hi = p.get_lo_pos();
let tc: ast::ty_constr_ = {path: path, args: args, id: p.get_id()};
t = ast::ty_ptr(parse_mt(p));
} else if p.peek() == token::LBRACE {
let elems =
- parse_seq(token::LBRACE, token::RBRACE, some(token::COMMA),
+ parse_seq(token::LBRACE, token::RBRACE, seq_sep_opt(token::COMMA),
parse_ty_field, p);
let hi = elems.span.hi;
t = ast::ty_rec(elems.node);
ret spanned(lo, hi, result);
}
-fn parse_seq_to_end<copy T>(ket: token::token, sep: option::t<token::token>,
+fn parse_seq_to_end<copy T>(ket: token::token, sep: seq_sep,
f: block(parser) -> T, p: parser) -> [T] {
let val = parse_seq_to_before_end(ket, sep, f, p);
p.bump();
ret val;
}
+type seq_sep = {
+ sep: option::t<token::token>,
+ trailing_opt: bool // is trailing separator optional?
+};
+
+fn seq_sep(t: token::token) -> seq_sep {
+ ret {sep: option::some(t), trailing_opt: false};
+}
+fn seq_sep_opt(t: token::token) -> seq_sep {
+ ret {sep: option::some(t), trailing_opt: true};
+}
+fn seq_sep_none() -> seq_sep {
+ ret {sep: option::none, trailing_opt: false};
+}
+
fn parse_seq_to_before_end<copy T>(ket: token::token,
- sep: option::t<token::token>,
+ sep: seq_sep,
f: block(parser) -> T, p: parser) -> [T] {
let first: bool = true;
let v: [T] = [];
while p.peek() != ket {
- alt sep {
+ alt sep.sep {
some(t) { if first { first = false; } else { expect(p, t); } }
_ { }
}
+ if sep.trailing_opt && p.peek() == ket { break; }
v += [f(p)];
}
ret v;
fn parse_seq<copy T>(bra: token::token, ket: token::token,
- sep: option::t<token::token>, f: block(parser) -> T,
+ sep: seq_sep, f: block(parser) -> T,
p: parser) -> spanned<[T]> {
let lo = p.get_lo_pos();
expect(p, bra);
while p.peek() != token::RBRACE {
if eat_word(p, "with") { base = some(parse_expr(p)); break; }
expect(p, token::COMMA);
+ if p.peek() == token::RBRACE {
+ // record ends by an optional trailing comma
+ break;
+ }
fields += [parse_field(p, token::COLON)];
}
hi = p.get_hi_pos();
p.bump();
let mut = parse_mutability(p);
let es =
- parse_seq_to_end(token::RBRACKET, some(token::COMMA), parse_expr,
- p);
+ parse_seq_to_end(token::RBRACKET, seq_sep(token::COMMA),
+ parse_expr, p);
ex = ast::expr_vec(es, mut);
} else if p.peek() == token::POUND_LT {
p.bump();
if p.peek() == token::LPAREN {
p.bump();
fields =
- some(parse_seq_to_end(token::RPAREN, some(token::COMMA),
+ some(parse_seq_to_end(token::RPAREN, seq_sep(token::COMMA),
parse_anon_obj_field, p));
}
let meths: [@ast::method] = [];
}
}
let es =
- parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA),
+ parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
parse_expr_opt, p);
hi = es.span.hi;
ex = ast::expr_bind(e, es.node);
// The rest is a call expression.
let f: @ast::expr = parse_self_method(p);
let es =
- parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA),
+ parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
parse_expr, p);
hi = es.span.hi;
ex = ast::expr_call(f, es.node, false);
p.fatal("expected a syntax expander name");
}
//temporary for a backwards-compatible cycle:
+ let sep = seq_sep(token::COMMA);
let es =
if p.peek() == token::LPAREN {
- parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA),
- parse_expr, p)
+ parse_seq(token::LPAREN, token::RPAREN, sep, parse_expr, p)
} else {
- parse_seq(token::LBRACKET, token::RBRACKET, some(token::COMMA),
- parse_expr, p)
+ parse_seq(token::LBRACKET, token::RBRACKET, sep, parse_expr, p)
};
let hi = es.span.hi;
let e = mk_expr(p, es.span.lo, hi, ast::expr_vec(es.node, ast::imm));
} else {
// Call expr.
let es = parse_seq(token::LPAREN, token::RPAREN,
- some(token::COMMA), parse_expr, p);
+ seq_sep(token::COMMA), parse_expr, p);
hi = es.span.hi;
let nd = ast::expr_call(e, es.node, false);
e = mk_expr(p, lo, hi, nd);
token::LPAREN. {
let a =
parse_seq(token::LPAREN, token::RPAREN,
- some(token::COMMA), parse_pat, p);
+ seq_sep(token::COMMA), parse_pat, p);
args = a.node;
hi = a.span.hi;
}
fn parse_fn_decl(p: parser, purity: ast::purity, il: ast::inlineness) ->
ast::fn_decl {
let inputs: ast::spanned<[ast::arg]> =
- parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA), parse_arg,
- p);
+ parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
+ parse_arg, p);
// Use the args list to translate each bound variable
// mentioned in a constraint to an arg index.
// Seems weird to do this in the parser, but I'm not sure how else to.
[]
} else {
parse_seq(token::BINOP(token::OR), token::BINOP(token::OR),
- some(token::COMMA), parse_fn_block_arg, p).node
+ seq_sep(token::COMMA), parse_fn_block_arg, p).node
};
ret {inputs: inputs,
output: @spanned(p.get_lo_pos(), p.get_hi_pos(), ast::ty_infer),
let ident = parse_value_ident(p);
let ty_params = parse_ty_params(p);
let fields: ast::spanned<[ast::obj_field]> =
- parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA),
+ parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
parse_obj_field, p);
let meths: [@ast::method] = [];
expect(p, token::LBRACE);
alt p.peek() {
token::LPAREN. {
let arg_tys = parse_seq(token::LPAREN, token::RPAREN,
- some(token::COMMA),
+ seq_sep(token::COMMA),
{|p| parse_ty(p, false)}, p);
for ty: @ast::ty in arg_tys.node {
args += [{ty: ty, id: p.get_id()}];
}
fn parse_meta_seq(p: parser) -> [@ast::meta_item] {
- ret parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA),
+ ret parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
parse_meta_item, p).node;
}
ret spanned(lo, hi, {name: ident, id: p.get_id()});
}
let from_idents_ =
- parse_seq(token::LBRACE, token::RBRACE, some(token::COMMA),
+ parse_seq(token::LBRACE, token::RBRACE, seq_sep(token::COMMA),
parse_import_ident, p).node;
if vec::is_empty(from_idents_) {
p.fatal("at least one import is required");
fn parse_export(p: parser) -> ast::view_item_ {
let ids =
- parse_seq_to_before_end(token::SEMI, option::some(token::COMMA),
+ parse_seq_to_before_end(token::SEMI, seq_sep(token::COMMA),
parse_ident, p);
ret ast::view_item_export(ids, p.get_id());
}