aboutsummaryrefslogtreecommitdiff
path: root/crates/libsyntax2/src/grammar/params.rs
blob: 32e905cb22497640efcd5342beb0b96587695043 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use super::*;

// test param_list
// fn a() {}
// fn b(x: i32) {}
// fn c(x: i32, ) {}
// fn d(x: i32, y: ()) {}
pub(super) fn param_list(p: &mut Parser) {
    list_(p, Flavor::Normal)
}

// test param_list_opt_patterns
// fn foo<F: FnMut(&mut Foo<'a>)>(){}
pub(super) fn param_list_opt_patterns(p: &mut Parser) {
    list_(p, Flavor::OptionalPattern)
}

pub(super) fn param_list_opt_types(p: &mut Parser) {
    list_(p, Flavor::OptionalType)
}

#[derive(Clone, Copy, Eq, PartialEq)]
enum Flavor {
    OptionalType,
    OptionalPattern,
    Normal,
}

impl Flavor {
    fn type_required(self) -> bool {
        match self {
            Flavor::OptionalType => false,
            _ => true,
        }
    }
}

fn list_(p: &mut Parser, flavor: Flavor) {
    let (bra, ket) = if flavor.type_required() {
        (L_PAREN, R_PAREN)
    } else {
        (PIPE, PIPE)
    };
    assert!(p.at(bra));
    let m = p.start();
    p.bump();
    if flavor.type_required() {
        self_param(p);
    }
    while !p.at(EOF) && !p.at(ket) {
        value_parameter(p, flavor);
        if !p.at(ket) {
            p.expect(COMMA);
        }
    }
    p.expect(ket);
    m.complete(p, PARAM_LIST);
}

fn value_parameter(p: &mut Parser, flavor: Flavor) {
    let m = p.start();
    match flavor {
        Flavor::OptionalType | Flavor::Normal => {
            patterns::pattern(p);
            if p.at(COLON) || flavor.type_required() {
                types::ascription(p)
            }
        },
        // test value_parameters_no_patterns
        // type F = Box<Fn(a: i32, &b: &i32, &mut c: &i32, ())>;
        Flavor::OptionalPattern => {
            let la0 = p.current();
            let la1 = p.nth(1);
            let la2 = p.nth(2);
            let la3 = p.nth(3);
            if la0 == IDENT && la1 == COLON
                || la0 == AMP && la1 == IDENT && la2 == COLON
                || la0 == AMP && la1 == MUT_KW && la2 == IDENT && la3 == COLON {
                patterns::pattern(p);
                types::ascription(p);
            } else {
                types::type_(p);
            }
        },
    }
    m.complete(p, PARAM);
}

// test self_param
// impl S {
//     fn a(self) {}
//     fn b(&self,) {}
//     fn c(&'a self,) {}
//     fn d(&'a mut self, x: i32) {}
// }
fn self_param(p: &mut Parser) {
    let la1 = p.nth(1);
    let la2 = p.nth(2);
    let la3 = p.nth(3);
    let n_toks = match (p.current(), la1, la2, la3) {
        (SELF_KW, _, _, _) => 1,
        (AMP, SELF_KW, _, _) => 2,
        (AMP, MUT_KW, SELF_KW, _) => 3,
        (AMP, LIFETIME, SELF_KW, _) => 3,
        (AMP, LIFETIME, MUT_KW, SELF_KW) => 4,
        _ => return,
    };
    let m = p.start();
    for _ in 0..n_toks {
        p.bump();
    }
    m.complete(p, SELF_PARAM);
    if !p.at(R_PAREN) {
        p.expect(COMMA);
    }
}