use super::*;
pub(super) fn param_list_fn_def(p: &mut Parser) {
list_(p, Flavor::FnDef)
}
pub(super) fn param_list_fn_trait(p: &mut Parser) {
list_(p, Flavor::FnTrait)
}
pub(super) fn param_list_fn_ptr(p: &mut Parser) {
list_(p, Flavor::FnPointer)
}
pub(super) fn param_list_closure(p: &mut Parser) {
list_(p, Flavor::Closure)
}
#[derive(Debug, Clone, Copy)]
enum Flavor {
FnDef, FnTrait, FnPointer,
Closure,
}
fn list_(p: &mut Parser, flavor: Flavor) {
use Flavor::*;
let (bra, ket) = match flavor {
Closure => (T![|], T![|]),
FnDef | FnTrait | FnPointer => (T!['('], T![')']),
};
let m = p.start();
p.bump(bra);
if let FnDef = flavor {
attributes::outer_attrs(p);
opt_self_param(p);
}
while !p.at(EOF) && !p.at(ket) {
attributes::outer_attrs(p);
if !p.at_ts(PARAM_FIRST) {
p.error("expected value parameter");
break;
}
let param = param(p, flavor);
if !p.at(ket) {
p.expect(T![,]);
}
if let Variadic(true) = param {
break;
}
}
p.expect(ket);
m.complete(p, PARAM_LIST);
}
const PARAM_FIRST: TokenSet = patterns::PATTERN_FIRST.union(types::TYPE_FIRST);
struct Variadic(bool);
fn param(p: &mut Parser, flavor: Flavor) -> Variadic {
let mut res = Variadic(false);
let m = p.start();
match flavor {
Flavor::FnDef | Flavor::FnPointer if p.eat(T![...]) => res = Variadic(true),
Flavor::FnDef => {
patterns::pattern(p);
if variadic_param(p) {
res = Variadic(true)
} else {
types::ascription(p);
}
}
Flavor::FnTrait => {
types::type_(p);
}
Flavor::FnPointer => {
if (p.at(IDENT) || p.at(UNDERSCORE)) && p.nth(1) == T![:] && !p.nth_at(1, T![::]) {
patterns::pattern_single(p);
if variadic_param(p) {
res = Variadic(true)
} else {
types::ascription(p);
}
} else {
types::type_(p);
}
}
Flavor::Closure => {
patterns::pattern_single(p);
if p.at(T![:]) && !p.at(T![::]) {
types::ascription(p);
}
}
}
m.complete(p, PARAM);
res
}
fn variadic_param(p: &mut Parser) -> bool {
if p.at(T![:]) && p.nth_at(1, T![...]) {
p.bump(T![:]);
p.bump(T![...]);
true
} else {
false
}
}
fn opt_self_param(p: &mut Parser) {
let m;
if p.at(T![self]) || p.at(T![mut]) && p.nth(1) == T![self] {
m = p.start();
p.eat(T![mut]);
p.eat(T![self]);
if p.at(T![:]) {
types::ascription(p);
}
} else {
let la1 = p.nth(1);
let la2 = p.nth(2);
let la3 = p.nth(3);
let n_toks = match (p.current(), la1, la2, la3) {
(T![&], T![self], _, _) => 2,
(T![&], T![mut], T![self], _) => 3,
(T![&], LIFETIME, T![self], _) => 3,
(T![&], LIFETIME, T![mut], T![self]) => 4,
_ => return,
};
m = p.start();
for _ in 0..n_toks {
p.bump_any();
}
}
m.complete(p, SELF_PARAM);
if !p.at(T![')']) {
p.expect(T![,]);
}
}