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