aboutsummaryrefslogtreecommitdiff
path: root/crates/parser/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/parser/src')
-rw-r--r--crates/parser/src/event.rs130
-rw-r--r--crates/parser/src/grammar.rs293
-rw-r--r--crates/parser/src/grammar/attributes.rs48
-rw-r--r--crates/parser/src/grammar/expressions.rs651
-rw-r--r--crates/parser/src/grammar/expressions/atom.rs611
-rw-r--r--crates/parser/src/grammar/items.rs432
-rw-r--r--crates/parser/src/grammar/items/adt.rs178
-rw-r--r--crates/parser/src/grammar/items/consts.rs33
-rw-r--r--crates/parser/src/grammar/items/traits.rs153
-rw-r--r--crates/parser/src/grammar/items/use_item.rs132
-rw-r--r--crates/parser/src/grammar/params.rs188
-rw-r--r--crates/parser/src/grammar/paths.rs115
-rw-r--r--crates/parser/src/grammar/patterns.rs379
-rw-r--r--crates/parser/src/grammar/type_args.rs63
-rw-r--r--crates/parser/src/grammar/type_params.rs209
-rw-r--r--crates/parser/src/grammar/types.rs324
-rw-r--r--crates/parser/src/lib.rs149
-rw-r--r--crates/parser/src/parser.rs350
-rw-r--r--crates/parser/src/syntax_kind.rs25
-rw-r--r--crates/parser/src/syntax_kind/generated.rs367
-rw-r--r--crates/parser/src/token_set.rs42
21 files changed, 4872 insertions, 0 deletions
diff --git a/crates/parser/src/event.rs b/crates/parser/src/event.rs
new file mode 100644
index 000000000..a7d06a815
--- /dev/null
+++ b/crates/parser/src/event.rs
@@ -0,0 +1,130 @@
1//! This module provides a way to construct a `File`.
2//! It is intended to be completely decoupled from the
3//! parser, so as to allow to evolve the tree representation
4//! and the parser algorithm independently.
5//!
6//! The `TreeSink` trait is the bridge between the parser and the
7//! tree builder: the parser produces a stream of events like
8//! `start node`, `finish node`, and `FileBuilder` converts
9//! this stream to a real tree.
10use std::mem;
11
12use crate::{
13 ParseError,
14 SyntaxKind::{self, *},
15 TreeSink,
16};
17
18/// `Parser` produces a flat list of `Event`s.
19/// They are converted to a tree-structure in
20/// a separate pass, via `TreeBuilder`.
21#[derive(Debug)]
22pub(crate) enum Event {
23 /// This event signifies the start of the node.
24 /// It should be either abandoned (in which case the
25 /// `kind` is `TOMBSTONE`, and the event is ignored),
26 /// or completed via a `Finish` event.
27 ///
28 /// All tokens between a `Start` and a `Finish` would
29 /// become the children of the respective node.
30 ///
31 /// For left-recursive syntactic constructs, the parser produces
32 /// a child node before it sees a parent. `forward_parent`
33 /// saves the position of current event's parent.
34 ///
35 /// Consider this path
36 ///
37 /// foo::bar
38 ///
39 /// The events for it would look like this:
40 ///
41 ///
42 /// START(PATH) IDENT('foo') FINISH START(PATH) T![::] IDENT('bar') FINISH
43 /// | /\
44 /// | |
45 /// +------forward-parent------+
46 ///
47 /// And the tree would look like this
48 ///
49 /// +--PATH---------+
50 /// | | |
51 /// | | |
52 /// | '::' 'bar'
53 /// |
54 /// PATH
55 /// |
56 /// 'foo'
57 ///
58 /// See also `CompletedMarker::precede`.
59 Start {
60 kind: SyntaxKind,
61 forward_parent: Option<u32>,
62 },
63
64 /// Complete the previous `Start` event
65 Finish,
66
67 /// Produce a single leaf-element.
68 /// `n_raw_tokens` is used to glue complex contextual tokens.
69 /// For example, lexer tokenizes `>>` as `>`, `>`, and
70 /// `n_raw_tokens = 2` is used to produced a single `>>`.
71 Token {
72 kind: SyntaxKind,
73 n_raw_tokens: u8,
74 },
75
76 Error {
77 msg: ParseError,
78 },
79}
80
81impl Event {
82 pub(crate) fn tombstone() -> Self {
83 Event::Start { kind: TOMBSTONE, forward_parent: None }
84 }
85}
86
87/// Generate the syntax tree with the control of events.
88pub(super) fn process(sink: &mut dyn TreeSink, mut events: Vec<Event>) {
89 let mut forward_parents = Vec::new();
90
91 for i in 0..events.len() {
92 match mem::replace(&mut events[i], Event::tombstone()) {
93 Event::Start { kind: TOMBSTONE, .. } => (),
94
95 Event::Start { kind, forward_parent } => {
96 // For events[A, B, C], B is A's forward_parent, C is B's forward_parent,
97 // in the normal control flow, the parent-child relation: `A -> B -> C`,
98 // while with the magic forward_parent, it writes: `C <- B <- A`.
99
100 // append `A` into parents.
101 forward_parents.push(kind);
102 let mut idx = i;
103 let mut fp = forward_parent;
104 while let Some(fwd) = fp {
105 idx += fwd as usize;
106 // append `A`'s forward_parent `B`
107 fp = match mem::replace(&mut events[idx], Event::tombstone()) {
108 Event::Start { kind, forward_parent } => {
109 if kind != TOMBSTONE {
110 forward_parents.push(kind);
111 }
112 forward_parent
113 }
114 _ => unreachable!(),
115 };
116 // append `B`'s forward_parent `C` in the next stage.
117 }
118
119 for kind in forward_parents.drain(..).rev() {
120 sink.start_node(kind);
121 }
122 }
123 Event::Finish => sink.finish_node(),
124 Event::Token { kind, n_raw_tokens } => {
125 sink.token(kind, n_raw_tokens);
126 }
127 Event::Error { msg } => sink.error(msg),
128 }
129 }
130}
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs
new file mode 100644
index 000000000..88468bc97
--- /dev/null
+++ b/crates/parser/src/grammar.rs
@@ -0,0 +1,293 @@
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 formal 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 function_with_zero_parameters
18//! // fn foo() {}
19//! ```
20//!
21//! After adding a new inline-test, run `cargo xtask codegen` to
22//! extract it as a standalone text-fixture into
23//! `crates/ra_syntax/test_data/parser/`, and run `cargo test` once to
24//! create the "gold" value.
25//!
26//! Coding convention: rules like `where_clause` always produce either a
27//! node or an error, rules like `opt_where_clause` may produce nothing.
28//! Non-opt rules typically start with `assert!(p.at(FIRST_TOKEN))`, the
29//! caller is responsible for branching on the first token.
30mod attributes;
31mod expressions;
32mod items;
33mod params;
34mod paths;
35mod patterns;
36mod type_args;
37mod type_params;
38mod types;
39
40use crate::{
41 parser::{CompletedMarker, Marker, Parser},
42 SyntaxKind::{self, *},
43 TokenSet,
44};
45
46pub(crate) fn root(p: &mut Parser) {
47 let m = p.start();
48 p.eat(SHEBANG);
49 items::mod_contents(p, false);
50 m.complete(p, SOURCE_FILE);
51}
52
53/// Various pieces of syntax that can be parsed by macros by example
54pub(crate) mod fragments {
55 use super::*;
56
57 pub(crate) use super::{
58 expressions::block_expr, paths::type_path as path, patterns::pattern, types::type_,
59 };
60
61 pub(crate) fn expr(p: &mut Parser) {
62 let _ = expressions::expr(p);
63 }
64
65 pub(crate) fn stmt(p: &mut Parser) {
66 expressions::stmt(p, expressions::StmtWithSemi::No)
67 }
68
69 pub(crate) fn opt_visibility(p: &mut Parser) {
70 let _ = super::opt_visibility(p);
71 }
72
73 // Parse a meta item , which excluded [], e.g : #[ MetaItem ]
74 pub(crate) fn meta_item(p: &mut Parser) {
75 fn is_delimiter(p: &mut Parser) -> bool {
76 matches!(p.current(), T!['{'] | T!['('] | T!['['])
77 }
78
79 if is_delimiter(p) {
80 items::token_tree(p);
81 return;
82 }
83
84 let m = p.start();
85 while !p.at(EOF) {
86 if is_delimiter(p) {
87 items::token_tree(p);
88 break;
89 } else {
90 // https://doc.rust-lang.org/reference/attributes.html
91 // https://doc.rust-lang.org/reference/paths.html#simple-paths
92 // The start of an meta must be a simple path
93 match p.current() {
94 IDENT | T![::] | T![super] | T![self] | T![crate] => p.bump_any(),
95 T![=] => {
96 p.bump_any();
97 match p.current() {
98 c if c.is_literal() => p.bump_any(),
99 T![true] | T![false] => p.bump_any(),
100 _ => {}
101 }
102 break;
103 }
104 _ => break,
105 }
106 }
107 }
108
109 m.complete(p, TOKEN_TREE);
110 }
111
112 pub(crate) fn item(p: &mut Parser) {
113 items::item_or_macro(p, true)
114 }
115
116 pub(crate) fn macro_items(p: &mut Parser) {
117 let m = p.start();
118 items::mod_contents(p, false);
119 m.complete(p, MACRO_ITEMS);
120 }
121
122 pub(crate) fn macro_stmts(p: &mut Parser) {
123 let m = p.start();
124
125 while !p.at(EOF) {
126 if p.at(T![;]) {
127 p.bump(T![;]);
128 continue;
129 }
130
131 expressions::stmt(p, expressions::StmtWithSemi::Optional);
132 }
133
134 m.complete(p, MACRO_STMTS);
135 }
136}
137
138pub(crate) fn reparser(
139 node: SyntaxKind,
140 first_child: Option<SyntaxKind>,
141 parent: Option<SyntaxKind>,
142) -> Option<fn(&mut Parser)> {
143 let res = match node {
144 BLOCK_EXPR => expressions::block_expr,
145 RECORD_FIELD_LIST => items::record_field_def_list,
146 RECORD_EXPR_FIELD_LIST => items::record_field_list,
147 VARIANT_LIST => items::enum_variant_list,
148 MATCH_ARM_LIST => items::match_arm_list,
149 USE_TREE_LIST => items::use_tree_list,
150 EXTERN_ITEM_LIST => items::extern_item_list,
151 TOKEN_TREE if first_child? == T!['{'] => items::token_tree,
152 ASSOC_ITEM_LIST => match parent? {
153 IMPL => items::impl_item_list,
154 TRAIT => items::trait_item_list,
155 _ => return None,
156 },
157 ITEM_LIST => items::mod_item_list,
158 _ => return None,
159 };
160 Some(res)
161}
162
163#[derive(Clone, Copy, PartialEq, Eq)]
164enum BlockLike {
165 Block,
166 NotBlock,
167}
168
169impl BlockLike {
170 fn is_block(self) -> bool {
171 self == BlockLike::Block
172 }
173}
174
175fn opt_visibility(p: &mut Parser) -> bool {
176 match p.current() {
177 T![pub] => {
178 let m = p.start();
179 p.bump(T![pub]);
180 if p.at(T!['(']) {
181 match p.nth(1) {
182 // test crate_visibility
183 // pub(crate) struct S;
184 // pub(self) struct S;
185 // pub(self) struct S;
186 // pub(self) struct S;
187 T![crate] | T![self] | T![super] => {
188 p.bump_any();
189 p.bump_any();
190 p.expect(T![')']);
191 }
192 T![in] => {
193 p.bump_any();
194 p.bump_any();
195 paths::use_path(p);
196 p.expect(T![')']);
197 }
198 _ => (),
199 }
200 }
201 m.complete(p, VISIBILITY);
202 }
203 // test crate_keyword_vis
204 // crate fn main() { }
205 // struct S { crate field: u32 }
206 // struct T(crate u32);
207 //
208 // test crate_keyword_path
209 // fn foo() { crate::foo(); }
210 T![crate] if !p.nth_at(1, T![::]) => {
211 let m = p.start();
212 p.bump(T![crate]);
213 m.complete(p, VISIBILITY);
214 }
215 _ => return false,
216 }
217 true
218}
219
220fn opt_alias(p: &mut Parser) {
221 if p.at(T![as]) {
222 let m = p.start();
223 p.bump(T![as]);
224 if !p.eat(T![_]) {
225 name(p);
226 }
227 m.complete(p, RENAME);
228 }
229}
230
231fn abi(p: &mut Parser) {
232 assert!(p.at(T![extern]));
233 let abi = p.start();
234 p.bump(T![extern]);
235 match p.current() {
236 STRING | RAW_STRING => p.bump_any(),
237 _ => (),
238 }
239 abi.complete(p, ABI);
240}
241
242fn opt_fn_ret_type(p: &mut Parser) -> bool {
243 if p.at(T![->]) {
244 let m = p.start();
245 p.bump(T![->]);
246 types::type_no_bounds(p);
247 m.complete(p, RET_TYPE);
248 true
249 } else {
250 false
251 }
252}
253
254fn name_r(p: &mut Parser, recovery: TokenSet) {
255 if p.at(IDENT) {
256 let m = p.start();
257 p.bump(IDENT);
258 m.complete(p, NAME);
259 } else {
260 p.err_recover("expected a name", recovery);
261 }
262}
263
264fn name(p: &mut Parser) {
265 name_r(p, TokenSet::EMPTY)
266}
267
268fn name_ref(p: &mut Parser) {
269 if p.at(IDENT) {
270 let m = p.start();
271 p.bump(IDENT);
272 m.complete(p, NAME_REF);
273 } else {
274 p.err_and_bump("expected identifier");
275 }
276}
277
278fn name_ref_or_index(p: &mut Parser) {
279 assert!(p.at(IDENT) || p.at(INT_NUMBER));
280 let m = p.start();
281 p.bump_any();
282 m.complete(p, NAME_REF);
283}
284
285fn error_block(p: &mut Parser, message: &str) {
286 assert!(p.at(T!['{']));
287 let m = p.start();
288 p.error(message);
289 p.bump(T!['{']);
290 expressions::expr_block_contents(p);
291 p.eat(T!['}']);
292 m.complete(p, ERROR);
293}
diff --git a/crates/parser/src/grammar/attributes.rs b/crates/parser/src/grammar/attributes.rs
new file mode 100644
index 000000000..f3158ade3
--- /dev/null
+++ b/crates/parser/src/grammar/attributes.rs
@@ -0,0 +1,48 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) fn inner_attributes(p: &mut Parser) {
6 while p.at(T![#]) && p.nth(1) == T![!] {
7 attribute(p, true)
8 }
9}
10
11pub(super) fn outer_attributes(p: &mut Parser) {
12 while p.at(T![#]) {
13 attribute(p, false)
14 }
15}
16
17fn attribute(p: &mut Parser, inner: bool) {
18 let attr = p.start();
19 assert!(p.at(T![#]));
20 p.bump(T![#]);
21
22 if inner {
23 assert!(p.at(T![!]));
24 p.bump(T![!]);
25 }
26
27 if p.eat(T!['[']) {
28 paths::use_path(p);
29
30 match p.current() {
31 T![=] => {
32 p.bump(T![=]);
33 if expressions::literal(p).is_none() {
34 p.error("expected literal");
35 }
36 }
37 T!['('] | T!['['] | T!['{'] => items::token_tree(p),
38 _ => {}
39 }
40
41 if !p.eat(T![']']) {
42 p.error("expected `]`");
43 }
44 } else {
45 p.error("expected `[`");
46 }
47 attr.complete(p, ATTR);
48}
diff --git a/crates/parser/src/grammar/expressions.rs b/crates/parser/src/grammar/expressions.rs
new file mode 100644
index 000000000..3291e3f14
--- /dev/null
+++ b/crates/parser/src/grammar/expressions.rs
@@ -0,0 +1,651 @@
1//! FIXME: write short doc here
2
3mod atom;
4
5pub(crate) use self::atom::{block_expr, match_arm_list};
6pub(super) use self::atom::{literal, LITERAL_FIRST};
7use super::*;
8
9pub(super) enum StmtWithSemi {
10 Yes,
11 No,
12 Optional,
13}
14
15const EXPR_FIRST: TokenSet = LHS_FIRST;
16
17pub(super) fn expr(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) {
18 let r = Restrictions { forbid_structs: false, prefer_stmt: false };
19 expr_bp(p, r, 1)
20}
21
22pub(super) fn expr_with_attrs(p: &mut Parser) -> bool {
23 let m = p.start();
24 let has_attrs = p.at(T![#]);
25 attributes::outer_attributes(p);
26
27 let (cm, _block_like) = expr(p);
28 let success = cm.is_some();
29
30 match (has_attrs, cm) {
31 (true, Some(cm)) => {
32 let kind = cm.kind();
33 cm.undo_completion(p).abandon(p);
34 m.complete(p, kind);
35 }
36 _ => m.abandon(p),
37 }
38
39 success
40}
41
42pub(super) fn expr_stmt(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) {
43 let r = Restrictions { forbid_structs: false, prefer_stmt: true };
44 expr_bp(p, r, 1)
45}
46
47fn expr_no_struct(p: &mut Parser) {
48 let r = Restrictions { forbid_structs: true, prefer_stmt: false };
49 expr_bp(p, r, 1);
50}
51
52fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool {
53 let forbid = matches!(kind, BIN_EXPR | RANGE_EXPR);
54 !forbid
55}
56
57pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) {
58 let m = p.start();
59 // test attr_on_expr_stmt
60 // fn foo() {
61 // #[A] foo();
62 // #[B] bar!{}
63 // #[C] #[D] {}
64 // #[D] return ();
65 // }
66 let has_attrs = p.at(T![#]);
67 attributes::outer_attributes(p);
68
69 if p.at(T![let]) {
70 let_stmt(p, m, with_semi);
71 return;
72 }
73
74 // test block_items
75 // fn a() { fn b() {} }
76 let m = match items::maybe_item(p, m) {
77 Ok(()) => return,
78 Err(m) => m,
79 };
80
81 let (cm, blocklike) = expr_stmt(p);
82 let kind = cm.as_ref().map(|cm| cm.kind()).unwrap_or(ERROR);
83
84 if has_attrs && !is_expr_stmt_attr_allowed(kind) {
85 // test_err attr_on_expr_not_allowed
86 // fn foo() {
87 // #[A] 1 + 2;
88 // #[B] if true {};
89 // }
90 p.error(format!("attributes are not allowed on {:?}", kind));
91 }
92
93 if p.at(T!['}']) {
94 // test attr_on_last_expr_in_block
95 // fn foo() {
96 // { #[A] bar!()? }
97 // #[B] &()
98 // }
99 if let Some(cm) = cm {
100 cm.undo_completion(p).abandon(p);
101 m.complete(p, kind);
102 } else {
103 m.abandon(p);
104 }
105 } else {
106 // test no_semi_after_block
107 // fn foo() {
108 // if true {}
109 // loop {}
110 // match () {}
111 // while true {}
112 // for _ in () {}
113 // {}
114 // {}
115 // macro_rules! test {
116 // () => {}
117 // }
118 // test!{}
119 // }
120
121 match with_semi {
122 StmtWithSemi::Yes => {
123 if blocklike.is_block() {
124 p.eat(T![;]);
125 } else {
126 p.expect(T![;]);
127 }
128 }
129 StmtWithSemi::No => {}
130 StmtWithSemi::Optional => {
131 if p.at(T![;]) {
132 p.eat(T![;]);
133 }
134 }
135 }
136
137 m.complete(p, EXPR_STMT);
138 }
139
140 // test let_stmt
141 // fn foo() {
142 // let a;
143 // let b: i32;
144 // let c = 92;
145 // let d: i32 = 92;
146 // let e: !;
147 // let _: ! = {};
148 // let f = #[attr]||{};
149 // }
150 fn let_stmt(p: &mut Parser, m: Marker, with_semi: StmtWithSemi) {
151 assert!(p.at(T![let]));
152 p.bump(T![let]);
153 patterns::pattern(p);
154 if p.at(T![:]) {
155 types::ascription(p);
156 }
157 if p.eat(T![=]) {
158 expressions::expr_with_attrs(p);
159 }
160
161 match with_semi {
162 StmtWithSemi::Yes => {
163 p.expect(T![;]);
164 }
165 StmtWithSemi::No => {}
166 StmtWithSemi::Optional => {
167 if p.at(T![;]) {
168 p.eat(T![;]);
169 }
170 }
171 }
172 m.complete(p, LET_STMT);
173 }
174}
175
176pub(super) fn expr_block_contents(p: &mut Parser) {
177 // This is checked by a validator
178 attributes::inner_attributes(p);
179
180 while !p.at(EOF) && !p.at(T!['}']) {
181 // test nocontentexpr
182 // fn foo(){
183 // ;;;some_expr();;;;{;;;};;;;Ok(())
184 // }
185
186 // test nocontentexpr_after_item
187 // fn simple_function() {
188 // enum LocalEnum {
189 // One,
190 // Two,
191 // };
192 // fn f() {};
193 // struct S {};
194 // }
195
196 if p.at(T![;]) {
197 p.bump(T![;]);
198 continue;
199 }
200
201 stmt(p, StmtWithSemi::Yes)
202 }
203}
204
205#[derive(Clone, Copy)]
206struct Restrictions {
207 forbid_structs: bool,
208 prefer_stmt: bool,
209}
210
211/// Binding powers of operators for a Pratt parser.
212///
213/// See https://www.oilshell.org/blog/2016/11/03.html
214#[rustfmt::skip]
215fn current_op(p: &Parser) -> (u8, SyntaxKind) {
216 const NOT_AN_OP: (u8, SyntaxKind) = (0, T![@]);
217 match p.current() {
218 T![|] if p.at(T![||]) => (3, T![||]),
219 T![|] if p.at(T![|=]) => (1, T![|=]),
220 T![|] => (6, T![|]),
221 T![>] if p.at(T![>>=]) => (1, T![>>=]),
222 T![>] if p.at(T![>>]) => (9, T![>>]),
223 T![>] if p.at(T![>=]) => (5, T![>=]),
224 T![>] => (5, T![>]),
225 T![=] if p.at(T![=>]) => NOT_AN_OP,
226 T![=] if p.at(T![==]) => (5, T![==]),
227 T![=] => (1, T![=]),
228 T![<] if p.at(T![<=]) => (5, T![<=]),
229 T![<] if p.at(T![<<=]) => (1, T![<<=]),
230 T![<] if p.at(T![<<]) => (9, T![<<]),
231 T![<] => (5, T![<]),
232 T![+] if p.at(T![+=]) => (1, T![+=]),
233 T![+] => (10, T![+]),
234 T![^] if p.at(T![^=]) => (1, T![^=]),
235 T![^] => (7, T![^]),
236 T![%] if p.at(T![%=]) => (1, T![%=]),
237 T![%] => (11, T![%]),
238 T![&] if p.at(T![&=]) => (1, T![&=]),
239 T![&] if p.at(T![&&]) => (4, T![&&]),
240 T![&] => (8, T![&]),
241 T![/] if p.at(T![/=]) => (1, T![/=]),
242 T![/] => (11, T![/]),
243 T![*] if p.at(T![*=]) => (1, T![*=]),
244 T![*] => (11, T![*]),
245 T![.] if p.at(T![..=]) => (2, T![..=]),
246 T![.] if p.at(T![..]) => (2, T![..]),
247 T![!] if p.at(T![!=]) => (5, T![!=]),
248 T![-] if p.at(T![-=]) => (1, T![-=]),
249 T![-] => (10, T![-]),
250 T![as] => (12, T![as]),
251
252 _ => NOT_AN_OP
253 }
254}
255
256// Parses expression with binding power of at least bp.
257fn expr_bp(p: &mut Parser, mut r: Restrictions, bp: u8) -> (Option<CompletedMarker>, BlockLike) {
258 let mut lhs = match lhs(p, r) {
259 Some((lhs, blocklike)) => {
260 // test stmt_bin_expr_ambiguity
261 // fn foo() {
262 // let _ = {1} & 2;
263 // {1} &2;
264 // }
265 if r.prefer_stmt && blocklike.is_block() {
266 return (Some(lhs), BlockLike::Block);
267 }
268 lhs
269 }
270 None => return (None, BlockLike::NotBlock),
271 };
272
273 loop {
274 let is_range = p.at(T![..]) || p.at(T![..=]);
275 let (op_bp, op) = current_op(p);
276 if op_bp < bp {
277 break;
278 }
279 // test as_precedence
280 // fn foo() {
281 // let _ = &1 as *const i32;
282 // }
283 if p.at(T![as]) {
284 lhs = cast_expr(p, lhs);
285 continue;
286 }
287 let m = lhs.precede(p);
288 p.bump(op);
289
290 // test binop_resets_statementness
291 // fn foo() {
292 // v = {1}&2;
293 // }
294 r = Restrictions { prefer_stmt: false, ..r };
295
296 if is_range {
297 // test postfix_range
298 // fn foo() {
299 // let x = 1..;
300 // match 1.. { _ => () };
301 // match a.b()..S { _ => () };
302 // }
303 let has_trailing_expression =
304 p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{']));
305 if !has_trailing_expression {
306 // no RHS
307 lhs = m.complete(p, RANGE_EXPR);
308 break;
309 }
310 }
311
312 expr_bp(p, Restrictions { prefer_stmt: false, ..r }, op_bp + 1);
313 lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR });
314 }
315 (Some(lhs), BlockLike::NotBlock)
316}
317
318const LHS_FIRST: TokenSet =
319 atom::ATOM_EXPR_FIRST.union(token_set![T![&], T![*], T![!], T![.], T![-]]);
320
321fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
322 let m;
323 let kind = match p.current() {
324 // test ref_expr
325 // fn foo() {
326 // // reference operator
327 // let _ = &1;
328 // let _ = &mut &f();
329 // let _ = &raw;
330 // let _ = &raw.0;
331 // // raw reference operator
332 // let _ = &raw mut foo;
333 // let _ = &raw const foo;
334 // }
335 T![&] => {
336 m = p.start();
337 p.bump(T![&]);
338 if p.at(IDENT)
339 && p.at_contextual_kw("raw")
340 && (p.nth_at(1, T![mut]) || p.nth_at(1, T![const]))
341 {
342 p.bump_remap(T![raw]);
343 p.bump_any();
344 } else {
345 p.eat(T![mut]);
346 }
347 REF_EXPR
348 }
349 // test unary_expr
350 // fn foo() {
351 // **&1;
352 // !!true;
353 // --1;
354 // }
355 T![*] | T![!] | T![-] => {
356 m = p.start();
357 p.bump_any();
358 PREFIX_EXPR
359 }
360 _ => {
361 // test full_range_expr
362 // fn foo() { xs[..]; }
363 for &op in [T![..=], T![..]].iter() {
364 if p.at(op) {
365 m = p.start();
366 p.bump(op);
367 if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])) {
368 expr_bp(p, r, 2);
369 }
370 return Some((m.complete(p, RANGE_EXPR), BlockLike::NotBlock));
371 }
372 }
373
374 // test expression_after_block
375 // fn foo() {
376 // let mut p = F{x: 5};
377 // {p}.x = 10;
378 // }
379 //
380 let (lhs, blocklike) = atom::atom_expr(p, r)?;
381 return Some(postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block())));
382 }
383 };
384 // parse the interior of the unary expression
385 expr_bp(p, r, 255);
386 Some((m.complete(p, kind), BlockLike::NotBlock))
387}
388
389fn postfix_expr(
390 p: &mut Parser,
391 mut lhs: CompletedMarker,
392 // Calls are disallowed if the type is a block and we prefer statements because the call cannot be disambiguated from a tuple
393 // E.g. `while true {break}();` is parsed as
394 // `while true {break}; ();`
395 mut block_like: BlockLike,
396 mut allow_calls: bool,
397) -> (CompletedMarker, BlockLike) {
398 loop {
399 lhs = match p.current() {
400 // test stmt_postfix_expr_ambiguity
401 // fn foo() {
402 // match () {
403 // _ => {}
404 // () => {}
405 // [] => {}
406 // }
407 // }
408 T!['('] if allow_calls => call_expr(p, lhs),
409 T!['['] if allow_calls => index_expr(p, lhs),
410 T![.] => match postfix_dot_expr(p, lhs) {
411 Ok(it) => it,
412 Err(it) => {
413 lhs = it;
414 break;
415 }
416 },
417 T![?] => try_expr(p, lhs),
418 _ => break,
419 };
420 allow_calls = true;
421 block_like = BlockLike::NotBlock;
422 }
423 return (lhs, block_like);
424
425 fn postfix_dot_expr(
426 p: &mut Parser,
427 lhs: CompletedMarker,
428 ) -> Result<CompletedMarker, CompletedMarker> {
429 assert!(p.at(T![.]));
430 if p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])) {
431 return Ok(method_call_expr(p, lhs));
432 }
433
434 // test await_expr
435 // fn foo() {
436 // x.await;
437 // x.0.await;
438 // x.0().await?.hello();
439 // }
440 if p.nth(1) == T![await] {
441 let m = lhs.precede(p);
442 p.bump(T![.]);
443 p.bump(T![await]);
444 return Ok(m.complete(p, AWAIT_EXPR));
445 }
446
447 if p.at(T![..=]) || p.at(T![..]) {
448 return Err(lhs);
449 }
450
451 Ok(field_expr(p, lhs))
452 }
453}
454
455// test call_expr
456// fn foo() {
457// let _ = f();
458// let _ = f()(1)(1, 2,);
459// let _ = f(<Foo>::func());
460// f(<Foo as Trait>::func());
461// }
462fn call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
463 assert!(p.at(T!['(']));
464 let m = lhs.precede(p);
465 arg_list(p);
466 m.complete(p, CALL_EXPR)
467}
468
469// test index_expr
470// fn foo() {
471// x[1][2];
472// }
473fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
474 assert!(p.at(T!['[']));
475 let m = lhs.precede(p);
476 p.bump(T!['[']);
477 expr(p);
478 p.expect(T![']']);
479 m.complete(p, INDEX_EXPR)
480}
481
482// test method_call_expr
483// fn foo() {
484// x.foo();
485// y.bar::<T>(1, 2,);
486// }
487fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
488 assert!(p.at(T![.]) && p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])));
489 let m = lhs.precede(p);
490 p.bump_any();
491 name_ref(p);
492 type_args::opt_type_arg_list(p, true);
493 if p.at(T!['(']) {
494 arg_list(p);
495 }
496 m.complete(p, METHOD_CALL_EXPR)
497}
498
499// test field_expr
500// fn foo() {
501// x.foo;
502// x.0.bar;
503// x.0();
504// }
505
506// test_err bad_tuple_index_expr
507// fn foo() {
508// x.0.;
509// x.1i32;
510// x.0x01;
511// }
512fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
513 assert!(p.at(T![.]));
514 let m = lhs.precede(p);
515 p.bump(T![.]);
516 if p.at(IDENT) || p.at(INT_NUMBER) {
517 name_ref_or_index(p)
518 } else if p.at(FLOAT_NUMBER) {
519 // FIXME: How to recover and instead parse INT + T![.]?
520 p.bump_any();
521 } else {
522 p.error("expected field name or number")
523 }
524 m.complete(p, FIELD_EXPR)
525}
526
527// test try_expr
528// fn foo() {
529// x?;
530// }
531fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
532 assert!(p.at(T![?]));
533 let m = lhs.precede(p);
534 p.bump(T![?]);
535 m.complete(p, TRY_EXPR)
536}
537
538// test cast_expr
539// fn foo() {
540// 82 as i32;
541// 81 as i8 + 1;
542// 79 as i16 - 1;
543// 0x36 as u8 <= 0x37;
544// }
545fn cast_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
546 assert!(p.at(T![as]));
547 let m = lhs.precede(p);
548 p.bump(T![as]);
549 // Use type_no_bounds(), because cast expressions are not
550 // allowed to have bounds.
551 types::type_no_bounds(p);
552 m.complete(p, CAST_EXPR)
553}
554
555fn arg_list(p: &mut Parser) {
556 assert!(p.at(T!['(']));
557 let m = p.start();
558 p.bump(T!['(']);
559 while !p.at(T![')']) && !p.at(EOF) {
560 // test arg_with_attr
561 // fn main() {
562 // foo(#[attr] 92)
563 // }
564 if !expr_with_attrs(p) {
565 break;
566 }
567 if !p.at(T![')']) && !p.expect(T![,]) {
568 break;
569 }
570 }
571 p.eat(T![')']);
572 m.complete(p, ARG_LIST);
573}
574
575// test path_expr
576// fn foo() {
577// let _ = a;
578// let _ = a::b;
579// let _ = ::a::<b>;
580// let _ = format!();
581// }
582fn path_expr(p: &mut Parser, r: Restrictions) -> (CompletedMarker, BlockLike) {
583 assert!(paths::is_path_start(p));
584 let m = p.start();
585 paths::expr_path(p);
586 match p.current() {
587 T!['{'] if !r.forbid_structs => {
588 record_field_list(p);
589 (m.complete(p, RECORD_EXPR), BlockLike::NotBlock)
590 }
591 T![!] if !p.at(T![!=]) => {
592 let block_like = items::macro_call_after_excl(p);
593 (m.complete(p, MACRO_CALL), block_like)
594 }
595 _ => (m.complete(p, PATH_EXPR), BlockLike::NotBlock),
596 }
597}
598
599// test record_lit
600// fn foo() {
601// S {};
602// S { x, y: 32, };
603// S { x, y: 32, ..Default::default() };
604// TupleStruct { 0: 1 };
605// }
606pub(crate) fn record_field_list(p: &mut Parser) {
607 assert!(p.at(T!['{']));
608 let m = p.start();
609 p.bump(T!['{']);
610 while !p.at(EOF) && !p.at(T!['}']) {
611 let m = p.start();
612 // test record_literal_field_with_attr
613 // fn main() {
614 // S { #[cfg(test)] field: 1 }
615 // }
616 attributes::outer_attributes(p);
617
618 match p.current() {
619 IDENT | INT_NUMBER => {
620 // test_err record_literal_before_ellipsis_recovery
621 // fn main() {
622 // S { field ..S::default() }
623 // }
624 if p.nth_at(1, T![:]) || p.nth_at(1, T![..]) {
625 name_ref_or_index(p);
626 p.expect(T![:]);
627 }
628 expr(p);
629 m.complete(p, RECORD_EXPR_FIELD);
630 }
631 T![.] if p.at(T![..]) => {
632 m.abandon(p);
633 p.bump(T![..]);
634 expr(p);
635 }
636 T!['{'] => {
637 error_block(p, "expected a field");
638 m.abandon(p);
639 }
640 _ => {
641 p.err_and_bump("expected identifier");
642 m.abandon(p);
643 }
644 }
645 if !p.at(T!['}']) {
646 p.expect(T![,]);
647 }
648 }
649 p.expect(T!['}']);
650 m.complete(p, RECORD_EXPR_FIELD_LIST);
651}
diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs
new file mode 100644
index 000000000..0b01d3bc6
--- /dev/null
+++ b/crates/parser/src/grammar/expressions/atom.rs
@@ -0,0 +1,611 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5// test expr_literals
6// fn foo() {
7// let _ = true;
8// let _ = false;
9// let _ = 1;
10// let _ = 2.0;
11// let _ = b'a';
12// let _ = 'b';
13// let _ = "c";
14// let _ = r"d";
15// let _ = b"e";
16// let _ = br"f";
17// }
18pub(crate) const LITERAL_FIRST: TokenSet = token_set![
19 TRUE_KW,
20 FALSE_KW,
21 INT_NUMBER,
22 FLOAT_NUMBER,
23 BYTE,
24 CHAR,
25 STRING,
26 RAW_STRING,
27 BYTE_STRING,
28 RAW_BYTE_STRING
29];
30
31pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> {
32 if !p.at_ts(LITERAL_FIRST) {
33 return None;
34 }
35 let m = p.start();
36 p.bump_any();
37 Some(m.complete(p, LITERAL))
38}
39
40// E.g. for after the break in `if break {}`, this should not match
41pub(super) const ATOM_EXPR_FIRST: TokenSet =
42 LITERAL_FIRST.union(paths::PATH_FIRST).union(token_set![
43 T!['('],
44 T!['{'],
45 T!['['],
46 L_DOLLAR,
47 T![|],
48 T![move],
49 T![box],
50 T![if],
51 T![while],
52 T![match],
53 T![unsafe],
54 T![return],
55 T![break],
56 T![continue],
57 T![async],
58 T![try],
59 T![loop],
60 T![for],
61 LIFETIME,
62 ]);
63
64const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW, R_DOLLAR];
65
66pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
67 if let Some(m) = literal(p) {
68 return Some((m, BlockLike::NotBlock));
69 }
70 if paths::is_path_start(p) {
71 return Some(path_expr(p, r));
72 }
73 let la = p.nth(1);
74 let done = match p.current() {
75 T!['('] => tuple_expr(p),
76 T!['['] => array_expr(p),
77 L_DOLLAR => meta_var_expr(p),
78 T![|] => lambda_expr(p),
79 T![move] if la == T![|] => lambda_expr(p),
80 T![async] if la == T![|] || (la == T![move] && p.nth(2) == T![|]) => lambda_expr(p),
81 T![if] => if_expr(p),
82
83 T![loop] => loop_expr(p, None),
84 T![box] => box_expr(p, None),
85 T![for] => for_expr(p, None),
86 T![while] => while_expr(p, None),
87 T![try] => try_block_expr(p, None),
88 LIFETIME if la == T![:] => {
89 let m = p.start();
90 label(p);
91 match p.current() {
92 T![loop] => loop_expr(p, Some(m)),
93 T![for] => for_expr(p, Some(m)),
94 T![while] => while_expr(p, Some(m)),
95 // test labeled_block
96 // fn f() { 'label: {}; }
97 T!['{'] => {
98 block_expr(p);
99 m.complete(p, EFFECT_EXPR)
100 }
101 _ => {
102 // test_err misplaced_label_err
103 // fn main() {
104 // 'loop: impl
105 // }
106 p.error("expected a loop");
107 m.complete(p, ERROR);
108 return None;
109 }
110 }
111 }
112 T![async] if la == T!['{'] || (la == T![move] && p.nth(2) == T!['{']) => {
113 let m = p.start();
114 p.bump(T![async]);
115 p.eat(T![move]);
116 block_expr(p);
117 m.complete(p, EFFECT_EXPR)
118 }
119 T![match] => match_expr(p),
120 // test unsafe_block
121 // fn f() { unsafe { } }
122 T![unsafe] if la == T!['{'] => {
123 let m = p.start();
124 p.bump(T![unsafe]);
125 block_expr(p);
126 m.complete(p, EFFECT_EXPR)
127 }
128 T!['{'] => {
129 // test for_range_from
130 // fn foo() {
131 // for x in 0 .. {
132 // break;
133 // }
134 // }
135 block_expr_unchecked(p)
136 }
137 T![return] => return_expr(p),
138 T![continue] => continue_expr(p),
139 T![break] => break_expr(p, r),
140 _ => {
141 p.err_recover("expected expression", EXPR_RECOVERY_SET);
142 return None;
143 }
144 };
145 let blocklike = match done.kind() {
146 IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR | EFFECT_EXPR => {
147 BlockLike::Block
148 }
149 _ => BlockLike::NotBlock,
150 };
151 Some((done, blocklike))
152}
153
154// test tuple_expr
155// fn foo() {
156// ();
157// (1);
158// (1,);
159// }
160fn tuple_expr(p: &mut Parser) -> CompletedMarker {
161 assert!(p.at(T!['(']));
162 let m = p.start();
163 p.expect(T!['(']);
164
165 let mut saw_comma = false;
166 let mut saw_expr = false;
167 while !p.at(EOF) && !p.at(T![')']) {
168 saw_expr = true;
169 if !p.at_ts(EXPR_FIRST) {
170 p.error("expected expression");
171 break;
172 }
173 expr(p);
174 if !p.at(T![')']) {
175 saw_comma = true;
176 p.expect(T![,]);
177 }
178 }
179 p.expect(T![')']);
180 m.complete(p, if saw_expr && !saw_comma { PAREN_EXPR } else { TUPLE_EXPR })
181}
182
183// test array_expr
184// fn foo() {
185// [];
186// [1];
187// [1, 2,];
188// [1; 2];
189// }
190fn array_expr(p: &mut Parser) -> CompletedMarker {
191 assert!(p.at(T!['[']));
192 let m = p.start();
193
194 let mut n_exprs = 0u32;
195 let mut has_semi = false;
196
197 p.bump(T!['[']);
198 while !p.at(EOF) && !p.at(T![']']) {
199 n_exprs += 1;
200
201 // test array_attrs
202 // const A: &[i64] = &[1, #[cfg(test)] 2];
203 if !expr_with_attrs(p) {
204 break;
205 }
206
207 if n_exprs == 1 && p.eat(T![;]) {
208 has_semi = true;
209 continue;
210 }
211
212 if has_semi || !p.at(T![']']) && !p.expect(T![,]) {
213 break;
214 }
215 }
216 p.expect(T![']']);
217
218 m.complete(p, ARRAY_EXPR)
219}
220
221// test lambda_expr
222// fn foo() {
223// || ();
224// || -> i32 { 92 };
225// |x| x;
226// move |x: i32,| x;
227// async || {};
228// move || {};
229// async move || {};
230// }
231fn lambda_expr(p: &mut Parser) -> CompletedMarker {
232 assert!(
233 p.at(T![|])
234 || (p.at(T![move]) && p.nth(1) == T![|])
235 || (p.at(T![async]) && p.nth(1) == T![|])
236 || (p.at(T![async]) && p.nth(1) == T![move] && p.nth(2) == T![|])
237 );
238 let m = p.start();
239 p.eat(T![async]);
240 p.eat(T![move]);
241 params::param_list_closure(p);
242 if opt_fn_ret_type(p) {
243 // test lambda_ret_block
244 // fn main() { || -> i32 { 92 }(); }
245 block_expr(p);
246 } else {
247 if p.at_ts(EXPR_FIRST) {
248 expr(p);
249 } else {
250 p.error("expected expression");
251 }
252 }
253 m.complete(p, CLOSURE_EXPR)
254}
255
256// test if_expr
257// fn foo() {
258// if true {};
259// if true {} else {};
260// if true {} else if false {} else {};
261// if S {};
262// if { true } { } else { };
263// }
264fn if_expr(p: &mut Parser) -> CompletedMarker {
265 assert!(p.at(T![if]));
266 let m = p.start();
267 p.bump(T![if]);
268 cond(p);
269 block_expr(p);
270 if p.at(T![else]) {
271 p.bump(T![else]);
272 if p.at(T![if]) {
273 if_expr(p);
274 } else {
275 block_expr(p);
276 }
277 }
278 m.complete(p, IF_EXPR)
279}
280
281// test label
282// fn foo() {
283// 'a: loop {}
284// 'b: while true {}
285// 'c: for x in () {}
286// }
287fn label(p: &mut Parser) {
288 assert!(p.at(LIFETIME) && p.nth(1) == T![:]);
289 let m = p.start();
290 p.bump(LIFETIME);
291 p.bump_any();
292 m.complete(p, LABEL);
293}
294
295// test loop_expr
296// fn foo() {
297// loop {};
298// }
299fn loop_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
300 assert!(p.at(T![loop]));
301 let m = m.unwrap_or_else(|| p.start());
302 p.bump(T![loop]);
303 block_expr(p);
304 m.complete(p, LOOP_EXPR)
305}
306
307// test while_expr
308// fn foo() {
309// while true {};
310// while let Some(x) = it.next() {};
311// while { true } {};
312// }
313fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
314 assert!(p.at(T![while]));
315 let m = m.unwrap_or_else(|| p.start());
316 p.bump(T![while]);
317 cond(p);
318 block_expr(p);
319 m.complete(p, WHILE_EXPR)
320}
321
322// test for_expr
323// fn foo() {
324// for x in [] {};
325// }
326fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
327 assert!(p.at(T![for]));
328 let m = m.unwrap_or_else(|| p.start());
329 p.bump(T![for]);
330 patterns::pattern(p);
331 p.expect(T![in]);
332 expr_no_struct(p);
333 block_expr(p);
334 m.complete(p, FOR_EXPR)
335}
336
337// test cond
338// fn foo() { if let Some(_) = None {} }
339// fn bar() {
340// if let Some(_) | Some(_) = None {}
341// if let | Some(_) = None {}
342// while let Some(_) | Some(_) = None {}
343// while let | Some(_) = None {}
344// }
345fn cond(p: &mut Parser) {
346 let m = p.start();
347 if p.eat(T![let]) {
348 patterns::pattern_top(p);
349 p.expect(T![=]);
350 }
351 expr_no_struct(p);
352 m.complete(p, CONDITION);
353}
354
355// test match_expr
356// fn foo() {
357// match () { };
358// match S {};
359// match { } { _ => () };
360// match { S {} } {};
361// }
362fn match_expr(p: &mut Parser) -> CompletedMarker {
363 assert!(p.at(T![match]));
364 let m = p.start();
365 p.bump(T![match]);
366 expr_no_struct(p);
367 if p.at(T!['{']) {
368 match_arm_list(p);
369 } else {
370 p.error("expected `{`")
371 }
372 m.complete(p, MATCH_EXPR)
373}
374
375pub(crate) fn match_arm_list(p: &mut Parser) {
376 assert!(p.at(T!['{']));
377 let m = p.start();
378 p.eat(T!['{']);
379
380 // test match_arms_inner_attribute
381 // fn foo() {
382 // match () {
383 // #![doc("Inner attribute")]
384 // #![doc("Can be")]
385 // #![doc("Stacked")]
386 // _ => (),
387 // }
388 // }
389 attributes::inner_attributes(p);
390
391 while !p.at(EOF) && !p.at(T!['}']) {
392 if p.at(T!['{']) {
393 error_block(p, "expected match arm");
394 continue;
395 }
396
397 // test match_arms_commas
398 // fn foo() {
399 // match () {
400 // _ => (),
401 // _ => {}
402 // _ => ()
403 // }
404 // }
405 if match_arm(p).is_block() {
406 p.eat(T![,]);
407 } else if !p.at(T!['}']) {
408 p.expect(T![,]);
409 }
410 }
411 p.expect(T!['}']);
412 m.complete(p, MATCH_ARM_LIST);
413}
414
415// test match_arm
416// fn foo() {
417// match () {
418// _ => (),
419// _ if Test > Test{field: 0} => (),
420// X | Y if Z => (),
421// | X | Y if Z => (),
422// | X => (),
423// };
424// }
425fn match_arm(p: &mut Parser) -> BlockLike {
426 let m = p.start();
427 // test match_arms_outer_attributes
428 // fn foo() {
429 // match () {
430 // #[cfg(feature = "some")]
431 // _ => (),
432 // #[cfg(feature = "other")]
433 // _ => (),
434 // #[cfg(feature = "many")]
435 // #[cfg(feature = "attributes")]
436 // #[cfg(feature = "before")]
437 // _ => (),
438 // }
439 // }
440 attributes::outer_attributes(p);
441
442 patterns::pattern_top_r(p, TokenSet::EMPTY);
443 if p.at(T![if]) {
444 match_guard(p);
445 }
446 p.expect(T![=>]);
447 let blocklike = expr_stmt(p).1;
448 m.complete(p, MATCH_ARM);
449 blocklike
450}
451
452// test match_guard
453// fn foo() {
454// match () {
455// _ if foo => (),
456// }
457// }
458fn match_guard(p: &mut Parser) -> CompletedMarker {
459 assert!(p.at(T![if]));
460 let m = p.start();
461 p.bump(T![if]);
462 expr(p);
463 m.complete(p, MATCH_GUARD)
464}
465
466// test block
467// fn a() {}
468// fn b() { let _ = 1; }
469// fn c() { 1; 2; }
470// fn d() { 1; 2 }
471pub(crate) fn block_expr(p: &mut Parser) {
472 if !p.at(T!['{']) {
473 p.error("expected a block");
474 return;
475 }
476 block_expr_unchecked(p);
477}
478
479fn block_expr_unchecked(p: &mut Parser) -> CompletedMarker {
480 assert!(p.at(T!['{']));
481 let m = p.start();
482 p.bump(T!['{']);
483 expr_block_contents(p);
484 p.expect(T!['}']);
485 m.complete(p, BLOCK_EXPR)
486}
487
488// test return_expr
489// fn foo() {
490// return;
491// return 92;
492// }
493fn return_expr(p: &mut Parser) -> CompletedMarker {
494 assert!(p.at(T![return]));
495 let m = p.start();
496 p.bump(T![return]);
497 if p.at_ts(EXPR_FIRST) {
498 expr(p);
499 }
500 m.complete(p, RETURN_EXPR)
501}
502
503// test continue_expr
504// fn foo() {
505// loop {
506// continue;
507// continue 'l;
508// }
509// }
510fn continue_expr(p: &mut Parser) -> CompletedMarker {
511 assert!(p.at(T![continue]));
512 let m = p.start();
513 p.bump(T![continue]);
514 p.eat(LIFETIME);
515 m.complete(p, CONTINUE_EXPR)
516}
517
518// test break_expr
519// fn foo() {
520// loop {
521// break;
522// break 'l;
523// break 92;
524// break 'l 92;
525// }
526// }
527fn break_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker {
528 assert!(p.at(T![break]));
529 let m = p.start();
530 p.bump(T![break]);
531 p.eat(LIFETIME);
532 // test break_ambiguity
533 // fn foo(){
534 // if break {}
535 // while break {}
536 // for i in break {}
537 // match break {}
538 // }
539 if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])) {
540 expr(p);
541 }
542 m.complete(p, BREAK_EXPR)
543}
544
545// test try_block_expr
546// fn foo() {
547// let _ = try {};
548// }
549fn try_block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
550 assert!(p.at(T![try]));
551 let m = m.unwrap_or_else(|| p.start());
552 // Special-case `try!` as macro.
553 // This is a hack until we do proper edition support
554 if p.nth_at(1, T![!]) {
555 // test try_macro_fallback
556 // fn foo() { try!(Ok(())); }
557 let path = p.start();
558 let path_segment = p.start();
559 let name_ref = p.start();
560 p.bump_remap(IDENT);
561 name_ref.complete(p, NAME_REF);
562 path_segment.complete(p, PATH_SEGMENT);
563 path.complete(p, PATH);
564 let _block_like = items::macro_call_after_excl(p);
565 return m.complete(p, MACRO_CALL);
566 }
567
568 p.bump(T![try]);
569 block_expr(p);
570 m.complete(p, EFFECT_EXPR)
571}
572
573// test box_expr
574// fn foo() {
575// let x = box 1i32;
576// let y = (box 1i32, box 2i32);
577// let z = Foo(box 1i32, box 2i32);
578// }
579fn box_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
580 assert!(p.at(T![box]));
581 let m = m.unwrap_or_else(|| p.start());
582 p.bump(T![box]);
583 if p.at_ts(EXPR_FIRST) {
584 expr(p);
585 }
586 m.complete(p, BOX_EXPR)
587}
588
589/// Expression from `$var` macro expansion, wrapped in dollars
590fn meta_var_expr(p: &mut Parser) -> CompletedMarker {
591 assert!(p.at(L_DOLLAR));
592 let m = p.start();
593 p.bump(L_DOLLAR);
594 let (completed, _is_block) =
595 expr_bp(p, Restrictions { forbid_structs: false, prefer_stmt: false }, 1);
596
597 match (completed, p.current()) {
598 (Some(it), R_DOLLAR) => {
599 p.bump(R_DOLLAR);
600 m.abandon(p);
601 it
602 }
603 _ => {
604 while !p.at(R_DOLLAR) {
605 p.bump_any()
606 }
607 p.bump(R_DOLLAR);
608 m.complete(p, ERROR)
609 }
610 }
611}
diff --git a/crates/parser/src/grammar/items.rs b/crates/parser/src/grammar/items.rs
new file mode 100644
index 000000000..d091b0fbb
--- /dev/null
+++ b/crates/parser/src/grammar/items.rs
@@ -0,0 +1,432 @@
1//! FIXME: write short doc here
2
3mod consts;
4mod adt;
5mod traits;
6mod use_item;
7
8pub(crate) use self::{
9 adt::{enum_variant_list, record_field_def_list},
10 expressions::{match_arm_list, record_field_list},
11 traits::{impl_item_list, trait_item_list},
12 use_item::use_tree_list,
13};
14use super::*;
15
16// test mod_contents
17// fn foo() {}
18// macro_rules! foo {}
19// foo::bar!();
20// super::baz! {}
21// struct S;
22pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) {
23 attributes::inner_attributes(p);
24 while !(stop_on_r_curly && p.at(T!['}']) || p.at(EOF)) {
25 item_or_macro(p, stop_on_r_curly)
26 }
27}
28
29pub(super) const ITEM_RECOVERY_SET: TokenSet = token_set![
30 FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW, MOD_KW, PUB_KW,
31 CRATE_KW, USE_KW, MACRO_KW
32];
33
34pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool) {
35 let m = p.start();
36 attributes::outer_attributes(p);
37 let m = match maybe_item(p, m) {
38 Ok(()) => {
39 if p.at(T![;]) {
40 p.err_and_bump(
41 "expected item, found `;`\n\
42 consider removing this semicolon",
43 );
44 }
45 return;
46 }
47 Err(m) => m,
48 };
49 if paths::is_use_path_start(p) {
50 match macro_call(p) {
51 BlockLike::Block => (),
52 BlockLike::NotBlock => {
53 p.expect(T![;]);
54 }
55 }
56 m.complete(p, MACRO_CALL);
57 } else {
58 m.abandon(p);
59 if p.at(T!['{']) {
60 error_block(p, "expected an item");
61 } else if p.at(T!['}']) && !stop_on_r_curly {
62 let e = p.start();
63 p.error("unmatched `}`");
64 p.bump(T!['}']);
65 e.complete(p, ERROR);
66 } else if !p.at(EOF) && !p.at(T!['}']) {
67 p.err_and_bump("expected an item");
68 } else {
69 p.error("expected an item");
70 }
71 }
72}
73
74pub(super) fn maybe_item(p: &mut Parser, m: Marker) -> Result<(), Marker> {
75 // test_err pub_expr
76 // fn foo() { pub 92; }
77 let has_visibility = opt_visibility(p);
78
79 let m = match items_without_modifiers(p, m) {
80 Ok(()) => return Ok(()),
81 Err(m) => m,
82 };
83
84 let mut has_mods = false;
85
86 // modifiers
87 has_mods |= p.eat(T![const]);
88
89 // test_err async_without_semicolon
90 // fn foo() { let _ = async {} }
91 if p.at(T![async]) && p.nth(1) != T!['{'] && p.nth(1) != T![move] && p.nth(1) != T![|] {
92 p.eat(T![async]);
93 has_mods = true;
94 }
95
96 // test_err unsafe_block_in_mod
97 // fn foo(){} unsafe { } fn bar(){}
98 if p.at(T![unsafe]) && p.nth(1) != T!['{'] {
99 p.eat(T![unsafe]);
100 has_mods = true;
101 }
102
103 if p.at(T![extern]) {
104 has_mods = true;
105 abi(p);
106 }
107 if p.at(IDENT) && p.at_contextual_kw("auto") && p.nth(1) == T![trait] {
108 p.bump_remap(T![auto]);
109 has_mods = true;
110 }
111
112 // test default_item
113 // default impl T for Foo {}
114 if p.at(IDENT) && p.at_contextual_kw("default") {
115 match p.nth(1) {
116 T![fn] | T![type] | T![const] | T![impl] => {
117 p.bump_remap(T![default]);
118 has_mods = true;
119 }
120 T![unsafe] => {
121 // test default_unsafe_item
122 // default unsafe impl T for Foo {
123 // default unsafe fn foo() {}
124 // }
125 if matches!(p.nth(2), T![impl] | T![fn]) {
126 p.bump_remap(T![default]);
127 p.bump(T![unsafe]);
128 has_mods = true;
129 }
130 }
131 _ => (),
132 }
133 }
134
135 // test existential_type
136 // existential type Foo: Fn() -> usize;
137 if p.at(IDENT) && p.at_contextual_kw("existential") && p.nth(1) == T![type] {
138 p.bump_remap(T![existential]);
139 has_mods = true;
140 }
141
142 // items
143 match p.current() {
144 // test fn
145 // fn foo() {}
146 T![fn] => {
147 fn_def(p);
148 m.complete(p, FN);
149 }
150
151 // test trait
152 // trait T {}
153 T![trait] => {
154 traits::trait_def(p);
155 m.complete(p, TRAIT);
156 }
157
158 T![const] => {
159 consts::const_def(p, m);
160 }
161
162 // test impl
163 // impl T for S {}
164 T![impl] => {
165 traits::impl_def(p);
166 m.complete(p, IMPL);
167 }
168
169 T![type] => {
170 type_def(p, m);
171 }
172 _ => {
173 if !has_visibility && !has_mods {
174 return Err(m);
175 } else {
176 if has_mods {
177 p.error("expected existential, fn, trait or impl");
178 } else {
179 p.error("expected an item");
180 }
181 m.complete(p, ERROR);
182 }
183 }
184 }
185 Ok(())
186}
187
188fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> {
189 let la = p.nth(1);
190 match p.current() {
191 // test extern_crate
192 // extern crate foo;
193 T![extern] if la == T![crate] => extern_crate_item(p, m),
194 T![type] => {
195 type_def(p, m);
196 }
197 T![mod] => mod_item(p, m),
198 T![struct] => {
199 // test struct_items
200 // struct Foo;
201 // struct Foo {}
202 // struct Foo();
203 // struct Foo(String, usize);
204 // struct Foo {
205 // a: i32,
206 // b: f32,
207 // }
208 adt::struct_def(p, m);
209 }
210 // test pub_macro_def
211 // pub macro m($:ident) {}
212 T![macro] => {
213 macro_def(p, m);
214 }
215 IDENT if p.at_contextual_kw("union") && p.nth(1) == IDENT => {
216 // test union_items
217 // union Foo {}
218 // union Foo {
219 // a: i32,
220 // b: f32,
221 // }
222 adt::union_def(p, m);
223 }
224 T![enum] => adt::enum_def(p, m),
225 T![use] => use_item::use_item(p, m),
226 T![const] if (la == IDENT || la == T![_] || la == T![mut]) => consts::const_def(p, m),
227 T![static] => consts::static_def(p, m),
228 // test extern_block
229 // extern {}
230 T![extern]
231 if la == T!['{'] || ((la == STRING || la == RAW_STRING) && p.nth(2) == T!['{']) =>
232 {
233 abi(p);
234 extern_item_list(p);
235 m.complete(p, EXTERN_BLOCK);
236 }
237 _ => return Err(m),
238 };
239 Ok(())
240}
241
242fn extern_crate_item(p: &mut Parser, m: Marker) {
243 assert!(p.at(T![extern]));
244 p.bump(T![extern]);
245 assert!(p.at(T![crate]));
246 p.bump(T![crate]);
247
248 if p.at(T![self]) {
249 p.bump(T![self]);
250 } else {
251 name_ref(p);
252 }
253
254 opt_alias(p);
255 p.expect(T![;]);
256 m.complete(p, EXTERN_CRATE);
257}
258
259pub(crate) fn extern_item_list(p: &mut Parser) {
260 assert!(p.at(T!['{']));
261 let m = p.start();
262 p.bump(T!['{']);
263 mod_contents(p, true);
264 p.expect(T!['}']);
265 m.complete(p, EXTERN_ITEM_LIST);
266}
267
268fn fn_def(p: &mut Parser) {
269 assert!(p.at(T![fn]));
270 p.bump(T![fn]);
271
272 name_r(p, ITEM_RECOVERY_SET);
273 // test function_type_params
274 // fn foo<T: Clone + Copy>(){}
275 type_params::opt_type_param_list(p);
276
277 if p.at(T!['(']) {
278 params::param_list_fn_def(p);
279 } else {
280 p.error("expected function arguments");
281 }
282 // test function_ret_type
283 // fn foo() {}
284 // fn bar() -> () {}
285 opt_fn_ret_type(p);
286
287 // test function_where_clause
288 // fn foo<T>() where T: Copy {}
289 type_params::opt_where_clause(p);
290
291 // test fn_decl
292 // trait T { fn foo(); }
293 if p.at(T![;]) {
294 p.bump(T![;]);
295 } else {
296 expressions::block_expr(p)
297 }
298}
299
300// test type_item
301// type Foo = Bar;
302fn type_def(p: &mut Parser, m: Marker) {
303 assert!(p.at(T![type]));
304 p.bump(T![type]);
305
306 name(p);
307
308 // test type_item_type_params
309 // type Result<T> = ();
310 type_params::opt_type_param_list(p);
311
312 if p.at(T![:]) {
313 type_params::bounds(p);
314 }
315
316 // test type_item_where_clause
317 // type Foo where Foo: Copy = ();
318 type_params::opt_where_clause(p);
319 if p.eat(T![=]) {
320 types::type_(p);
321 }
322 p.expect(T![;]);
323 m.complete(p, TYPE_ALIAS);
324}
325
326pub(crate) fn mod_item(p: &mut Parser, m: Marker) {
327 assert!(p.at(T![mod]));
328 p.bump(T![mod]);
329
330 name(p);
331 if p.at(T!['{']) {
332 mod_item_list(p);
333 } else if !p.eat(T![;]) {
334 p.error("expected `;` or `{`");
335 }
336 m.complete(p, MODULE);
337}
338
339pub(crate) fn mod_item_list(p: &mut Parser) {
340 assert!(p.at(T!['{']));
341 let m = p.start();
342 p.bump(T!['{']);
343 mod_contents(p, true);
344 p.expect(T!['}']);
345 m.complete(p, ITEM_LIST);
346}
347
348// test macro_def
349// macro m { ($i:ident) => {} }
350// macro m($i:ident) {}
351fn macro_def(p: &mut Parser, m: Marker) {
352 p.expect(T![macro]);
353 name_r(p, ITEM_RECOVERY_SET);
354 if p.at(T!['{']) {
355 token_tree(p);
356 } else if !p.at(T!['(']) {
357 p.error("unmatched `(`");
358 } else {
359 let m = p.start();
360 token_tree(p);
361 match p.current() {
362 T!['{'] | T!['['] | T!['('] => token_tree(p),
363 _ => p.error("expected `{`, `[`, `(`"),
364 }
365 m.complete(p, TOKEN_TREE);
366 }
367
368 m.complete(p, MACRO_DEF);
369}
370
371fn macro_call(p: &mut Parser) -> BlockLike {
372 assert!(paths::is_use_path_start(p));
373 paths::use_path(p);
374 macro_call_after_excl(p)
375}
376
377pub(super) fn macro_call_after_excl(p: &mut Parser) -> BlockLike {
378 p.expect(T![!]);
379 if p.at(IDENT) {
380 name(p);
381 }
382 // Special-case `macro_rules! try`.
383 // This is a hack until we do proper edition support
384
385 // test try_macro_rules
386 // macro_rules! try { () => {} }
387 if p.at(T![try]) {
388 let m = p.start();
389 p.bump_remap(IDENT);
390 m.complete(p, NAME);
391 }
392
393 match p.current() {
394 T!['{'] => {
395 token_tree(p);
396 BlockLike::Block
397 }
398 T!['('] | T!['['] => {
399 token_tree(p);
400 BlockLike::NotBlock
401 }
402 _ => {
403 p.error("expected `{`, `[`, `(`");
404 BlockLike::NotBlock
405 }
406 }
407}
408
409pub(crate) fn token_tree(p: &mut Parser) {
410 let closing_paren_kind = match p.current() {
411 T!['{'] => T!['}'],
412 T!['('] => T![')'],
413 T!['['] => T![']'],
414 _ => unreachable!(),
415 };
416 let m = p.start();
417 p.bump_any();
418 while !p.at(EOF) && !p.at(closing_paren_kind) {
419 match p.current() {
420 T!['{'] | T!['('] | T!['['] => token_tree(p),
421 T!['}'] => {
422 p.error("unmatched `}`");
423 m.complete(p, TOKEN_TREE);
424 return;
425 }
426 T![')'] | T![']'] => p.err_and_bump("unmatched brace"),
427 _ => p.bump_any(),
428 }
429 }
430 p.expect(closing_paren_kind);
431 m.complete(p, TOKEN_TREE);
432}
diff --git a/crates/parser/src/grammar/items/adt.rs b/crates/parser/src/grammar/items/adt.rs
new file mode 100644
index 000000000..addfb59d4
--- /dev/null
+++ b/crates/parser/src/grammar/items/adt.rs
@@ -0,0 +1,178 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) fn struct_def(p: &mut Parser, m: Marker) {
6 assert!(p.at(T![struct]));
7 p.bump(T![struct]);
8 struct_or_union(p, m, T![struct], STRUCT);
9}
10
11pub(super) fn union_def(p: &mut Parser, m: Marker) {
12 assert!(p.at_contextual_kw("union"));
13 p.bump_remap(T![union]);
14 struct_or_union(p, m, T![union], UNION);
15}
16
17fn struct_or_union(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) {
18 name_r(p, ITEM_RECOVERY_SET);
19 type_params::opt_type_param_list(p);
20 match p.current() {
21 T![where] => {
22 type_params::opt_where_clause(p);
23 match p.current() {
24 T![;] => {
25 p.bump(T![;]);
26 }
27 T!['{'] => record_field_def_list(p),
28 _ => {
29 //FIXME: special case `(` error message
30 p.error("expected `;` or `{`");
31 }
32 }
33 }
34 T![;] if kw == T![struct] => {
35 p.bump(T![;]);
36 }
37 T!['{'] => record_field_def_list(p),
38 T!['('] if kw == T![struct] => {
39 tuple_field_def_list(p);
40 // test tuple_struct_where
41 // struct Test<T>(T) where T: Clone;
42 // struct Test<T>(T);
43 type_params::opt_where_clause(p);
44 p.expect(T![;]);
45 }
46 _ if kw == T![struct] => {
47 p.error("expected `;`, `{`, or `(`");
48 }
49 _ => {
50 p.error("expected `{`");
51 }
52 }
53 m.complete(p, def);
54}
55
56pub(super) fn enum_def(p: &mut Parser, m: Marker) {
57 assert!(p.at(T![enum]));
58 p.bump(T![enum]);
59 name_r(p, ITEM_RECOVERY_SET);
60 type_params::opt_type_param_list(p);
61 type_params::opt_where_clause(p);
62 if p.at(T!['{']) {
63 enum_variant_list(p);
64 } else {
65 p.error("expected `{`")
66 }
67 m.complete(p, ENUM);
68}
69
70pub(crate) fn enum_variant_list(p: &mut Parser) {
71 assert!(p.at(T!['{']));
72 let m = p.start();
73 p.bump(T!['{']);
74 while !p.at(EOF) && !p.at(T!['}']) {
75 if p.at(T!['{']) {
76 error_block(p, "expected enum variant");
77 continue;
78 }
79 let var = p.start();
80 attributes::outer_attributes(p);
81 if p.at(IDENT) {
82 name(p);
83 match p.current() {
84 T!['{'] => record_field_def_list(p),
85 T!['('] => tuple_field_def_list(p),
86 _ => (),
87 }
88
89 // test variant_discriminant
90 // enum E { X(i32) = 10 }
91 if p.eat(T![=]) {
92 expressions::expr(p);
93 }
94 var.complete(p, VARIANT);
95 } else {
96 var.abandon(p);
97 p.err_and_bump("expected enum variant");
98 }
99 if !p.at(T!['}']) {
100 p.expect(T![,]);
101 }
102 }
103 p.expect(T!['}']);
104 m.complete(p, VARIANT_LIST);
105}
106
107pub(crate) fn record_field_def_list(p: &mut Parser) {
108 assert!(p.at(T!['{']));
109 let m = p.start();
110 p.bump(T!['{']);
111 while !p.at(T!['}']) && !p.at(EOF) {
112 if p.at(T!['{']) {
113 error_block(p, "expected field");
114 continue;
115 }
116 record_field_def(p);
117 if !p.at(T!['}']) {
118 p.expect(T![,]);
119 }
120 }
121 p.expect(T!['}']);
122 m.complete(p, RECORD_FIELD_LIST);
123
124 fn record_field_def(p: &mut Parser) {
125 let m = p.start();
126 // test record_field_attrs
127 // struct S {
128 // #[serde(with = "url_serde")]
129 // pub uri: Uri,
130 // }
131 attributes::outer_attributes(p);
132 opt_visibility(p);
133 if p.at(IDENT) {
134 name(p);
135 p.expect(T![:]);
136 types::type_(p);
137 m.complete(p, RECORD_FIELD);
138 } else {
139 m.abandon(p);
140 p.err_and_bump("expected field declaration");
141 }
142 }
143}
144
145fn tuple_field_def_list(p: &mut Parser) {
146 assert!(p.at(T!['(']));
147 let m = p.start();
148 if !p.expect(T!['(']) {
149 return;
150 }
151 while !p.at(T![')']) && !p.at(EOF) {
152 let m = p.start();
153 // test tuple_field_attrs
154 // struct S (
155 // #[serde(with = "url_serde")]
156 // pub Uri,
157 // );
158 //
159 // enum S {
160 // Uri(#[serde(with = "url_serde")] Uri),
161 // }
162 attributes::outer_attributes(p);
163 opt_visibility(p);
164 if !p.at_ts(types::TYPE_FIRST) {
165 p.error("expected a type");
166 m.complete(p, ERROR);
167 break;
168 }
169 types::type_(p);
170 m.complete(p, TUPLE_FIELD);
171
172 if !p.at(T![')']) {
173 p.expect(T![,]);
174 }
175 }
176 p.expect(T![')']);
177 m.complete(p, TUPLE_FIELD_LIST);
178}
diff --git a/crates/parser/src/grammar/items/consts.rs b/crates/parser/src/grammar/items/consts.rs
new file mode 100644
index 000000000..35ad766dc
--- /dev/null
+++ b/crates/parser/src/grammar/items/consts.rs
@@ -0,0 +1,33 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) fn static_def(p: &mut Parser, m: Marker) {
6 const_or_static(p, m, T![static], STATIC)
7}
8
9pub(super) fn const_def(p: &mut Parser, m: Marker) {
10 const_or_static(p, m, T![const], CONST)
11}
12
13fn const_or_static(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) {
14 assert!(p.at(kw));
15 p.bump(kw);
16 p.eat(T![mut]); // FIXME: validator to forbid const mut
17
18 // Allow `_` in place of an identifier in a `const`.
19 let is_const_underscore = kw == T![const] && p.eat(T![_]);
20 if !is_const_underscore {
21 name(p);
22 }
23
24 // test_err static_underscore
25 // static _: i32 = 5;
26
27 types::ascription(p);
28 if p.eat(T![=]) {
29 expressions::expr(p);
30 }
31 p.expect(T![;]);
32 m.complete(p, def);
33}
diff --git a/crates/parser/src/grammar/items/traits.rs b/crates/parser/src/grammar/items/traits.rs
new file mode 100644
index 000000000..751ce65f2
--- /dev/null
+++ b/crates/parser/src/grammar/items/traits.rs
@@ -0,0 +1,153 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5// test trait_item
6// trait T<U>: Hash + Clone where U: Copy {}
7// trait X<U: Debug + Display>: Hash + Clone where U: Copy {}
8pub(super) fn trait_def(p: &mut Parser) {
9 assert!(p.at(T![trait]));
10 p.bump(T![trait]);
11 name_r(p, ITEM_RECOVERY_SET);
12 type_params::opt_type_param_list(p);
13 // test trait_alias
14 // trait Z<U> = T<U>;
15 // trait Z<U> = T<U> where U: Copy;
16 // trait Z<U> = where Self: T<U>;
17 if p.eat(T![=]) {
18 type_params::bounds_without_colon(p);
19 type_params::opt_where_clause(p);
20 p.expect(T![;]);
21 return;
22 }
23 if p.at(T![:]) {
24 type_params::bounds(p);
25 }
26 type_params::opt_where_clause(p);
27 if p.at(T!['{']) {
28 trait_item_list(p);
29 } else {
30 p.error("expected `{`");
31 }
32}
33
34// test trait_item_list
35// impl F {
36// type A: Clone;
37// const B: i32;
38// fn foo() {}
39// fn bar(&self);
40// }
41pub(crate) fn trait_item_list(p: &mut Parser) {
42 assert!(p.at(T!['{']));
43 let m = p.start();
44 p.bump(T!['{']);
45 while !p.at(EOF) && !p.at(T!['}']) {
46 if p.at(T!['{']) {
47 error_block(p, "expected an item");
48 continue;
49 }
50 item_or_macro(p, true);
51 }
52 p.expect(T!['}']);
53 m.complete(p, ASSOC_ITEM_LIST);
54}
55
56// test impl_def
57// impl Foo {}
58pub(super) fn impl_def(p: &mut Parser) {
59 assert!(p.at(T![impl]));
60 p.bump(T![impl]);
61 if choose_type_params_over_qpath(p) {
62 type_params::opt_type_param_list(p);
63 }
64
65 // FIXME: never type
66 // impl ! {}
67
68 // test impl_def_neg
69 // impl !Send for X {}
70 p.eat(T![!]);
71 impl_type(p);
72 if p.eat(T![for]) {
73 impl_type(p);
74 }
75 type_params::opt_where_clause(p);
76 if p.at(T!['{']) {
77 impl_item_list(p);
78 } else {
79 p.error("expected `{`");
80 }
81}
82
83// test impl_item_list
84// impl F {
85// type A = i32;
86// const B: i32 = 92;
87// fn foo() {}
88// fn bar(&self) {}
89// }
90pub(crate) fn impl_item_list(p: &mut Parser) {
91 assert!(p.at(T!['{']));
92 let m = p.start();
93 p.bump(T!['{']);
94 // test impl_inner_attributes
95 // enum F{}
96 // impl F {
97 // //! This is a doc comment
98 // #![doc("This is also a doc comment")]
99 // }
100 attributes::inner_attributes(p);
101
102 while !p.at(EOF) && !p.at(T!['}']) {
103 if p.at(T!['{']) {
104 error_block(p, "expected an item");
105 continue;
106 }
107 item_or_macro(p, true);
108 }
109 p.expect(T!['}']);
110 m.complete(p, ASSOC_ITEM_LIST);
111}
112
113// test impl_type_params
114// impl<const N: u32> Bar<N> {}
115fn choose_type_params_over_qpath(p: &Parser) -> bool {
116 // There's an ambiguity between generic parameters and qualified paths in impls.
117 // If we see `<` it may start both, so we have to inspect some following tokens.
118 // The following combinations can only start generics,
119 // but not qualified paths (with one exception):
120 // `<` `>` - empty generic parameters
121 // `<` `#` - generic parameters with attributes
122 // `<` `const` - const generic parameters
123 // `<` (LIFETIME|IDENT) `>` - single generic parameter
124 // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list
125 // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds
126 // `<` (LIFETIME|IDENT) `=` - generic parameter with a default
127 // The only truly ambiguous case is
128 // `<` IDENT `>` `::` IDENT ...
129 // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
130 // because this is what almost always expected in practice, qualified paths in impls
131 // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment.
132 if !p.at(T![<]) {
133 return false;
134 }
135 if p.nth(1) == T![#] || p.nth(1) == T![>] || p.nth(1) == CONST_KW {
136 return true;
137 }
138 (p.nth(1) == LIFETIME || p.nth(1) == IDENT)
139 && (p.nth(2) == T![>] || p.nth(2) == T![,] || p.nth(2) == T![:] || p.nth(2) == T![=])
140}
141
142// test_err impl_type
143// impl Type {}
144// impl Trait1 for T {}
145// impl impl NotType {}
146// impl Trait2 for impl NotType {}
147pub(crate) fn impl_type(p: &mut Parser) {
148 if p.at(T![impl]) {
149 p.error("expected trait or type");
150 return;
151 }
152 types::type_(p);
153}
diff --git a/crates/parser/src/grammar/items/use_item.rs b/crates/parser/src/grammar/items/use_item.rs
new file mode 100644
index 000000000..8e836a77e
--- /dev/null
+++ b/crates/parser/src/grammar/items/use_item.rs
@@ -0,0 +1,132 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) fn use_item(p: &mut Parser, m: Marker) {
6 assert!(p.at(T![use]));
7 p.bump(T![use]);
8 use_tree(p, true);
9 p.expect(T![;]);
10 m.complete(p, USE);
11}
12
13/// Parse a use 'tree', such as `some::path` in `use some::path;`
14/// Note that this is called both by `use_item` and `use_tree_list`,
15/// so handles both `some::path::{inner::path}` and `inner::path` in
16/// `use some::path::{inner::path};`
17fn use_tree(p: &mut Parser, top_level: bool) {
18 let m = p.start();
19 match p.current() {
20 // Finish the use_tree for cases of e.g.
21 // `use some::path::{self, *};` or `use *;`
22 // This does not handle cases such as `use some::path::*`
23 // N.B. in Rust 2015 `use *;` imports all from crate root
24 // however in Rust 2018 `use *;` errors: ('cannot glob-import all possible crates')
25 // FIXME: Add this error (if not out of scope)
26
27 // test use_star
28 // use *;
29 // use ::*;
30 // use some::path::{*};
31 // use some::path::{::*};
32 T![*] => p.bump(T![*]),
33 T![:] if p.at(T![::]) && p.nth(2) == T![*] => {
34 // Parse `use ::*;`, which imports all from the crate root in Rust 2015
35 // This is invalid inside a use_tree_list, (e.g. `use some::path::{::*}`)
36 // but still parses and errors later: ('crate root in paths can only be used in start position')
37 // FIXME: Add this error (if not out of scope)
38 // In Rust 2018, it is always invalid (see above)
39 p.bump(T![::]);
40 p.bump(T![*]);
41 }
42 // Open a use tree list
43 // Handles cases such as `use {some::path};` or `{inner::path}` in
44 // `use some::path::{{inner::path}, other::path}`
45
46 // test use_tree_list
47 // use {crate::path::from::root, or::path::from::crate_name}; // Rust 2018 (with a crate named `or`)
48 // use {path::from::root}; // Rust 2015
49 // use ::{some::arbritrary::path}; // Rust 2015
50 // use ::{{{root::export}}}; // Nonsensical but perfectly legal nesting
51 T!['{'] => {
52 use_tree_list(p);
53 }
54 T![:] if p.at(T![::]) && p.nth(2) == T!['{'] => {
55 p.bump(T![::]);
56 use_tree_list(p);
57 }
58 // Parse a 'standard' path.
59 // Also handles aliases (e.g. `use something as something_else`)
60
61 // test use_path
62 // use ::crate_name; // Rust 2018 - All flavours
63 // use crate_name; // Rust 2018 - Anchored paths
64 // use item_in_scope_or_crate_name; // Rust 2018 - Uniform Paths
65 //
66 // use self::module::Item;
67 // use crate::Item;
68 // use self::some::Struct;
69 // use crate_name::some_item;
70 _ if paths::is_use_path_start(p) => {
71 paths::use_path(p);
72 match p.current() {
73 T![as] => {
74 // test use_alias
75 // use some::path as some_name;
76 // use some::{
77 // other::path as some_other_name,
78 // different::path as different_name,
79 // yet::another::path,
80 // running::out::of::synonyms::for_::different::*
81 // };
82 // use Trait as _;
83 opt_alias(p);
84 }
85 T![:] if p.at(T![::]) => {
86 p.bump(T![::]);
87 match p.current() {
88 T![*] => {
89 p.bump(T![*]);
90 }
91 // test use_tree_list_after_path
92 // use crate::{Item};
93 // use self::{Item};
94 T!['{'] => use_tree_list(p),
95 _ => {
96 // is this unreachable?
97 p.error("expected `{` or `*`");
98 }
99 }
100 }
101 _ => (),
102 }
103 }
104 _ => {
105 m.abandon(p);
106 let msg = "expected one of `*`, `::`, `{`, `self`, `super` or an identifier";
107 if top_level {
108 p.err_recover(msg, ITEM_RECOVERY_SET);
109 } else {
110 // if we are parsing a nested tree, we have to eat a token to
111 // main balanced `{}`
112 p.err_and_bump(msg);
113 }
114 return;
115 }
116 }
117 m.complete(p, USE_TREE);
118}
119
120pub(crate) fn use_tree_list(p: &mut Parser) {
121 assert!(p.at(T!['{']));
122 let m = p.start();
123 p.bump(T!['{']);
124 while !p.at(EOF) && !p.at(T!['}']) {
125 use_tree(p, false);
126 if !p.at(T!['}']) {
127 p.expect(T![,]);
128 }
129 }
130 p.expect(T!['}']);
131 m.complete(p, USE_TREE_LIST);
132}
diff --git a/crates/parser/src/grammar/params.rs b/crates/parser/src/grammar/params.rs
new file mode 100644
index 000000000..f0da173cc
--- /dev/null
+++ b/crates/parser/src/grammar/params.rs
@@ -0,0 +1,188 @@
1//! FIXME: write short doc here
2
3use 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: ()) {}
10pub(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>)>(){}
16pub(super) fn param_list_fn_trait(p: &mut Parser) {
17 list_(p, Flavor::FnTrait)
18}
19
20pub(super) fn param_list_fn_ptr(p: &mut Parser) {
21 list_(p, Flavor::FnPointer)
22}
23
24pub(super) fn param_list_closure(p: &mut Parser) {
25 list_(p, Flavor::Closure)
26}
27
28#[derive(Debug, Clone, Copy)]
29enum 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
36fn 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_attributes(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_attributes(p);
58
59 if !p.at_ts(VALUE_PARAMETER_FIRST) {
60 p.error("expected value parameter");
61 break;
62 }
63 let param = value_parameter(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
76const VALUE_PARAMETER_FIRST: TokenSet = patterns::PATTERN_FIRST.union(types::TYPE_FIRST);
77
78struct Variadic(bool);
79
80fn value_parameter(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
136fn 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// }
154fn 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}
diff --git a/crates/parser/src/grammar/paths.rs b/crates/parser/src/grammar/paths.rs
new file mode 100644
index 000000000..b503af1dc
--- /dev/null
+++ b/crates/parser/src/grammar/paths.rs
@@ -0,0 +1,115 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) const PATH_FIRST: TokenSet =
6 token_set![IDENT, T![self], T![super], T![crate], T![:], T![<]];
7
8pub(super) fn is_path_start(p: &Parser) -> bool {
9 is_use_path_start(p) || p.at(T![<])
10}
11
12pub(super) fn is_use_path_start(p: &Parser) -> bool {
13 match p.current() {
14 IDENT | T![self] | T![super] | T![crate] => true,
15 T![:] if p.at(T![::]) => true,
16 _ => false,
17 }
18}
19
20pub(super) fn use_path(p: &mut Parser) {
21 path(p, Mode::Use)
22}
23
24pub(crate) fn type_path(p: &mut Parser) {
25 path(p, Mode::Type)
26}
27
28pub(super) fn expr_path(p: &mut Parser) {
29 path(p, Mode::Expr)
30}
31
32#[derive(Clone, Copy, Eq, PartialEq)]
33enum Mode {
34 Use,
35 Type,
36 Expr,
37}
38
39fn path(p: &mut Parser, mode: Mode) {
40 let path = p.start();
41 path_segment(p, mode, true);
42 let mut qual = path.complete(p, PATH);
43 loop {
44 let use_tree = matches!(p.nth(2), T![*] | T!['{']);
45 if p.at(T![::]) && !use_tree {
46 let path = qual.precede(p);
47 p.bump(T![::]);
48 path_segment(p, mode, false);
49 let path = path.complete(p, PATH);
50 qual = path;
51 } else {
52 break;
53 }
54 }
55}
56
57fn path_segment(p: &mut Parser, mode: Mode, first: bool) {
58 let m = p.start();
59 // test qual_paths
60 // type X = <A as B>::Output;
61 // fn foo() { <usize as Default>::default(); }
62 if first && p.eat(T![<]) {
63 types::type_(p);
64 if p.eat(T![as]) {
65 if is_use_path_start(p) {
66 types::path_type(p);
67 } else {
68 p.error("expected a trait");
69 }
70 }
71 p.expect(T![>]);
72 } else {
73 let mut empty = true;
74 if first {
75 p.eat(T![::]);
76 empty = false;
77 }
78 match p.current() {
79 IDENT => {
80 name_ref(p);
81 opt_path_type_args(p, mode);
82 }
83 // test crate_path
84 // use crate::foo;
85 T![self] | T![super] | T![crate] => p.bump_any(),
86 _ => {
87 p.err_recover("expected identifier", items::ITEM_RECOVERY_SET);
88 if empty {
89 // test_err empty_segment
90 // use crate::;
91 m.abandon(p);
92 return;
93 }
94 }
95 };
96 }
97 m.complete(p, PATH_SEGMENT);
98}
99
100fn opt_path_type_args(p: &mut Parser, mode: Mode) {
101 match mode {
102 Mode::Use => {}
103 Mode::Type => {
104 // test path_fn_trait_args
105 // type F = Box<Fn(i32) -> ()>;
106 if p.at(T!['(']) {
107 params::param_list_fn_trait(p);
108 opt_fn_ret_type(p);
109 } else {
110 type_args::opt_type_arg_list(p, false)
111 }
112 }
113 Mode::Expr => type_args::opt_type_arg_list(p, true),
114 }
115}
diff --git a/crates/parser/src/grammar/patterns.rs b/crates/parser/src/grammar/patterns.rs
new file mode 100644
index 000000000..716bdc978
--- /dev/null
+++ b/crates/parser/src/grammar/patterns.rs
@@ -0,0 +1,379 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) const PATTERN_FIRST: TokenSet = expressions::LITERAL_FIRST
6 .union(paths::PATH_FIRST)
7 .union(token_set![T![box], T![ref], T![mut], T!['('], T!['['], T![&], T![_], T![-], T![.]]);
8
9pub(crate) fn pattern(p: &mut Parser) {
10 pattern_r(p, PAT_RECOVERY_SET);
11}
12
13/// Parses a pattern list separated by pipes `|`
14pub(super) fn pattern_top(p: &mut Parser) {
15 pattern_top_r(p, PAT_RECOVERY_SET)
16}
17
18pub(crate) fn pattern_single(p: &mut Parser) {
19 pattern_single_r(p, PAT_RECOVERY_SET);
20}
21
22/// Parses a pattern list separated by pipes `|`
23/// using the given `recovery_set`
24pub(super) fn pattern_top_r(p: &mut Parser, recovery_set: TokenSet) {
25 p.eat(T![|]);
26 pattern_r(p, recovery_set);
27}
28
29/// Parses a pattern list separated by pipes `|`, with no leading `|`,using the
30/// given `recovery_set`
31// test or_pattern
32// fn main() {
33// match () {
34// (_ | _) => (),
35// &(_ | _) => (),
36// (_ | _,) => (),
37// [_ | _,] => (),
38// }
39// }
40fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
41 let m = p.start();
42 pattern_single_r(p, recovery_set);
43
44 if !p.at(T![|]) {
45 m.abandon(p);
46 return;
47 }
48 while p.eat(T![|]) {
49 pattern_single_r(p, recovery_set);
50 }
51 m.complete(p, OR_PAT);
52}
53
54fn pattern_single_r(p: &mut Parser, recovery_set: TokenSet) {
55 if let Some(lhs) = atom_pat(p, recovery_set) {
56 // test range_pat
57 // fn main() {
58 // match 92 {
59 // 0 ... 100 => (),
60 // 101 ..= 200 => (),
61 // 200 .. 301=> (),
62 // }
63 // }
64 for &range_op in [T![...], T![..=], T![..]].iter() {
65 if p.at(range_op) {
66 let m = lhs.precede(p);
67 p.bump(range_op);
68 atom_pat(p, recovery_set);
69 m.complete(p, RANGE_PAT);
70 return;
71 }
72 }
73 }
74}
75
76const PAT_RECOVERY_SET: TokenSet =
77 token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA];
78
79fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
80 let m = match p.nth(0) {
81 T![box] => box_pat(p),
82 T![ref] | T![mut] => bind_pat(p, true),
83 IDENT => match p.nth(1) {
84 // Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro
85 // (T![x]).
86 T!['('] | T!['{'] | T![!] => path_or_macro_pat(p),
87 T![:] if p.nth_at(1, T![::]) => path_or_macro_pat(p),
88 _ => bind_pat(p, true),
89 },
90
91 // test type_path_in_pattern
92 // fn main() { let <_>::Foo = (); }
93 _ if paths::is_path_start(p) => path_or_macro_pat(p),
94 _ if is_literal_pat_start(p) => literal_pat(p),
95
96 T![.] if p.at(T![..]) => dot_dot_pat(p),
97 T![_] => placeholder_pat(p),
98 T![&] => ref_pat(p),
99 T!['('] => tuple_pat(p),
100 T!['['] => slice_pat(p),
101
102 _ => {
103 p.err_recover("expected pattern", recovery_set);
104 return None;
105 }
106 };
107
108 Some(m)
109}
110
111fn is_literal_pat_start(p: &Parser) -> bool {
112 p.at(T![-]) && (p.nth(1) == INT_NUMBER || p.nth(1) == FLOAT_NUMBER)
113 || p.at_ts(expressions::LITERAL_FIRST)
114}
115
116// test literal_pattern
117// fn main() {
118// match () {
119// -1 => (),
120// 92 => (),
121// 'c' => (),
122// "hello" => (),
123// }
124// }
125fn literal_pat(p: &mut Parser) -> CompletedMarker {
126 assert!(is_literal_pat_start(p));
127 let m = p.start();
128 if p.at(T![-]) {
129 p.bump(T![-]);
130 }
131 expressions::literal(p);
132 m.complete(p, LITERAL_PAT)
133}
134
135// test path_part
136// fn foo() {
137// let foo::Bar = ();
138// let ::Bar = ();
139// let Bar { .. } = ();
140// let Bar(..) = ();
141// }
142fn path_or_macro_pat(p: &mut Parser) -> CompletedMarker {
143 assert!(paths::is_path_start(p));
144 let m = p.start();
145 paths::expr_path(p);
146 let kind = match p.current() {
147 T!['('] => {
148 tuple_pat_fields(p);
149 TUPLE_STRUCT_PAT
150 }
151 T!['{'] => {
152 record_field_pat_list(p);
153 RECORD_PAT
154 }
155 // test marco_pat
156 // fn main() {
157 // let m!(x) = 0;
158 // }
159 T![!] => {
160 items::macro_call_after_excl(p);
161 return m.complete(p, MACRO_CALL).precede(p).complete(p, MACRO_PAT);
162 }
163 _ => PATH_PAT,
164 };
165 m.complete(p, kind)
166}
167
168// test tuple_pat_fields
169// fn foo() {
170// let S() = ();
171// let S(_) = ();
172// let S(_,) = ();
173// let S(_, .. , x) = ();
174// }
175fn tuple_pat_fields(p: &mut Parser) {
176 assert!(p.at(T!['(']));
177 p.bump(T!['(']);
178 pat_list(p, T![')']);
179 p.expect(T![')']);
180}
181
182// test record_field_pat_list
183// fn foo() {
184// let S {} = ();
185// let S { f, ref mut g } = ();
186// let S { h: _, ..} = ();
187// let S { h: _, } = ();
188// }
189fn record_field_pat_list(p: &mut Parser) {
190 assert!(p.at(T!['{']));
191 let m = p.start();
192 p.bump(T!['{']);
193 while !p.at(EOF) && !p.at(T!['}']) {
194 match p.current() {
195 // A trailing `..` is *not* treated as a REST_PAT.
196 T![.] if p.at(T![..]) => p.bump(T![..]),
197 T!['{'] => error_block(p, "expected ident"),
198
199 c => {
200 let m = p.start();
201 match c {
202 // test record_field_pat
203 // fn foo() {
204 // let S { 0: 1 } = ();
205 // let S { x: 1 } = ();
206 // }
207 IDENT | INT_NUMBER if p.nth(1) == T![:] => {
208 name_ref_or_index(p);
209 p.bump(T![:]);
210 pattern(p);
211 }
212 T![box] => {
213 // FIXME: not all box patterns should be allowed
214 box_pat(p);
215 }
216 _ => {
217 bind_pat(p, false);
218 }
219 }
220 m.complete(p, RECORD_PAT_FIELD);
221 }
222 }
223 if !p.at(T!['}']) {
224 p.expect(T![,]);
225 }
226 }
227 p.expect(T!['}']);
228 m.complete(p, RECORD_PAT_FIELD_LIST);
229}
230
231// test placeholder_pat
232// fn main() { let _ = (); }
233fn placeholder_pat(p: &mut Parser) -> CompletedMarker {
234 assert!(p.at(T![_]));
235 let m = p.start();
236 p.bump(T![_]);
237 m.complete(p, WILDCARD_PAT)
238}
239
240// test dot_dot_pat
241// fn main() {
242// let .. = ();
243// //
244// // Tuples
245// //
246// let (a, ..) = ();
247// let (a, ..,) = ();
248// let Tuple(a, ..) = ();
249// let Tuple(a, ..,) = ();
250// let (.., ..) = ();
251// let Tuple(.., ..) = ();
252// let (.., a, ..) = ();
253// let Tuple(.., a, ..) = ();
254// //
255// // Slices
256// //
257// let [..] = ();
258// let [head, ..] = ();
259// let [head, tail @ ..] = ();
260// let [head, .., cons] = ();
261// let [head, mid @ .., cons] = ();
262// let [head, .., .., cons] = ();
263// let [head, .., mid, tail @ ..] = ();
264// let [head, .., mid, .., cons] = ();
265// }
266fn dot_dot_pat(p: &mut Parser) -> CompletedMarker {
267 assert!(p.at(T![..]));
268 let m = p.start();
269 p.bump(T![..]);
270 m.complete(p, REST_PAT)
271}
272
273// test ref_pat
274// fn main() {
275// let &a = ();
276// let &mut b = ();
277// }
278fn ref_pat(p: &mut Parser) -> CompletedMarker {
279 assert!(p.at(T![&]));
280 let m = p.start();
281 p.bump(T![&]);
282 p.eat(T![mut]);
283 pattern_single(p);
284 m.complete(p, REF_PAT)
285}
286
287// test tuple_pat
288// fn main() {
289// let (a, b, ..) = ();
290// let (a,) = ();
291// let (..) = ();
292// let () = ();
293// }
294fn tuple_pat(p: &mut Parser) -> CompletedMarker {
295 assert!(p.at(T!['(']));
296 let m = p.start();
297 p.bump(T!['(']);
298 let mut has_comma = false;
299 let mut has_pat = false;
300 let mut has_rest = false;
301 while !p.at(EOF) && !p.at(T![')']) {
302 has_pat = true;
303 if !p.at_ts(PATTERN_FIRST) {
304 p.error("expected a pattern");
305 break;
306 }
307 has_rest |= p.at(T![..]);
308
309 pattern(p);
310 if !p.at(T![')']) {
311 has_comma = true;
312 p.expect(T![,]);
313 }
314 }
315 p.expect(T![')']);
316
317 m.complete(p, if !has_comma && !has_rest && has_pat { PAREN_PAT } else { TUPLE_PAT })
318}
319
320// test slice_pat
321// fn main() {
322// let [a, b, ..] = [];
323// }
324fn slice_pat(p: &mut Parser) -> CompletedMarker {
325 assert!(p.at(T!['[']));
326 let m = p.start();
327 p.bump(T!['[']);
328 pat_list(p, T![']']);
329 p.expect(T![']']);
330 m.complete(p, SLICE_PAT)
331}
332
333fn pat_list(p: &mut Parser, ket: SyntaxKind) {
334 while !p.at(EOF) && !p.at(ket) {
335 if !p.at_ts(PATTERN_FIRST) {
336 p.error("expected a pattern");
337 break;
338 }
339
340 pattern(p);
341 if !p.at(ket) {
342 p.expect(T![,]);
343 }
344 }
345}
346
347// test bind_pat
348// fn main() {
349// let a = ();
350// let mut b = ();
351// let ref c = ();
352// let ref mut d = ();
353// let e @ _ = ();
354// let ref mut f @ g @ _ = ();
355// }
356fn bind_pat(p: &mut Parser, with_at: bool) -> CompletedMarker {
357 let m = p.start();
358 p.eat(T![ref]);
359 p.eat(T![mut]);
360 name(p);
361 if with_at && p.eat(T![@]) {
362 pattern_single(p);
363 }
364 m.complete(p, IDENT_PAT)
365}
366
367// test box_pat
368// fn main() {
369// let box i = ();
370// let box Outer { box i, j: box Inner(box &x) } = ();
371// let box ref mut i = ();
372// }
373fn box_pat(p: &mut Parser) -> CompletedMarker {
374 assert!(p.at(T![box]));
375 let m = p.start();
376 p.bump(T![box]);
377 pattern_single(p);
378 m.complete(p, BOX_PAT)
379}
diff --git a/crates/parser/src/grammar/type_args.rs b/crates/parser/src/grammar/type_args.rs
new file mode 100644
index 000000000..aef7cd6fb
--- /dev/null
+++ b/crates/parser/src/grammar/type_args.rs
@@ -0,0 +1,63 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) fn opt_type_arg_list(p: &mut Parser, colon_colon_required: bool) {
6 let m;
7 if p.at(T![::]) && p.nth(2) == T![<] {
8 m = p.start();
9 p.bump(T![::]);
10 p.bump(T![<]);
11 } else if !colon_colon_required && p.at(T![<]) && p.nth(1) != T![=] {
12 m = p.start();
13 p.bump(T![<]);
14 } else {
15 return;
16 }
17
18 while !p.at(EOF) && !p.at(T![>]) {
19 type_arg(p);
20 if !p.at(T![>]) && !p.expect(T![,]) {
21 break;
22 }
23 }
24 p.expect(T![>]);
25 m.complete(p, GENERIC_ARG_LIST);
26}
27
28// test type_arg
29// type A = B<'static, i32, 1, { 2 }, Item=u64>;
30fn type_arg(p: &mut Parser) {
31 let m = p.start();
32 match p.current() {
33 LIFETIME => {
34 p.bump(LIFETIME);
35 m.complete(p, LIFETIME_ARG);
36 }
37 // test associated_type_bounds
38 // fn print_all<T: Iterator<Item: Display>>(printables: T) {}
39 IDENT if p.nth(1) == T![:] && p.nth(2) != T![:] => {
40 name_ref(p);
41 type_params::bounds(p);
42 m.complete(p, ASSOC_TYPE_ARG);
43 }
44 IDENT if p.nth(1) == T![=] => {
45 name_ref(p);
46 p.bump_any();
47 types::type_(p);
48 m.complete(p, ASSOC_TYPE_ARG);
49 }
50 T!['{'] => {
51 expressions::block_expr(p);
52 m.complete(p, CONST_ARG);
53 }
54 k if k.is_literal() => {
55 expressions::literal(p);
56 m.complete(p, CONST_ARG);
57 }
58 _ => {
59 types::type_(p);
60 m.complete(p, TYPE_ARG);
61 }
62 }
63}
diff --git a/crates/parser/src/grammar/type_params.rs b/crates/parser/src/grammar/type_params.rs
new file mode 100644
index 000000000..90dabb4c0
--- /dev/null
+++ b/crates/parser/src/grammar/type_params.rs
@@ -0,0 +1,209 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) fn opt_type_param_list(p: &mut Parser) {
6 if !p.at(T![<]) {
7 return;
8 }
9 type_param_list(p);
10}
11
12fn type_param_list(p: &mut Parser) {
13 assert!(p.at(T![<]));
14 let m = p.start();
15 p.bump(T![<]);
16
17 while !p.at(EOF) && !p.at(T![>]) {
18 let m = p.start();
19
20 // test generic_lifetime_type_attribute
21 // fn foo<#[derive(Lifetime)] 'a, #[derive(Type)] T>(_: &'a T) {
22 // }
23 attributes::outer_attributes(p);
24
25 match p.current() {
26 LIFETIME => lifetime_param(p, m),
27 IDENT => type_param(p, m),
28 CONST_KW => type_const_param(p, m),
29 _ => {
30 m.abandon(p);
31 p.err_and_bump("expected type parameter")
32 }
33 }
34 if !p.at(T![>]) && !p.expect(T![,]) {
35 break;
36 }
37 }
38 p.expect(T![>]);
39 m.complete(p, GENERIC_PARAM_LIST);
40}
41
42fn lifetime_param(p: &mut Parser, m: Marker) {
43 assert!(p.at(LIFETIME));
44 p.bump(LIFETIME);
45 if p.at(T![:]) {
46 lifetime_bounds(p);
47 }
48 m.complete(p, LIFETIME_PARAM);
49}
50
51fn type_param(p: &mut Parser, m: Marker) {
52 assert!(p.at(IDENT));
53 name(p);
54 if p.at(T![:]) {
55 bounds(p);
56 }
57 // test type_param_default
58 // struct S<T = i32>;
59 if p.at(T![=]) {
60 p.bump(T![=]);
61 types::type_(p)
62 }
63 m.complete(p, TYPE_PARAM);
64}
65
66// test const_param
67// struct S<const N: u32>;
68fn type_const_param(p: &mut Parser, m: Marker) {
69 assert!(p.at(CONST_KW));
70 p.bump(T![const]);
71 name(p);
72 types::ascription(p);
73 m.complete(p, CONST_PARAM);
74}
75
76// test type_param_bounds
77// struct S<T: 'a + ?Sized + (Copy)>;
78pub(super) fn bounds(p: &mut Parser) {
79 assert!(p.at(T![:]));
80 p.bump(T![:]);
81 bounds_without_colon(p);
82}
83
84fn lifetime_bounds(p: &mut Parser) {
85 assert!(p.at(T![:]));
86 p.bump(T![:]);
87 while p.at(LIFETIME) {
88 p.bump(LIFETIME);
89 if !p.eat(T![+]) {
90 break;
91 }
92 }
93}
94
95pub(super) fn bounds_without_colon_m(p: &mut Parser, marker: Marker) -> CompletedMarker {
96 while type_bound(p) {
97 if !p.eat(T![+]) {
98 break;
99 }
100 }
101
102 marker.complete(p, TYPE_BOUND_LIST)
103}
104
105pub(super) fn bounds_without_colon(p: &mut Parser) {
106 let m = p.start();
107 bounds_without_colon_m(p, m);
108}
109
110fn type_bound(p: &mut Parser) -> bool {
111 let m = p.start();
112 let has_paren = p.eat(T!['(']);
113 p.eat(T![?]);
114 match p.current() {
115 LIFETIME => p.bump(LIFETIME),
116 T![for] => types::for_type(p),
117 _ if paths::is_use_path_start(p) => types::path_type_(p, false),
118 _ => {
119 m.abandon(p);
120 return false;
121 }
122 }
123 if has_paren {
124 p.expect(T![')']);
125 }
126 m.complete(p, TYPE_BOUND);
127
128 true
129}
130
131// test where_clause
132// fn foo()
133// where
134// 'a: 'b + 'c,
135// T: Clone + Copy + 'static,
136// Iterator::Item: 'a,
137// <T as Iterator>::Item: 'a
138// {}
139pub(super) fn opt_where_clause(p: &mut Parser) {
140 if !p.at(T![where]) {
141 return;
142 }
143 let m = p.start();
144 p.bump(T![where]);
145
146 while is_where_predicate(p) {
147 where_predicate(p);
148
149 let comma = p.eat(T![,]);
150
151 if is_where_clause_end(p) {
152 break;
153 }
154
155 if !comma {
156 p.error("expected comma");
157 }
158 }
159
160 m.complete(p, WHERE_CLAUSE);
161}
162
163fn is_where_predicate(p: &mut Parser) -> bool {
164 match p.current() {
165 LIFETIME => true,
166 T![impl] => false,
167 token => types::TYPE_FIRST.contains(token),
168 }
169}
170
171fn is_where_clause_end(p: &mut Parser) -> bool {
172 matches!(p.current(), T!['{'] | T![;] | T![=])
173}
174
175fn where_predicate(p: &mut Parser) {
176 let m = p.start();
177 match p.current() {
178 LIFETIME => {
179 p.bump(LIFETIME);
180 if p.at(T![:]) {
181 bounds(p);
182 } else {
183 p.error("expected colon");
184 }
185 }
186 T![impl] => {
187 p.error("expected lifetime or type");
188 }
189 _ => {
190 // test where_pred_for
191 // fn for_trait<F>()
192 // where
193 // for<'a> F: Fn(&'a str)
194 // { }
195 if p.at(T![for]) {
196 types::for_binder(p);
197 }
198
199 types::type_(p);
200
201 if p.at(T![:]) {
202 bounds(p);
203 } else {
204 p.error("expected colon");
205 }
206 }
207 }
208 m.complete(p, WHERE_PRED);
209}
diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs
new file mode 100644
index 000000000..0aa173a52
--- /dev/null
+++ b/crates/parser/src/grammar/types.rs
@@ -0,0 +1,324 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(token_set![
6 T!['('],
7 T!['['],
8 T![<],
9 T![!],
10 T![*],
11 T![&],
12 T![_],
13 T![fn],
14 T![unsafe],
15 T![extern],
16 T![for],
17 T![impl],
18 T![dyn],
19]);
20
21const TYPE_RECOVERY_SET: TokenSet = token_set![R_PAREN, COMMA, L_DOLLAR];
22
23pub(crate) fn type_(p: &mut Parser) {
24 type_with_bounds_cond(p, true);
25}
26
27pub(super) fn type_no_bounds(p: &mut Parser) {
28 type_with_bounds_cond(p, false);
29}
30
31fn type_with_bounds_cond(p: &mut Parser, allow_bounds: bool) {
32 match p.current() {
33 T!['('] => paren_or_tuple_type(p),
34 T![!] => never_type(p),
35 T![*] => pointer_type(p),
36 T!['['] => array_or_slice_type(p),
37 T![&] => reference_type(p),
38 T![_] => placeholder_type(p),
39 T![fn] | T![unsafe] | T![extern] => fn_pointer_type(p),
40 T![for] => for_type(p),
41 T![impl] => impl_trait_type(p),
42 T![dyn] => dyn_trait_type(p),
43 // Some path types are not allowed to have bounds (no plus)
44 T![<] => path_type_(p, allow_bounds),
45 _ if paths::is_use_path_start(p) => path_or_macro_type_(p, allow_bounds),
46 _ => {
47 p.err_recover("expected type", TYPE_RECOVERY_SET);
48 }
49 }
50}
51
52pub(super) fn ascription(p: &mut Parser) {
53 p.expect(T![:]);
54 type_(p)
55}
56
57fn paren_or_tuple_type(p: &mut Parser) {
58 assert!(p.at(T!['(']));
59 let m = p.start();
60 p.bump(T!['(']);
61 let mut n_types: u32 = 0;
62 let mut trailing_comma: bool = false;
63 while !p.at(EOF) && !p.at(T![')']) {
64 n_types += 1;
65 type_(p);
66 if p.eat(T![,]) {
67 trailing_comma = true;
68 } else {
69 trailing_comma = false;
70 break;
71 }
72 }
73 p.expect(T![')']);
74
75 let kind = if n_types == 1 && !trailing_comma {
76 // test paren_type
77 // type T = (i32);
78 PAREN_TYPE
79 } else {
80 // test unit_type
81 // type T = ();
82
83 // test singleton_tuple_type
84 // type T = (i32,);
85 TUPLE_TYPE
86 };
87 m.complete(p, kind);
88}
89
90// test never_type
91// type Never = !;
92fn never_type(p: &mut Parser) {
93 assert!(p.at(T![!]));
94 let m = p.start();
95 p.bump(T![!]);
96 m.complete(p, NEVER_TYPE);
97}
98
99fn pointer_type(p: &mut Parser) {
100 assert!(p.at(T![*]));
101 let m = p.start();
102 p.bump(T![*]);
103
104 match p.current() {
105 // test pointer_type_mut
106 // type M = *mut ();
107 // type C = *mut ();
108 T![mut] | T![const] => p.bump_any(),
109 _ => {
110 // test_err pointer_type_no_mutability
111 // type T = *();
112 p.error(
113 "expected mut or const in raw pointer type \
114 (use `*mut T` or `*const T` as appropriate)",
115 );
116 }
117 };
118
119 type_no_bounds(p);
120 m.complete(p, PTR_TYPE);
121}
122
123fn array_or_slice_type(p: &mut Parser) {
124 assert!(p.at(T!['[']));
125 let m = p.start();
126 p.bump(T!['[']);
127
128 type_(p);
129 let kind = match p.current() {
130 // test slice_type
131 // type T = [()];
132 T![']'] => {
133 p.bump(T![']']);
134 SLICE_TYPE
135 }
136
137 // test array_type
138 // type T = [(); 92];
139 T![;] => {
140 p.bump(T![;]);
141 expressions::expr(p);
142 p.expect(T![']']);
143 ARRAY_TYPE
144 }
145 // test_err array_type_missing_semi
146 // type T = [() 92];
147 _ => {
148 p.error("expected `;` or `]`");
149 SLICE_TYPE
150 }
151 };
152 m.complete(p, kind);
153}
154
155// test reference_type;
156// type A = &();
157// type B = &'static ();
158// type C = &mut ();
159fn reference_type(p: &mut Parser) {
160 assert!(p.at(T![&]));
161 let m = p.start();
162 p.bump(T![&]);
163 p.eat(LIFETIME);
164 p.eat(T![mut]);
165 type_no_bounds(p);
166 m.complete(p, REF_TYPE);
167}
168
169// test placeholder_type
170// type Placeholder = _;
171fn placeholder_type(p: &mut Parser) {
172 assert!(p.at(T![_]));
173 let m = p.start();
174 p.bump(T![_]);
175 m.complete(p, INFER_TYPE);
176}
177
178// test fn_pointer_type
179// type A = fn();
180// type B = unsafe fn();
181// type C = unsafe extern "C" fn();
182// type D = extern "C" fn ( u8 , ... ) -> u8;
183fn fn_pointer_type(p: &mut Parser) {
184 let m = p.start();
185 p.eat(T![unsafe]);
186 if p.at(T![extern]) {
187 abi(p);
188 }
189 // test_err fn_pointer_type_missing_fn
190 // type F = unsafe ();
191 if !p.eat(T![fn]) {
192 m.abandon(p);
193 p.error("expected `fn`");
194 return;
195 }
196 if p.at(T!['(']) {
197 params::param_list_fn_ptr(p);
198 } else {
199 p.error("expected parameters")
200 }
201 // test fn_pointer_type_with_ret
202 // type F = fn() -> ();
203 opt_fn_ret_type(p);
204 m.complete(p, FN_PTR_TYPE);
205}
206
207pub(super) fn for_binder(p: &mut Parser) {
208 assert!(p.at(T![for]));
209 p.bump(T![for]);
210 if p.at(T![<]) {
211 type_params::opt_type_param_list(p);
212 } else {
213 p.error("expected `<`");
214 }
215}
216
217// test for_type
218// type A = for<'a> fn() -> ();
219// type B = for<'a> unsafe extern "C" fn(&'a ()) -> ();
220// type Obj = for<'a> PartialEq<&'a i32>;
221pub(super) fn for_type(p: &mut Parser) {
222 assert!(p.at(T![for]));
223 let m = p.start();
224 for_binder(p);
225 match p.current() {
226 T![fn] | T![unsafe] | T![extern] => {}
227 // OK: legacy trait object format
228 _ if paths::is_use_path_start(p) => {}
229 _ => {
230 p.error("expected a function pointer or path");
231 }
232 }
233 type_no_bounds(p);
234 m.complete(p, FOR_TYPE);
235}
236
237// test impl_trait_type
238// type A = impl Iterator<Item=Foo<'a>> + 'a;
239fn impl_trait_type(p: &mut Parser) {
240 assert!(p.at(T![impl]));
241 let m = p.start();
242 p.bump(T![impl]);
243 type_params::bounds_without_colon(p);
244 m.complete(p, IMPL_TRAIT_TYPE);
245}
246
247// test dyn_trait_type
248// type A = dyn Iterator<Item=Foo<'a>> + 'a;
249fn dyn_trait_type(p: &mut Parser) {
250 assert!(p.at(T![dyn]));
251 let m = p.start();
252 p.bump(T![dyn]);
253 type_params::bounds_without_colon(p);
254 m.complete(p, DYN_TRAIT_TYPE);
255}
256
257// test path_type
258// type A = Foo;
259// type B = ::Foo;
260// type C = self::Foo;
261// type D = super::Foo;
262pub(super) fn path_type(p: &mut Parser) {
263 path_type_(p, true)
264}
265
266// test macro_call_type
267// type A = foo!();
268// type B = crate::foo!();
269fn path_or_macro_type_(p: &mut Parser, allow_bounds: bool) {
270 assert!(paths::is_path_start(p));
271 let m = p.start();
272 paths::type_path(p);
273
274 let kind = if p.at(T![!]) && !p.at(T![!=]) {
275 items::macro_call_after_excl(p);
276 MACRO_CALL
277 } else {
278 PATH_TYPE
279 };
280
281 let path = m.complete(p, kind);
282
283 if allow_bounds {
284 opt_path_type_bounds_as_dyn_trait_type(p, path);
285 }
286}
287
288pub(super) fn path_type_(p: &mut Parser, allow_bounds: bool) {
289 assert!(paths::is_path_start(p));
290 let m = p.start();
291 paths::type_path(p);
292
293 // test path_type_with_bounds
294 // fn foo() -> Box<T + 'f> {}
295 // fn foo() -> Box<dyn T + 'f> {}
296 let path = m.complete(p, PATH_TYPE);
297 if allow_bounds {
298 opt_path_type_bounds_as_dyn_trait_type(p, path);
299 }
300}
301
302/// This turns a parsed PATH_TYPE optionally into a DYN_TRAIT_TYPE
303/// with a TYPE_BOUND_LIST
304fn opt_path_type_bounds_as_dyn_trait_type(p: &mut Parser, path_type_marker: CompletedMarker) {
305 if !p.at(T![+]) {
306 return;
307 }
308
309 // First create a TYPE_BOUND from the completed PATH_TYPE
310 let m = path_type_marker.precede(p).complete(p, TYPE_BOUND);
311
312 // Next setup a marker for the TYPE_BOUND_LIST
313 let m = m.precede(p);
314
315 // This gets consumed here so it gets properly set
316 // in the TYPE_BOUND_LIST
317 p.eat(T![+]);
318
319 // Parse rest of the bounds into the TYPE_BOUND_LIST
320 let m = type_params::bounds_without_colon_m(p, m);
321
322 // Finally precede everything with DYN_TRAIT_TYPE
323 m.precede(p).complete(p, DYN_TRAIT_TYPE);
324}
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs
new file mode 100644
index 000000000..eeb8ad66b
--- /dev/null
+++ b/crates/parser/src/lib.rs
@@ -0,0 +1,149 @@
1//! The Rust parser.
2//!
3//! The parser doesn't know about concrete representation of tokens and syntax
4//! trees. Abstract `TokenSource` and `TreeSink` traits are used instead. As a
5//! consequence, this crates does not contain a lexer.
6//!
7//! The `Parser` struct from the `parser` module is a cursor into the sequence
8//! of tokens. Parsing routines use `Parser` to inspect current state and
9//! advance the parsing.
10//!
11//! The actual parsing happens in the `grammar` module.
12//!
13//! Tests for this crate live in `ra_syntax` crate.
14
15#[macro_use]
16mod token_set;
17#[macro_use]
18mod syntax_kind;
19mod event;
20mod parser;
21mod grammar;
22
23pub(crate) use token_set::TokenSet;
24
25pub use syntax_kind::SyntaxKind;
26
27#[derive(Debug, Clone, PartialEq, Eq, Hash)]
28pub struct ParseError(pub Box<String>);
29
30/// `TokenSource` abstracts the source of the tokens parser operates on.
31///
32/// Hopefully this will allow us to treat text and token trees in the same way!
33pub trait TokenSource {
34 fn current(&self) -> Token;
35
36 /// Lookahead n token
37 fn lookahead_nth(&self, n: usize) -> Token;
38
39 /// bump cursor to next token
40 fn bump(&mut self);
41
42 /// Is the current token a specified keyword?
43 fn is_keyword(&self, kw: &str) -> bool;
44}
45
46/// `Token` abstracts the cursor of `TokenSource` operates on.
47#[derive(Debug, Copy, Clone, Eq, PartialEq)]
48pub struct Token {
49 /// What is the current token?
50 pub kind: SyntaxKind,
51
52 /// Is the current token joined to the next one (`> >` vs `>>`).
53 pub is_jointed_to_next: bool,
54}
55
56/// `TreeSink` abstracts details of a particular syntax tree implementation.
57pub trait TreeSink {
58 /// Adds new token to the current branch.
59 fn token(&mut self, kind: SyntaxKind, n_tokens: u8);
60
61 /// Start new branch and make it current.
62 fn start_node(&mut self, kind: SyntaxKind);
63
64 /// Finish current branch and restore previous
65 /// branch as current.
66 fn finish_node(&mut self);
67
68 fn error(&mut self, error: ParseError);
69}
70
71fn parse_from_tokens<F>(token_source: &mut dyn TokenSource, tree_sink: &mut dyn TreeSink, f: F)
72where
73 F: FnOnce(&mut parser::Parser),
74{
75 let mut p = parser::Parser::new(token_source);
76 f(&mut p);
77 let events = p.finish();
78 event::process(tree_sink, events);
79}
80
81/// Parse given tokens into the given sink as a rust file.
82pub fn parse(token_source: &mut dyn TokenSource, tree_sink: &mut dyn TreeSink) {
83 parse_from_tokens(token_source, tree_sink, grammar::root);
84}
85
86#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
87pub enum FragmentKind {
88 Path,
89 Expr,
90 Statement,
91 Type,
92 Pattern,
93 Item,
94 Block,
95 Visibility,
96 MetaItem,
97
98 // These kinds are used when parsing the result of expansion
99 // FIXME: use separate fragment kinds for macro inputs and outputs?
100 Items,
101 Statements,
102}
103
104pub fn parse_fragment(
105 token_source: &mut dyn TokenSource,
106 tree_sink: &mut dyn TreeSink,
107 fragment_kind: FragmentKind,
108) {
109 let parser: fn(&'_ mut parser::Parser) = match fragment_kind {
110 FragmentKind::Path => grammar::fragments::path,
111 FragmentKind::Expr => grammar::fragments::expr,
112 FragmentKind::Type => grammar::fragments::type_,
113 FragmentKind::Pattern => grammar::fragments::pattern,
114 FragmentKind::Item => grammar::fragments::item,
115 FragmentKind::Block => grammar::fragments::block_expr,
116 FragmentKind::Visibility => grammar::fragments::opt_visibility,
117 FragmentKind::MetaItem => grammar::fragments::meta_item,
118 FragmentKind::Statement => grammar::fragments::stmt,
119 FragmentKind::Items => grammar::fragments::macro_items,
120 FragmentKind::Statements => grammar::fragments::macro_stmts,
121 };
122 parse_from_tokens(token_source, tree_sink, parser)
123}
124
125/// A parsing function for a specific braced-block.
126pub struct Reparser(fn(&mut parser::Parser));
127
128impl Reparser {
129 /// If the node is a braced block, return the corresponding `Reparser`.
130 pub fn for_node(
131 node: SyntaxKind,
132 first_child: Option<SyntaxKind>,
133 parent: Option<SyntaxKind>,
134 ) -> Option<Reparser> {
135 grammar::reparser(node, first_child, parent).map(Reparser)
136 }
137
138 /// Re-parse given tokens using this `Reparser`.
139 ///
140 /// Tokens must start with `{`, end with `}` and form a valid brace
141 /// sequence.
142 pub fn parse(self, token_source: &mut dyn TokenSource, tree_sink: &mut dyn TreeSink) {
143 let Reparser(r) = self;
144 let mut p = parser::Parser::new(token_source);
145 r(&mut p);
146 let events = p.finish();
147 event::process(tree_sink, events);
148 }
149}
diff --git a/crates/parser/src/parser.rs b/crates/parser/src/parser.rs
new file mode 100644
index 000000000..d2487acc3
--- /dev/null
+++ b/crates/parser/src/parser.rs
@@ -0,0 +1,350 @@
1//! FIXME: write short doc here
2
3use std::cell::Cell;
4
5use drop_bomb::DropBomb;
6
7use crate::{
8 event::Event,
9 ParseError,
10 SyntaxKind::{self, EOF, ERROR, TOMBSTONE},
11 TokenSet, TokenSource, T,
12};
13
14/// `Parser` struct provides the low-level API for
15/// navigating through the stream of tokens and
16/// constructing the parse tree. The actual parsing
17/// happens in the `grammar` module.
18///
19/// However, the result of this `Parser` is not a real
20/// tree, but rather a flat stream of events of the form
21/// "start expression, consume number literal,
22/// finish expression". See `Event` docs for more.
23pub(crate) struct Parser<'t> {
24 token_source: &'t mut dyn TokenSource,
25 events: Vec<Event>,
26 steps: Cell<u32>,
27}
28
29impl<'t> Parser<'t> {
30 pub(super) fn new(token_source: &'t mut dyn TokenSource) -> Parser<'t> {
31 Parser { token_source, events: Vec::new(), steps: Cell::new(0) }
32 }
33
34 pub(crate) fn finish(self) -> Vec<Event> {
35 self.events
36 }
37
38 /// Returns the kind of the current token.
39 /// If parser has already reached the end of input,
40 /// the special `EOF` kind is returned.
41 pub(crate) fn current(&self) -> SyntaxKind {
42 self.nth(0)
43 }
44
45 /// Lookahead operation: returns the kind of the next nth
46 /// token.
47 pub(crate) fn nth(&self, n: usize) -> SyntaxKind {
48 assert!(n <= 3);
49
50 let steps = self.steps.get();
51 assert!(steps <= 10_000_000, "the parser seems stuck");
52 self.steps.set(steps + 1);
53
54 self.token_source.lookahead_nth(n).kind
55 }
56
57 /// Checks if the current token is `kind`.
58 pub(crate) fn at(&self, kind: SyntaxKind) -> bool {
59 self.nth_at(0, kind)
60 }
61
62 pub(crate) fn nth_at(&self, n: usize, kind: SyntaxKind) -> bool {
63 match kind {
64 T![-=] => self.at_composite2(n, T![-], T![=]),
65 T![->] => self.at_composite2(n, T![-], T![>]),
66 T![::] => self.at_composite2(n, T![:], T![:]),
67 T![!=] => self.at_composite2(n, T![!], T![=]),
68 T![..] => self.at_composite2(n, T![.], T![.]),
69 T![*=] => self.at_composite2(n, T![*], T![=]),
70 T![/=] => self.at_composite2(n, T![/], T![=]),
71 T![&&] => self.at_composite2(n, T![&], T![&]),
72 T![&=] => self.at_composite2(n, T![&], T![=]),
73 T![%=] => self.at_composite2(n, T![%], T![=]),
74 T![^=] => self.at_composite2(n, T![^], T![=]),
75 T![+=] => self.at_composite2(n, T![+], T![=]),
76 T![<<] => self.at_composite2(n, T![<], T![<]),
77 T![<=] => self.at_composite2(n, T![<], T![=]),
78 T![==] => self.at_composite2(n, T![=], T![=]),
79 T![=>] => self.at_composite2(n, T![=], T![>]),
80 T![>=] => self.at_composite2(n, T![>], T![=]),
81 T![>>] => self.at_composite2(n, T![>], T![>]),
82 T![|=] => self.at_composite2(n, T![|], T![=]),
83 T![||] => self.at_composite2(n, T![|], T![|]),
84
85 T![...] => self.at_composite3(n, T![.], T![.], T![.]),
86 T![..=] => self.at_composite3(n, T![.], T![.], T![=]),
87 T![<<=] => self.at_composite3(n, T![<], T![<], T![=]),
88 T![>>=] => self.at_composite3(n, T![>], T![>], T![=]),
89
90 _ => self.token_source.lookahead_nth(n).kind == kind,
91 }
92 }
93
94 /// Consume the next token if `kind` matches.
95 pub(crate) fn eat(&mut self, kind: SyntaxKind) -> bool {
96 if !self.at(kind) {
97 return false;
98 }
99 let n_raw_tokens = match kind {
100 T![-=]
101 | T![->]
102 | T![::]
103 | T![!=]
104 | T![..]
105 | T![*=]
106 | T![/=]
107 | T![&&]
108 | T![&=]
109 | T![%=]
110 | T![^=]
111 | T![+=]
112 | T![<<]
113 | T![<=]
114 | T![==]
115 | T![=>]
116 | T![>=]
117 | T![>>]
118 | T![|=]
119 | T![||] => 2,
120
121 T![...] | T![..=] | T![<<=] | T![>>=] => 3,
122 _ => 1,
123 };
124 self.do_bump(kind, n_raw_tokens);
125 true
126 }
127
128 fn at_composite2(&self, n: usize, k1: SyntaxKind, k2: SyntaxKind) -> bool {
129 let t1 = self.token_source.lookahead_nth(n);
130 if t1.kind != k1 || !t1.is_jointed_to_next {
131 return false;
132 }
133 let t2 = self.token_source.lookahead_nth(n + 1);
134 t2.kind == k2
135 }
136
137 fn at_composite3(&self, n: usize, k1: SyntaxKind, k2: SyntaxKind, k3: SyntaxKind) -> bool {
138 let t1 = self.token_source.lookahead_nth(n);
139 if t1.kind != k1 || !t1.is_jointed_to_next {
140 return false;
141 }
142 let t2 = self.token_source.lookahead_nth(n + 1);
143 if t2.kind != k2 || !t2.is_jointed_to_next {
144 return false;
145 }
146 let t3 = self.token_source.lookahead_nth(n + 2);
147 t3.kind == k3
148 }
149
150 /// Checks if the current token is in `kinds`.
151 pub(crate) fn at_ts(&self, kinds: TokenSet) -> bool {
152 kinds.contains(self.current())
153 }
154
155 /// Checks if the current token is contextual keyword with text `t`.
156 pub(crate) fn at_contextual_kw(&self, kw: &str) -> bool {
157 self.token_source.is_keyword(kw)
158 }
159
160 /// Starts a new node in the syntax tree. All nodes and tokens
161 /// consumed between the `start` and the corresponding `Marker::complete`
162 /// belong to the same node.
163 pub(crate) fn start(&mut self) -> Marker {
164 let pos = self.events.len() as u32;
165 self.push_event(Event::tombstone());
166 Marker::new(pos)
167 }
168
169 /// Consume the next token if `kind` matches.
170 pub(crate) fn bump(&mut self, kind: SyntaxKind) {
171 assert!(self.eat(kind));
172 }
173
174 /// Advances the parser by one token
175 pub(crate) fn bump_any(&mut self) {
176 let kind = self.nth(0);
177 if kind == EOF {
178 return;
179 }
180 self.do_bump(kind, 1)
181 }
182
183 /// Advances the parser by one token, remapping its kind.
184 /// This is useful to create contextual keywords from
185 /// identifiers. For example, the lexer creates an `union`
186 /// *identifier* token, but the parser remaps it to the
187 /// `union` keyword, and keyword is what ends up in the
188 /// final tree.
189 pub(crate) fn bump_remap(&mut self, kind: SyntaxKind) {
190 if self.nth(0) == EOF {
191 // FIXME: panic!?
192 return;
193 }
194 self.do_bump(kind, 1);
195 }
196
197 /// Emit error with the `message`
198 /// FIXME: this should be much more fancy and support
199 /// structured errors with spans and notes, like rustc
200 /// does.
201 pub(crate) fn error<T: Into<String>>(&mut self, message: T) {
202 let msg = ParseError(Box::new(message.into()));
203 self.push_event(Event::Error { msg })
204 }
205
206 /// Consume the next token if it is `kind` or emit an error
207 /// otherwise.
208 pub(crate) fn expect(&mut self, kind: SyntaxKind) -> bool {
209 if self.eat(kind) {
210 return true;
211 }
212 self.error(format!("expected {:?}", kind));
213 false
214 }
215
216 /// Create an error node and consume the next token.
217 pub(crate) fn err_and_bump(&mut self, message: &str) {
218 self.err_recover(message, TokenSet::EMPTY);
219 }
220
221 /// Create an error node and consume the next token.
222 pub(crate) fn err_recover(&mut self, message: &str, recovery: TokenSet) {
223 match self.current() {
224 T!['{'] | T!['}'] => {
225 self.error(message);
226 return;
227 }
228 _ => (),
229 }
230
231 if self.at_ts(recovery) {
232 self.error(message);
233 return;
234 }
235
236 let m = self.start();
237 self.error(message);
238 self.bump_any();
239 m.complete(self, ERROR);
240 }
241
242 fn do_bump(&mut self, kind: SyntaxKind, n_raw_tokens: u8) {
243 for _ in 0..n_raw_tokens {
244 self.token_source.bump();
245 }
246
247 self.push_event(Event::Token { kind, n_raw_tokens });
248 }
249
250 fn push_event(&mut self, event: Event) {
251 self.events.push(event)
252 }
253}
254
255/// See `Parser::start`.
256pub(crate) struct Marker {
257 pos: u32,
258 bomb: DropBomb,
259}
260
261impl Marker {
262 fn new(pos: u32) -> Marker {
263 Marker { pos, bomb: DropBomb::new("Marker must be either completed or abandoned") }
264 }
265
266 /// Finishes the syntax tree node and assigns `kind` to it,
267 /// and mark the create a `CompletedMarker` for possible future
268 /// operation like `.precede()` to deal with forward_parent.
269 pub(crate) fn complete(mut self, p: &mut Parser, kind: SyntaxKind) -> CompletedMarker {
270 self.bomb.defuse();
271 let idx = self.pos as usize;
272 match &mut p.events[idx] {
273 Event::Start { kind: slot, .. } => {
274 *slot = kind;
275 }
276 _ => unreachable!(),
277 }
278 let finish_pos = p.events.len() as u32;
279 p.push_event(Event::Finish);
280 CompletedMarker::new(self.pos, finish_pos, kind)
281 }
282
283 /// Abandons the syntax tree node. All its children
284 /// are attached to its parent instead.
285 pub(crate) fn abandon(mut self, p: &mut Parser) {
286 self.bomb.defuse();
287 let idx = self.pos as usize;
288 if idx == p.events.len() - 1 {
289 match p.events.pop() {
290 Some(Event::Start { kind: TOMBSTONE, forward_parent: None }) => (),
291 _ => unreachable!(),
292 }
293 }
294 }
295}
296
297pub(crate) struct CompletedMarker {
298 start_pos: u32,
299 finish_pos: u32,
300 kind: SyntaxKind,
301}
302
303impl CompletedMarker {
304 fn new(start_pos: u32, finish_pos: u32, kind: SyntaxKind) -> Self {
305 CompletedMarker { start_pos, finish_pos, kind }
306 }
307
308 /// This method allows to create a new node which starts
309 /// *before* the current one. That is, parser could start
310 /// node `A`, then complete it, and then after parsing the
311 /// whole `A`, decide that it should have started some node
312 /// `B` before starting `A`. `precede` allows to do exactly
313 /// that. See also docs about `forward_parent` in `Event::Start`.
314 ///
315 /// Given completed events `[START, FINISH]` and its corresponding
316 /// `CompletedMarker(pos: 0, _)`.
317 /// Append a new `START` events as `[START, FINISH, NEWSTART]`,
318 /// then mark `NEWSTART` as `START`'s parent with saving its relative
319 /// distance to `NEWSTART` into forward_parent(=2 in this case);
320 pub(crate) fn precede(self, p: &mut Parser) -> Marker {
321 let new_pos = p.start();
322 let idx = self.start_pos as usize;
323 match &mut p.events[idx] {
324 Event::Start { forward_parent, .. } => {
325 *forward_parent = Some(new_pos.pos - self.start_pos);
326 }
327 _ => unreachable!(),
328 }
329 new_pos
330 }
331
332 /// Undo this completion and turns into a `Marker`
333 pub(crate) fn undo_completion(self, p: &mut Parser) -> Marker {
334 let start_idx = self.start_pos as usize;
335 let finish_idx = self.finish_pos as usize;
336 match &mut p.events[start_idx] {
337 Event::Start { kind, forward_parent: None } => *kind = TOMBSTONE,
338 _ => unreachable!(),
339 }
340 match &mut p.events[finish_idx] {
341 slot @ Event::Finish => *slot = Event::tombstone(),
342 _ => unreachable!(),
343 }
344 Marker::new(self.start_pos)
345 }
346
347 pub(crate) fn kind(&self) -> SyntaxKind {
348 self.kind
349 }
350}
diff --git a/crates/parser/src/syntax_kind.rs b/crates/parser/src/syntax_kind.rs
new file mode 100644
index 000000000..63204436c
--- /dev/null
+++ b/crates/parser/src/syntax_kind.rs
@@ -0,0 +1,25 @@
1//! FIXME: write short doc here
2
3#[macro_use]
4mod generated;
5
6pub use self::generated::SyntaxKind;
7
8impl From<u16> for SyntaxKind {
9 fn from(d: u16) -> SyntaxKind {
10 assert!(d <= (SyntaxKind::__LAST as u16));
11 unsafe { std::mem::transmute::<u16, SyntaxKind>(d) }
12 }
13}
14
15impl From<SyntaxKind> for u16 {
16 fn from(k: SyntaxKind) -> u16 {
17 k as u16
18 }
19}
20
21impl SyntaxKind {
22 pub fn is_trivia(self) -> bool {
23 matches!(self, SyntaxKind::WHITESPACE | SyntaxKind::COMMENT)
24 }
25}
diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs
new file mode 100644
index 000000000..192ecd864
--- /dev/null
+++ b/crates/parser/src/syntax_kind/generated.rs
@@ -0,0 +1,367 @@
1//! Generated file, do not edit by hand, see `xtask/src/codegen`
2
3#![allow(bad_style, missing_docs, unreachable_pub)]
4#[doc = r" The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT`."]
5#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
6#[repr(u16)]
7pub enum SyntaxKind {
8 #[doc(hidden)]
9 TOMBSTONE,
10 #[doc(hidden)]
11 EOF,
12 SEMICOLON,
13 COMMA,
14 L_PAREN,
15 R_PAREN,
16 L_CURLY,
17 R_CURLY,
18 L_BRACK,
19 R_BRACK,
20 L_ANGLE,
21 R_ANGLE,
22 AT,
23 POUND,
24 TILDE,
25 QUESTION,
26 DOLLAR,
27 AMP,
28 PIPE,
29 PLUS,
30 STAR,
31 SLASH,
32 CARET,
33 PERCENT,
34 UNDERSCORE,
35 DOT,
36 DOT2,
37 DOT3,
38 DOT2EQ,
39 COLON,
40 COLON2,
41 EQ,
42 EQ2,
43 FAT_ARROW,
44 BANG,
45 NEQ,
46 MINUS,
47 THIN_ARROW,
48 LTEQ,
49 GTEQ,
50 PLUSEQ,
51 MINUSEQ,
52 PIPEEQ,
53 AMPEQ,
54 CARETEQ,
55 SLASHEQ,
56 STAREQ,
57 PERCENTEQ,
58 AMP2,
59 PIPE2,
60 SHL,
61 SHR,
62 SHLEQ,
63 SHREQ,
64 AS_KW,
65 ASYNC_KW,
66 AWAIT_KW,
67 BOX_KW,
68 BREAK_KW,
69 CONST_KW,
70 CONTINUE_KW,
71 CRATE_KW,
72 DYN_KW,
73 ELSE_KW,
74 ENUM_KW,
75 EXTERN_KW,
76 FALSE_KW,
77 FN_KW,
78 FOR_KW,
79 IF_KW,
80 IMPL_KW,
81 IN_KW,
82 LET_KW,
83 LOOP_KW,
84 MACRO_KW,
85 MATCH_KW,
86 MOD_KW,
87 MOVE_KW,
88 MUT_KW,
89 PUB_KW,
90 REF_KW,
91 RETURN_KW,
92 SELF_KW,
93 STATIC_KW,
94 STRUCT_KW,
95 SUPER_KW,
96 TRAIT_KW,
97 TRUE_KW,
98 TRY_KW,
99 TYPE_KW,
100 UNSAFE_KW,
101 USE_KW,
102 WHERE_KW,
103 WHILE_KW,
104 AUTO_KW,
105 DEFAULT_KW,
106 EXISTENTIAL_KW,
107 UNION_KW,
108 RAW_KW,
109 INT_NUMBER,
110 FLOAT_NUMBER,
111 CHAR,
112 BYTE,
113 STRING,
114 RAW_STRING,
115 BYTE_STRING,
116 RAW_BYTE_STRING,
117 ERROR,
118 IDENT,
119 WHITESPACE,
120 LIFETIME,
121 COMMENT,
122 SHEBANG,
123 L_DOLLAR,
124 R_DOLLAR,
125 SOURCE_FILE,
126 STRUCT,
127 UNION,
128 ENUM,
129 FN,
130 RET_TYPE,
131 EXTERN_CRATE,
132 MODULE,
133 USE,
134 STATIC,
135 CONST,
136 TRAIT,
137 IMPL,
138 TYPE_ALIAS,
139 MACRO_CALL,
140 TOKEN_TREE,
141 MACRO_DEF,
142 PAREN_TYPE,
143 TUPLE_TYPE,
144 NEVER_TYPE,
145 PATH_TYPE,
146 PTR_TYPE,
147 ARRAY_TYPE,
148 SLICE_TYPE,
149 REF_TYPE,
150 INFER_TYPE,
151 FN_PTR_TYPE,
152 FOR_TYPE,
153 IMPL_TRAIT_TYPE,
154 DYN_TRAIT_TYPE,
155 OR_PAT,
156 PAREN_PAT,
157 REF_PAT,
158 BOX_PAT,
159 IDENT_PAT,
160 WILDCARD_PAT,
161 REST_PAT,
162 PATH_PAT,
163 RECORD_PAT,
164 RECORD_PAT_FIELD_LIST,
165 RECORD_PAT_FIELD,
166 TUPLE_STRUCT_PAT,
167 TUPLE_PAT,
168 SLICE_PAT,
169 RANGE_PAT,
170 LITERAL_PAT,
171 MACRO_PAT,
172 TUPLE_EXPR,
173 ARRAY_EXPR,
174 PAREN_EXPR,
175 PATH_EXPR,
176 CLOSURE_EXPR,
177 IF_EXPR,
178 WHILE_EXPR,
179 CONDITION,
180 LOOP_EXPR,
181 FOR_EXPR,
182 CONTINUE_EXPR,
183 BREAK_EXPR,
184 LABEL,
185 BLOCK_EXPR,
186 RETURN_EXPR,
187 MATCH_EXPR,
188 MATCH_ARM_LIST,
189 MATCH_ARM,
190 MATCH_GUARD,
191 RECORD_EXPR,
192 RECORD_EXPR_FIELD_LIST,
193 RECORD_EXPR_FIELD,
194 EFFECT_EXPR,
195 BOX_EXPR,
196 CALL_EXPR,
197 INDEX_EXPR,
198 METHOD_CALL_EXPR,
199 FIELD_EXPR,
200 AWAIT_EXPR,
201 TRY_EXPR,
202 CAST_EXPR,
203 REF_EXPR,
204 PREFIX_EXPR,
205 RANGE_EXPR,
206 BIN_EXPR,
207 EXTERN_BLOCK,
208 EXTERN_ITEM_LIST,
209 VARIANT,
210 RECORD_FIELD_LIST,
211 RECORD_FIELD,
212 TUPLE_FIELD_LIST,
213 TUPLE_FIELD,
214 VARIANT_LIST,
215 ITEM_LIST,
216 ASSOC_ITEM_LIST,
217 ATTR,
218 META_ITEM,
219 USE_TREE,
220 USE_TREE_LIST,
221 PATH,
222 PATH_SEGMENT,
223 LITERAL,
224 RENAME,
225 VISIBILITY,
226 WHERE_CLAUSE,
227 WHERE_PRED,
228 ABI,
229 NAME,
230 NAME_REF,
231 LET_STMT,
232 EXPR_STMT,
233 GENERIC_PARAM_LIST,
234 GENERIC_PARAM,
235 LIFETIME_PARAM,
236 TYPE_PARAM,
237 CONST_PARAM,
238 GENERIC_ARG_LIST,
239 LIFETIME_ARG,
240 TYPE_ARG,
241 ASSOC_TYPE_ARG,
242 CONST_ARG,
243 PARAM_LIST,
244 PARAM,
245 SELF_PARAM,
246 ARG_LIST,
247 TYPE_BOUND,
248 TYPE_BOUND_LIST,
249 MACRO_ITEMS,
250 MACRO_STMTS,
251 #[doc(hidden)]
252 __LAST,
253}
254use self::SyntaxKind::*;
255impl SyntaxKind {
256 pub fn is_keyword(self) -> bool {
257 match self {
258 AS_KW | ASYNC_KW | AWAIT_KW | BOX_KW | BREAK_KW | CONST_KW | CONTINUE_KW | CRATE_KW
259 | DYN_KW | ELSE_KW | ENUM_KW | EXTERN_KW | FALSE_KW | FN_KW | FOR_KW | IF_KW
260 | IMPL_KW | IN_KW | LET_KW | LOOP_KW | MACRO_KW | MATCH_KW | MOD_KW | MOVE_KW
261 | MUT_KW | PUB_KW | REF_KW | RETURN_KW | SELF_KW | STATIC_KW | STRUCT_KW | SUPER_KW
262 | TRAIT_KW | TRUE_KW | TRY_KW | TYPE_KW | UNSAFE_KW | USE_KW | WHERE_KW | WHILE_KW
263 | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW | RAW_KW => true,
264 _ => false,
265 }
266 }
267 pub fn is_punct(self) -> bool {
268 match self {
269 SEMICOLON | COMMA | L_PAREN | R_PAREN | L_CURLY | R_CURLY | L_BRACK | R_BRACK
270 | L_ANGLE | R_ANGLE | AT | POUND | TILDE | QUESTION | DOLLAR | AMP | PIPE | PLUS
271 | STAR | SLASH | CARET | PERCENT | UNDERSCORE | DOT | DOT2 | DOT3 | DOT2EQ | COLON
272 | COLON2 | EQ | EQ2 | FAT_ARROW | BANG | NEQ | MINUS | THIN_ARROW | LTEQ | GTEQ
273 | PLUSEQ | MINUSEQ | PIPEEQ | AMPEQ | CARETEQ | SLASHEQ | STAREQ | PERCENTEQ | AMP2
274 | PIPE2 | SHL | SHR | SHLEQ | SHREQ => true,
275 _ => false,
276 }
277 }
278 pub fn is_literal(self) -> bool {
279 match self {
280 INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE | STRING | RAW_STRING | BYTE_STRING
281 | RAW_BYTE_STRING => true,
282 _ => false,
283 }
284 }
285 pub fn from_keyword(ident: &str) -> Option<SyntaxKind> {
286 let kw = match ident {
287 "as" => AS_KW,
288 "async" => ASYNC_KW,
289 "await" => AWAIT_KW,
290 "box" => BOX_KW,
291 "break" => BREAK_KW,
292 "const" => CONST_KW,
293 "continue" => CONTINUE_KW,
294 "crate" => CRATE_KW,
295 "dyn" => DYN_KW,
296 "else" => ELSE_KW,
297 "enum" => ENUM_KW,
298 "extern" => EXTERN_KW,
299 "false" => FALSE_KW,
300 "fn" => FN_KW,
301 "for" => FOR_KW,
302 "if" => IF_KW,
303 "impl" => IMPL_KW,
304 "in" => IN_KW,
305 "let" => LET_KW,
306 "loop" => LOOP_KW,
307 "macro" => MACRO_KW,
308 "match" => MATCH_KW,
309 "mod" => MOD_KW,
310 "move" => MOVE_KW,
311 "mut" => MUT_KW,
312 "pub" => PUB_KW,
313 "ref" => REF_KW,
314 "return" => RETURN_KW,
315 "self" => SELF_KW,
316 "static" => STATIC_KW,
317 "struct" => STRUCT_KW,
318 "super" => SUPER_KW,
319 "trait" => TRAIT_KW,
320 "true" => TRUE_KW,
321 "try" => TRY_KW,
322 "type" => TYPE_KW,
323 "unsafe" => UNSAFE_KW,
324 "use" => USE_KW,
325 "where" => WHERE_KW,
326 "while" => WHILE_KW,
327 _ => return None,
328 };
329 Some(kw)
330 }
331 pub fn from_char(c: char) -> Option<SyntaxKind> {
332 let tok = match c {
333 ';' => SEMICOLON,
334 ',' => COMMA,
335 '(' => L_PAREN,
336 ')' => R_PAREN,
337 '{' => L_CURLY,
338 '}' => R_CURLY,
339 '[' => L_BRACK,
340 ']' => R_BRACK,
341 '<' => L_ANGLE,
342 '>' => R_ANGLE,
343 '@' => AT,
344 '#' => POUND,
345 '~' => TILDE,
346 '?' => QUESTION,
347 '$' => DOLLAR,
348 '&' => AMP,
349 '|' => PIPE,
350 '+' => PLUS,
351 '*' => STAR,
352 '/' => SLASH,
353 '^' => CARET,
354 '%' => PERCENT,
355 '_' => UNDERSCORE,
356 '.' => DOT,
357 ':' => COLON,
358 '=' => EQ,
359 '!' => BANG,
360 '-' => MINUS,
361 _ => return None,
362 };
363 Some(tok)
364 }
365}
366#[macro_export]
367macro_rules ! T { [ ; ] => { $ crate :: SyntaxKind :: SEMICOLON } ; [ , ] => { $ crate :: SyntaxKind :: COMMA } ; [ '(' ] => { $ crate :: SyntaxKind :: L_PAREN } ; [ ')' ] => { $ crate :: SyntaxKind :: R_PAREN } ; [ '{' ] => { $ crate :: SyntaxKind :: L_CURLY } ; [ '}' ] => { $ crate :: SyntaxKind :: R_CURLY } ; [ '[' ] => { $ crate :: SyntaxKind :: L_BRACK } ; [ ']' ] => { $ crate :: SyntaxKind :: R_BRACK } ; [ < ] => { $ crate :: SyntaxKind :: L_ANGLE } ; [ > ] => { $ crate :: SyntaxKind :: R_ANGLE } ; [ @ ] => { $ crate :: SyntaxKind :: AT } ; [ # ] => { $ crate :: SyntaxKind :: POUND } ; [ ~ ] => { $ crate :: SyntaxKind :: TILDE } ; [ ? ] => { $ crate :: SyntaxKind :: QUESTION } ; [ $ ] => { $ crate :: SyntaxKind :: DOLLAR } ; [ & ] => { $ crate :: SyntaxKind :: AMP } ; [ | ] => { $ crate :: SyntaxKind :: PIPE } ; [ + ] => { $ crate :: SyntaxKind :: PLUS } ; [ * ] => { $ crate :: SyntaxKind :: STAR } ; [ / ] => { $ crate :: SyntaxKind :: SLASH } ; [ ^ ] => { $ crate :: SyntaxKind :: CARET } ; [ % ] => { $ crate :: SyntaxKind :: PERCENT } ; [ _ ] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [ . ] => { $ crate :: SyntaxKind :: DOT } ; [ .. ] => { $ crate :: SyntaxKind :: DOT2 } ; [ ... ] => { $ crate :: SyntaxKind :: DOT3 } ; [ ..= ] => { $ crate :: SyntaxKind :: DOT2EQ } ; [ : ] => { $ crate :: SyntaxKind :: COLON } ; [ :: ] => { $ crate :: SyntaxKind :: COLON2 } ; [ = ] => { $ crate :: SyntaxKind :: EQ } ; [ == ] => { $ crate :: SyntaxKind :: EQ2 } ; [ => ] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [ ! ] => { $ crate :: SyntaxKind :: BANG } ; [ != ] => { $ crate :: SyntaxKind :: NEQ } ; [ - ] => { $ crate :: SyntaxKind :: MINUS } ; [ -> ] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [ <= ] => { $ crate :: SyntaxKind :: LTEQ } ; [ >= ] => { $ crate :: SyntaxKind :: GTEQ } ; [ += ] => { $ crate :: SyntaxKind :: PLUSEQ } ; [ -= ] => { $ crate :: SyntaxKind :: MINUSEQ } ; [ |= ] => { $ crate :: SyntaxKind :: PIPEEQ } ; [ &= ] => { $ crate :: SyntaxKind :: AMPEQ } ; [ ^= ] => { $ crate :: SyntaxKind :: CARETEQ } ; [ /= ] => { $ crate :: SyntaxKind :: SLASHEQ } ; [ *= ] => { $ crate :: SyntaxKind :: STAREQ } ; [ %= ] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [ && ] => { $ crate :: SyntaxKind :: AMP2 } ; [ || ] => { $ crate :: SyntaxKind :: PIPE2 } ; [ << ] => { $ crate :: SyntaxKind :: SHL } ; [ >> ] => { $ crate :: SyntaxKind :: SHR } ; [ <<= ] => { $ crate :: SyntaxKind :: SHLEQ } ; [ >>= ] => { $ crate :: SyntaxKind :: SHREQ } ; [ as ] => { $ crate :: SyntaxKind :: AS_KW } ; [ async ] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [ await ] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [ box ] => { $ crate :: SyntaxKind :: BOX_KW } ; [ break ] => { $ crate :: SyntaxKind :: BREAK_KW } ; [ const ] => { $ crate :: SyntaxKind :: CONST_KW } ; [ continue ] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [ crate ] => { $ crate :: SyntaxKind :: CRATE_KW } ; [ dyn ] => { $ crate :: SyntaxKind :: DYN_KW } ; [ else ] => { $ crate :: SyntaxKind :: ELSE_KW } ; [ enum ] => { $ crate :: SyntaxKind :: ENUM_KW } ; [ extern ] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [ false ] => { $ crate :: SyntaxKind :: FALSE_KW } ; [ fn ] => { $ crate :: SyntaxKind :: FN_KW } ; [ for ] => { $ crate :: SyntaxKind :: FOR_KW } ; [ if ] => { $ crate :: SyntaxKind :: IF_KW } ; [ impl ] => { $ crate :: SyntaxKind :: IMPL_KW } ; [ in ] => { $ crate :: SyntaxKind :: IN_KW } ; [ let ] => { $ crate :: SyntaxKind :: LET_KW } ; [ loop ] => { $ crate :: SyntaxKind :: LOOP_KW } ; [ macro ] => { $ crate :: SyntaxKind :: MACRO_KW } ; [ match ] => { $ crate :: SyntaxKind :: MATCH_KW } ; [ mod ] => { $ crate :: SyntaxKind :: MOD_KW } ; [ move ] => { $ crate :: SyntaxKind :: MOVE_KW } ; [ mut ] => { $ crate :: SyntaxKind :: MUT_KW } ; [ pub ] => { $ crate :: SyntaxKind :: PUB_KW } ; [ ref ] => { $ crate :: SyntaxKind :: REF_KW } ; [ return ] => { $ crate :: SyntaxKind :: RETURN_KW } ; [ self ] => { $ crate :: SyntaxKind :: SELF_KW } ; [ static ] => { $ crate :: SyntaxKind :: STATIC_KW } ; [ struct ] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [ super ] => { $ crate :: SyntaxKind :: SUPER_KW } ; [ trait ] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [ true ] => { $ crate :: SyntaxKind :: TRUE_KW } ; [ try ] => { $ crate :: SyntaxKind :: TRY_KW } ; [ type ] => { $ crate :: SyntaxKind :: TYPE_KW } ; [ unsafe ] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [ use ] => { $ crate :: SyntaxKind :: USE_KW } ; [ where ] => { $ crate :: SyntaxKind :: WHERE_KW } ; [ while ] => { $ crate :: SyntaxKind :: WHILE_KW } ; [ auto ] => { $ crate :: SyntaxKind :: AUTO_KW } ; [ default ] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [ existential ] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [ union ] => { $ crate :: SyntaxKind :: UNION_KW } ; [ raw ] => { $ crate :: SyntaxKind :: RAW_KW } ; [ lifetime ] => { $ crate :: SyntaxKind :: LIFETIME } ; [ ident ] => { $ crate :: SyntaxKind :: IDENT } ; [ shebang ] => { $ crate :: SyntaxKind :: SHEBANG } ; }
diff --git a/crates/parser/src/token_set.rs b/crates/parser/src/token_set.rs
new file mode 100644
index 000000000..994017acf
--- /dev/null
+++ b/crates/parser/src/token_set.rs
@@ -0,0 +1,42 @@
1//! A bit-set of `SyntaxKind`s.
2
3use crate::SyntaxKind;
4
5/// A bit-set of `SyntaxKind`s
6#[derive(Clone, Copy)]
7pub(crate) struct TokenSet(u128);
8
9impl TokenSet {
10 pub(crate) const EMPTY: TokenSet = TokenSet(0);
11
12 pub(crate) const fn singleton(kind: SyntaxKind) -> TokenSet {
13 TokenSet(mask(kind))
14 }
15
16 pub(crate) const fn union(self, other: TokenSet) -> TokenSet {
17 TokenSet(self.0 | other.0)
18 }
19
20 pub(crate) fn contains(&self, kind: SyntaxKind) -> bool {
21 self.0 & mask(kind) != 0
22 }
23}
24
25const fn mask(kind: SyntaxKind) -> u128 {
26 1u128 << (kind as usize)
27}
28
29#[macro_export]
30macro_rules! token_set {
31 ($($t:expr),*) => { TokenSet::EMPTY$(.union(TokenSet::singleton($t)))* };
32 ($($t:expr),* ,) => { token_set!($($t),*) };
33}
34
35#[test]
36fn token_set_works_for_tokens() {
37 use crate::SyntaxKind::*;
38 let ts = token_set![EOF, SHEBANG];
39 assert!(ts.contains(EOF));
40 assert!(ts.contains(SHEBANG));
41 assert!(!ts.contains(PLUS));
42}