diff options
Diffstat (limited to 'crates/parser/src')
21 files changed, 4862 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. | ||
10 | use std::mem; | ||
11 | |||
12 | use 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)] | ||
22 | pub(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 | |||
81 | impl 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. | ||
88 | pub(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..562e92252 --- /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/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. | ||
30 | mod attributes; | ||
31 | mod expressions; | ||
32 | mod items; | ||
33 | mod params; | ||
34 | mod paths; | ||
35 | mod patterns; | ||
36 | mod type_args; | ||
37 | mod type_params; | ||
38 | mod types; | ||
39 | |||
40 | use crate::{ | ||
41 | parser::{CompletedMarker, Marker, Parser}, | ||
42 | SyntaxKind::{self, *}, | ||
43 | TokenSet, | ||
44 | }; | ||
45 | |||
46 | pub(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 | ||
54 | pub(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 | |||
138 | pub(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_list, | ||
146 | RECORD_EXPR_FIELD_LIST => items::record_expr_field_list, | ||
147 | VARIANT_LIST => items::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::assoc_item_list, | ||
154 | TRAIT => items::assoc_item_list, | ||
155 | _ => return None, | ||
156 | }, | ||
157 | ITEM_LIST => items::item_list, | ||
158 | _ => return None, | ||
159 | }; | ||
160 | Some(res) | ||
161 | } | ||
162 | |||
163 | #[derive(Clone, Copy, PartialEq, Eq)] | ||
164 | enum BlockLike { | ||
165 | Block, | ||
166 | NotBlock, | ||
167 | } | ||
168 | |||
169 | impl BlockLike { | ||
170 | fn is_block(self) -> bool { | ||
171 | self == BlockLike::Block | ||
172 | } | ||
173 | } | ||
174 | |||
175 | fn 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 | |||
220 | fn opt_rename(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 | |||
231 | fn 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 | |||
242 | fn opt_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 | |||
254 | fn 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 | |||
264 | fn name(p: &mut Parser) { | ||
265 | name_r(p, TokenSet::EMPTY) | ||
266 | } | ||
267 | |||
268 | fn 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 | |||
278 | fn 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 | |||
285 | fn 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..dab0f62c3 --- /dev/null +++ b/crates/parser/src/grammar/attributes.rs | |||
@@ -0,0 +1,48 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use super::*; | ||
4 | |||
5 | pub(super) fn inner_attrs(p: &mut Parser) { | ||
6 | while p.at(T![#]) && p.nth(1) == T![!] { | ||
7 | attr(p, true) | ||
8 | } | ||
9 | } | ||
10 | |||
11 | pub(super) fn outer_attrs(p: &mut Parser) { | ||
12 | while p.at(T![#]) { | ||
13 | attr(p, false) | ||
14 | } | ||
15 | } | ||
16 | |||
17 | fn attr(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..e72929f8c --- /dev/null +++ b/crates/parser/src/grammar/expressions.rs | |||
@@ -0,0 +1,651 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | mod atom; | ||
4 | |||
5 | pub(crate) use self::atom::{block_expr, match_arm_list}; | ||
6 | pub(super) use self::atom::{literal, LITERAL_FIRST}; | ||
7 | use super::*; | ||
8 | |||
9 | pub(super) enum StmtWithSemi { | ||
10 | Yes, | ||
11 | No, | ||
12 | Optional, | ||
13 | } | ||
14 | |||
15 | const EXPR_FIRST: TokenSet = LHS_FIRST; | ||
16 | |||
17 | pub(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 | |||
22 | pub(super) fn expr_with_attrs(p: &mut Parser) -> bool { | ||
23 | let m = p.start(); | ||
24 | let has_attrs = p.at(T![#]); | ||
25 | attributes::outer_attrs(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 | |||
42 | pub(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 | |||
47 | fn expr_no_struct(p: &mut Parser) { | ||
48 | let r = Restrictions { forbid_structs: true, prefer_stmt: false }; | ||
49 | expr_bp(p, r, 1); | ||
50 | } | ||
51 | |||
52 | fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool { | ||
53 | let forbid = matches!(kind, BIN_EXPR | RANGE_EXPR); | ||
54 | !forbid | ||
55 | } | ||
56 | |||
57 | pub(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_attrs(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 | |||
176 | pub(super) fn expr_block_contents(p: &mut Parser) { | ||
177 | // This is checked by a validator | ||
178 | attributes::inner_attrs(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)] | ||
206 | struct 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] | ||
215 | fn 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. | ||
257 | fn 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 | |||
318 | const LHS_FIRST: TokenSet = | ||
319 | atom::ATOM_EXPR_FIRST.union(token_set![T![&], T![*], T![!], T![.], T![-]]); | ||
320 | |||
321 | fn 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 | |||
389 | fn 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 | // } | ||
462 | fn 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 | // } | ||
473 | fn 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 | // } | ||
487 | fn 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_generic_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 | // } | ||
512 | fn 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 | // } | ||
531 | fn 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 | // } | ||
545 | fn 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 | |||
555 | fn 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 | // } | ||
582 | fn 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_expr_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 | // } | ||
606 | pub(crate) fn record_expr_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_attrs(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..ba6dd2fbc --- /dev/null +++ b/crates/parser/src/grammar/expressions/atom.rs | |||
@@ -0,0 +1,611 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use 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 | // } | ||
18 | pub(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 | |||
31 | pub(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 | ||
41 | pub(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 | |||
64 | const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW, R_DOLLAR]; | ||
65 | |||
66 | pub(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![|] => closure_expr(p), | ||
79 | T![move] if la == T![|] => closure_expr(p), | ||
80 | T![async] if la == T![|] || (la == T![move] && p.nth(2) == T![|]) => closure_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 | // } | ||
160 | fn 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 | // } | ||
190 | fn 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 | // } | ||
231 | fn closure_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_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 | // } | ||
264 | fn if_expr(p: &mut Parser) -> CompletedMarker { | ||
265 | assert!(p.at(T![if])); | ||
266 | let m = p.start(); | ||
267 | p.bump(T![if]); | ||
268 | condition(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 | // } | ||
287 | fn 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 | // } | ||
299 | fn 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 | // } | ||
313 | fn 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 | condition(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 | // } | ||
326 | fn 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 | // } | ||
345 | fn condition(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 | // } | ||
362 | fn 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 | |||
375 | pub(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_attrs(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 | // } | ||
425 | fn 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_attrs(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 | // } | ||
458 | fn 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 } | ||
471 | pub(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 | |||
479 | fn 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 | // } | ||
493 | fn 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 | // } | ||
510 | fn 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 | // } | ||
527 | fn 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 | // } | ||
549 | fn 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 | // } | ||
579 | fn 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 | ||
590 | fn 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..8fd8f3b80 --- /dev/null +++ b/crates/parser/src/grammar/items.rs | |||
@@ -0,0 +1,444 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | mod consts; | ||
4 | mod adt; | ||
5 | mod traits; | ||
6 | mod use_item; | ||
7 | |||
8 | pub(crate) use self::{ | ||
9 | adt::{record_field_list, variant_list}, | ||
10 | expressions::{match_arm_list, record_expr_field_list}, | ||
11 | traits::assoc_item_list, | ||
12 | use_item::use_tree_list, | ||
13 | }; | ||
14 | use super::*; | ||
15 | |||
16 | // test mod_contents | ||
17 | // fn foo() {} | ||
18 | // macro_rules! foo {} | ||
19 | // foo::bar!(); | ||
20 | // super::baz! {} | ||
21 | // struct S; | ||
22 | pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) { | ||
23 | attributes::inner_attrs(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 | |||
29 | pub(super) const ITEM_RECOVERY_SET: TokenSet = token_set![ | ||
30 | FN_KW, | ||
31 | STRUCT_KW, | ||
32 | ENUM_KW, | ||
33 | IMPL_KW, | ||
34 | TRAIT_KW, | ||
35 | CONST_KW, | ||
36 | STATIC_KW, | ||
37 | LET_KW, | ||
38 | MOD_KW, | ||
39 | PUB_KW, | ||
40 | CRATE_KW, | ||
41 | USE_KW, | ||
42 | MACRO_KW, | ||
43 | T![;], | ||
44 | ]; | ||
45 | |||
46 | pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool) { | ||
47 | let m = p.start(); | ||
48 | attributes::outer_attrs(p); | ||
49 | let m = match maybe_item(p, m) { | ||
50 | Ok(()) => { | ||
51 | if p.at(T![;]) { | ||
52 | p.err_and_bump( | ||
53 | "expected item, found `;`\n\ | ||
54 | consider removing this semicolon", | ||
55 | ); | ||
56 | } | ||
57 | return; | ||
58 | } | ||
59 | Err(m) => m, | ||
60 | }; | ||
61 | if paths::is_use_path_start(p) { | ||
62 | match macro_call(p) { | ||
63 | BlockLike::Block => (), | ||
64 | BlockLike::NotBlock => { | ||
65 | p.expect(T![;]); | ||
66 | } | ||
67 | } | ||
68 | m.complete(p, MACRO_CALL); | ||
69 | } else { | ||
70 | m.abandon(p); | ||
71 | if p.at(T!['{']) { | ||
72 | error_block(p, "expected an item"); | ||
73 | } else if p.at(T!['}']) && !stop_on_r_curly { | ||
74 | let e = p.start(); | ||
75 | p.error("unmatched `}`"); | ||
76 | p.bump(T!['}']); | ||
77 | e.complete(p, ERROR); | ||
78 | } else if !p.at(EOF) && !p.at(T!['}']) { | ||
79 | p.err_and_bump("expected an item"); | ||
80 | } else { | ||
81 | p.error("expected an item"); | ||
82 | } | ||
83 | } | ||
84 | } | ||
85 | |||
86 | pub(super) fn maybe_item(p: &mut Parser, m: Marker) -> Result<(), Marker> { | ||
87 | // test_err pub_expr | ||
88 | // fn foo() { pub 92; } | ||
89 | let has_visibility = opt_visibility(p); | ||
90 | |||
91 | let m = match items_without_modifiers(p, m) { | ||
92 | Ok(()) => return Ok(()), | ||
93 | Err(m) => m, | ||
94 | }; | ||
95 | |||
96 | let mut has_mods = false; | ||
97 | |||
98 | // modifiers | ||
99 | has_mods |= p.eat(T![const]); | ||
100 | |||
101 | // test_err async_without_semicolon | ||
102 | // fn foo() { let _ = async {} } | ||
103 | if p.at(T![async]) && p.nth(1) != T!['{'] && p.nth(1) != T![move] && p.nth(1) != T![|] { | ||
104 | p.eat(T![async]); | ||
105 | has_mods = true; | ||
106 | } | ||
107 | |||
108 | // test_err unsafe_block_in_mod | ||
109 | // fn foo(){} unsafe { } fn bar(){} | ||
110 | if p.at(T![unsafe]) && p.nth(1) != T!['{'] { | ||
111 | p.eat(T![unsafe]); | ||
112 | has_mods = true; | ||
113 | } | ||
114 | |||
115 | if p.at(T![extern]) { | ||
116 | has_mods = true; | ||
117 | abi(p); | ||
118 | } | ||
119 | if p.at(IDENT) && p.at_contextual_kw("auto") && p.nth(1) == T![trait] { | ||
120 | p.bump_remap(T![auto]); | ||
121 | has_mods = true; | ||
122 | } | ||
123 | |||
124 | // test default_item | ||
125 | // default impl T for Foo {} | ||
126 | if p.at(IDENT) && p.at_contextual_kw("default") { | ||
127 | match p.nth(1) { | ||
128 | T![fn] | T![type] | T![const] | T![impl] => { | ||
129 | p.bump_remap(T![default]); | ||
130 | has_mods = true; | ||
131 | } | ||
132 | T![unsafe] => { | ||
133 | // test default_unsafe_item | ||
134 | // default unsafe impl T for Foo { | ||
135 | // default unsafe fn foo() {} | ||
136 | // } | ||
137 | if matches!(p.nth(2), T![impl] | T![fn]) { | ||
138 | p.bump_remap(T![default]); | ||
139 | p.bump(T![unsafe]); | ||
140 | has_mods = true; | ||
141 | } | ||
142 | } | ||
143 | _ => (), | ||
144 | } | ||
145 | } | ||
146 | |||
147 | // test existential_type | ||
148 | // existential type Foo: Fn() -> usize; | ||
149 | if p.at(IDENT) && p.at_contextual_kw("existential") && p.nth(1) == T![type] { | ||
150 | p.bump_remap(T![existential]); | ||
151 | has_mods = true; | ||
152 | } | ||
153 | |||
154 | // items | ||
155 | match p.current() { | ||
156 | // test fn | ||
157 | // fn foo() {} | ||
158 | T![fn] => { | ||
159 | fn_(p); | ||
160 | m.complete(p, FN); | ||
161 | } | ||
162 | |||
163 | // test trait | ||
164 | // trait T {} | ||
165 | T![trait] => { | ||
166 | traits::trait_(p); | ||
167 | m.complete(p, TRAIT); | ||
168 | } | ||
169 | |||
170 | T![const] => { | ||
171 | consts::konst(p, m); | ||
172 | } | ||
173 | |||
174 | // test impl | ||
175 | // impl T for S {} | ||
176 | T![impl] => { | ||
177 | traits::impl_(p); | ||
178 | m.complete(p, IMPL); | ||
179 | } | ||
180 | |||
181 | T![type] => { | ||
182 | type_alias(p, m); | ||
183 | } | ||
184 | _ => { | ||
185 | if !has_visibility && !has_mods { | ||
186 | return Err(m); | ||
187 | } else { | ||
188 | if has_mods { | ||
189 | p.error("expected existential, fn, trait or impl"); | ||
190 | } else { | ||
191 | p.error("expected an item"); | ||
192 | } | ||
193 | m.complete(p, ERROR); | ||
194 | } | ||
195 | } | ||
196 | } | ||
197 | Ok(()) | ||
198 | } | ||
199 | |||
200 | fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> { | ||
201 | let la = p.nth(1); | ||
202 | match p.current() { | ||
203 | // test extern_crate | ||
204 | // extern crate foo; | ||
205 | T![extern] if la == T![crate] => extern_crate(p, m), | ||
206 | T![type] => { | ||
207 | type_alias(p, m); | ||
208 | } | ||
209 | T![mod] => mod_item(p, m), | ||
210 | T![struct] => { | ||
211 | // test struct_items | ||
212 | // struct Foo; | ||
213 | // struct Foo {} | ||
214 | // struct Foo(); | ||
215 | // struct Foo(String, usize); | ||
216 | // struct Foo { | ||
217 | // a: i32, | ||
218 | // b: f32, | ||
219 | // } | ||
220 | adt::strukt(p, m); | ||
221 | } | ||
222 | // test pub_macro_def | ||
223 | // pub macro m($:ident) {} | ||
224 | T![macro] => { | ||
225 | macro_def(p, m); | ||
226 | } | ||
227 | IDENT if p.at_contextual_kw("union") && p.nth(1) == IDENT => { | ||
228 | // test union_items | ||
229 | // union Foo {} | ||
230 | // union Foo { | ||
231 | // a: i32, | ||
232 | // b: f32, | ||
233 | // } | ||
234 | adt::union(p, m); | ||
235 | } | ||
236 | T![enum] => adt::enum_(p, m), | ||
237 | T![use] => use_item::use_(p, m), | ||
238 | T![const] if (la == IDENT || la == T![_] || la == T![mut]) => consts::konst(p, m), | ||
239 | T![static] => consts::static_(p, m), | ||
240 | // test extern_block | ||
241 | // extern {} | ||
242 | T![extern] | ||
243 | if la == T!['{'] || ((la == STRING || la == RAW_STRING) && p.nth(2) == T!['{']) => | ||
244 | { | ||
245 | abi(p); | ||
246 | extern_item_list(p); | ||
247 | m.complete(p, EXTERN_BLOCK); | ||
248 | } | ||
249 | _ => return Err(m), | ||
250 | }; | ||
251 | Ok(()) | ||
252 | } | ||
253 | |||
254 | fn extern_crate(p: &mut Parser, m: Marker) { | ||
255 | assert!(p.at(T![extern])); | ||
256 | p.bump(T![extern]); | ||
257 | assert!(p.at(T![crate])); | ||
258 | p.bump(T![crate]); | ||
259 | |||
260 | if p.at(T![self]) { | ||
261 | p.bump(T![self]); | ||
262 | } else { | ||
263 | name_ref(p); | ||
264 | } | ||
265 | |||
266 | opt_rename(p); | ||
267 | p.expect(T![;]); | ||
268 | m.complete(p, EXTERN_CRATE); | ||
269 | } | ||
270 | |||
271 | pub(crate) fn extern_item_list(p: &mut Parser) { | ||
272 | assert!(p.at(T!['{'])); | ||
273 | let m = p.start(); | ||
274 | p.bump(T!['{']); | ||
275 | mod_contents(p, true); | ||
276 | p.expect(T!['}']); | ||
277 | m.complete(p, EXTERN_ITEM_LIST); | ||
278 | } | ||
279 | |||
280 | fn fn_(p: &mut Parser) { | ||
281 | assert!(p.at(T![fn])); | ||
282 | p.bump(T![fn]); | ||
283 | |||
284 | name_r(p, ITEM_RECOVERY_SET); | ||
285 | // test function_type_params | ||
286 | // fn foo<T: Clone + Copy>(){} | ||
287 | type_params::opt_generic_param_list(p); | ||
288 | |||
289 | if p.at(T!['(']) { | ||
290 | params::param_list_fn_def(p); | ||
291 | } else { | ||
292 | p.error("expected function arguments"); | ||
293 | } | ||
294 | // test function_ret_type | ||
295 | // fn foo() {} | ||
296 | // fn bar() -> () {} | ||
297 | opt_ret_type(p); | ||
298 | |||
299 | // test function_where_clause | ||
300 | // fn foo<T>() where T: Copy {} | ||
301 | type_params::opt_where_clause(p); | ||
302 | |||
303 | // test fn_decl | ||
304 | // trait T { fn foo(); } | ||
305 | if p.at(T![;]) { | ||
306 | p.bump(T![;]); | ||
307 | } else { | ||
308 | expressions::block_expr(p) | ||
309 | } | ||
310 | } | ||
311 | |||
312 | // test type_item | ||
313 | // type Foo = Bar; | ||
314 | fn type_alias(p: &mut Parser, m: Marker) { | ||
315 | assert!(p.at(T![type])); | ||
316 | p.bump(T![type]); | ||
317 | |||
318 | name(p); | ||
319 | |||
320 | // test type_item_type_params | ||
321 | // type Result<T> = (); | ||
322 | type_params::opt_generic_param_list(p); | ||
323 | |||
324 | if p.at(T![:]) { | ||
325 | type_params::bounds(p); | ||
326 | } | ||
327 | |||
328 | // test type_item_where_clause | ||
329 | // type Foo where Foo: Copy = (); | ||
330 | type_params::opt_where_clause(p); | ||
331 | if p.eat(T![=]) { | ||
332 | types::type_(p); | ||
333 | } | ||
334 | p.expect(T![;]); | ||
335 | m.complete(p, TYPE_ALIAS); | ||
336 | } | ||
337 | |||
338 | pub(crate) fn mod_item(p: &mut Parser, m: Marker) { | ||
339 | assert!(p.at(T![mod])); | ||
340 | p.bump(T![mod]); | ||
341 | |||
342 | name(p); | ||
343 | if p.at(T!['{']) { | ||
344 | item_list(p); | ||
345 | } else if !p.eat(T![;]) { | ||
346 | p.error("expected `;` or `{`"); | ||
347 | } | ||
348 | m.complete(p, MODULE); | ||
349 | } | ||
350 | |||
351 | pub(crate) fn item_list(p: &mut Parser) { | ||
352 | assert!(p.at(T!['{'])); | ||
353 | let m = p.start(); | ||
354 | p.bump(T!['{']); | ||
355 | mod_contents(p, true); | ||
356 | p.expect(T!['}']); | ||
357 | m.complete(p, ITEM_LIST); | ||
358 | } | ||
359 | |||
360 | // test macro_def | ||
361 | // macro m { ($i:ident) => {} } | ||
362 | // macro m($i:ident) {} | ||
363 | fn macro_def(p: &mut Parser, m: Marker) { | ||
364 | p.expect(T![macro]); | ||
365 | name_r(p, ITEM_RECOVERY_SET); | ||
366 | if p.at(T!['{']) { | ||
367 | token_tree(p); | ||
368 | } else if !p.at(T!['(']) { | ||
369 | p.error("unmatched `(`"); | ||
370 | } else { | ||
371 | let m = p.start(); | ||
372 | token_tree(p); | ||
373 | match p.current() { | ||
374 | T!['{'] | T!['['] | T!['('] => token_tree(p), | ||
375 | _ => p.error("expected `{`, `[`, `(`"), | ||
376 | } | ||
377 | m.complete(p, TOKEN_TREE); | ||
378 | } | ||
379 | |||
380 | m.complete(p, MACRO_DEF); | ||
381 | } | ||
382 | |||
383 | fn macro_call(p: &mut Parser) -> BlockLike { | ||
384 | assert!(paths::is_use_path_start(p)); | ||
385 | paths::use_path(p); | ||
386 | macro_call_after_excl(p) | ||
387 | } | ||
388 | |||
389 | pub(super) fn macro_call_after_excl(p: &mut Parser) -> BlockLike { | ||
390 | p.expect(T![!]); | ||
391 | if p.at(IDENT) { | ||
392 | name(p); | ||
393 | } | ||
394 | // Special-case `macro_rules! try`. | ||
395 | // This is a hack until we do proper edition support | ||
396 | |||
397 | // test try_macro_rules | ||
398 | // macro_rules! try { () => {} } | ||
399 | if p.at(T![try]) { | ||
400 | let m = p.start(); | ||
401 | p.bump_remap(IDENT); | ||
402 | m.complete(p, NAME); | ||
403 | } | ||
404 | |||
405 | match p.current() { | ||
406 | T!['{'] => { | ||
407 | token_tree(p); | ||
408 | BlockLike::Block | ||
409 | } | ||
410 | T!['('] | T!['['] => { | ||
411 | token_tree(p); | ||
412 | BlockLike::NotBlock | ||
413 | } | ||
414 | _ => { | ||
415 | p.error("expected `{`, `[`, `(`"); | ||
416 | BlockLike::NotBlock | ||
417 | } | ||
418 | } | ||
419 | } | ||
420 | |||
421 | pub(crate) fn token_tree(p: &mut Parser) { | ||
422 | let closing_paren_kind = match p.current() { | ||
423 | T!['{'] => T!['}'], | ||
424 | T!['('] => T![')'], | ||
425 | T!['['] => T![']'], | ||
426 | _ => unreachable!(), | ||
427 | }; | ||
428 | let m = p.start(); | ||
429 | p.bump_any(); | ||
430 | while !p.at(EOF) && !p.at(closing_paren_kind) { | ||
431 | match p.current() { | ||
432 | T!['{'] | T!['('] | T!['['] => token_tree(p), | ||
433 | T!['}'] => { | ||
434 | p.error("unmatched `}`"); | ||
435 | m.complete(p, TOKEN_TREE); | ||
436 | return; | ||
437 | } | ||
438 | T![')'] | T![']'] => p.err_and_bump("unmatched brace"), | ||
439 | _ => p.bump_any(), | ||
440 | } | ||
441 | } | ||
442 | p.expect(closing_paren_kind); | ||
443 | m.complete(p, TOKEN_TREE); | ||
444 | } | ||
diff --git a/crates/parser/src/grammar/items/adt.rs b/crates/parser/src/grammar/items/adt.rs new file mode 100644 index 000000000..67c0c5697 --- /dev/null +++ b/crates/parser/src/grammar/items/adt.rs | |||
@@ -0,0 +1,178 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use super::*; | ||
4 | |||
5 | pub(super) fn strukt(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 | |||
11 | pub(super) fn union(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 | |||
17 | fn struct_or_union(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) { | ||
18 | name_r(p, ITEM_RECOVERY_SET); | ||
19 | type_params::opt_generic_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_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_list(p), | ||
38 | T!['('] if kw == T![struct] => { | ||
39 | tuple_field_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 | |||
56 | pub(super) fn enum_(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_generic_param_list(p); | ||
61 | type_params::opt_where_clause(p); | ||
62 | if p.at(T!['{']) { | ||
63 | variant_list(p); | ||
64 | } else { | ||
65 | p.error("expected `{`") | ||
66 | } | ||
67 | m.complete(p, ENUM); | ||
68 | } | ||
69 | |||
70 | pub(crate) fn 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_attrs(p); | ||
81 | if p.at(IDENT) { | ||
82 | name(p); | ||
83 | match p.current() { | ||
84 | T!['{'] => record_field_list(p), | ||
85 | T!['('] => tuple_field_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 | |||
107 | pub(crate) fn record_field_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_attrs(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 | |||
145 | fn tuple_field_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_attrs(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..eb7d1f828 --- /dev/null +++ b/crates/parser/src/grammar/items/consts.rs | |||
@@ -0,0 +1,33 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use super::*; | ||
4 | |||
5 | pub(super) fn static_(p: &mut Parser, m: Marker) { | ||
6 | const_or_static(p, m, T![static], STATIC) | ||
7 | } | ||
8 | |||
9 | pub(super) fn konst(p: &mut Parser, m: Marker) { | ||
10 | const_or_static(p, m, T![const], CONST) | ||
11 | } | ||
12 | |||
13 | fn 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..8394020da --- /dev/null +++ b/crates/parser/src/grammar/items/traits.rs | |||
@@ -0,0 +1,131 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use 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 {} | ||
8 | pub(super) fn trait_(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_generic_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 | assoc_item_list(p); | ||
29 | } else { | ||
30 | p.error("expected `{`"); | ||
31 | } | ||
32 | } | ||
33 | |||
34 | // test impl_def | ||
35 | // impl Foo {} | ||
36 | pub(super) fn impl_(p: &mut Parser) { | ||
37 | assert!(p.at(T![impl])); | ||
38 | p.bump(T![impl]); | ||
39 | if choose_type_params_over_qpath(p) { | ||
40 | type_params::opt_generic_param_list(p); | ||
41 | } | ||
42 | |||
43 | // FIXME: never type | ||
44 | // impl ! {} | ||
45 | |||
46 | // test impl_def_neg | ||
47 | // impl !Send for X {} | ||
48 | p.eat(T![!]); | ||
49 | impl_type(p); | ||
50 | if p.eat(T![for]) { | ||
51 | impl_type(p); | ||
52 | } | ||
53 | type_params::opt_where_clause(p); | ||
54 | if p.at(T!['{']) { | ||
55 | assoc_item_list(p); | ||
56 | } else { | ||
57 | p.error("expected `{`"); | ||
58 | } | ||
59 | } | ||
60 | |||
61 | // test impl_item_list | ||
62 | // impl F { | ||
63 | // type A = i32; | ||
64 | // const B: i32 = 92; | ||
65 | // fn foo() {} | ||
66 | // fn bar(&self) {} | ||
67 | // } | ||
68 | pub(crate) fn assoc_item_list(p: &mut Parser) { | ||
69 | assert!(p.at(T!['{'])); | ||
70 | let m = p.start(); | ||
71 | p.bump(T!['{']); | ||
72 | // test impl_inner_attributes | ||
73 | // enum F{} | ||
74 | // impl F { | ||
75 | // //! This is a doc comment | ||
76 | // #![doc("This is also a doc comment")] | ||
77 | // } | ||
78 | attributes::inner_attrs(p); | ||
79 | |||
80 | while !p.at(EOF) && !p.at(T!['}']) { | ||
81 | if p.at(T!['{']) { | ||
82 | error_block(p, "expected an item"); | ||
83 | continue; | ||
84 | } | ||
85 | item_or_macro(p, true); | ||
86 | } | ||
87 | p.expect(T!['}']); | ||
88 | m.complete(p, ASSOC_ITEM_LIST); | ||
89 | } | ||
90 | |||
91 | // test impl_type_params | ||
92 | // impl<const N: u32> Bar<N> {} | ||
93 | fn choose_type_params_over_qpath(p: &Parser) -> bool { | ||
94 | // There's an ambiguity between generic parameters and qualified paths in impls. | ||
95 | // If we see `<` it may start both, so we have to inspect some following tokens. | ||
96 | // The following combinations can only start generics, | ||
97 | // but not qualified paths (with one exception): | ||
98 | // `<` `>` - empty generic parameters | ||
99 | // `<` `#` - generic parameters with attributes | ||
100 | // `<` `const` - const generic parameters | ||
101 | // `<` (LIFETIME|IDENT) `>` - single generic parameter | ||
102 | // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list | ||
103 | // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds | ||
104 | // `<` (LIFETIME|IDENT) `=` - generic parameter with a default | ||
105 | // The only truly ambiguous case is | ||
106 | // `<` IDENT `>` `::` IDENT ... | ||
107 | // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`) | ||
108 | // because this is what almost always expected in practice, qualified paths in impls | ||
109 | // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment. | ||
110 | if !p.at(T![<]) { | ||
111 | return false; | ||
112 | } | ||
113 | if p.nth(1) == T![#] || p.nth(1) == T![>] || p.nth(1) == CONST_KW { | ||
114 | return true; | ||
115 | } | ||
116 | (p.nth(1) == LIFETIME || p.nth(1) == IDENT) | ||
117 | && (p.nth(2) == T![>] || p.nth(2) == T![,] || p.nth(2) == T![:] || p.nth(2) == T![=]) | ||
118 | } | ||
119 | |||
120 | // test_err impl_type | ||
121 | // impl Type {} | ||
122 | // impl Trait1 for T {} | ||
123 | // impl impl NotType {} | ||
124 | // impl Trait2 for impl NotType {} | ||
125 | pub(crate) fn impl_type(p: &mut Parser) { | ||
126 | if p.at(T![impl]) { | ||
127 | p.error("expected trait or type"); | ||
128 | return; | ||
129 | } | ||
130 | types::type_(p); | ||
131 | } | ||
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..20e6a13cf --- /dev/null +++ b/crates/parser/src/grammar/items/use_item.rs | |||
@@ -0,0 +1,132 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use super::*; | ||
4 | |||
5 | pub(super) fn use_(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};` | ||
17 | fn 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_rename(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 | |||
120 | pub(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..a665ffc13 --- /dev/null +++ b/crates/parser/src/grammar/params.rs | |||
@@ -0,0 +1,188 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use super::*; | ||
4 | |||
5 | // test param_list | ||
6 | // fn a() {} | ||
7 | // fn b(x: i32) {} | ||
8 | // fn c(x: i32, ) {} | ||
9 | // fn d(x: i32, y: ()) {} | ||
10 | pub(super) fn param_list_fn_def(p: &mut Parser) { | ||
11 | list_(p, Flavor::FnDef) | ||
12 | } | ||
13 | |||
14 | // test param_list_opt_patterns | ||
15 | // fn foo<F: FnMut(&mut Foo<'a>)>(){} | ||
16 | pub(super) fn param_list_fn_trait(p: &mut Parser) { | ||
17 | list_(p, Flavor::FnTrait) | ||
18 | } | ||
19 | |||
20 | pub(super) fn param_list_fn_ptr(p: &mut Parser) { | ||
21 | list_(p, Flavor::FnPointer) | ||
22 | } | ||
23 | |||
24 | pub(super) fn param_list_closure(p: &mut Parser) { | ||
25 | list_(p, Flavor::Closure) | ||
26 | } | ||
27 | |||
28 | #[derive(Debug, Clone, Copy)] | ||
29 | enum Flavor { | ||
30 | FnDef, // Includes trait fn params; omitted param idents are not supported | ||
31 | FnTrait, // Params for `Fn(...)`/`FnMut(...)`/`FnOnce(...)` annotations | ||
32 | FnPointer, | ||
33 | Closure, | ||
34 | } | ||
35 | |||
36 | fn list_(p: &mut Parser, flavor: Flavor) { | ||
37 | use Flavor::*; | ||
38 | |||
39 | let (bra, ket) = match flavor { | ||
40 | Closure => (T![|], T![|]), | ||
41 | FnDef | FnTrait | FnPointer => (T!['('], T![')']), | ||
42 | }; | ||
43 | |||
44 | let m = p.start(); | ||
45 | p.bump(bra); | ||
46 | |||
47 | if let FnDef = flavor { | ||
48 | // test self_param_outer_attr | ||
49 | // fn f(#[must_use] self) {} | ||
50 | attributes::outer_attrs(p); | ||
51 | opt_self_param(p); | ||
52 | } | ||
53 | |||
54 | while !p.at(EOF) && !p.at(ket) { | ||
55 | // test param_outer_arg | ||
56 | // fn f(#[attr1] pat: Type) {} | ||
57 | attributes::outer_attrs(p); | ||
58 | |||
59 | if !p.at_ts(PARAM_FIRST) { | ||
60 | p.error("expected value parameter"); | ||
61 | break; | ||
62 | } | ||
63 | let param = param(p, flavor); | ||
64 | if !p.at(ket) { | ||
65 | p.expect(T![,]); | ||
66 | } | ||
67 | if let Variadic(true) = param { | ||
68 | break; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | p.expect(ket); | ||
73 | m.complete(p, PARAM_LIST); | ||
74 | } | ||
75 | |||
76 | const PARAM_FIRST: TokenSet = patterns::PATTERN_FIRST.union(types::TYPE_FIRST); | ||
77 | |||
78 | struct Variadic(bool); | ||
79 | |||
80 | fn param(p: &mut Parser, flavor: Flavor) -> Variadic { | ||
81 | let mut res = Variadic(false); | ||
82 | let m = p.start(); | ||
83 | match flavor { | ||
84 | // test param_list_vararg | ||
85 | // extern "C" { fn printf(format: *const i8, ...) -> i32; } | ||
86 | Flavor::FnDef | Flavor::FnPointer if p.eat(T![...]) => res = Variadic(true), | ||
87 | |||
88 | // test fn_def_param | ||
89 | // fn foo((x, y): (i32, i32)) {} | ||
90 | Flavor::FnDef => { | ||
91 | patterns::pattern(p); | ||
92 | if variadic_param(p) { | ||
93 | res = Variadic(true) | ||
94 | } else { | ||
95 | types::ascription(p); | ||
96 | } | ||
97 | } | ||
98 | // test value_parameters_no_patterns | ||
99 | // type F = Box<Fn(i32, &i32, &i32, ())>; | ||
100 | Flavor::FnTrait => { | ||
101 | types::type_(p); | ||
102 | } | ||
103 | // test fn_pointer_param_ident_path | ||
104 | // type Foo = fn(Bar::Baz); | ||
105 | // type Qux = fn(baz: Bar::Baz); | ||
106 | |||
107 | // test fn_pointer_unnamed_arg | ||
108 | // type Foo = fn(_: bar); | ||
109 | Flavor::FnPointer => { | ||
110 | if (p.at(IDENT) || p.at(UNDERSCORE)) && p.nth(1) == T![:] && !p.nth_at(1, T![::]) { | ||
111 | patterns::pattern_single(p); | ||
112 | if variadic_param(p) { | ||
113 | res = Variadic(true) | ||
114 | } else { | ||
115 | types::ascription(p); | ||
116 | } | ||
117 | } else { | ||
118 | types::type_(p); | ||
119 | } | ||
120 | } | ||
121 | // test closure_params | ||
122 | // fn main() { | ||
123 | // let foo = |bar, baz: Baz, qux: Qux::Quux| (); | ||
124 | // } | ||
125 | Flavor::Closure => { | ||
126 | patterns::pattern_single(p); | ||
127 | if p.at(T![:]) && !p.at(T![::]) { | ||
128 | types::ascription(p); | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | m.complete(p, PARAM); | ||
133 | res | ||
134 | } | ||
135 | |||
136 | fn variadic_param(p: &mut Parser) -> bool { | ||
137 | if p.at(T![:]) && p.nth_at(1, T![...]) { | ||
138 | p.bump(T![:]); | ||
139 | p.bump(T![...]); | ||
140 | true | ||
141 | } else { | ||
142 | false | ||
143 | } | ||
144 | } | ||
145 | |||
146 | // test self_param | ||
147 | // impl S { | ||
148 | // fn a(self) {} | ||
149 | // fn b(&self,) {} | ||
150 | // fn c(&'a self,) {} | ||
151 | // fn d(&'a mut self, x: i32) {} | ||
152 | // fn e(mut self) {} | ||
153 | // } | ||
154 | fn opt_self_param(p: &mut Parser) { | ||
155 | let m; | ||
156 | if p.at(T![self]) || p.at(T![mut]) && p.nth(1) == T![self] { | ||
157 | m = p.start(); | ||
158 | p.eat(T![mut]); | ||
159 | p.eat(T![self]); | ||
160 | // test arb_self_types | ||
161 | // impl S { | ||
162 | // fn a(self: &Self) {} | ||
163 | // fn b(mut self: Box<Self>) {} | ||
164 | // } | ||
165 | if p.at(T![:]) { | ||
166 | types::ascription(p); | ||
167 | } | ||
168 | } else { | ||
169 | let la1 = p.nth(1); | ||
170 | let la2 = p.nth(2); | ||
171 | let la3 = p.nth(3); | ||
172 | let n_toks = match (p.current(), la1, la2, la3) { | ||
173 | (T![&], T![self], _, _) => 2, | ||
174 | (T![&], T![mut], T![self], _) => 3, | ||
175 | (T![&], LIFETIME, T![self], _) => 3, | ||
176 | (T![&], LIFETIME, T![mut], T![self]) => 4, | ||
177 | _ => return, | ||
178 | }; | ||
179 | m = p.start(); | ||
180 | for _ in 0..n_toks { | ||
181 | p.bump_any(); | ||
182 | } | ||
183 | } | ||
184 | m.complete(p, SELF_PARAM); | ||
185 | if !p.at(T![')']) { | ||
186 | p.expect(T![,]); | ||
187 | } | ||
188 | } | ||
diff --git a/crates/parser/src/grammar/paths.rs b/crates/parser/src/grammar/paths.rs new file mode 100644 index 000000000..52562afa4 --- /dev/null +++ b/crates/parser/src/grammar/paths.rs | |||
@@ -0,0 +1,115 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use super::*; | ||
4 | |||
5 | pub(super) const PATH_FIRST: TokenSet = | ||
6 | token_set![IDENT, T![self], T![super], T![crate], T![:], T![<]]; | ||
7 | |||
8 | pub(super) fn is_path_start(p: &Parser) -> bool { | ||
9 | is_use_path_start(p) || p.at(T![<]) | ||
10 | } | ||
11 | |||
12 | pub(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 | |||
20 | pub(super) fn use_path(p: &mut Parser) { | ||
21 | path(p, Mode::Use) | ||
22 | } | ||
23 | |||
24 | pub(crate) fn type_path(p: &mut Parser) { | ||
25 | path(p, Mode::Type) | ||
26 | } | ||
27 | |||
28 | pub(super) fn expr_path(p: &mut Parser) { | ||
29 | path(p, Mode::Expr) | ||
30 | } | ||
31 | |||
32 | #[derive(Clone, Copy, Eq, PartialEq)] | ||
33 | enum Mode { | ||
34 | Use, | ||
35 | Type, | ||
36 | Expr, | ||
37 | } | ||
38 | |||
39 | fn 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 | |||
57 | fn 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 | |||
100 | fn 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_ret_type(p); | ||
109 | } else { | ||
110 | type_args::opt_generic_arg_list(p, false) | ||
111 | } | ||
112 | } | ||
113 | Mode::Expr => type_args::opt_generic_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..07b1d6dd5 --- /dev/null +++ b/crates/parser/src/grammar/patterns.rs | |||
@@ -0,0 +1,379 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use super::*; | ||
4 | |||
5 | pub(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 | |||
9 | pub(crate) fn pattern(p: &mut Parser) { | ||
10 | pattern_r(p, PAT_RECOVERY_SET); | ||
11 | } | ||
12 | |||
13 | /// Parses a pattern list separated by pipes `|` | ||
14 | pub(super) fn pattern_top(p: &mut Parser) { | ||
15 | pattern_top_r(p, PAT_RECOVERY_SET) | ||
16 | } | ||
17 | |||
18 | pub(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` | ||
24 | pub(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 | // } | ||
40 | fn 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 | |||
54 | fn 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 | |||
76 | const PAT_RECOVERY_SET: TokenSet = | ||
77 | token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA]; | ||
78 | |||
79 | fn 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] => ident_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 | _ => ident_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![..]) => rest_pat(p), | ||
97 | T![_] => wildcard_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 | |||
111 | fn 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 | // } | ||
125 | fn 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 | // } | ||
142 | fn 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_pat_field_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 | // } | ||
175 | fn 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 | // } | ||
189 | fn record_pat_field_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 | ident_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 _ = (); } | ||
233 | fn wildcard_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 | // } | ||
266 | fn rest_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 | // } | ||
278 | fn 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 | // } | ||
294 | fn 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 | // } | ||
324 | fn 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 | |||
333 | fn 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 | // } | ||
356 | fn ident_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 | // } | ||
373 | fn 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..f2d34a749 --- /dev/null +++ b/crates/parser/src/grammar/type_args.rs | |||
@@ -0,0 +1,63 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use super::*; | ||
4 | |||
5 | pub(super) fn opt_generic_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 | generic_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>; | ||
30 | fn generic_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..bc7d8d724 --- /dev/null +++ b/crates/parser/src/grammar/type_params.rs | |||
@@ -0,0 +1,209 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use super::*; | ||
4 | |||
5 | pub(super) fn opt_generic_param_list(p: &mut Parser) { | ||
6 | if !p.at(T![<]) { | ||
7 | return; | ||
8 | } | ||
9 | generic_param_list(p); | ||
10 | } | ||
11 | |||
12 | fn generic_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_attrs(p); | ||
24 | |||
25 | match p.current() { | ||
26 | LIFETIME => lifetime_param(p, m), | ||
27 | IDENT => type_param(p, m), | ||
28 | CONST_KW => 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 | |||
42 | fn 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 | |||
51 | fn 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>; | ||
68 | fn 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)>; | ||
78 | pub(super) fn bounds(p: &mut Parser) { | ||
79 | assert!(p.at(T![:])); | ||
80 | p.bump(T![:]); | ||
81 | bounds_without_colon(p); | ||
82 | } | ||
83 | |||
84 | fn 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 | |||
95 | pub(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 | |||
105 | pub(super) fn bounds_without_colon(p: &mut Parser) { | ||
106 | let m = p.start(); | ||
107 | bounds_without_colon_m(p, m); | ||
108 | } | ||
109 | |||
110 | fn 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 | // {} | ||
139 | pub(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 | |||
163 | fn 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 | |||
171 | fn is_where_clause_end(p: &mut Parser) -> bool { | ||
172 | matches!(p.current(), T!['{'] | T![;] | T![=]) | ||
173 | } | ||
174 | |||
175 | fn 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..c876545f4 --- /dev/null +++ b/crates/parser/src/grammar/types.rs | |||
@@ -0,0 +1,324 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use super::*; | ||
4 | |||
5 | pub(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 | |||
21 | const TYPE_RECOVERY_SET: TokenSet = token_set![R_PAREN, COMMA, L_DOLLAR]; | ||
22 | |||
23 | pub(crate) fn type_(p: &mut Parser) { | ||
24 | type_with_bounds_cond(p, true); | ||
25 | } | ||
26 | |||
27 | pub(super) fn type_no_bounds(p: &mut Parser) { | ||
28 | type_with_bounds_cond(p, false); | ||
29 | } | ||
30 | |||
31 | fn 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![*] => ptr_type(p), | ||
36 | T!['['] => array_or_slice_type(p), | ||
37 | T![&] => ref_type(p), | ||
38 | T![_] => infer_type(p), | ||
39 | T![fn] | T![unsafe] | T![extern] => fn_ptr_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 | |||
52 | pub(super) fn ascription(p: &mut Parser) { | ||
53 | p.expect(T![:]); | ||
54 | type_(p) | ||
55 | } | ||
56 | |||
57 | fn 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 = !; | ||
92 | fn 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 | |||
99 | fn ptr_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 | |||
123 | fn 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 (); | ||
159 | fn ref_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 = _; | ||
171 | fn infer_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; | ||
183 | fn fn_ptr_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_ret_type(p); | ||
204 | m.complete(p, FN_PTR_TYPE); | ||
205 | } | ||
206 | |||
207 | pub(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_generic_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>; | ||
221 | pub(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; | ||
239 | fn 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; | ||
249 | fn 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; | ||
262 | pub(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!(); | ||
269 | fn 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 | |||
288 | pub(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 | ||
304 | fn 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..41e62116f --- /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 `syntax` crate. | ||
14 | |||
15 | #[macro_use] | ||
16 | mod token_set; | ||
17 | #[macro_use] | ||
18 | mod syntax_kind; | ||
19 | mod event; | ||
20 | mod parser; | ||
21 | mod grammar; | ||
22 | |||
23 | pub(crate) use token_set::TokenSet; | ||
24 | |||
25 | pub use syntax_kind::SyntaxKind; | ||
26 | |||
27 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
28 | pub 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! | ||
33 | pub 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)] | ||
48 | pub 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. | ||
57 | pub 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 | |||
71 | fn parse_from_tokens<F>(token_source: &mut dyn TokenSource, tree_sink: &mut dyn TreeSink, f: F) | ||
72 | where | ||
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. | ||
82 | pub 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)] | ||
87 | pub 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 | |||
104 | pub 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. | ||
126 | pub struct Reparser(fn(&mut parser::Parser)); | ||
127 | |||
128 | impl 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 | |||
3 | use std::cell::Cell; | ||
4 | |||
5 | use drop_bomb::DropBomb; | ||
6 | |||
7 | use 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. | ||
23 | pub(crate) struct Parser<'t> { | ||
24 | token_source: &'t mut dyn TokenSource, | ||
25 | events: Vec<Event>, | ||
26 | steps: Cell<u32>, | ||
27 | } | ||
28 | |||
29 | impl<'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`. | ||
256 | pub(crate) struct Marker { | ||
257 | pos: u32, | ||
258 | bomb: DropBomb, | ||
259 | } | ||
260 | |||
261 | impl 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 | |||
297 | pub(crate) struct CompletedMarker { | ||
298 | start_pos: u32, | ||
299 | finish_pos: u32, | ||
300 | kind: SyntaxKind, | ||
301 | } | ||
302 | |||
303 | impl 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] | ||
4 | mod generated; | ||
5 | |||
6 | pub use self::generated::SyntaxKind; | ||
7 | |||
8 | impl 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 | |||
15 | impl From<SyntaxKind> for u16 { | ||
16 | fn from(k: SyntaxKind) -> u16 { | ||
17 | k as u16 | ||
18 | } | ||
19 | } | ||
20 | |||
21 | impl 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)] | ||
7 | pub 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 | } | ||
254 | use self::SyntaxKind::*; | ||
255 | impl 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] | ||
367 | macro_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 | |||
3 | use crate::SyntaxKind; | ||
4 | |||
5 | /// A bit-set of `SyntaxKind`s | ||
6 | #[derive(Clone, Copy)] | ||
7 | pub(crate) struct TokenSet(u128); | ||
8 | |||
9 | impl 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 | |||
25 | const fn mask(kind: SyntaxKind) -> u128 { | ||
26 | 1u128 << (kind as usize) | ||
27 | } | ||
28 | |||
29 | #[macro_export] | ||
30 | macro_rules! token_set { | ||
31 | ($($t:expr),*) => { TokenSet::EMPTY$(.union(TokenSet::singleton($t)))* }; | ||
32 | ($($t:expr),* ,) => { token_set!($($t),*) }; | ||
33 | } | ||
34 | |||
35 | #[test] | ||
36 | fn 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 | } | ||