diff options
Diffstat (limited to 'crates/parser/src/grammar/params.rs')
-rw-r--r-- | crates/parser/src/grammar/params.rs | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/crates/parser/src/grammar/params.rs b/crates/parser/src/grammar/params.rs new file mode 100644 index 000000000..a665ffc13 --- /dev/null +++ b/crates/parser/src/grammar/params.rs | |||
@@ -0,0 +1,188 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use super::*; | ||
4 | |||
5 | // test param_list | ||
6 | // fn a() {} | ||
7 | // fn b(x: i32) {} | ||
8 | // fn c(x: i32, ) {} | ||
9 | // fn d(x: i32, y: ()) {} | ||
10 | pub(super) fn param_list_fn_def(p: &mut Parser) { | ||
11 | list_(p, Flavor::FnDef) | ||
12 | } | ||
13 | |||
14 | // test param_list_opt_patterns | ||
15 | // fn foo<F: FnMut(&mut Foo<'a>)>(){} | ||
16 | pub(super) fn param_list_fn_trait(p: &mut Parser) { | ||
17 | list_(p, Flavor::FnTrait) | ||
18 | } | ||
19 | |||
20 | pub(super) fn param_list_fn_ptr(p: &mut Parser) { | ||
21 | list_(p, Flavor::FnPointer) | ||
22 | } | ||
23 | |||
24 | pub(super) fn param_list_closure(p: &mut Parser) { | ||
25 | list_(p, Flavor::Closure) | ||
26 | } | ||
27 | |||
28 | #[derive(Debug, Clone, Copy)] | ||
29 | enum Flavor { | ||
30 | FnDef, // Includes trait fn params; omitted param idents are not supported | ||
31 | FnTrait, // Params for `Fn(...)`/`FnMut(...)`/`FnOnce(...)` annotations | ||
32 | FnPointer, | ||
33 | Closure, | ||
34 | } | ||
35 | |||
36 | fn list_(p: &mut Parser, flavor: Flavor) { | ||
37 | use Flavor::*; | ||
38 | |||
39 | let (bra, ket) = match flavor { | ||
40 | Closure => (T![|], T![|]), | ||
41 | FnDef | FnTrait | FnPointer => (T!['('], T![')']), | ||
42 | }; | ||
43 | |||
44 | let m = p.start(); | ||
45 | p.bump(bra); | ||
46 | |||
47 | if let FnDef = flavor { | ||
48 | // test self_param_outer_attr | ||
49 | // fn f(#[must_use] self) {} | ||
50 | attributes::outer_attrs(p); | ||
51 | opt_self_param(p); | ||
52 | } | ||
53 | |||
54 | while !p.at(EOF) && !p.at(ket) { | ||
55 | // test param_outer_arg | ||
56 | // fn f(#[attr1] pat: Type) {} | ||
57 | attributes::outer_attrs(p); | ||
58 | |||
59 | if !p.at_ts(PARAM_FIRST) { | ||
60 | p.error("expected value parameter"); | ||
61 | break; | ||
62 | } | ||
63 | let param = param(p, flavor); | ||
64 | if !p.at(ket) { | ||
65 | p.expect(T![,]); | ||
66 | } | ||
67 | if let Variadic(true) = param { | ||
68 | break; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | p.expect(ket); | ||
73 | m.complete(p, PARAM_LIST); | ||
74 | } | ||
75 | |||
76 | const PARAM_FIRST: TokenSet = patterns::PATTERN_FIRST.union(types::TYPE_FIRST); | ||
77 | |||
78 | struct Variadic(bool); | ||
79 | |||
80 | fn param(p: &mut Parser, flavor: Flavor) -> Variadic { | ||
81 | let mut res = Variadic(false); | ||
82 | let m = p.start(); | ||
83 | match flavor { | ||
84 | // test param_list_vararg | ||
85 | // extern "C" { fn printf(format: *const i8, ...) -> i32; } | ||
86 | Flavor::FnDef | Flavor::FnPointer if p.eat(T![...]) => res = Variadic(true), | ||
87 | |||
88 | // test fn_def_param | ||
89 | // fn foo((x, y): (i32, i32)) {} | ||
90 | Flavor::FnDef => { | ||
91 | patterns::pattern(p); | ||
92 | if variadic_param(p) { | ||
93 | res = Variadic(true) | ||
94 | } else { | ||
95 | types::ascription(p); | ||
96 | } | ||
97 | } | ||
98 | // test value_parameters_no_patterns | ||
99 | // type F = Box<Fn(i32, &i32, &i32, ())>; | ||
100 | Flavor::FnTrait => { | ||
101 | types::type_(p); | ||
102 | } | ||
103 | // test fn_pointer_param_ident_path | ||
104 | // type Foo = fn(Bar::Baz); | ||
105 | // type Qux = fn(baz: Bar::Baz); | ||
106 | |||
107 | // test fn_pointer_unnamed_arg | ||
108 | // type Foo = fn(_: bar); | ||
109 | Flavor::FnPointer => { | ||
110 | if (p.at(IDENT) || p.at(UNDERSCORE)) && p.nth(1) == T![:] && !p.nth_at(1, T![::]) { | ||
111 | patterns::pattern_single(p); | ||
112 | if variadic_param(p) { | ||
113 | res = Variadic(true) | ||
114 | } else { | ||
115 | types::ascription(p); | ||
116 | } | ||
117 | } else { | ||
118 | types::type_(p); | ||
119 | } | ||
120 | } | ||
121 | // test closure_params | ||
122 | // fn main() { | ||
123 | // let foo = |bar, baz: Baz, qux: Qux::Quux| (); | ||
124 | // } | ||
125 | Flavor::Closure => { | ||
126 | patterns::pattern_single(p); | ||
127 | if p.at(T![:]) && !p.at(T![::]) { | ||
128 | types::ascription(p); | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | m.complete(p, PARAM); | ||
133 | res | ||
134 | } | ||
135 | |||
136 | fn variadic_param(p: &mut Parser) -> bool { | ||
137 | if p.at(T![:]) && p.nth_at(1, T![...]) { | ||
138 | p.bump(T![:]); | ||
139 | p.bump(T![...]); | ||
140 | true | ||
141 | } else { | ||
142 | false | ||
143 | } | ||
144 | } | ||
145 | |||
146 | // test self_param | ||
147 | // impl S { | ||
148 | // fn a(self) {} | ||
149 | // fn b(&self,) {} | ||
150 | // fn c(&'a self,) {} | ||
151 | // fn d(&'a mut self, x: i32) {} | ||
152 | // fn e(mut self) {} | ||
153 | // } | ||
154 | fn opt_self_param(p: &mut Parser) { | ||
155 | let m; | ||
156 | if p.at(T![self]) || p.at(T![mut]) && p.nth(1) == T![self] { | ||
157 | m = p.start(); | ||
158 | p.eat(T![mut]); | ||
159 | p.eat(T![self]); | ||
160 | // test arb_self_types | ||
161 | // impl S { | ||
162 | // fn a(self: &Self) {} | ||
163 | // fn b(mut self: Box<Self>) {} | ||
164 | // } | ||
165 | if p.at(T![:]) { | ||
166 | types::ascription(p); | ||
167 | } | ||
168 | } else { | ||
169 | let la1 = p.nth(1); | ||
170 | let la2 = p.nth(2); | ||
171 | let la3 = p.nth(3); | ||
172 | let n_toks = match (p.current(), la1, la2, la3) { | ||
173 | (T![&], T![self], _, _) => 2, | ||
174 | (T![&], T![mut], T![self], _) => 3, | ||
175 | (T![&], LIFETIME, T![self], _) => 3, | ||
176 | (T![&], LIFETIME, T![mut], T![self]) => 4, | ||
177 | _ => return, | ||
178 | }; | ||
179 | m = p.start(); | ||
180 | for _ in 0..n_toks { | ||
181 | p.bump_any(); | ||
182 | } | ||
183 | } | ||
184 | m.complete(p, SELF_PARAM); | ||
185 | if !p.at(T![')']) { | ||
186 | p.expect(T![,]); | ||
187 | } | ||
188 | } | ||