aboutsummaryrefslogtreecommitdiff
path: root/src/grammar
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-07-31 21:38:19 +0100
committerAleksey Kladov <[email protected]>2018-07-31 21:44:31 +0100
commit7912189ec304b28c4df0030b5282cf3d21074154 (patch)
tree03a0a1b128439fdefbd1d012b392995ca8a6e264 /src/grammar
parentd1400e95d7ad701fcba1191cb00968c2eae8b394 (diff)
reorganize
Diffstat (limited to 'src/grammar')
-rw-r--r--src/grammar/attributes.rs79
-rw-r--r--src/grammar/expressions.rs284
-rw-r--r--src/grammar/items/consts.rs20
-rw-r--r--src/grammar/items/mod.rs290
-rw-r--r--src/grammar/items/structs.rs116
-rw-r--r--src/grammar/items/traits.rs77
-rw-r--r--src/grammar/items/use_item.rs66
-rw-r--r--src/grammar/mod.rs141
-rw-r--r--src/grammar/params.rs70
-rw-r--r--src/grammar/paths.rs77
-rw-r--r--src/grammar/patterns.rs53
-rw-r--r--src/grammar/type_args.rs48
-rw-r--r--src/grammar/type_params.rs95
-rw-r--r--src/grammar/types.rs207
14 files changed, 1623 insertions, 0 deletions
diff --git a/src/grammar/attributes.rs b/src/grammar/attributes.rs
new file mode 100644
index 000000000..c411d4d7f
--- /dev/null
+++ b/src/grammar/attributes.rs
@@ -0,0 +1,79 @@
1use super::*;
2
3pub(super) fn inner_attributes(p: &mut Parser) {
4 while p.current() == POUND && p.nth(1) == EXCL {
5 attribute(p, true)
6 }
7}
8
9pub(super) fn outer_attributes(p: &mut Parser) {
10 while p.at(POUND) {
11 attribute(p, false)
12 }
13}
14
15fn attribute(p: &mut Parser, inner: bool) {
16 let attr = p.start();
17 assert!(p.at(POUND));
18 p.bump();
19
20 if inner {
21 assert!(p.at(EXCL));
22 p.bump();
23 }
24
25 if p.expect(L_BRACK) {
26 meta_item(p);
27 p.expect(R_BRACK);
28 }
29 attr.complete(p, ATTR);
30}
31
32fn meta_item(p: &mut Parser) {
33 if p.at(IDENT) {
34 let meta_item = p.start();
35 p.bump();
36 match p.current() {
37 EQ => {
38 p.bump();
39 if expressions::literal(p).is_none() {
40 p.error("expected literal");
41 }
42 }
43 L_PAREN => meta_item_arg_list(p),
44 _ => (),
45 }
46 meta_item.complete(p, META_ITEM);
47 } else {
48 p.error("expected attribute value");
49 }
50}
51
52fn meta_item_arg_list(p: &mut Parser) {
53 assert!(p.at(L_PAREN));
54 p.bump();
55 loop {
56 match p.current() {
57 EOF | R_PAREN => break,
58 IDENT => meta_item(p),
59 c => if expressions::literal(p).is_none() {
60 let message = "expected attribute";
61
62 if items::ITEM_FIRST.contains(c) {
63 p.error(message);
64 return;
65 }
66
67 let err = p.start();
68 p.error(message);
69 p.bump();
70 err.complete(p, ERROR);
71 continue;
72 },
73 }
74 if !p.at(R_PAREN) {
75 p.expect(COMMA);
76 }
77 }
78 p.expect(R_PAREN);
79}
diff --git a/src/grammar/expressions.rs b/src/grammar/expressions.rs
new file mode 100644
index 000000000..06f9105c6
--- /dev/null
+++ b/src/grammar/expressions.rs
@@ -0,0 +1,284 @@
1use super::*;
2
3// test expr_literals
4// fn foo() {
5// let _ = true;
6// let _ = false;
7// let _ = 1;
8// let _ = 2.0;
9// let _ = b'a';
10// let _ = 'b';
11// let _ = "c";
12// let _ = r"d";
13// let _ = b"e";
14// let _ = br"f";
15// }
16pub(super) fn literal(p: &mut Parser) -> Option<CompletedMarker> {
17 match p.current() {
18 TRUE_KW | FALSE_KW | INT_NUMBER | FLOAT_NUMBER | BYTE | CHAR | STRING | RAW_STRING
19 | BYTE_STRING | RAW_BYTE_STRING => {
20 let m = p.start();
21 p.bump();
22 Some(m.complete(p, LITERAL))
23 }
24 _ => None,
25 }
26}
27
28pub(super) fn expr(p: &mut Parser) {
29 let mut lhs = match prefix_expr(p) {
30 Some(lhs) => lhs,
31 None => return,
32 };
33
34 loop {
35 lhs = match p.current() {
36 L_PAREN => call_expr(p, lhs),
37 DOT if p.nth(1) == IDENT => if p.nth(2) == L_PAREN {
38 method_call_expr(p, lhs)
39 } else {
40 field_expr(p, lhs)
41 },
42 _ => break,
43 }
44 }
45}
46
47// test block
48// fn a() {}
49// fn b() { let _ = 1; }
50// fn c() { 1; 2; }
51// fn d() { 1; 2 }
52pub(super) fn block(p: &mut Parser) {
53 if !p.at(L_CURLY) {
54 p.error("expected block");
55 }
56 let m = p.start();
57 p.bump();
58 while !p.at(EOF) && !p.at(R_CURLY) {
59 match p.current() {
60 LET_KW => let_stmt(p),
61 c => {
62 // test block_items
63 // fn a() { fn b() {} }
64 if items::ITEM_FIRST.contains(c) {
65 items::item(p)
66 } else {
67 let expr_stmt = p.start();
68 expressions::expr(p);
69 if p.eat(SEMI) {
70 expr_stmt.complete(p, EXPR_STMT);
71 } else {
72 expr_stmt.abandon(p);
73 }
74 }
75 }
76 }
77 }
78 p.expect(R_CURLY);
79 m.complete(p, BLOCK);
80}
81
82// test let_stmt;
83// fn foo() {
84// let a;
85// let b: i32;
86// let c = 92;
87// let d: i32 = 92;
88// }
89fn let_stmt(p: &mut Parser) {
90 assert!(p.at(LET_KW));
91 let m = p.start();
92 p.bump();
93 patterns::pattern(p);
94 if p.at(COLON) {
95 types::ascription(p);
96 }
97 if p.eat(EQ) {
98 expressions::expr(p);
99 }
100 p.expect(SEMI);
101 m.complete(p, LET_STMT);
102}
103
104fn prefix_expr(p: &mut Parser) -> Option<CompletedMarker> {
105 match p.current() {
106 AMPERSAND => Some(ref_expr(p)),
107 STAR => Some(deref_expr(p)),
108 _ => atom_expr(p),
109 }
110}
111
112// test ref_expr
113// fn foo() {
114// let _ = &1;
115// let _ = &mut &f();
116// }
117fn ref_expr(p: &mut Parser) -> CompletedMarker {
118 assert!(p.at(AMPERSAND));
119 let m = p.start();
120 p.bump();
121 p.eat(MUT_KW);
122 expr(p);
123 m.complete(p, REF_EXPR)
124}
125
126// test deref_expr
127// fn foo() {
128// **&1;
129// }
130fn deref_expr(p: &mut Parser) -> CompletedMarker {
131 assert!(p.at(STAR));
132 let m = p.start();
133 p.bump();
134 expr(p);
135 m.complete(p, DEREF_EXPR)
136}
137
138fn atom_expr(p: &mut Parser) -> Option<CompletedMarker> {
139 match literal(p) {
140 Some(m) => return Some(m),
141 None => (),
142 }
143 if paths::is_path_start(p) {
144 return Some(path_expr(p));
145 }
146
147 match p.current() {
148 L_PAREN => Some(tuple_expr(p)),
149 PIPE => Some(lambda_expr(p)),
150 _ => {
151 p.err_and_bump("expected expression");
152 None
153 }
154 }
155}
156
157fn tuple_expr(p: &mut Parser) -> CompletedMarker {
158 assert!(p.at(L_PAREN));
159 let m = p.start();
160 p.expect(L_PAREN);
161 p.expect(R_PAREN);
162 m.complete(p, TUPLE_EXPR)
163}
164
165// test lambda_expr
166// fn foo() {
167// || ();
168// || -> i32 { 92 };
169// |x| x;
170// |x: i32,| x;
171// }
172fn lambda_expr(p: &mut Parser) -> CompletedMarker {
173 assert!(p.at(PIPE));
174 let m = p.start();
175 params::param_list_opt_types(p);
176 if fn_ret_type(p) {
177 block(p);
178 } else {
179 expr(p)
180 }
181 m.complete(p, LAMBDA_EXPR)
182}
183
184// test call_expr
185// fn foo() {
186// let _ = f();
187// let _ = f()(1)(1, 2,);
188// }
189fn call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
190 assert!(p.at(L_PAREN));
191 let m = lhs.precede(p);
192 arg_list(p);
193 m.complete(p, CALL_EXPR)
194}
195
196// test method_call_expr
197// fn foo() {
198// x.foo();
199// y.bar(1, 2,);
200// }
201fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
202 assert!(p.at(DOT) && p.nth(1) == IDENT && p.nth(2) == L_PAREN);
203 let m = lhs.precede(p);
204 p.bump();
205 p.bump();
206 arg_list(p);
207 m.complete(p, METHOD_CALL_EXPR)
208}
209
210// test field_expr
211// fn foo() {
212// x.foo.bar;
213// }
214fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
215 assert!(p.at(DOT) && p.nth(1) == IDENT);
216 let m = lhs.precede(p);
217 p.bump();
218 p.bump();
219 m.complete(p, FIELD_EXPR)
220}
221
222fn arg_list(p: &mut Parser) {
223 assert!(p.at(L_PAREN));
224 let m = p.start();
225 p.bump();
226 while !p.at(R_PAREN) && !p.at(EOF) {
227 expr(p);
228 if !p.at(R_PAREN) && !p.expect(COMMA) {
229 break;
230 }
231 }
232 p.eat(R_PAREN);
233 m.complete(p, ARG_LIST);
234}
235
236// test path_expr
237// fn foo() {
238// let _ = a;
239// let _ = a::b;
240// let _ = ::a::<b>;
241// }
242fn path_expr(p: &mut Parser) -> CompletedMarker {
243 assert!(paths::is_path_start(p));
244 let m = p.start();
245 paths::expr_path(p);
246 if p.at(L_CURLY) {
247 struct_lit(p);
248 m.complete(p, STRUCT_LIT)
249 } else {
250 m.complete(p, PATH_EXPR)
251 }
252}
253
254// test struct_lit
255// fn foo() {
256// S {};
257// S { x, y: 32, };
258// S { x, y: 32, ..Default::default() };
259// }
260fn struct_lit(p: &mut Parser) {
261 assert!(p.at(L_CURLY));
262 p.bump();
263 while !p.at(EOF) && !p.at(R_CURLY) {
264 match p.current() {
265 IDENT => {
266 let m = p.start();
267 name_ref(p);
268 if p.eat(COLON) {
269 expr(p);
270 }
271 m.complete(p, STRUCT_LIT_FIELD);
272 }
273 DOTDOT => {
274 p.bump();
275 expr(p);
276 }
277 _ => p.err_and_bump("expected identifier"),
278 }
279 if !p.at(R_CURLY) {
280 p.expect(COMMA);
281 }
282 }
283 p.expect(R_CURLY);
284}
diff --git a/src/grammar/items/consts.rs b/src/grammar/items/consts.rs
new file mode 100644
index 000000000..ca26a7814
--- /dev/null
+++ b/src/grammar/items/consts.rs
@@ -0,0 +1,20 @@
1use super::*;
2
3pub(super) fn static_item(p: &mut Parser) {
4 const_or_static(p, STATIC_KW)
5}
6
7pub(super) fn const_item(p: &mut Parser) {
8 const_or_static(p, CONST_KW)
9}
10
11fn const_or_static(p: &mut Parser, kw: SyntaxKind) {
12 assert!(p.at(kw));
13 p.bump();
14 p.eat(MUT_KW); // TODO: validator to forbid const mut
15 name(p);
16 types::ascription(p);
17 p.expect(EQ);
18 expressions::expr(p);
19 p.expect(SEMI);
20}
diff --git a/src/grammar/items/mod.rs b/src/grammar/items/mod.rs
new file mode 100644
index 000000000..d5f75f13d
--- /dev/null
+++ b/src/grammar/items/mod.rs
@@ -0,0 +1,290 @@
1use super::*;
2
3mod consts;
4mod structs;
5mod traits;
6mod use_item;
7
8pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) {
9 attributes::inner_attributes(p);
10 while !p.at(EOF) && !(stop_on_r_curly && p.at(R_CURLY)) {
11 item(p);
12 }
13}
14
15pub(super) const ITEM_FIRST: TokenSet =
16 token_set![EXTERN_KW, MOD_KW, USE_KW, STRUCT_KW, ENUM_KW, FN_KW, PUB_KW, POUND];
17
18pub(super) fn item(p: &mut Parser) {
19 let item = p.start();
20 attributes::outer_attributes(p);
21 visibility(p);
22 let la = p.nth(1);
23 let item_kind = match p.current() {
24 USE_KW => {
25 use_item::use_item(p);
26 USE_ITEM
27 }
28 // test extern_crate
29 // extern crate foo;
30 EXTERN_KW if la == CRATE_KW => {
31 extern_crate_item(p);
32 EXTERN_CRATE_ITEM
33 }
34 EXTERN_KW => {
35 abi(p);
36 match p.current() {
37 // test extern_fn
38 // extern fn foo() {}
39 FN_KW => {
40 fn_item(p);
41 FN_ITEM
42 }
43 // test extern_block
44 // extern {}
45 L_CURLY => {
46 extern_block(p);
47 EXTERN_BLOCK
48 }
49 // test extern_struct
50 // extern struct Foo;
51 _ => {
52 item.abandon(p);
53 p.error("expected `fn` or `{`");
54 return;
55 }
56 }
57 }
58 STATIC_KW => {
59 consts::static_item(p);
60 STATIC_ITEM
61 }
62 CONST_KW => match p.nth(1) {
63 // test const_fn
64 // const fn foo() {}
65 FN_KW => {
66 p.bump();
67 fn_item(p);
68 FN_ITEM
69 }
70 // test const_unsafe_fn
71 // const unsafe fn foo() {}
72 UNSAFE_KW if p.nth(2) == FN_KW => {
73 p.bump();
74 p.bump();
75 fn_item(p);
76 FN_ITEM
77 }
78 _ => {
79 consts::const_item(p);
80 CONST_ITEM
81 }
82 },
83 UNSAFE_KW => {
84 p.bump();
85 let la = p.nth(1);
86 match p.current() {
87 // test unsafe_trait
88 // unsafe trait T {}
89 TRAIT_KW => {
90 traits::trait_item(p);
91 TRAIT_ITEM
92 }
93
94 // test unsafe_auto_trait
95 // unsafe auto trait T {}
96 IDENT if p.at_contextual_kw("auto") && la == TRAIT_KW => {
97 p.bump_remap(AUTO_KW);
98 traits::trait_item(p);
99 TRAIT_ITEM
100 }
101
102 // test unsafe_impl
103 // unsafe impl Foo {}
104 IMPL_KW => {
105 traits::impl_item(p);
106 IMPL_ITEM
107 }
108
109 // test unsafe_default_impl
110 // unsafe default impl Foo {}
111 IDENT if p.at_contextual_kw("default") && la == IMPL_KW => {
112 p.bump_remap(DEFAULT_KW);
113 traits::impl_item(p);
114 IMPL_ITEM
115 }
116
117 // test unsafe_extern_fn
118 // unsafe extern "C" fn foo() {}
119 EXTERN_KW => {
120 abi(p);
121 if !p.at(FN_KW) {
122 item.abandon(p);
123 p.error("expected function");
124 return;
125 }
126 fn_item(p);
127 FN_ITEM
128 }
129
130 // test unsafe_fn
131 // unsafe fn foo() {}
132 FN_KW => {
133 fn_item(p);
134 FN_ITEM
135 }
136
137 t => {
138 item.abandon(p);
139 let message = "expected `trait`, `impl` or `fn`";
140
141 // test unsafe_block_in_mod
142 // fn foo(){} unsafe { } fn bar(){}
143 if t == L_CURLY {
144 error_block(p, message);
145 } else {
146 p.error(message);
147 }
148 return;
149 }
150 }
151 }
152 TRAIT_KW => {
153 traits::trait_item(p);
154 TRAIT_ITEM
155 }
156 // test auto_trait
157 // auto trait T {}
158 IDENT if p.at_contextual_kw("auto") && la == TRAIT_KW => {
159 p.bump_remap(AUTO_KW);
160 traits::trait_item(p);
161 TRAIT_ITEM
162 }
163 IMPL_KW => {
164 traits::impl_item(p);
165 IMPL_ITEM
166 }
167 // test default_impl
168 // default impl Foo {}
169 IDENT if p.at_contextual_kw("default") && la == IMPL_KW => {
170 p.bump_remap(DEFAULT_KW);
171 traits::impl_item(p);
172 IMPL_ITEM
173 }
174
175 FN_KW => {
176 fn_item(p);
177 FN_ITEM
178 }
179 TYPE_KW => {
180 type_item(p);
181 TYPE_ITEM
182 }
183 MOD_KW => {
184 mod_item(p);
185 MOD_ITEM
186 }
187 STRUCT_KW => {
188 structs::struct_item(p);
189 STRUCT_ITEM
190 }
191 ENUM_KW => {
192 structs::enum_item(p);
193 ENUM_ITEM
194 }
195 L_CURLY => {
196 item.abandon(p);
197 error_block(p, "expected item");
198 return;
199 }
200 err_token => {
201 item.abandon(p);
202 let message = if err_token == SEMI {
203 //TODO: if the item is incomplete, this message is misleading
204 "expected item, found `;`\n\
205 consider removing this semicolon"
206 } else {
207 "expected item"
208 };
209 p.err_and_bump(message);
210 return;
211 }
212 };
213 item.complete(p, item_kind);
214}
215
216fn extern_crate_item(p: &mut Parser) {
217 assert!(p.at(EXTERN_KW));
218 p.bump();
219 assert!(p.at(CRATE_KW));
220 p.bump();
221 name(p);
222 alias(p);
223 p.expect(SEMI);
224}
225
226fn extern_block(p: &mut Parser) {
227 assert!(p.at(L_CURLY));
228 p.bump();
229 p.expect(R_CURLY);
230}
231
232fn fn_item(p: &mut Parser) {
233 assert!(p.at(FN_KW));
234 p.bump();
235
236 name(p);
237 // test fn_item_type_params
238 // fn foo<T: Clone + Copy>(){}
239 type_params::type_param_list(p);
240
241 if p.at(L_PAREN) {
242 params::param_list(p);
243 } else {
244 p.error("expected function arguments");
245 }
246 // test fn_item_ret_type
247 // fn foo() {}
248 // fn bar() -> () {}
249 fn_ret_type(p);
250
251 // test fn_item_where_clause
252 // fn foo<T>() where T: Copy {}
253 type_params::where_clause(p);
254
255 expressions::block(p);
256}
257
258// test type_item
259// type Foo = Bar;
260fn type_item(p: &mut Parser) {
261 assert!(p.at(TYPE_KW));
262 p.bump();
263
264 name(p);
265
266 // test type_item_type_params
267 // type Result<T> = ();
268 type_params::type_param_list(p);
269
270 // test type_item_where_clause
271 // type Foo where Foo: Copy = ();
272 type_params::where_clause(p);
273
274 p.expect(EQ);
275 types::type_(p);
276 p.expect(SEMI);
277}
278
279fn mod_item(p: &mut Parser) {
280 assert!(p.at(MOD_KW));
281 p.bump();
282
283 name(p);
284 if !p.eat(SEMI) {
285 if p.expect(L_CURLY) {
286 mod_contents(p, true);
287 p.expect(R_CURLY);
288 }
289 }
290}
diff --git a/src/grammar/items/structs.rs b/src/grammar/items/structs.rs
new file mode 100644
index 000000000..7ced542a4
--- /dev/null
+++ b/src/grammar/items/structs.rs
@@ -0,0 +1,116 @@
1use super::*;
2
3pub(super) fn struct_item(p: &mut Parser) {
4 assert!(p.at(STRUCT_KW));
5 p.bump();
6
7 name(p);
8 type_params::type_param_list(p);
9 match p.current() {
10 WHERE_KW => {
11 type_params::where_clause(p);
12 match p.current() {
13 SEMI => {
14 p.bump();
15 return;
16 }
17 L_CURLY => named_fields(p),
18 _ => {
19 //TODO: special case `(` error message
20 p.error("expected `;` or `{`");
21 return;
22 }
23 }
24 }
25 SEMI => {
26 p.bump();
27 return;
28 }
29 L_CURLY => named_fields(p),
30 L_PAREN => {
31 pos_fields(p);
32 p.expect(SEMI);
33 }
34 _ => {
35 p.error("expected `;`, `{`, or `(`");
36 return;
37 }
38 }
39}
40
41pub(super) fn enum_item(p: &mut Parser) {
42 assert!(p.at(ENUM_KW));
43 p.bump();
44 name(p);
45 type_params::type_param_list(p);
46 type_params::where_clause(p);
47 if p.expect(L_CURLY) {
48 while !p.at(EOF) && !p.at(R_CURLY) {
49 let var = p.start();
50 attributes::outer_attributes(p);
51 if p.at(IDENT) {
52 p.bump();
53 match p.current() {
54 L_CURLY => named_fields(p),
55 L_PAREN => pos_fields(p),
56 EQ => {
57 p.bump();
58 expressions::expr(p);
59 }
60 _ => (),
61 }
62 var.complete(p, ENUM_VARIANT);
63 } else {
64 var.abandon(p);
65 p.err_and_bump("expected enum variant");
66 }
67 if !p.at(R_CURLY) {
68 p.expect(COMMA);
69 }
70 }
71 p.expect(R_CURLY);
72 }
73}
74
75fn named_fields(p: &mut Parser) {
76 assert!(p.at(L_CURLY));
77 p.bump();
78 while !p.at(R_CURLY) && !p.at(EOF) {
79 named_field(p);
80 if !p.at(R_CURLY) {
81 p.expect(COMMA);
82 }
83 }
84 p.expect(R_CURLY);
85
86 fn named_field(p: &mut Parser) {
87 let field = p.start();
88 visibility(p);
89 if p.at(IDENT) {
90 name(p);
91 p.expect(COLON);
92 types::type_(p);
93 field.complete(p, NAMED_FIELD);
94 } else {
95 field.abandon(p);
96 p.err_and_bump("expected field declaration");
97 }
98 }
99}
100
101fn pos_fields(p: &mut Parser) {
102 if !p.expect(L_PAREN) {
103 return;
104 }
105 while !p.at(R_PAREN) && !p.at(EOF) {
106 let pos_field = p.start();
107 visibility(p);
108 types::type_(p);
109 pos_field.complete(p, POS_FIELD);
110
111 if !p.at(R_PAREN) {
112 p.expect(COMMA);
113 }
114 }
115 p.expect(R_PAREN);
116}
diff --git a/src/grammar/items/traits.rs b/src/grammar/items/traits.rs
new file mode 100644
index 000000000..bda13e565
--- /dev/null
+++ b/src/grammar/items/traits.rs
@@ -0,0 +1,77 @@
1use super::*;
2
3// test trait_item
4// trait T<U>: Hash + Clone where U: Copy {}
5pub(super) fn trait_item(p: &mut Parser) {
6 assert!(p.at(TRAIT_KW));
7 p.bump();
8 name(p);
9 type_params::type_param_list(p);
10 if p.at(COLON) {
11 type_params::bounds(p);
12 }
13 type_params::where_clause(p);
14 p.expect(L_CURLY);
15 p.expect(R_CURLY);
16}
17
18// test impl_item
19// impl Foo {}
20pub(super) fn impl_item(p: &mut Parser) {
21 assert!(p.at(IMPL_KW));
22 p.bump();
23 if choose_type_params_over_qpath(p) {
24 type_params::type_param_list(p);
25 }
26
27 // TODO: never type
28 // impl ! {}
29
30 // test impl_item_neg
31 // impl !Send for X {}
32 p.eat(EXCL);
33 types::type_(p);
34 if p.eat(FOR_KW) {
35 types::type_(p);
36 }
37 type_params::where_clause(p);
38 p.expect(L_CURLY);
39
40 // test impl_item_items
41 // impl F {
42 // type A = i32;
43 // const B: i32 = 92;
44 // fn foo() {}
45 // fn bar(&self) {}
46 // }
47 while !p.at(EOF) && !p.at(R_CURLY) {
48 item(p);
49 }
50 p.expect(R_CURLY);
51}
52
53fn choose_type_params_over_qpath(p: &Parser) -> bool {
54 // There's an ambiguity between generic parameters and qualified paths in impls.
55 // If we see `<` it may start both, so we have to inspect some following tokens.
56 // The following combinations can only start generics,
57 // but not qualified paths (with one exception):
58 // `<` `>` - empty generic parameters
59 // `<` `#` - generic parameters with attributes
60 // `<` (LIFETIME|IDENT) `>` - single generic parameter
61 // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list
62 // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds
63 // `<` (LIFETIME|IDENT) `=` - generic parameter with a default
64 // The only truly ambiguous case is
65 // `<` IDENT `>` `::` IDENT ...
66 // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
67 // because this is what almost always expected in practice, qualified paths in impls
68 // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment.
69 if !p.at(L_ANGLE) {
70 return false;
71 }
72 if p.nth(1) == POUND || p.nth(1) == R_ANGLE {
73 return true;
74 }
75 (p.nth(1) == LIFETIME || p.nth(1) == IDENT)
76 && (p.nth(2) == R_ANGLE || p.nth(2) == COMMA || p.nth(2) == COLON || p.nth(2) == EQ)
77}
diff --git a/src/grammar/items/use_item.rs b/src/grammar/items/use_item.rs
new file mode 100644
index 000000000..a3f7f0da8
--- /dev/null
+++ b/src/grammar/items/use_item.rs
@@ -0,0 +1,66 @@
1use super::*;
2
3pub(super) fn use_item(p: &mut Parser) {
4 assert!(p.at(USE_KW));
5 p.bump();
6 use_tree(p);
7 p.expect(SEMI);
8}
9
10fn use_tree(p: &mut Parser) {
11 let la = p.nth(1);
12 let m = p.start();
13 match (p.current(), la) {
14 (STAR, _) => p.bump(),
15 (COLONCOLON, STAR) => {
16 p.bump();
17 p.bump();
18 }
19 (L_CURLY, _) | (COLONCOLON, L_CURLY) => {
20 if p.at(COLONCOLON) {
21 p.bump();
22 }
23 nested_trees(p);
24 }
25 _ if paths::is_path_start(p) => {
26 paths::use_path(p);
27 match p.current() {
28 AS_KW => {
29 alias(p);
30 }
31 COLONCOLON => {
32 p.bump();
33 match p.current() {
34 STAR => {
35 p.bump();
36 }
37 L_CURLY => nested_trees(p),
38 _ => {
39 // is this unreachable?
40 p.error("expected `{` or `*`");
41 }
42 }
43 }
44 _ => (),
45 }
46 }
47 _ => {
48 m.abandon(p);
49 p.err_and_bump("expected one of `*`, `::`, `{`, `self`, `super`, `indent`");
50 return;
51 }
52 }
53 m.complete(p, USE_TREE);
54}
55
56fn nested_trees(p: &mut Parser) {
57 assert!(p.at(L_CURLY));
58 p.bump();
59 while !p.at(EOF) && !p.at(R_CURLY) {
60 use_tree(p);
61 if !p.at(R_CURLY) {
62 p.expect(COMMA);
63 }
64 }
65 p.expect(R_CURLY);
66}
diff --git a/src/grammar/mod.rs b/src/grammar/mod.rs
new file mode 100644
index 000000000..b558da477
--- /dev/null
+++ b/src/grammar/mod.rs
@@ -0,0 +1,141 @@
1//! This is the actual "grammar" of the Rust language.
2//!
3//! Each function in this module and its children corresponds
4//! to a production of the format grammar. Submodules roughly
5//! correspond to different *areas* of the grammar. By convention,
6//! each submodule starts with `use super::*` import and exports
7//! "public" productions via `pub(super)`.
8//!
9//! See docs for `Parser` to learn about API, available to the grammar,
10//! and see docs for `Event` to learn how this actually manages to
11//! produce parse trees.
12//!
13//! Code in this module also contains inline tests, which start with
14//! `// test name-of-the-test` comment and look like this:
15//!
16//! ```
17//! // test fn_item_with_zero_parameters
18//! // fn foo() {}
19//! ```
20//!
21//! After adding a new inline-test, run `cargo collect-tests` to extract
22//! it as a standalone text-fixture into `tests/data/parser/inline`, and
23//! run `cargo test` once to create the "gold" value.
24mod attributes;
25mod expressions;
26mod items;
27mod params;
28mod paths;
29mod patterns;
30mod type_args;
31mod type_params;
32mod types;
33
34use {
35 parser_api::{CompletedMarker, Parser, TokenSet},
36 SyntaxKind::{self, *},
37};
38
39pub(crate) fn file(p: &mut Parser) {
40 let file = p.start();
41 p.eat(SHEBANG);
42 items::mod_contents(p, false);
43 file.complete(p, FILE);
44}
45
46fn visibility(p: &mut Parser) {
47 if p.at(PUB_KW) {
48 let vis = p.start();
49 p.bump();
50 if p.at(L_PAREN) {
51 match p.nth(1) {
52 // test crate_visibility
53 // pub(crate) struct S;
54 // pub(self) struct S;
55 // pub(self) struct S;
56 // pub(self) struct S;
57 CRATE_KW | SELF_KW | SUPER_KW => {
58 p.bump();
59 p.bump();
60 p.expect(R_PAREN);
61 }
62 IN_KW => {
63 p.bump();
64 p.bump();
65 paths::use_path(p);
66 p.expect(R_PAREN);
67 }
68 _ => (),
69 }
70 }
71 vis.complete(p, VISIBILITY);
72 }
73}
74
75fn alias(p: &mut Parser) -> bool {
76 if p.at(AS_KW) {
77 let alias = p.start();
78 p.bump();
79 name(p);
80 alias.complete(p, ALIAS);
81 }
82 true //FIXME: return false if three are errors
83}
84
85fn abi(p: &mut Parser) {
86 assert!(p.at(EXTERN_KW));
87 let abi = p.start();
88 p.bump();
89 match p.current() {
90 STRING | RAW_STRING => p.bump(),
91 _ => (),
92 }
93 abi.complete(p, ABI);
94}
95
96fn fn_ret_type(p: &mut Parser) -> bool {
97 if p.at(THIN_ARROW) {
98 p.bump();
99 types::type_(p);
100 true
101 } else {
102 false
103 }
104}
105
106fn name(p: &mut Parser) {
107 if p.at(IDENT) {
108 let m = p.start();
109 p.bump();
110 m.complete(p, NAME);
111 } else {
112 p.error("expected a name");
113 }
114}
115
116fn name_ref(p: &mut Parser) {
117 if p.at(IDENT) {
118 let m = p.start();
119 p.bump();
120 m.complete(p, NAME_REF);
121 } else {
122 p.error("expected identifier");
123 }
124}
125
126fn error_block(p: &mut Parser, message: &str) {
127 assert!(p.at(L_CURLY));
128 let err = p.start();
129 p.error(message);
130 p.bump();
131 let mut level: u32 = 1;
132 while level > 0 && !p.at(EOF) {
133 match p.current() {
134 L_CURLY => level += 1,
135 R_CURLY => level -= 1,
136 _ => (),
137 }
138 p.bump();
139 }
140 err.complete(p, ERROR);
141}
diff --git a/src/grammar/params.rs b/src/grammar/params.rs
new file mode 100644
index 000000000..be985c80f
--- /dev/null
+++ b/src/grammar/params.rs
@@ -0,0 +1,70 @@
1use super::*;
2
3// test param_list
4// fn a() {}
5// fn b(x: i32) {}
6// fn c(x: i32, ) {}
7// fn d(x: i32, y: ()) {}
8pub(super) fn param_list(p: &mut Parser) {
9 list_(p, true)
10}
11
12pub(super) fn param_list_opt_types(p: &mut Parser) {
13 list_(p, false)
14}
15
16fn list_(p: &mut Parser, require_types: bool) {
17 assert!(p.at(if require_types { L_PAREN } else { PIPE }));
18 let m = p.start();
19 p.bump();
20 if require_types {
21 self_param(p);
22 }
23 let terminator = if require_types { R_PAREN } else { PIPE };
24 while !p.at(EOF) && !p.at(terminator) {
25 value_parameter(p, require_types);
26 if !p.at(terminator) {
27 p.expect(COMMA);
28 }
29 }
30 p.expect(terminator);
31 m.complete(p, PARAM_LIST);
32}
33
34fn value_parameter(p: &mut Parser, require_type: bool) {
35 let m = p.start();
36 patterns::pattern(p);
37 if p.at(COLON) || require_type {
38 types::ascription(p)
39 }
40 m.complete(p, PARAM);
41}
42
43// test self_param
44// impl S {
45// fn a(self) {}
46// fn b(&self,) {}
47// fn c(&'a self,) {}
48// fn d(&'a mut self, x: i32) {}
49// }
50fn self_param(p: &mut Parser) {
51 let la1 = p.nth(1);
52 let la2 = p.nth(2);
53 let la3 = p.nth(3);
54 let n_toks = match (p.current(), la1, la2, la3) {
55 (SELF_KW, _, _, _) => 1,
56 (AMPERSAND, SELF_KW, _, _) => 2,
57 (AMPERSAND, MUT_KW, SELF_KW, _) => 3,
58 (AMPERSAND, LIFETIME, SELF_KW, _) => 3,
59 (AMPERSAND, LIFETIME, MUT_KW, SELF_KW) => 4,
60 _ => return,
61 };
62 let m = p.start();
63 for _ in 0..n_toks {
64 p.bump();
65 }
66 m.complete(p, SELF_PARAM);
67 if !p.at(R_PAREN) {
68 p.expect(COMMA);
69 }
70}
diff --git a/src/grammar/paths.rs b/src/grammar/paths.rs
new file mode 100644
index 000000000..fe69db096
--- /dev/null
+++ b/src/grammar/paths.rs
@@ -0,0 +1,77 @@
1use super::*;
2
3pub(super) fn is_path_start(p: &Parser) -> bool {
4 match p.current() {
5 IDENT | SELF_KW | SUPER_KW | COLONCOLON => true,
6 _ => false,
7 }
8}
9
10pub(super) fn use_path(p: &mut Parser) {
11 path(p, Mode::Use)
12}
13
14pub(super) fn type_path(p: &mut Parser) {
15 path(p, Mode::Type)
16}
17
18pub(super) fn expr_path(p: &mut Parser) {
19 path(p, Mode::Expr)
20}
21
22#[derive(Clone, Copy, Eq, PartialEq)]
23enum Mode {
24 Use,
25 Type,
26 Expr,
27}
28
29fn path(p: &mut Parser, mode: Mode) {
30 if !is_path_start(p) {
31 return;
32 }
33 let path = p.start();
34 path_segment(p, mode, true);
35 let mut qual = path.complete(p, PATH);
36 loop {
37 let use_tree = match p.nth(1) {
38 STAR | L_CURLY => true,
39 _ => false,
40 };
41 if p.at(COLONCOLON) && !use_tree {
42 let path = qual.precede(p);
43 p.bump();
44 path_segment(p, mode, false);
45 let path = path.complete(p, PATH);
46 qual = path;
47 } else {
48 break;
49 }
50 }
51}
52
53fn path_segment(p: &mut Parser, mode: Mode, first: bool) {
54 let segment = p.start();
55 if first {
56 p.eat(COLONCOLON);
57 }
58 match p.current() {
59 IDENT => {
60 name_ref(p);
61 path_generic_args(p, mode);
62 }
63 SELF_KW | SUPER_KW => p.bump(),
64 _ => {
65 p.error("expected identifier");
66 }
67 };
68 segment.complete(p, PATH_SEGMENT);
69}
70
71fn path_generic_args(p: &mut Parser, mode: Mode) {
72 match mode {
73 Mode::Use => return,
74 Mode::Type => type_args::type_arg_list(p, false),
75 Mode::Expr => type_args::type_arg_list(p, true),
76 }
77}
diff --git a/src/grammar/patterns.rs b/src/grammar/patterns.rs
new file mode 100644
index 000000000..7216807fd
--- /dev/null
+++ b/src/grammar/patterns.rs
@@ -0,0 +1,53 @@
1use super::*;
2
3pub(super) fn pattern(p: &mut Parser) {
4 match p.current() {
5 UNDERSCORE => placeholder_pat(p),
6 AMPERSAND => ref_pat(p),
7 IDENT | REF_KW | MUT_KW => bind_pat(p),
8 _ => p.err_and_bump("expected pattern"),
9 }
10}
11
12// test placeholder_pat
13// fn main() { let _ = (); }
14fn placeholder_pat(p: &mut Parser) {
15 assert!(p.at(UNDERSCORE));
16 let m = p.start();
17 p.bump();
18 m.complete(p, PLACEHOLDER_PAT);
19}
20
21// test ref_pat
22// fn main() {
23// let &a = ();
24// let &mut b = ();
25// }
26fn ref_pat(p: &mut Parser) {
27 assert!(p.at(AMPERSAND));
28 let m = p.start();
29 p.bump();
30 p.eat(MUT_KW);
31 pattern(p);
32 m.complete(p, REF_PAT);
33}
34
35// test bind_pat
36// fn main() {
37// let a = ();
38// let mut b = ();
39// let ref c = ();
40// let ref mut d = ();
41// let e @ _ = ();
42// let ref mut f @ g @ _ = ();
43// }
44fn bind_pat(p: &mut Parser) {
45 let m = p.start();
46 p.eat(REF_KW);
47 p.eat(MUT_KW);
48 name(p);
49 if p.eat(AT) {
50 pattern(p);
51 }
52 m.complete(p, BIND_PAT);
53}
diff --git a/src/grammar/type_args.rs b/src/grammar/type_args.rs
new file mode 100644
index 000000000..5b960f10b
--- /dev/null
+++ b/src/grammar/type_args.rs
@@ -0,0 +1,48 @@
1use super::*;
2
3pub(super) fn type_arg_list(p: &mut Parser, colon_colon_required: bool) {
4 let m;
5 match (colon_colon_required, p.nth(0), p.nth(1)) {
6 (_, COLONCOLON, L_ANGLE) => {
7 m = p.start();
8 p.bump();
9 p.bump();
10 }
11 (false, L_ANGLE, _) => {
12 m = p.start();
13 p.bump();
14 }
15 _ => return,
16 };
17
18 while !p.at(EOF) && !p.at(R_ANGLE) {
19 type_arg(p);
20 if !p.at(R_ANGLE) && !p.expect(COMMA) {
21 break;
22 }
23 }
24 p.expect(R_ANGLE);
25 m.complete(p, TYPE_ARG_LIST);
26}
27
28// test type_arg
29// type A = B<'static, i32, Item=u64>
30fn type_arg(p: &mut Parser) {
31 let m = p.start();
32 match p.current() {
33 LIFETIME => {
34 p.bump();
35 m.complete(p, LIFETIME_ARG);
36 }
37 IDENT if p.nth(1) == EQ => {
38 name_ref(p);
39 p.bump();
40 types::type_(p);
41 m.complete(p, ASSOC_TYPE_ARG);
42 }
43 _ => {
44 types::type_(p);
45 m.complete(p, TYPE_ARG);
46 }
47 }
48}
diff --git a/src/grammar/type_params.rs b/src/grammar/type_params.rs
new file mode 100644
index 000000000..1227482ad
--- /dev/null
+++ b/src/grammar/type_params.rs
@@ -0,0 +1,95 @@
1use super::*;
2
3pub(super) fn type_param_list(p: &mut Parser) {
4 if !p.at(L_ANGLE) {
5 return;
6 }
7 let m = p.start();
8 p.bump();
9
10 while !p.at(EOF) && !p.at(R_ANGLE) {
11 match p.current() {
12 LIFETIME => lifetime_param(p),
13 IDENT => type_param(p),
14 _ => p.err_and_bump("expected type parameter"),
15 }
16 if !p.at(R_ANGLE) && !p.expect(COMMA) {
17 break;
18 }
19 }
20 p.expect(R_ANGLE);
21 m.complete(p, TYPE_PARAM_LIST);
22
23 fn lifetime_param(p: &mut Parser) {
24 assert!(p.at(LIFETIME));
25 let m = p.start();
26 p.bump();
27 if p.eat(COLON) {
28 while p.at(LIFETIME) {
29 p.bump();
30 if !p.eat(PLUS) {
31 break;
32 }
33 }
34 }
35 m.complete(p, LIFETIME_PARAM);
36 }
37
38 fn type_param(p: &mut Parser) {
39 assert!(p.at(IDENT));
40 let m = p.start();
41 name(p);
42 if p.at(COLON) {
43 bounds(p);
44 }
45 // test type_param_default
46 // struct S<T = i32>;
47 if p.at(EQ) {
48 p.bump();
49 types::type_(p)
50 }
51 m.complete(p, TYPE_PARAM);
52 }
53}
54
55// test type_param_bounds
56// struct S<T: 'a + ?Sized + (Copy)>;
57pub(super) fn bounds(p: &mut Parser) {
58 assert!(p.at(COLON));
59 p.bump();
60 bounds_without_colon(p);
61}
62
63pub(super) fn bounds_without_colon(p: &mut Parser) {
64 loop {
65 let has_paren = p.eat(L_PAREN);
66 p.eat(QUESTION);
67 if p.at(FOR_KW) {
68 //TODO
69 }
70 if p.at(LIFETIME) {
71 p.bump();
72 } else if paths::is_path_start(p) {
73 paths::type_path(p);
74 } else {
75 break;
76 }
77 if has_paren {
78 p.expect(R_PAREN);
79 }
80 if !p.eat(PLUS) {
81 break;
82 }
83 }
84}
85
86pub(super) fn where_clause(p: &mut Parser) {
87 if p.at(WHERE_KW) {
88 let m = p.start();
89 p.bump();
90 p.expect(IDENT);
91 p.expect(COLON);
92 p.expect(IDENT);
93 m.complete(p, WHERE_CLAUSE);
94 }
95}
diff --git a/src/grammar/types.rs b/src/grammar/types.rs
new file mode 100644
index 000000000..565037cb0
--- /dev/null
+++ b/src/grammar/types.rs
@@ -0,0 +1,207 @@
1use super::*;
2
3pub(super) fn type_(p: &mut Parser) {
4 match p.current() {
5 L_PAREN => paren_or_tuple_type(p),
6 EXCL => never_type(p),
7 STAR => pointer_type(p),
8 L_BRACK => array_or_slice_type(p),
9 AMPERSAND => reference_type(p),
10 UNDERSCORE => placeholder_type(p),
11 FN_KW | UNSAFE_KW | EXTERN_KW => fn_pointer_type(p),
12 FOR_KW => for_type(p),
13 IMPL_KW => impl_trait_type(p),
14 _ if paths::is_path_start(p) => path_type(p),
15 _ => {
16 p.error("expected type");
17 }
18 }
19}
20
21pub(super) fn ascription(p: &mut Parser) {
22 p.expect(COLON);
23 type_(p)
24}
25
26fn type_no_plus(p: &mut Parser) {
27 type_(p);
28}
29
30fn paren_or_tuple_type(p: &mut Parser) {
31 assert!(p.at(L_PAREN));
32 let m = p.start();
33 p.bump();
34 let mut n_types: u32 = 0;
35 let mut trailing_comma: bool = false;
36 while !p.at(EOF) && !p.at(R_PAREN) {
37 n_types += 1;
38 type_(p);
39 if p.eat(COMMA) {
40 trailing_comma = true;
41 } else {
42 trailing_comma = false;
43 break;
44 }
45 }
46 p.expect(R_PAREN);
47
48 let kind = if n_types == 1 && !trailing_comma {
49 // test paren_type
50 // type T = (i32);
51 PAREN_TYPE
52 } else {
53 // test unit_type
54 // type T = ();
55
56 // test singleton_tuple_type
57 // type T = (i32,);
58 TUPLE_TYPE
59 };
60 m.complete(p, kind);
61}
62
63// test never_type
64// type Never = !;
65fn never_type(p: &mut Parser) {
66 assert!(p.at(EXCL));
67 let m = p.start();
68 p.bump();
69 m.complete(p, NEVER_TYPE);
70}
71
72fn pointer_type(p: &mut Parser) {
73 assert!(p.at(STAR));
74 let m = p.start();
75 p.bump();
76
77 match p.current() {
78 // test pointer_type_mut
79 // type M = *mut ();
80 // type C = *mut ();
81 MUT_KW | CONST_KW => p.bump(),
82 _ => {
83 // test pointer_type_no_mutability
84 // type T = *();
85 p.error(
86 "expected mut or const in raw pointer type \
87 (use `*mut T` or `*const T` as appropriate)",
88 );
89 }
90 };
91
92 type_no_plus(p);
93 m.complete(p, POINTER_TYPE);
94}
95
96fn array_or_slice_type(p: &mut Parser) {
97 assert!(p.at(L_BRACK));
98 let m = p.start();
99 p.bump();
100
101 type_(p);
102 let kind = match p.current() {
103 // test slice_type
104 // type T = [()];
105 R_BRACK => {
106 p.bump();
107 SLICE_TYPE
108 }
109
110 // test array_type
111 // type T = [(); 92];
112 SEMI => {
113 p.bump();
114 expressions::expr(p);
115 p.expect(R_BRACK);
116 ARRAY_TYPE
117 }
118 // test array_type_missing_semi
119 // type T = [() 92];
120 _ => {
121 p.error("expected `;` or `]`");
122 SLICE_TYPE
123 }
124 };
125 m.complete(p, kind);
126}
127
128// test reference_type;
129// type A = &();
130// type B = &'static ();
131// type C = &mut ();
132fn reference_type(p: &mut Parser) {
133 assert!(p.at(AMPERSAND));
134 let m = p.start();
135 p.bump();
136 p.eat(LIFETIME);
137 p.eat(MUT_KW);
138 type_no_plus(p);
139 m.complete(p, REFERENCE_TYPE);
140}
141
142// test placeholder_type
143// type Placeholder = _;
144fn placeholder_type(p: &mut Parser) {
145 assert!(p.at(UNDERSCORE));
146 let m = p.start();
147 p.bump();
148 m.complete(p, PLACEHOLDER_TYPE);
149}
150
151// test fn_pointer_type
152// type A = fn();
153// type B = unsafe fn();
154// type C = unsafe extern "C" fn();
155fn fn_pointer_type(p: &mut Parser) {
156 let m = p.start();
157 p.eat(UNSAFE_KW);
158 if p.at(EXTERN_KW) {
159 abi(p);
160 }
161 // test fn_pointer_type_missing_fn
162 // type F = unsafe ();
163 if !p.eat(FN_KW) {
164 m.abandon(p);
165 p.error("expected `fn`");
166 return;
167 }
168
169 params::param_list(p);
170 // test fn_pointer_type_with_ret
171 // type F = fn() -> ();
172 fn_ret_type(p);
173 m.complete(p, FN_POINTER_TYPE);
174}
175
176// test for_type
177// type A = for<'a> fn() -> ();
178fn for_type(p: &mut Parser) {
179 assert!(p.at(FOR_KW));
180 let m = p.start();
181 p.bump();
182 type_params::type_param_list(p);
183 type_(p);
184 m.complete(p, FOR_TYPE);
185}
186
187// test impl_trait_type
188// type A = impl Iterator<Item=Foo<'a>> + 'a;
189fn impl_trait_type(p: &mut Parser) {
190 assert!(p.at(IMPL_KW));
191 let m = p.start();
192 p.bump();
193 type_params::bounds_without_colon(p);
194 m.complete(p, IMPL_TRAIT_TYPE);
195}
196
197// test path_type
198// type A = Foo;
199// type B = ::Foo;
200// type C = self::Foo;
201// type D = super::Foo;
202fn path_type(p: &mut Parser) {
203 assert!(paths::is_path_start(p));
204 let m = p.start();
205 paths::type_path(p);
206 m.complete(p, PATH_TYPE);
207}