aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/parsing/grammar.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/parsing/grammar.rs')
-rw-r--r--crates/ra_syntax/src/parsing/grammar.rs204
1 files changed, 204 insertions, 0 deletions
diff --git a/crates/ra_syntax/src/parsing/grammar.rs b/crates/ra_syntax/src/parsing/grammar.rs
new file mode 100644
index 000000000..bcdcd9f57
--- /dev/null
+++ b/crates/ra_syntax/src/parsing/grammar.rs
@@ -0,0 +1,204 @@
1//! This is the actual "grammar" of the Rust language.
2//!
3//! Each function in this module and its children corresponds
4//! to a production of the format grammar. Submodules roughly
5//! correspond to different *areas* of the grammar. By convention,
6//! each submodule starts with `use super::*` import and exports
7//! "public" productions via `pub(super)`.
8//!
9//! See docs for `Parser` to learn about API, available to the grammar,
10//! and see docs for `Event` to learn how this actually manages to
11//! produce parse trees.
12//!
13//! Code in this module also contains inline tests, which start with
14//! `// test name-of-the-test` comment and look like this:
15//!
16//! ```
17//! // test function_with_zero_parameters
18//! // fn foo() {}
19//! ```
20//!
21//! After adding a new inline-test, run `cargo collect-tests` to extract
22//! it as a standalone text-fixture into `tests/data/parser/inline`, and
23//! run `cargo test` once to create the "gold" value.
24//!
25//! Coding convention: rules like `where_clause` always produce either a
26//! node or an error, rules like `opt_where_clause` may produce nothing.
27//! Non-opt rules typically start with `assert!(p.at(FIRST_TOKEN))`, the
28//! caller is responsible for branching on the first token.
29mod attributes;
30mod expressions;
31mod items;
32mod params;
33mod paths;
34mod patterns;
35mod type_args;
36mod type_params;
37mod types;
38
39use crate::{
40 SyntaxNode,
41 SyntaxKind::{self, *},
42 parsing::{
43 token_set::TokenSet,
44 parser_api::{CompletedMarker, Marker, Parser}
45 },
46};
47
48pub(super) fn root(p: &mut Parser) {
49 let m = p.start();
50 p.eat(SHEBANG);
51 items::mod_contents(p, false);
52 m.complete(p, SOURCE_FILE);
53}
54
55pub(super) fn reparser(node: &SyntaxNode) -> Option<fn(&mut Parser)> {
56 let res = match node.kind() {
57 BLOCK => expressions::block,
58 NAMED_FIELD_DEF_LIST => items::named_field_def_list,
59 NAMED_FIELD_LIST => items::named_field_list,
60 ENUM_VARIANT_LIST => items::enum_variant_list,
61 MATCH_ARM_LIST => items::match_arm_list,
62 USE_TREE_LIST => items::use_tree_list,
63 EXTERN_ITEM_LIST => items::extern_item_list,
64 TOKEN_TREE if node.first_child().unwrap().kind() == L_CURLY => items::token_tree,
65 ITEM_LIST => {
66 let parent = node.parent().unwrap();
67 match parent.kind() {
68 IMPL_BLOCK => items::impl_item_list,
69 TRAIT_DEF => items::trait_item_list,
70 MODULE => items::mod_item_list,
71 _ => return None,
72 }
73 }
74 _ => return None,
75 };
76 Some(res)
77}
78
79#[derive(Clone, Copy, PartialEq, Eq)]
80enum BlockLike {
81 Block,
82 NotBlock,
83}
84
85impl BlockLike {
86 fn is_block(self) -> bool {
87 self == BlockLike::Block
88 }
89}
90
91fn opt_visibility(p: &mut Parser) {
92 match p.current() {
93 PUB_KW => {
94 let m = p.start();
95 p.bump();
96 if p.at(L_PAREN) {
97 match p.nth(1) {
98 // test crate_visibility
99 // pub(crate) struct S;
100 // pub(self) struct S;
101 // pub(self) struct S;
102 // pub(self) struct S;
103 CRATE_KW | SELF_KW | SUPER_KW => {
104 p.bump();
105 p.bump();
106 p.expect(R_PAREN);
107 }
108 IN_KW => {
109 p.bump();
110 p.bump();
111 paths::use_path(p);
112 p.expect(R_PAREN);
113 }
114 _ => (),
115 }
116 }
117 m.complete(p, VISIBILITY);
118 }
119 // test crate_keyword_vis
120 // crate fn main() { }
121 CRATE_KW => {
122 let m = p.start();
123 p.bump();
124 m.complete(p, VISIBILITY);
125 }
126 _ => (),
127 }
128}
129
130fn opt_alias(p: &mut Parser) {
131 if p.at(AS_KW) {
132 let m = p.start();
133 p.bump();
134 name(p);
135 m.complete(p, ALIAS);
136 }
137}
138
139fn abi(p: &mut Parser) {
140 assert!(p.at(EXTERN_KW));
141 let abi = p.start();
142 p.bump();
143 match p.current() {
144 STRING | RAW_STRING => p.bump(),
145 _ => (),
146 }
147 abi.complete(p, ABI);
148}
149
150fn opt_fn_ret_type(p: &mut Parser) -> bool {
151 if p.at(THIN_ARROW) {
152 let m = p.start();
153 p.bump();
154 types::type_(p);
155 m.complete(p, RET_TYPE);
156 true
157 } else {
158 false
159 }
160}
161
162fn name_r(p: &mut Parser, recovery: TokenSet) {
163 if p.at(IDENT) {
164 let m = p.start();
165 p.bump();
166 m.complete(p, NAME);
167 } else {
168 p.err_recover("expected a name", recovery);
169 }
170}
171
172fn name(p: &mut Parser) {
173 name_r(p, TokenSet::empty())
174}
175
176fn name_ref(p: &mut Parser) {
177 if p.at(IDENT) {
178 let m = p.start();
179 p.bump();
180 m.complete(p, NAME_REF);
181 } else {
182 p.err_and_bump("expected identifier");
183 }
184}
185
186fn error_block(p: &mut Parser, message: &str) {
187 go(p, Some(message));
188 fn go(p: &mut Parser, message: Option<&str>) {
189 assert!(p.at(L_CURLY));
190 let m = p.start();
191 if let Some(message) = message {
192 p.error(message);
193 }
194 p.bump();
195 while !p.at(EOF) && !p.at(R_CURLY) {
196 match p.current() {
197 L_CURLY => go(p, None),
198 _ => p.bump(),
199 }
200 }
201 p.eat(R_CURLY);
202 m.complete(p, ERROR);
203 }
204}