aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_macros/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_macros/src')
-rw-r--r--crates/ra_macros/src/lib.rs14
-rw-r--r--crates/ra_macros/src/mbe.rs249
-rw-r--r--crates/ra_macros/src/tt.rs45
3 files changed, 308 insertions, 0 deletions
diff --git a/crates/ra_macros/src/lib.rs b/crates/ra_macros/src/lib.rs
new file mode 100644
index 000000000..6063c06c2
--- /dev/null
+++ b/crates/ra_macros/src/lib.rs
@@ -0,0 +1,14 @@
1macro_rules! impl_froms {
2 ($e:ident: $($v:ident), *) => {
3 $(
4 impl From<$v> for $e {
5 fn from(it: $v) -> $e {
6 $e::$v(it)
7 }
8 }
9 )*
10 }
11}
12
13pub mod tt;
14pub mod mbe;
diff --git a/crates/ra_macros/src/mbe.rs b/crates/ra_macros/src/mbe.rs
new file mode 100644
index 000000000..1aa6be736
--- /dev/null
+++ b/crates/ra_macros/src/mbe.rs
@@ -0,0 +1,249 @@
1use smol_str::SmolStr;
2
3use crate::tt::{self, Delimiter};
4
5#[derive(Debug)]
6pub struct MacroRules {
7 rules: Vec<Rule>,
8}
9
10#[derive(Debug)]
11struct Rule {
12 lhs: Subtree,
13 rhs: Subtree,
14}
15
16#[derive(Debug)]
17enum TokenTree {
18 Leaf(Leaf),
19 Subtree(Subtree),
20 Repeat(Repeat),
21}
22impl_froms!(TokenTree: Leaf, Subtree, Repeat);
23
24#[derive(Debug)]
25enum Leaf {
26 Literal(Literal),
27 Punct(Punct),
28 Ident(Ident),
29 Var(Var),
30}
31impl_froms!(Leaf: Literal, Punct, Ident, Var);
32
33#[derive(Debug)]
34struct Subtree {
35 delimiter: Delimiter,
36 token_trees: Vec<TokenTree>,
37}
38
39#[derive(Debug)]
40struct Repeat {
41 subtree: Subtree,
42 kind: RepeatKind,
43 separator: Option<Punct>,
44}
45
46#[derive(Debug)]
47enum RepeatKind {
48 ZeroOrMore,
49 OneOrMore,
50 ZeroOrOne,
51}
52
53#[derive(Debug)]
54struct Literal {
55 text: SmolStr,
56}
57
58#[derive(Debug)]
59struct Punct {
60 char: char,
61}
62
63#[derive(Debug)]
64struct Ident {
65 text: SmolStr,
66}
67
68#[derive(Debug)]
69struct Var {
70 text: SmolStr,
71 kind: Option<SmolStr>,
72}
73
74pub 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
83fn 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
91fn 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
122fn 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
140fn 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
163struct RulesParser<'a> {
164 subtree: &'a tt::Subtree,
165 pos: usize,
166}
167
168impl<'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}
diff --git a/crates/ra_macros/src/tt.rs b/crates/ra_macros/src/tt.rs
new file mode 100644
index 000000000..364eed9e6
--- /dev/null
+++ b/crates/ra_macros/src/tt.rs
@@ -0,0 +1,45 @@
1use smol_str::SmolStr;
2
3#[derive(Debug)]
4pub enum TokenTree {
5 Leaf(Leaf),
6 Subtree(Subtree),
7}
8impl_froms!(TokenTree: Leaf, Subtree);
9
10#[derive(Debug)]
11pub enum Leaf {
12 Literal(Literal),
13 Punct(Punct),
14 Ident(Ident),
15}
16impl_froms!(Leaf: Literal, Punct, Ident);
17
18#[derive(Debug)]
19pub struct Subtree {
20 pub delimiter: Delimiter,
21 pub token_trees: Vec<TokenTree>,
22}
23
24#[derive(Clone, Copy, Debug)]
25pub enum Delimiter {
26 Parenthesis,
27 Brace,
28 Bracket,
29 None,
30}
31
32#[derive(Debug)]
33pub struct Literal {
34 pub text: SmolStr,
35}
36
37#[derive(Debug)]
38pub struct Punct {
39 pub char: char,
40}
41
42#[derive(Debug)]
43pub struct Ident {
44 pub text: SmolStr,
45}