diff options
Diffstat (limited to 'crates/ra_macros/src/mbe.rs')
-rw-r--r-- | crates/ra_macros/src/mbe.rs | 225 |
1 files changed, 25 insertions, 200 deletions
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 | } |