aboutsummaryrefslogtreecommitdiff
path: root/crates/parser/src/grammar.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/parser/src/grammar.rs')
-rw-r--r--crates/parser/src/grammar.rs293
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..88468bc97
--- /dev/null
+++ b/crates/parser/src/grammar.rs
@@ -0,0 +1,293 @@
1//! This is the actual "grammar" of the Rust language.
2//!
3//! Each function in this module and its children corresponds
4//! to a production of the formal grammar. Submodules roughly
5//! correspond to different *areas* of the grammar. By convention,
6//! each submodule starts with `use super::*` import and exports
7//! "public" productions via `pub(super)`.
8//!
9//! See docs for `Parser` to learn about API, available to the grammar,
10//! and see docs for `Event` to learn how this actually manages to
11//! produce parse trees.
12//!
13//! Code in this module also contains inline tests, which start with
14//! `// test name-of-the-test` comment and look like this:
15//!
16//! ```
17//! // test function_with_zero_parameters
18//! // fn foo() {}
19//! ```
20//!
21//! After adding a new inline-test, run `cargo xtask codegen` to
22//! extract it as a standalone text-fixture into
23//! `crates/ra_syntax/test_data/parser/`, and run `cargo test` once to
24//! create the "gold" value.
25//!
26//! Coding convention: rules like `where_clause` always produce either a
27//! node or an error, rules like `opt_where_clause` may produce nothing.
28//! Non-opt rules typically start with `assert!(p.at(FIRST_TOKEN))`, the
29//! caller is responsible for branching on the first token.
30mod attributes;
31mod expressions;
32mod items;
33mod params;
34mod paths;
35mod patterns;
36mod type_args;
37mod type_params;
38mod types;
39
40use crate::{
41 parser::{CompletedMarker, Marker, Parser},
42 SyntaxKind::{self, *},
43 TokenSet,
44};
45
46pub(crate) fn root(p: &mut Parser) {
47 let m = p.start();
48 p.eat(SHEBANG);
49 items::mod_contents(p, false);
50 m.complete(p, SOURCE_FILE);
51}
52
53/// Various pieces of syntax that can be parsed by macros by example
54pub(crate) mod fragments {
55 use super::*;
56
57 pub(crate) use super::{
58 expressions::block_expr, paths::type_path as path, patterns::pattern, types::type_,
59 };
60
61 pub(crate) fn expr(p: &mut Parser) {
62 let _ = expressions::expr(p);
63 }
64
65 pub(crate) fn stmt(p: &mut Parser) {
66 expressions::stmt(p, expressions::StmtWithSemi::No)
67 }
68
69 pub(crate) fn opt_visibility(p: &mut Parser) {
70 let _ = super::opt_visibility(p);
71 }
72
73 // Parse a meta item , which excluded [], e.g : #[ MetaItem ]
74 pub(crate) fn meta_item(p: &mut Parser) {
75 fn is_delimiter(p: &mut Parser) -> bool {
76 matches!(p.current(), T!['{'] | T!['('] | T!['['])
77 }
78
79 if is_delimiter(p) {
80 items::token_tree(p);
81 return;
82 }
83
84 let m = p.start();
85 while !p.at(EOF) {
86 if is_delimiter(p) {
87 items::token_tree(p);
88 break;
89 } else {
90 // https://doc.rust-lang.org/reference/attributes.html
91 // https://doc.rust-lang.org/reference/paths.html#simple-paths
92 // The start of an meta must be a simple path
93 match p.current() {
94 IDENT | T![::] | T![super] | T![self] | T![crate] => p.bump_any(),
95 T![=] => {
96 p.bump_any();
97 match p.current() {
98 c if c.is_literal() => p.bump_any(),
99 T![true] | T![false] => p.bump_any(),
100 _ => {}
101 }
102 break;
103 }
104 _ => break,
105 }
106 }
107 }
108
109 m.complete(p, TOKEN_TREE);
110 }
111
112 pub(crate) fn item(p: &mut Parser) {
113 items::item_or_macro(p, true)
114 }
115
116 pub(crate) fn macro_items(p: &mut Parser) {
117 let m = p.start();
118 items::mod_contents(p, false);
119 m.complete(p, MACRO_ITEMS);
120 }
121
122 pub(crate) fn macro_stmts(p: &mut Parser) {
123 let m = p.start();
124
125 while !p.at(EOF) {
126 if p.at(T![;]) {
127 p.bump(T![;]);
128 continue;
129 }
130
131 expressions::stmt(p, expressions::StmtWithSemi::Optional);
132 }
133
134 m.complete(p, MACRO_STMTS);
135 }
136}
137
138pub(crate) fn reparser(
139 node: SyntaxKind,
140 first_child: Option<SyntaxKind>,
141 parent: Option<SyntaxKind>,
142) -> Option<fn(&mut Parser)> {
143 let res = match node {
144 BLOCK_EXPR => expressions::block_expr,
145 RECORD_FIELD_LIST => items::record_field_def_list,
146 RECORD_EXPR_FIELD_LIST => items::record_field_list,
147 VARIANT_LIST => items::enum_variant_list,
148 MATCH_ARM_LIST => items::match_arm_list,
149 USE_TREE_LIST => items::use_tree_list,
150 EXTERN_ITEM_LIST => items::extern_item_list,
151 TOKEN_TREE if first_child? == T!['{'] => items::token_tree,
152 ASSOC_ITEM_LIST => match parent? {
153 IMPL => items::impl_item_list,
154 TRAIT => items::trait_item_list,
155 _ => return None,
156 },
157 ITEM_LIST => items::mod_item_list,
158 _ => return None,
159 };
160 Some(res)
161}
162
163#[derive(Clone, Copy, PartialEq, Eq)]
164enum BlockLike {
165 Block,
166 NotBlock,
167}
168
169impl BlockLike {
170 fn is_block(self) -> bool {
171 self == BlockLike::Block
172 }
173}
174
175fn opt_visibility(p: &mut Parser) -> bool {
176 match p.current() {
177 T![pub] => {
178 let m = p.start();
179 p.bump(T![pub]);
180 if p.at(T!['(']) {
181 match p.nth(1) {
182 // test crate_visibility
183 // pub(crate) struct S;
184 // pub(self) struct S;
185 // pub(self) struct S;
186 // pub(self) struct S;
187 T![crate] | T![self] | T![super] => {
188 p.bump_any();
189 p.bump_any();
190 p.expect(T![')']);
191 }
192 T![in] => {
193 p.bump_any();
194 p.bump_any();
195 paths::use_path(p);
196 p.expect(T![')']);
197 }
198 _ => (),
199 }
200 }
201 m.complete(p, VISIBILITY);
202 }
203 // test crate_keyword_vis
204 // crate fn main() { }
205 // struct S { crate field: u32 }
206 // struct T(crate u32);
207 //
208 // test crate_keyword_path
209 // fn foo() { crate::foo(); }
210 T![crate] if !p.nth_at(1, T![::]) => {
211 let m = p.start();
212 p.bump(T![crate]);
213 m.complete(p, VISIBILITY);
214 }
215 _ => return false,
216 }
217 true
218}
219
220fn opt_alias(p: &mut Parser) {
221 if p.at(T![as]) {
222 let m = p.start();
223 p.bump(T![as]);
224 if !p.eat(T![_]) {
225 name(p);
226 }
227 m.complete(p, RENAME);
228 }
229}
230
231fn abi(p: &mut Parser) {
232 assert!(p.at(T![extern]));
233 let abi = p.start();
234 p.bump(T![extern]);
235 match p.current() {
236 STRING | RAW_STRING => p.bump_any(),
237 _ => (),
238 }
239 abi.complete(p, ABI);
240}
241
242fn opt_fn_ret_type(p: &mut Parser) -> bool {
243 if p.at(T![->]) {
244 let m = p.start();
245 p.bump(T![->]);
246 types::type_no_bounds(p);
247 m.complete(p, RET_TYPE);
248 true
249 } else {
250 false
251 }
252}
253
254fn name_r(p: &mut Parser, recovery: TokenSet) {
255 if p.at(IDENT) {
256 let m = p.start();
257 p.bump(IDENT);
258 m.complete(p, NAME);
259 } else {
260 p.err_recover("expected a name", recovery);
261 }
262}
263
264fn name(p: &mut Parser) {
265 name_r(p, TokenSet::EMPTY)
266}
267
268fn name_ref(p: &mut Parser) {
269 if p.at(IDENT) {
270 let m = p.start();
271 p.bump(IDENT);
272 m.complete(p, NAME_REF);
273 } else {
274 p.err_and_bump("expected identifier");
275 }
276}
277
278fn name_ref_or_index(p: &mut Parser) {
279 assert!(p.at(IDENT) || p.at(INT_NUMBER));
280 let m = p.start();
281 p.bump_any();
282 m.complete(p, NAME_REF);
283}
284
285fn error_block(p: &mut Parser, message: &str) {
286 assert!(p.at(T!['{']));
287 let m = p.start();
288 p.error(message);
289 p.bump(T!['{']);
290 expressions::expr_block_contents(p);
291 p.eat(T!['}']);
292 m.complete(p, ERROR);
293}