diff options
Diffstat (limited to 'crates/parser/src/grammar.rs')
-rw-r--r-- | crates/parser/src/grammar.rs | 293 |
1 files changed, 293 insertions, 0 deletions
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 | } | ||