aboutsummaryrefslogtreecommitdiff
path: root/crates/parser/src/grammar/params.rs
blob: 5a78675fb4fbaeadb34bf382b41e5dfdedeade66 (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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
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_fn_def(p: &mut Parser) {
    list_(p, Flavor::FnDef)
}

// test param_list_opt_patterns
// fn foo<F: FnMut(&mut Foo<'a>)>(){}
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,   // Includes trait fn params; omitted param idents are not supported
    FnTrait, // Params for `Fn(...)`/`FnMut(...)`/`FnOnce(...)` annotations
    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 list_marker = p.start();
    p.bump(bra);

    let mut param_marker = None;
    if let FnDef = flavor {
        // test self_param_outer_attr
        // fn f(#[must_use] self) {}
        let m = p.start();
        attributes::outer_attrs(p);
        match opt_self_param(p, m) {
            Ok(()) => {}
            Err(m) => param_marker = Some(m),
        }
    }

    while !p.at(EOF) && !p.at(ket) {
        // test param_outer_arg
        // fn f(#[attr1] pat: Type) {}
        let m = match param_marker.take() {
            Some(m) => m,
            None => {
                let m = p.start();
                attributes::outer_attrs(p);
                m
            }
        };

        if !p.at_ts(PARAM_FIRST) {
            p.error("expected value parameter");
            m.abandon(p);
            break;
        }
        let param = param(p, m, flavor);
        if !p.at(ket) {
            p.expect(T![,]);
        }
        if let Variadic(true) = param {
            break;
        }
    }

    if let Some(m) = param_marker {
        m.abandon(p);
    }

    p.expect(ket);
    list_marker.complete(p, PARAM_LIST);
}

const PARAM_FIRST: TokenSet = patterns::PATTERN_FIRST.union(types::TYPE_FIRST);

struct Variadic(bool);

fn param(p: &mut Parser, m: Marker, flavor: Flavor) -> Variadic {
    let mut res = Variadic(false);
    match flavor {
        // test param_list_vararg
        // extern "C" { fn printf(format: *const i8, ...) -> i32; }
        Flavor::FnDef | Flavor::FnPointer if p.eat(T![...]) => res = Variadic(true),

        // test fn_def_param
        // fn foo((x, y): (i32, i32)) {}
        Flavor::FnDef => {
            patterns::pattern(p);
            if variadic_param(p) {
                res = Variadic(true)
            } else {
                types::ascription(p);
            }
        }
        // test value_parameters_no_patterns
        // type F = Box<Fn(i32, &i32, &i32, ())>;
        Flavor::FnTrait => {
            types::type_(p);
        }
        // test fn_pointer_param_ident_path
        // type Foo = fn(Bar::Baz);
        // type Qux = fn(baz: Bar::Baz);

        // test fn_pointer_unnamed_arg
        // type Foo = fn(_: bar);
        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);
            }
        }
        // test closure_params
        // fn main() {
        //    let foo = |bar, baz: Baz, qux: Qux::Quux| ();
        // }
        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
    }
}

// test self_param
// impl S {
//     fn a(self) {}
//     fn b(&self,) {}
//     fn c(&'a self,) {}
//     fn d(&'a mut self, x: i32) {}
//     fn e(mut self) {}
// }
fn opt_self_param(p: &mut Parser, m: Marker) -> Result<(), Marker> {
    if p.at(T![self]) || p.at(T![mut]) && p.nth(1) == T![self] {
        p.eat(T![mut]);
        self_as_name(p);
        // test arb_self_types
        // impl S {
        //     fn a(self: &Self) {}
        //     fn b(mut self: Box<Self>) {}
        // }
        if p.at(T![:]) {
            types::ascription(p);
        }
    } else {
        let la1 = p.nth(1);
        let la2 = p.nth(2);
        let la3 = p.nth(3);
        if !matches!(
            (p.current(), la1, la2, la3),
            (T![&], T![self], _, _)
                | (T![&], T![mut] | LIFETIME_IDENT, T![self], _)
                | (T![&], LIFETIME_IDENT, T![mut], T![self])
        ) {
            return Err(m);
        }
        p.bump(T![&]);
        if p.at(LIFETIME_IDENT) {
            lifetime(p);
        }
        p.eat(T![mut]);
        self_as_name(p);
    }
    m.complete(p, SELF_PARAM);
    if !p.at(T![')']) {
        p.expect(T![,]);
    }
    Ok(())
}

fn self_as_name(p: &mut Parser) {
    let m = p.start();
    p.bump(T![self]);
    m.complete(p, NAME);
}