aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/grammar.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/grammar.rs')
-rw-r--r--crates/ra_syntax/src/grammar.rs184
1 files changed, 184 insertions, 0 deletions
diff --git a/crates/ra_syntax/src/grammar.rs b/crates/ra_syntax/src/grammar.rs
new file mode 100644
index 000000000..06a37d648
--- /dev/null
+++ b/crates/ra_syntax/src/grammar.rs
@@ -0,0 +1,184 @@
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
39pub(crate) use self::{
40 expressions::block,
41 items::{
42 enum_variant_list, extern_item_list, impl_item_list, match_arm_list, mod_item_list,
43 named_field_def_list, named_field_list, token_tree, trait_item_list, use_tree_list,
44 },
45};
46use crate::{
47 parser_api::{CompletedMarker, Marker, Parser},
48 token_set::TokenSet,
49 SyntaxKind::{self, *},
50};
51
52pub(crate) fn root(p: &mut Parser) {
53 let m = p.start();
54 p.eat(SHEBANG);
55 items::mod_contents(p, false);
56 m.complete(p, SOURCE_FILE);
57}
58
59#[derive(Clone, Copy, PartialEq, Eq)]
60enum BlockLike {
61 Block,
62 NotBlock,
63}
64
65impl BlockLike {
66 fn is_block(self) -> bool {
67 self == BlockLike::Block
68 }
69}
70
71fn opt_visibility(p: &mut Parser) {
72 match p.current() {
73 PUB_KW => {
74 let m = p.start();
75 p.bump();
76 if p.at(L_PAREN) {
77 match p.nth(1) {
78 // test crate_visibility
79 // pub(crate) struct S;
80 // pub(self) struct S;
81 // pub(self) struct S;
82 // pub(self) struct S;
83 CRATE_KW | SELF_KW | SUPER_KW => {
84 p.bump();
85 p.bump();
86 p.expect(R_PAREN);
87 }
88 IN_KW => {
89 p.bump();
90 p.bump();
91 paths::use_path(p);
92 p.expect(R_PAREN);
93 }
94 _ => (),
95 }
96 }
97 m.complete(p, VISIBILITY);
98 }
99 // test crate_keyword_vis
100 // crate fn main() { }
101 CRATE_KW => {
102 let m = p.start();
103 p.bump();
104 m.complete(p, VISIBILITY);
105 }
106 _ => (),
107 }
108}
109
110fn opt_alias(p: &mut Parser) {
111 if p.at(AS_KW) {
112 let m = p.start();
113 p.bump();
114 name(p);
115 m.complete(p, ALIAS);
116 }
117}
118
119fn abi(p: &mut Parser) {
120 assert!(p.at(EXTERN_KW));
121 let abi = p.start();
122 p.bump();
123 match p.current() {
124 STRING | RAW_STRING => p.bump(),
125 _ => (),
126 }
127 abi.complete(p, ABI);
128}
129
130fn opt_fn_ret_type(p: &mut Parser) -> bool {
131 if p.at(THIN_ARROW) {
132 let m = p.start();
133 p.bump();
134 types::type_(p);
135 m.complete(p, RET_TYPE);
136 true
137 } else {
138 false
139 }
140}
141
142fn name_r(p: &mut Parser, recovery: TokenSet) {
143 if p.at(IDENT) {
144 let m = p.start();
145 p.bump();
146 m.complete(p, NAME);
147 } else {
148 p.err_recover("expected a name", recovery);
149 }
150}
151
152fn name(p: &mut Parser) {
153 name_r(p, TokenSet::EMPTY)
154}
155
156fn name_ref(p: &mut Parser) {
157 if p.at(IDENT) {
158 let m = p.start();
159 p.bump();
160 m.complete(p, NAME_REF);
161 } else {
162 p.err_and_bump("expected identifier");
163 }
164}
165
166fn error_block(p: &mut Parser, message: &str) {
167 go(p, Some(message));
168 fn go(p: &mut Parser, message: Option<&str>) {
169 assert!(p.at(L_CURLY));
170 let m = p.start();
171 if let Some(message) = message {
172 p.error(message);
173 }
174 p.bump();
175 while !p.at(EOF) && !p.at(R_CURLY) {
176 match p.current() {
177 L_CURLY => go(p, None),
178 _ => p.bump(),
179 }
180 }
181 p.eat(R_CURLY);
182 m.complete(p, ERROR);
183 }
184}