diff options
author | Aleksey Kladov <[email protected]> | 2019-01-31 10:46:40 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-01-31 20:23:30 +0000 |
commit | 2d88207853a38fa3f73c03ef1f9d5a1b8ce9924a (patch) | |
tree | 744ec60e60884684f391a2e8f4f99c9030b30dc0 | |
parent | ce3636798bc9481ec712b84b5cad9973b7844425 (diff) |
reshuffle
-rw-r--r-- | crates/ra_macros/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ra_macros/src/mbe.rs | 225 | ||||
-rw-r--r-- | crates/ra_macros/src/mbe_parser.rs | 184 |
3 files changed, 210 insertions, 200 deletions
diff --git a/crates/ra_macros/src/lib.rs b/crates/ra_macros/src/lib.rs index 6063c06c2..8c284fa71 100644 --- a/crates/ra_macros/src/lib.rs +++ b/crates/ra_macros/src/lib.rs | |||
@@ -12,3 +12,4 @@ macro_rules! impl_froms { | |||
12 | 12 | ||
13 | pub mod tt; | 13 | pub mod tt; |
14 | pub mod mbe; | 14 | pub mod mbe; |
15 | mod mbe_parser; | ||
diff --git a/crates/ra_macros/src/mbe.rs b/crates/ra_macros/src/mbe.rs index 1aa6be736..72d6707aa 100644 --- a/crates/ra_macros/src/mbe.rs +++ b/crates/ra_macros/src/mbe.rs | |||
@@ -2,19 +2,21 @@ use smol_str::SmolStr; | |||
2 | 2 | ||
3 | use crate::tt::{self, Delimiter}; | 3 | use crate::tt::{self, Delimiter}; |
4 | 4 | ||
5 | pub use crate::mbe_parser::parse; | ||
6 | |||
5 | #[derive(Debug)] | 7 | #[derive(Debug)] |
6 | pub struct MacroRules { | 8 | pub struct MacroRules { |
7 | rules: Vec<Rule>, | 9 | pub(crate) rules: Vec<Rule>, |
8 | } | 10 | } |
9 | 11 | ||
10 | #[derive(Debug)] | 12 | #[derive(Debug)] |
11 | struct Rule { | 13 | pub(crate) struct Rule { |
12 | lhs: Subtree, | 14 | pub(crate) lhs: Subtree, |
13 | rhs: Subtree, | 15 | pub(crate) rhs: Subtree, |
14 | } | 16 | } |
15 | 17 | ||
16 | #[derive(Debug)] | 18 | #[derive(Debug)] |
17 | enum TokenTree { | 19 | pub(crate) enum TokenTree { |
18 | Leaf(Leaf), | 20 | Leaf(Leaf), |
19 | Subtree(Subtree), | 21 | Subtree(Subtree), |
20 | Repeat(Repeat), | 22 | Repeat(Repeat), |
@@ -22,7 +24,7 @@ enum TokenTree { | |||
22 | impl_froms!(TokenTree: Leaf, Subtree, Repeat); | 24 | impl_froms!(TokenTree: Leaf, Subtree, Repeat); |
23 | 25 | ||
24 | #[derive(Debug)] | 26 | #[derive(Debug)] |
25 | enum Leaf { | 27 | pub(crate) enum Leaf { |
26 | Literal(Literal), | 28 | Literal(Literal), |
27 | Punct(Punct), | 29 | Punct(Punct), |
28 | Ident(Ident), | 30 | Ident(Ident), |
@@ -31,219 +33,42 @@ enum Leaf { | |||
31 | impl_froms!(Leaf: Literal, Punct, Ident, Var); | 33 | impl_froms!(Leaf: Literal, Punct, Ident, Var); |
32 | 34 | ||
33 | #[derive(Debug)] | 35 | #[derive(Debug)] |
34 | struct Subtree { | 36 | pub(crate) struct Subtree { |
35 | delimiter: Delimiter, | 37 | pub(crate) delimiter: Delimiter, |
36 | token_trees: Vec<TokenTree>, | 38 | pub(crate) token_trees: Vec<TokenTree>, |
37 | } | 39 | } |
38 | 40 | ||
39 | #[derive(Debug)] | 41 | #[derive(Debug)] |
40 | struct Repeat { | 42 | pub(crate) struct Repeat { |
41 | subtree: Subtree, | 43 | pub(crate) subtree: Subtree, |
42 | kind: RepeatKind, | 44 | pub(crate) kind: RepeatKind, |
43 | separator: Option<Punct>, | 45 | pub(crate) separator: Option<Punct>, |
44 | } | 46 | } |
45 | 47 | ||
46 | #[derive(Debug)] | 48 | #[derive(Debug)] |
47 | enum RepeatKind { | 49 | pub(crate) enum RepeatKind { |
48 | ZeroOrMore, | 50 | ZeroOrMore, |
49 | OneOrMore, | 51 | OneOrMore, |
50 | ZeroOrOne, | 52 | ZeroOrOne, |
51 | } | 53 | } |
52 | 54 | ||
53 | #[derive(Debug)] | 55 | #[derive(Debug)] |
54 | struct Literal { | 56 | pub(crate) struct Literal { |
55 | text: SmolStr, | 57 | pub(crate) text: SmolStr, |
56 | } | 58 | } |
57 | 59 | ||
58 | #[derive(Debug)] | 60 | #[derive(Debug)] |
59 | struct Punct { | 61 | pub(crate) struct Punct { |
60 | char: char, | 62 | pub(crate) char: char, |
61 | } | 63 | } |
62 | 64 | ||
63 | #[derive(Debug)] | 65 | #[derive(Debug)] |
64 | struct Ident { | 66 | pub(crate) struct Ident { |
65 | text: SmolStr, | 67 | pub(crate) text: SmolStr, |
66 | } | 68 | } |
67 | 69 | ||
68 | #[derive(Debug)] | 70 | #[derive(Debug)] |
69 | struct Var { | 71 | pub(crate) struct Var { |
70 | text: SmolStr, | 72 | pub(crate) text: SmolStr, |
71 | kind: Option<SmolStr>, | 73 | pub(crate) kind: Option<SmolStr>, |
72 | } | ||
73 | |||
74 | pub fn parse(tt: &tt::Subtree) -> Option<MacroRules> { | ||
75 | let mut parser = RulesParser::new(tt); | ||
76 | let mut rules = Vec::new(); | ||
77 | while !parser.is_eof() { | ||
78 | rules.push(parse_rule(&mut parser)?) | ||
79 | } | ||
80 | Some(MacroRules { rules }) | ||
81 | } | ||
82 | |||
83 | fn parse_rule(p: &mut RulesParser) -> Option<Rule> { | ||
84 | let lhs = parse_subtree(p.eat_subtree()?)?; | ||
85 | p.expect_char('=')?; | ||
86 | p.expect_char('>')?; | ||
87 | let rhs = parse_subtree(p.eat_subtree()?)?; | ||
88 | Some(Rule { lhs, rhs }) | ||
89 | } | ||
90 | |||
91 | fn parse_subtree(tt: &tt::Subtree) -> Option<Subtree> { | ||
92 | let mut token_trees = Vec::new(); | ||
93 | let mut p = RulesParser::new(tt); | ||
94 | while let Some(tt) = p.eat() { | ||
95 | let child: TokenTree = match tt { | ||
96 | tt::TokenTree::Leaf(leaf) => match leaf { | ||
97 | tt::Leaf::Punct(tt::Punct { char: '$' }) => { | ||
98 | if p.at_ident().is_some() { | ||
99 | Leaf::from(parse_var(&mut p)?).into() | ||
100 | } else { | ||
101 | parse_repeat(&mut p)?.into() | ||
102 | } | ||
103 | } | ||
104 | tt::Leaf::Punct(tt::Punct { char }) => Leaf::from(Punct { char: *char }).into(), | ||
105 | tt::Leaf::Ident(tt::Ident { text }) => { | ||
106 | Leaf::from(Ident { text: text.clone() }).into() | ||
107 | } | ||
108 | tt::Leaf::Literal(tt::Literal { text }) => { | ||
109 | Leaf::from(Literal { text: text.clone() }).into() | ||
110 | } | ||
111 | }, | ||
112 | tt::TokenTree::Subtree(subtree) => parse_subtree(subtree)?.into(), | ||
113 | }; | ||
114 | token_trees.push(child); | ||
115 | } | ||
116 | Some(Subtree { | ||
117 | token_trees, | ||
118 | delimiter: tt.delimiter, | ||
119 | }) | ||
120 | } | ||
121 | |||
122 | fn parse_var(p: &mut RulesParser) -> Option<Var> { | ||
123 | let ident = p.eat_ident().unwrap(); | ||
124 | let text = ident.text.clone(); | ||
125 | let kind = if p.at_char(':') { | ||
126 | p.bump(); | ||
127 | if let Some(ident) = p.eat_ident() { | ||
128 | Some(ident.text.clone()) | ||
129 | } else { | ||
130 | // ugly as hell :( | ||
131 | p.pos -= 1; | ||
132 | None | ||
133 | } | ||
134 | } else { | ||
135 | None | ||
136 | }; | ||
137 | Some(Var { text, kind }) | ||
138 | } | ||
139 | |||
140 | fn parse_repeat(p: &mut RulesParser) -> Option<Repeat> { | ||
141 | let subtree = p.eat_subtree().unwrap(); | ||
142 | let subtree = parse_subtree(subtree)?; | ||
143 | let sep = p.eat_punct()?; | ||
144 | let (separator, rep) = match sep.char { | ||
145 | '*' | '+' | '?' => (None, sep.char), | ||
146 | char => (Some(Punct { char }), p.eat_punct()?.char), | ||
147 | }; | ||
148 | |||
149 | let kind = match rep { | ||
150 | '*' => RepeatKind::ZeroOrMore, | ||
151 | '+' => RepeatKind::OneOrMore, | ||
152 | '?' => RepeatKind::ZeroOrMore, | ||
153 | _ => return None, | ||
154 | }; | ||
155 | p.bump(); | ||
156 | Some(Repeat { | ||
157 | subtree, | ||
158 | kind, | ||
159 | separator, | ||
160 | }) | ||
161 | } | ||
162 | |||
163 | struct RulesParser<'a> { | ||
164 | subtree: &'a tt::Subtree, | ||
165 | pos: usize, | ||
166 | } | ||
167 | |||
168 | impl<'a> RulesParser<'a> { | ||
169 | fn new(subtree: &'a tt::Subtree) -> RulesParser<'a> { | ||
170 | RulesParser { subtree, pos: 0 } | ||
171 | } | ||
172 | |||
173 | fn is_eof(&self) -> bool { | ||
174 | self.pos == self.subtree.token_trees.len() | ||
175 | } | ||
176 | |||
177 | fn current(&self) -> Option<&'a tt::TokenTree> { | ||
178 | self.subtree.token_trees.get(self.pos) | ||
179 | } | ||
180 | |||
181 | fn at_punct(&self) -> Option<&'a tt::Punct> { | ||
182 | match self.current() { | ||
183 | Some(tt::TokenTree::Leaf(tt::Leaf::Punct(it))) => Some(it), | ||
184 | _ => None, | ||
185 | } | ||
186 | } | ||
187 | |||
188 | fn at_char(&self, char: char) -> bool { | ||
189 | match self.at_punct() { | ||
190 | Some(tt::Punct { char: c }) if *c == char => true, | ||
191 | _ => false, | ||
192 | } | ||
193 | } | ||
194 | |||
195 | fn at_ident(&mut self) -> Option<&'a tt::Ident> { | ||
196 | match self.current() { | ||
197 | Some(tt::TokenTree::Leaf(tt::Leaf::Ident(i))) => Some(i), | ||
198 | _ => None, | ||
199 | } | ||
200 | } | ||
201 | |||
202 | fn bump(&mut self) { | ||
203 | self.pos += 1; | ||
204 | } | ||
205 | |||
206 | fn eat(&mut self) -> Option<&'a tt::TokenTree> { | ||
207 | match self.current() { | ||
208 | Some(it) => { | ||
209 | self.bump(); | ||
210 | Some(it) | ||
211 | } | ||
212 | None => None, | ||
213 | } | ||
214 | } | ||
215 | |||
216 | fn eat_subtree(&mut self) -> Option<&'a tt::Subtree> { | ||
217 | match self.current()? { | ||
218 | tt::TokenTree::Subtree(sub) => { | ||
219 | self.bump(); | ||
220 | Some(sub) | ||
221 | } | ||
222 | _ => return None, | ||
223 | } | ||
224 | } | ||
225 | |||
226 | fn eat_punct(&mut self) -> Option<&'a tt::Punct> { | ||
227 | if let Some(it) = self.at_punct() { | ||
228 | self.bump(); | ||
229 | return Some(it); | ||
230 | } | ||
231 | None | ||
232 | } | ||
233 | |||
234 | fn eat_ident(&mut self) -> Option<&'a tt::Ident> { | ||
235 | if let Some(i) = self.at_ident() { | ||
236 | self.bump(); | ||
237 | return Some(i); | ||
238 | } | ||
239 | None | ||
240 | } | ||
241 | |||
242 | fn expect_char(&mut self, char: char) -> Option<()> { | ||
243 | if self.at_char(char) { | ||
244 | self.bump(); | ||
245 | return Some(()); | ||
246 | } | ||
247 | None | ||
248 | } | ||
249 | } | 74 | } |
diff --git a/crates/ra_macros/src/mbe_parser.rs b/crates/ra_macros/src/mbe_parser.rs new file mode 100644 index 000000000..93c2d40b4 --- /dev/null +++ b/crates/ra_macros/src/mbe_parser.rs | |||
@@ -0,0 +1,184 @@ | |||
1 | use crate::{tt, mbe}; | ||
2 | |||
3 | /// This module parses a raw `tt::TokenStream` into macro-by-example token | ||
4 | /// stream. This is a *mostly* identify function, expect for handling of | ||
5 | /// `$var:tt_kind` and `$(repeat),*` constructs. | ||
6 | |||
7 | struct RulesParser<'a> { | ||
8 | subtree: &'a tt::Subtree, | ||
9 | pos: usize, | ||
10 | } | ||
11 | |||
12 | impl<'a> RulesParser<'a> { | ||
13 | fn new(subtree: &'a tt::Subtree) -> RulesParser<'a> { | ||
14 | RulesParser { subtree, pos: 0 } | ||
15 | } | ||
16 | |||
17 | fn is_eof(&self) -> bool { | ||
18 | self.pos == self.subtree.token_trees.len() | ||
19 | } | ||
20 | |||
21 | fn current(&self) -> Option<&'a tt::TokenTree> { | ||
22 | self.subtree.token_trees.get(self.pos) | ||
23 | } | ||
24 | |||
25 | fn at_punct(&self) -> Option<&'a tt::Punct> { | ||
26 | match self.current() { | ||
27 | Some(tt::TokenTree::Leaf(tt::Leaf::Punct(it))) => Some(it), | ||
28 | _ => None, | ||
29 | } | ||
30 | } | ||
31 | |||
32 | fn at_char(&self, char: char) -> bool { | ||
33 | match self.at_punct() { | ||
34 | Some(tt::Punct { char: c }) if *c == char => true, | ||
35 | _ => false, | ||
36 | } | ||
37 | } | ||
38 | |||
39 | fn at_ident(&mut self) -> Option<&'a tt::Ident> { | ||
40 | match self.current() { | ||
41 | Some(tt::TokenTree::Leaf(tt::Leaf::Ident(i))) => Some(i), | ||
42 | _ => None, | ||
43 | } | ||
44 | } | ||
45 | |||
46 | fn bump(&mut self) { | ||
47 | self.pos += 1; | ||
48 | } | ||
49 | |||
50 | fn eat(&mut self) -> Option<&'a tt::TokenTree> { | ||
51 | match self.current() { | ||
52 | Some(it) => { | ||
53 | self.bump(); | ||
54 | Some(it) | ||
55 | } | ||
56 | None => None, | ||
57 | } | ||
58 | } | ||
59 | |||
60 | fn eat_subtree(&mut self) -> Option<&'a tt::Subtree> { | ||
61 | match self.current()? { | ||
62 | tt::TokenTree::Subtree(sub) => { | ||
63 | self.bump(); | ||
64 | Some(sub) | ||
65 | } | ||
66 | _ => return None, | ||
67 | } | ||
68 | } | ||
69 | |||
70 | fn eat_punct(&mut self) -> Option<&'a tt::Punct> { | ||
71 | if let Some(it) = self.at_punct() { | ||
72 | self.bump(); | ||
73 | return Some(it); | ||
74 | } | ||
75 | None | ||
76 | } | ||
77 | |||
78 | fn eat_ident(&mut self) -> Option<&'a tt::Ident> { | ||
79 | if let Some(i) = self.at_ident() { | ||
80 | self.bump(); | ||
81 | return Some(i); | ||
82 | } | ||
83 | None | ||
84 | } | ||
85 | |||
86 | fn expect_char(&mut self, char: char) -> Option<()> { | ||
87 | if self.at_char(char) { | ||
88 | self.bump(); | ||
89 | return Some(()); | ||
90 | } | ||
91 | None | ||
92 | } | ||
93 | } | ||
94 | |||
95 | pub fn parse(tt: &tt::Subtree) -> Option<mbe::MacroRules> { | ||
96 | let mut parser = RulesParser::new(tt); | ||
97 | let mut rules = Vec::new(); | ||
98 | while !parser.is_eof() { | ||
99 | rules.push(parse_rule(&mut parser)?) | ||
100 | } | ||
101 | Some(mbe::MacroRules { rules }) | ||
102 | } | ||
103 | |||
104 | fn parse_rule(p: &mut RulesParser) -> Option<mbe::Rule> { | ||
105 | let lhs = parse_subtree(p.eat_subtree()?)?; | ||
106 | p.expect_char('=')?; | ||
107 | p.expect_char('>')?; | ||
108 | let rhs = parse_subtree(p.eat_subtree()?)?; | ||
109 | Some(mbe::Rule { lhs, rhs }) | ||
110 | } | ||
111 | |||
112 | fn parse_subtree(tt: &tt::Subtree) -> Option<mbe::Subtree> { | ||
113 | let mut token_trees = Vec::new(); | ||
114 | let mut p = RulesParser::new(tt); | ||
115 | while let Some(tt) = p.eat() { | ||
116 | let child: mbe::TokenTree = match tt { | ||
117 | tt::TokenTree::Leaf(leaf) => match leaf { | ||
118 | tt::Leaf::Punct(tt::Punct { char: '$' }) => { | ||
119 | if p.at_ident().is_some() { | ||
120 | mbe::Leaf::from(parse_var(&mut p)?).into() | ||
121 | } else { | ||
122 | parse_repeat(&mut p)?.into() | ||
123 | } | ||
124 | } | ||
125 | tt::Leaf::Punct(tt::Punct { char }) => { | ||
126 | mbe::Leaf::from(mbe::Punct { char: *char }).into() | ||
127 | } | ||
128 | tt::Leaf::Ident(tt::Ident { text }) => { | ||
129 | mbe::Leaf::from(mbe::Ident { text: text.clone() }).into() | ||
130 | } | ||
131 | tt::Leaf::Literal(tt::Literal { text }) => { | ||
132 | mbe::Leaf::from(mbe::Literal { text: text.clone() }).into() | ||
133 | } | ||
134 | }, | ||
135 | tt::TokenTree::Subtree(subtree) => parse_subtree(subtree)?.into(), | ||
136 | }; | ||
137 | token_trees.push(child); | ||
138 | } | ||
139 | Some(mbe::Subtree { | ||
140 | token_trees, | ||
141 | delimiter: tt.delimiter, | ||
142 | }) | ||
143 | } | ||
144 | |||
145 | fn parse_var(p: &mut RulesParser) -> Option<mbe::Var> { | ||
146 | let ident = p.eat_ident().unwrap(); | ||
147 | let text = ident.text.clone(); | ||
148 | let kind = if p.at_char(':') { | ||
149 | p.bump(); | ||
150 | if let Some(ident) = p.eat_ident() { | ||
151 | Some(ident.text.clone()) | ||
152 | } else { | ||
153 | // ugly as hell :( | ||
154 | p.pos -= 1; | ||
155 | None | ||
156 | } | ||
157 | } else { | ||
158 | None | ||
159 | }; | ||
160 | Some(mbe::Var { text, kind }) | ||
161 | } | ||
162 | |||
163 | fn parse_repeat(p: &mut RulesParser) -> Option<mbe::Repeat> { | ||
164 | let subtree = p.eat_subtree().unwrap(); | ||
165 | let subtree = parse_subtree(subtree)?; | ||
166 | let sep = p.eat_punct()?; | ||
167 | let (separator, rep) = match sep.char { | ||
168 | '*' | '+' | '?' => (None, sep.char), | ||
169 | char => (Some(mbe::Punct { char }), p.eat_punct()?.char), | ||
170 | }; | ||
171 | |||
172 | let kind = match rep { | ||
173 | '*' => mbe::RepeatKind::ZeroOrMore, | ||
174 | '+' => mbe::RepeatKind::OneOrMore, | ||
175 | '?' => mbe::RepeatKind::ZeroOrMore, | ||
176 | _ => return None, | ||
177 | }; | ||
178 | p.bump(); | ||
179 | Some(mbe::Repeat { | ||
180 | subtree, | ||
181 | kind, | ||
182 | separator, | ||
183 | }) | ||
184 | } | ||