aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-01-31 10:32:40 +0000
committerAleksey Kladov <[email protected]>2019-01-31 20:23:30 +0000
commit9a043a163c59dd2625727f7ff5466d586625a423 (patch)
tree33a8a6fe8f7a7f352c870bc0be2b93dfe9d410bc /crates/ra_hir/src
parent0d9210e9bc807ce64ea5fa694abb331ee5370c26 (diff)
parses simple macro
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/macros.rs4
-rw-r--r--crates/ra_hir/src/macros/mbe.rs148
-rw-r--r--crates/ra_hir/src/macros/tt.rs2
3 files changed, 131 insertions, 23 deletions
diff --git a/crates/ra_hir/src/macros.rs b/crates/ra_hir/src/macros.rs
index 0497d2168..dc016a704 100644
--- a/crates/ra_hir/src/macros.rs
+++ b/crates/ra_hir/src/macros.rs
@@ -260,7 +260,7 @@ fn convert_tt(tt: &SyntaxNode) -> Option<tt::Subtree> {
260fn test_convert_tt() { 260fn test_convert_tt() {
261 let text = r#" 261 let text = r#"
262macro_rules! impl_froms { 262macro_rules! impl_froms {
263 ($e:ident: $($v:ident), *) => { 263 ($e:ident: $($v:ident),*) => {
264 $( 264 $(
265 impl From<$v> for $e { 265 impl From<$v> for $e {
266 fn from(it: $v) -> $e { 266 fn from(it: $v) -> $e {
@@ -279,5 +279,5 @@ macro_rules! impl_froms {
279 .unwrap(); 279 .unwrap();
280 let tt = macro_call_to_tt(maco_call).unwrap(); 280 let tt = macro_call_to_tt(maco_call).unwrap();
281 let tt = mbe::parse(&tt); 281 let tt = mbe::parse(&tt);
282 dbg!(tt); 282 assert!(tt.is_some());
283} 283}
diff --git a/crates/ra_hir/src/macros/mbe.rs b/crates/ra_hir/src/macros/mbe.rs
index 62b7fa24c..6c93ae5e3 100644
--- a/crates/ra_hir/src/macros/mbe.rs
+++ b/crates/ra_hir/src/macros/mbe.rs
@@ -1,6 +1,6 @@
1use ra_syntax::SmolStr; 1use ra_syntax::SmolStr;
2 2
3use crate::macros::tt; 3use crate::macros::tt::{self, Delimiter};
4 4
5#[derive(Debug)] 5#[derive(Debug)]
6pub(crate) struct MacroRules { 6pub(crate) struct MacroRules {
@@ -19,6 +19,7 @@ enum TokenTree {
19 Subtree(Subtree), 19 Subtree(Subtree),
20 Repeat(Repeat), 20 Repeat(Repeat),
21} 21}
22impl_froms!(TokenTree: Leaf, Subtree, Repeat);
22 23
23#[derive(Debug)] 24#[derive(Debug)]
24enum Leaf { 25enum Leaf {
@@ -27,6 +28,7 @@ enum Leaf {
27 Ident(Ident), 28 Ident(Ident),
28 Var(Var), 29 Var(Var),
29} 30}
31impl_froms!(Leaf: Literal, Punct, Ident, Var);
30 32
31#[derive(Debug)] 33#[derive(Debug)]
32struct Subtree { 34struct Subtree {
@@ -35,17 +37,10 @@ struct Subtree {
35} 37}
36 38
37#[derive(Debug)] 39#[derive(Debug)]
38enum Delimiter {
39 Parenthesis,
40 Brace,
41 Bracket,
42 None,
43}
44
45#[derive(Debug)]
46struct Repeat { 40struct Repeat {
47 subtree: Subtree, 41 subtree: Subtree,
48 kind: RepeatKind, 42 kind: RepeatKind,
43 separator: Option<Punct>,
49} 44}
50 45
51#[derive(Debug)] 46#[derive(Debug)]
@@ -73,6 +68,7 @@ struct Ident {
73#[derive(Debug)] 68#[derive(Debug)]
74struct Var { 69struct Var {
75 text: SmolStr, 70 text: SmolStr,
71 kind: Option<SmolStr>,
76} 72}
77 73
78pub(crate) fn parse(tt: &tt::Subtree) -> Option<MacroRules> { 74pub(crate) fn parse(tt: &tt::Subtree) -> Option<MacroRules> {
@@ -86,16 +82,81 @@ pub(crate) fn parse(tt: &tt::Subtree) -> Option<MacroRules> {
86 82
87fn parse_rule(p: &mut RulesParser) -> Option<Rule> { 83fn parse_rule(p: &mut RulesParser) -> Option<Rule> {
88 let lhs = parse_subtree(p.eat_subtree()?)?; 84 let lhs = parse_subtree(p.eat_subtree()?)?;
89 p.eat_punct('=')?; 85 p.expect_char('=')?;
90 p.eat_punct('>')?; 86 p.expect_char('>')?;
91 let rhs = parse_subtree(p.eat_subtree()?)?; 87 let rhs = parse_subtree(p.eat_subtree()?)?;
92 Some(Rule { lhs, rhs }) 88 Some(Rule { lhs, rhs })
93} 89}
94 90
95fn parse_subtree(tt: &tt::Subtree) -> Option<Subtree> { 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 }
96 Some(Subtree { 116 Some(Subtree {
97 token_trees: Vec::new(), 117 token_trees,
98 delimiter: Delimiter::None, 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 mut 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,
99 }) 160 })
100} 161}
101 162
@@ -117,9 +178,41 @@ impl<'a> RulesParser<'a> {
117 self.subtree.token_trees.get(self.pos) 178 self.subtree.token_trees.get(self.pos)
118 } 179 }
119 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
120 fn bump(&mut self) { 202 fn bump(&mut self) {
121 self.pos += 1; 203 self.pos += 1;
122 } 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
123 fn eat_subtree(&mut self) -> Option<&'a tt::Subtree> { 216 fn eat_subtree(&mut self) -> Option<&'a tt::Subtree> {
124 match self.current()? { 217 match self.current()? {
125 tt::TokenTree::Subtree(sub) => { 218 tt::TokenTree::Subtree(sub) => {
@@ -129,13 +222,28 @@ impl<'a> RulesParser<'a> {
129 _ => return None, 222 _ => return None,
130 } 223 }
131 } 224 }
132 fn eat_punct(&mut self, char: char) -> Option<()> { 225
133 match self.current()? { 226 fn eat_punct(&mut self) -> Option<&'a tt::Punct> {
134 tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: c })) if *c == char => { 227 if let Some(it) = self.at_punct() {
135 self.bump(); 228 self.bump();
136 Some(()) 229 return Some(it);
137 } 230 }
138 _ => None, 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(());
139 } 246 }
247 None
140 } 248 }
141} 249}
diff --git a/crates/ra_hir/src/macros/tt.rs b/crates/ra_hir/src/macros/tt.rs
index 02ff422b5..64e88ddc5 100644
--- a/crates/ra_hir/src/macros/tt.rs
+++ b/crates/ra_hir/src/macros/tt.rs
@@ -21,7 +21,7 @@ pub(crate) struct Subtree {
21 pub(crate) token_trees: Vec<TokenTree>, 21 pub(crate) token_trees: Vec<TokenTree>,
22} 22}
23 23
24#[derive(Debug)] 24#[derive(Clone, Copy, Debug)]
25pub(crate) enum Delimiter { 25pub(crate) enum Delimiter {
26 Parenthesis, 26 Parenthesis,
27 Brace, 27 Brace,