diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-09-17 13:53:01 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2019-09-17 13:53:01 +0100 |
commit | 9421d2a953516b392ae35446bc4f2206dd993c84 (patch) | |
tree | e6c7b46cabe1f10f7da28f3db209df2260045fa8 /crates/ra_mbe/src/mbe_expander | |
parent | 8eb2697b7d2a98c952b3acd1711829a13e13cab1 (diff) | |
parent | 4551182f94fe81c314f79ddf8916a5520cfd03b0 (diff) |
Merge #1858
1858: use usual token tree for macro expansions r=matklad a=matklad
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_mbe/src/mbe_expander')
-rw-r--r-- | crates/ra_mbe/src/mbe_expander/matcher.rs | 361 | ||||
-rw-r--r-- | crates/ra_mbe/src/mbe_expander/transcriber.rs | 288 |
2 files changed, 388 insertions, 261 deletions
diff --git a/crates/ra_mbe/src/mbe_expander/matcher.rs b/crates/ra_mbe/src/mbe_expander/matcher.rs index 100a3b0e0..aff953102 100644 --- a/crates/ra_mbe/src/mbe_expander/matcher.rs +++ b/crates/ra_mbe/src/mbe_expander/matcher.rs | |||
@@ -1,11 +1,14 @@ | |||
1 | use crate::{ | 1 | use crate::{ |
2 | mbe_expander::{Binding, Bindings, Fragment}, | 2 | mbe_expander::{Binding, Bindings, Fragment}, |
3 | tt_cursor::TtCursor, | 3 | parser::{parse_pattern, Op, RepeatKind, Separator}, |
4 | subtree_source::SubtreeTokenSource, | ||
5 | tt_iter::TtIter, | ||
4 | ExpandError, | 6 | ExpandError, |
5 | }; | 7 | }; |
6 | 8 | ||
7 | use ra_parser::FragmentKind::*; | 9 | use ra_parser::{FragmentKind::*, TreeSink}; |
8 | use ra_syntax::SmolStr; | 10 | use ra_syntax::{SmolStr, SyntaxKind}; |
11 | use tt::buffer::{Cursor, TokenBuffer}; | ||
9 | 12 | ||
10 | impl Bindings { | 13 | impl Bindings { |
11 | fn push_optional(&mut self, name: &SmolStr) { | 14 | fn push_optional(&mut self, name: &SmolStr) { |
@@ -42,121 +45,247 @@ impl Bindings { | |||
42 | } | 45 | } |
43 | Ok(()) | 46 | Ok(()) |
44 | } | 47 | } |
48 | } | ||
45 | 49 | ||
46 | fn merge(&mut self, nested: Bindings) { | 50 | macro_rules! err { |
47 | self.inner.extend(nested.inner); | 51 | () => { |
48 | } | 52 | ExpandError::BindingError(format!("")) |
53 | }; | ||
54 | ($($tt:tt)*) => { | ||
55 | ExpandError::BindingError(format!($($tt)*)) | ||
56 | }; | ||
49 | } | 57 | } |
50 | 58 | ||
51 | pub(super) fn match_lhs( | 59 | macro_rules! bail { |
52 | pattern: &crate::Subtree, | 60 | ($($tt:tt)*) => { |
53 | input: &mut TtCursor, | 61 | return Err(err!($($tt)*)) |
54 | ) -> Result<Bindings, ExpandError> { | 62 | }; |
63 | } | ||
64 | |||
65 | pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Bindings, ExpandError> { | ||
66 | assert!(pattern.delimiter == tt::Delimiter::None); | ||
67 | |||
55 | let mut res = Bindings::default(); | 68 | let mut res = Bindings::default(); |
56 | for pat in pattern.token_trees.iter() { | 69 | let mut src = TtIter::new(src); |
57 | match pat { | 70 | |
58 | crate::TokenTree::Leaf(leaf) => match leaf { | 71 | match_subtree(&mut res, pattern, &mut src)?; |
59 | crate::Leaf::Var(crate::Var { text, kind }) => { | 72 | |
60 | let kind = kind.as_ref().ok_or(ExpandError::UnexpectedToken)?; | 73 | if src.len() > 0 { |
61 | match match_meta_var(kind.as_str(), input)? { | 74 | bail!("leftover tokens"); |
62 | Some(fragment) => { | 75 | } |
63 | res.inner.insert(text.clone(), Binding::Fragment(fragment)); | 76 | |
64 | } | 77 | Ok(res) |
65 | None => res.push_optional(text), | 78 | } |
66 | } | 79 | |
80 | fn match_subtree( | ||
81 | bindings: &mut Bindings, | ||
82 | pattern: &tt::Subtree, | ||
83 | src: &mut TtIter, | ||
84 | ) -> Result<(), ExpandError> { | ||
85 | for op in parse_pattern(pattern) { | ||
86 | match op? { | ||
87 | Op::TokenTree(tt::TokenTree::Leaf(lhs)) => { | ||
88 | let rhs = src.expect_leaf().map_err(|()| err!("expected leaf: `{}`", lhs))?; | ||
89 | match (lhs, rhs) { | ||
90 | ( | ||
91 | tt::Leaf::Punct(tt::Punct { char: lhs, .. }), | ||
92 | tt::Leaf::Punct(tt::Punct { char: rhs, .. }), | ||
93 | ) if lhs == rhs => (), | ||
94 | ( | ||
95 | tt::Leaf::Ident(tt::Ident { text: lhs, .. }), | ||
96 | tt::Leaf::Ident(tt::Ident { text: rhs, .. }), | ||
97 | ) if lhs == rhs => (), | ||
98 | ( | ||
99 | tt::Leaf::Literal(tt::Literal { text: lhs, .. }), | ||
100 | tt::Leaf::Literal(tt::Literal { text: rhs, .. }), | ||
101 | ) if lhs == rhs => (), | ||
102 | _ => Err(ExpandError::UnexpectedToken)?, | ||
67 | } | 103 | } |
68 | crate::Leaf::Punct(punct) => { | 104 | } |
69 | if !input.eat_punct().map(|p| p.char == punct.char).unwrap_or(false) { | 105 | Op::TokenTree(tt::TokenTree::Subtree(lhs)) => { |
70 | return Err(ExpandError::UnexpectedToken); | 106 | let rhs = src.expect_subtree().map_err(|()| err!("expected subtree"))?; |
71 | } | 107 | if lhs.delimiter != rhs.delimiter { |
108 | bail!("mismatched delimiter") | ||
72 | } | 109 | } |
73 | crate::Leaf::Ident(ident) => { | 110 | let mut src = TtIter::new(rhs); |
74 | if input.eat_ident().map(|i| &i.text) != Some(&ident.text) { | 111 | match_subtree(bindings, lhs, &mut src)?; |
75 | return Err(ExpandError::UnexpectedToken); | 112 | if src.len() > 0 { |
76 | } | 113 | bail!("leftover tokens"); |
77 | } | 114 | } |
78 | crate::Leaf::Literal(literal) => { | 115 | } |
79 | if input.eat_literal().map(|i| &i.text) != Some(&literal.text) { | 116 | Op::Var { name, kind } => { |
80 | return Err(ExpandError::UnexpectedToken); | 117 | let kind = kind.as_ref().ok_or(ExpandError::UnexpectedToken)?; |
118 | match match_meta_var(kind.as_str(), src)? { | ||
119 | Some(fragment) => { | ||
120 | bindings.inner.insert(name.clone(), Binding::Fragment(fragment)); | ||
81 | } | 121 | } |
122 | None => bindings.push_optional(name), | ||
82 | } | 123 | } |
124 | () | ||
125 | } | ||
126 | Op::Repeat { subtree, kind, separator } => { | ||
127 | match_repeat(bindings, subtree, kind, separator, src)? | ||
128 | } | ||
129 | } | ||
130 | } | ||
131 | Ok(()) | ||
132 | } | ||
133 | |||
134 | impl<'a> TtIter<'a> { | ||
135 | fn eat_separator(&mut self, separator: &Separator) -> bool { | ||
136 | let mut fork = self.clone(); | ||
137 | let ok = match separator { | ||
138 | Separator::Ident(lhs) => match fork.expect_ident() { | ||
139 | Ok(rhs) => rhs.text == lhs.text, | ||
140 | _ => false, | ||
83 | }, | 141 | }, |
84 | crate::TokenTree::Repeat(crate::Repeat { subtree, kind, separator }) => { | 142 | Separator::Literal(lhs) => match fork.expect_literal() { |
85 | // Dirty hack to make macro-expansion terminate. | 143 | Ok(rhs) => rhs.text == lhs.text, |
86 | // This should be replaced by a propper macro-by-example implementation | 144 | _ => false, |
87 | let mut limit = 65536; | 145 | }, |
88 | let mut counter = 0; | 146 | Separator::Puncts(lhss) => lhss.iter().all(|lhs| match fork.expect_punct() { |
89 | 147 | Ok(rhs) => rhs.char == lhs.char, | |
90 | let mut memento = input.save(); | 148 | _ => false, |
91 | 149 | }), | |
92 | loop { | 150 | }; |
93 | match match_lhs(subtree, input) { | 151 | if ok { |
94 | Ok(nested) => { | 152 | *self = fork; |
95 | limit -= 1; | 153 | } |
96 | if limit == 0 { | 154 | ok |
97 | log::warn!("match_lhs excced in repeat pattern exceed limit => {:#?}\n{:#?}\n{:#?}\n{:#?}", subtree, input, kind, separator); | 155 | } |
98 | break; | ||
99 | } | ||
100 | |||
101 | memento = input.save(); | ||
102 | res.push_nested(counter, nested)?; | ||
103 | counter += 1; | ||
104 | if counter == 1 { | ||
105 | if let crate::RepeatKind::ZeroOrOne = kind { | ||
106 | break; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | if let Some(separator) = separator { | ||
111 | if !input | ||
112 | .eat_seperator() | ||
113 | .map(|sep| sep == *separator) | ||
114 | .unwrap_or(false) | ||
115 | { | ||
116 | input.rollback(memento); | ||
117 | break; | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | Err(_) => { | ||
122 | input.rollback(memento); | ||
123 | break; | ||
124 | } | ||
125 | } | ||
126 | } | ||
127 | 156 | ||
128 | match kind { | 157 | pub(crate) fn expect_lifetime(&mut self) -> Result<&tt::Ident, ()> { |
129 | crate::RepeatKind::OneOrMore if counter == 0 => { | 158 | let ident = self.expect_ident()?; |
130 | return Err(ExpandError::UnexpectedToken); | 159 | // check if it start from "`" |
131 | } | 160 | if ident.text.chars().next() != Some('\'') { |
132 | _ if counter == 0 => { | 161 | return Err(()); |
133 | // Collect all empty variables in subtrees | 162 | } |
134 | collect_vars(subtree).iter().for_each(|s| res.push_empty(s)); | 163 | Ok(ident) |
135 | } | 164 | } |
136 | _ => {} | 165 | |
166 | pub(crate) fn expect_fragment( | ||
167 | &mut self, | ||
168 | fragment_kind: ra_parser::FragmentKind, | ||
169 | ) -> Result<tt::TokenTree, ()> { | ||
170 | pub(crate) struct OffsetTokenSink<'a> { | ||
171 | pub(crate) cursor: Cursor<'a>, | ||
172 | pub(crate) error: bool, | ||
173 | } | ||
174 | |||
175 | impl<'a> TreeSink for OffsetTokenSink<'a> { | ||
176 | fn token(&mut self, _kind: SyntaxKind, n_tokens: u8) { | ||
177 | for _ in 0..n_tokens { | ||
178 | self.cursor = self.cursor.bump_subtree(); | ||
137 | } | 179 | } |
138 | } | 180 | } |
139 | crate::TokenTree::Subtree(subtree) => { | 181 | fn start_node(&mut self, _kind: SyntaxKind) {} |
140 | let input_subtree = | 182 | fn finish_node(&mut self) {} |
141 | input.eat_subtree().map_err(|_| ExpandError::UnexpectedToken)?; | 183 | fn error(&mut self, _error: ra_parser::ParseError) { |
142 | if subtree.delimiter != input_subtree.delimiter { | 184 | self.error = true; |
143 | return Err(ExpandError::UnexpectedToken); | 185 | } |
186 | } | ||
187 | |||
188 | let buffer = TokenBuffer::new(self.inner.as_slice()); | ||
189 | let mut src = SubtreeTokenSource::new(&buffer); | ||
190 | let mut sink = OffsetTokenSink { cursor: buffer.begin(), error: false }; | ||
191 | |||
192 | ra_parser::parse_fragment(&mut src, &mut sink, fragment_kind); | ||
193 | |||
194 | if !sink.cursor.is_root() || sink.error { | ||
195 | return Err(()); | ||
196 | } | ||
197 | |||
198 | let mut curr = buffer.begin(); | ||
199 | let mut res = vec![]; | ||
200 | |||
201 | while curr != sink.cursor { | ||
202 | if let Some(token) = curr.token_tree() { | ||
203 | res.push(token); | ||
204 | } | ||
205 | curr = curr.bump(); | ||
206 | } | ||
207 | self.inner = self.inner.as_slice()[res.len()..].iter(); | ||
208 | match res.len() { | ||
209 | 0 => Err(()), | ||
210 | 1 => Ok(res[0].clone()), | ||
211 | _ => Ok(tt::TokenTree::Subtree(tt::Subtree { | ||
212 | delimiter: tt::Delimiter::None, | ||
213 | token_trees: res.into_iter().cloned().collect(), | ||
214 | })), | ||
215 | } | ||
216 | } | ||
217 | |||
218 | pub(crate) fn eat_vis(&mut self) -> Option<tt::TokenTree> { | ||
219 | let mut fork = self.clone(); | ||
220 | match fork.expect_fragment(Visibility) { | ||
221 | Ok(tt) => { | ||
222 | *self = fork; | ||
223 | Some(tt) | ||
224 | } | ||
225 | Err(()) => None, | ||
226 | } | ||
227 | } | ||
228 | } | ||
229 | |||
230 | pub(super) fn match_repeat( | ||
231 | bindings: &mut Bindings, | ||
232 | pattern: &tt::Subtree, | ||
233 | kind: RepeatKind, | ||
234 | separator: Option<Separator>, | ||
235 | src: &mut TtIter, | ||
236 | ) -> Result<(), ExpandError> { | ||
237 | // Dirty hack to make macro-expansion terminate. | ||
238 | // This should be replaced by a propper macro-by-example implementation | ||
239 | let mut limit = 65536; | ||
240 | let mut counter = 0; | ||
241 | |||
242 | for i in 0.. { | ||
243 | let mut fork = src.clone(); | ||
244 | |||
245 | if let Some(separator) = &separator { | ||
246 | if i != 0 && !fork.eat_separator(separator) { | ||
247 | break; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | let mut nested = Bindings::default(); | ||
252 | match match_subtree(&mut nested, pattern, &mut fork) { | ||
253 | Ok(()) => { | ||
254 | limit -= 1; | ||
255 | if limit == 0 { | ||
256 | log::warn!("match_lhs excced in repeat pattern exceed limit => {:#?}\n{:#?}\n{:#?}\n{:#?}", pattern, src, kind, separator); | ||
257 | break; | ||
144 | } | 258 | } |
259 | *src = fork; | ||
145 | 260 | ||
146 | let mut input = TtCursor::new(input_subtree); | 261 | bindings.push_nested(counter, nested)?; |
147 | let bindings = match_lhs(&subtree, &mut input)?; | 262 | counter += 1; |
148 | if !input.is_eof() { | 263 | if counter == 1 { |
149 | return Err(ExpandError::UnexpectedToken); | 264 | if let RepeatKind::ZeroOrOne = kind { |
265 | break; | ||
266 | } | ||
150 | } | 267 | } |
268 | } | ||
269 | Err(_) => break, | ||
270 | } | ||
271 | } | ||
151 | 272 | ||
152 | res.merge(bindings); | 273 | match (kind, counter) { |
274 | (RepeatKind::OneOrMore, 0) => return Err(ExpandError::UnexpectedToken), | ||
275 | (_, 0) => { | ||
276 | // Collect all empty variables in subtrees | ||
277 | let mut vars = Vec::new(); | ||
278 | collect_vars(&mut vars, pattern)?; | ||
279 | for var in vars { | ||
280 | bindings.push_empty(&var) | ||
153 | } | 281 | } |
154 | } | 282 | } |
283 | _ => (), | ||
155 | } | 284 | } |
156 | Ok(res) | 285 | Ok(()) |
157 | } | 286 | } |
158 | 287 | ||
159 | fn match_meta_var(kind: &str, input: &mut TtCursor) -> Result<Option<Fragment>, ExpandError> { | 288 | fn match_meta_var(kind: &str, input: &mut TtIter) -> Result<Option<Fragment>, ExpandError> { |
160 | let fragment = match kind { | 289 | let fragment = match kind { |
161 | "path" => Path, | 290 | "path" => Path, |
162 | "expr" => Expr, | 291 | "expr" => Expr, |
@@ -169,17 +298,20 @@ fn match_meta_var(kind: &str, input: &mut TtCursor) -> Result<Option<Fragment>, | |||
169 | _ => { | 298 | _ => { |
170 | let tt = match kind { | 299 | let tt = match kind { |
171 | "ident" => { | 300 | "ident" => { |
172 | let ident = input.eat_ident().ok_or(ExpandError::UnexpectedToken)?.clone(); | 301 | let ident = input.expect_ident().map_err(|()| err!("expected ident"))?.clone(); |
173 | tt::Leaf::from(ident).into() | 302 | tt::Leaf::from(ident).into() |
174 | } | 303 | } |
175 | "tt" => input.eat().ok_or(ExpandError::UnexpectedToken)?.clone(), | 304 | "tt" => input.next().ok_or_else(|| err!())?.clone(), |
176 | "lifetime" => input.eat_lifetime().ok_or(ExpandError::UnexpectedToken)?.clone(), | 305 | "lifetime" => { |
306 | let ident = input.expect_lifetime().map_err(|()| err!())?; | ||
307 | tt::Leaf::Ident(ident.clone()).into() | ||
308 | } | ||
177 | "literal" => { | 309 | "literal" => { |
178 | let literal = input.eat_literal().ok_or(ExpandError::UnexpectedToken)?.clone(); | 310 | let literal = input.expect_literal().map_err(|()| err!())?.clone(); |
179 | tt::Leaf::from(literal).into() | 311 | tt::Leaf::from(literal).into() |
180 | } | 312 | } |
181 | // `vis` is optional | 313 | // `vis` is optional |
182 | "vis" => match input.try_eat_vis() { | 314 | "vis" => match input.eat_vis() { |
183 | Some(vis) => vis, | 315 | Some(vis) => vis, |
184 | None => return Ok(None), | 316 | None => return Ok(None), |
185 | }, | 317 | }, |
@@ -188,28 +320,19 @@ fn match_meta_var(kind: &str, input: &mut TtCursor) -> Result<Option<Fragment>, | |||
188 | return Ok(Some(Fragment::Tokens(tt))); | 320 | return Ok(Some(Fragment::Tokens(tt))); |
189 | } | 321 | } |
190 | }; | 322 | }; |
191 | let tt = input.eat_fragment(fragment).ok_or(ExpandError::UnexpectedToken)?; | 323 | let tt = input.expect_fragment(fragment).map_err(|()| err!())?; |
192 | let fragment = if kind == "expr" { Fragment::Ast(tt) } else { Fragment::Tokens(tt) }; | 324 | let fragment = if kind == "expr" { Fragment::Ast(tt) } else { Fragment::Tokens(tt) }; |
193 | Ok(Some(fragment)) | 325 | Ok(Some(fragment)) |
194 | } | 326 | } |
195 | 327 | ||
196 | fn collect_vars(subtree: &crate::Subtree) -> Vec<SmolStr> { | 328 | fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &tt::Subtree) -> Result<(), ExpandError> { |
197 | let mut res = Vec::new(); | 329 | for op in parse_pattern(pattern) { |
198 | 330 | match op? { | |
199 | for tkn in subtree.token_trees.iter() { | 331 | Op::Var { name, .. } => buf.push(name.clone()), |
200 | match tkn { | 332 | Op::TokenTree(tt::TokenTree::Leaf(_)) => (), |
201 | crate::TokenTree::Leaf(crate::Leaf::Var(crate::Var { text, .. })) => { | 333 | Op::TokenTree(tt::TokenTree::Subtree(subtree)) => collect_vars(buf, subtree)?, |
202 | res.push(text.clone()); | 334 | Op::Repeat { subtree, .. } => collect_vars(buf, subtree)?, |
203 | } | ||
204 | crate::TokenTree::Subtree(subtree) => { | ||
205 | res.extend(collect_vars(subtree)); | ||
206 | } | ||
207 | crate::TokenTree::Repeat(crate::Repeat { subtree, .. }) => { | ||
208 | res.extend(collect_vars(subtree)); | ||
209 | } | ||
210 | _ => {} | ||
211 | } | 335 | } |
212 | } | 336 | } |
213 | 337 | Ok(()) | |
214 | res | ||
215 | } | 338 | } |
diff --git a/crates/ra_mbe/src/mbe_expander/transcriber.rs b/crates/ra_mbe/src/mbe_expander/transcriber.rs index a3df1b7de..c22680b93 100644 --- a/crates/ra_mbe/src/mbe_expander/transcriber.rs +++ b/crates/ra_mbe/src/mbe_expander/transcriber.rs | |||
@@ -1,16 +1,20 @@ | |||
1 | //! Transcraber takes a template, like `fn $ident() {}`, a set of bindings like | ||
2 | //! `$ident => foo`, interpolates variables in the template, to get `fn foo() {}` | ||
3 | |||
1 | use ra_syntax::SmolStr; | 4 | use ra_syntax::SmolStr; |
2 | 5 | ||
3 | use crate::{ | 6 | use crate::{ |
4 | mbe_expander::{Binding, Bindings, Fragment}, | 7 | mbe_expander::{Binding, Bindings, Fragment}, |
8 | parser::{parse_template, Op, RepeatKind, Separator}, | ||
5 | ExpandError, | 9 | ExpandError, |
6 | }; | 10 | }; |
7 | 11 | ||
8 | impl Bindings { | 12 | impl Bindings { |
9 | fn contains(&self, name: &SmolStr) -> bool { | 13 | fn contains(&self, name: &str) -> bool { |
10 | self.inner.contains_key(name) | 14 | self.inner.contains_key(name) |
11 | } | 15 | } |
12 | 16 | ||
13 | fn get(&self, name: &SmolStr, nesting: &[usize]) -> Result<&Fragment, ExpandError> { | 17 | fn get(&self, name: &str, nesting: &[usize]) -> Result<&Fragment, ExpandError> { |
14 | let mut b = self.inner.get(name).ok_or_else(|| { | 18 | let mut b = self.inner.get(name).ok_or_else(|| { |
15 | ExpandError::BindingError(format!("could not find binding `{}`", name)) | 19 | ExpandError::BindingError(format!("could not find binding `{}`", name)) |
16 | })?; | 20 | })?; |
@@ -43,11 +47,12 @@ impl Bindings { | |||
43 | } | 47 | } |
44 | 48 | ||
45 | pub(super) fn transcribe( | 49 | pub(super) fn transcribe( |
50 | template: &tt::Subtree, | ||
46 | bindings: &Bindings, | 51 | bindings: &Bindings, |
47 | template: &crate::Subtree, | ||
48 | ) -> Result<tt::Subtree, ExpandError> { | 52 | ) -> Result<tt::Subtree, ExpandError> { |
53 | assert!(template.delimiter == tt::Delimiter::None); | ||
49 | let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new(), var_expanded: false }; | 54 | let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new(), var_expanded: false }; |
50 | expand_subtree(template, &mut ctx) | 55 | expand_subtree(&mut ctx, template) |
51 | } | 56 | } |
52 | 57 | ||
53 | #[derive(Debug)] | 58 | #[derive(Debug)] |
@@ -57,159 +62,158 @@ struct ExpandCtx<'a> { | |||
57 | var_expanded: bool, | 62 | var_expanded: bool, |
58 | } | 63 | } |
59 | 64 | ||
60 | fn expand_subtree( | 65 | fn expand_subtree(ctx: &mut ExpandCtx, template: &tt::Subtree) -> Result<tt::Subtree, ExpandError> { |
61 | template: &crate::Subtree, | ||
62 | ctx: &mut ExpandCtx, | ||
63 | ) -> Result<tt::Subtree, ExpandError> { | ||
64 | let mut buf: Vec<tt::TokenTree> = Vec::new(); | 66 | let mut buf: Vec<tt::TokenTree> = Vec::new(); |
65 | for tt in template.token_trees.iter() { | 67 | for op in parse_template(template) { |
66 | let tt = expand_tt(tt, ctx)?; | 68 | match op? { |
67 | push_fragment(&mut buf, tt); | 69 | Op::TokenTree(tt @ tt::TokenTree::Leaf(..)) => buf.push(tt.clone()), |
70 | Op::TokenTree(tt::TokenTree::Subtree(tt)) => { | ||
71 | let tt = expand_subtree(ctx, tt)?; | ||
72 | buf.push(tt.into()); | ||
73 | } | ||
74 | Op::Var { name, kind: _ } => { | ||
75 | let fragment = expand_var(ctx, name)?; | ||
76 | push_fragment(&mut buf, fragment); | ||
77 | } | ||
78 | Op::Repeat { subtree, kind, separator } => { | ||
79 | let fragment = expand_repeat(ctx, subtree, kind, separator)?; | ||
80 | push_fragment(&mut buf, fragment) | ||
81 | } | ||
82 | } | ||
68 | } | 83 | } |
69 | |||
70 | Ok(tt::Subtree { delimiter: template.delimiter, token_trees: buf }) | 84 | Ok(tt::Subtree { delimiter: template.delimiter, token_trees: buf }) |
71 | } | 85 | } |
72 | 86 | ||
73 | fn expand_tt(template: &crate::TokenTree, ctx: &mut ExpandCtx) -> Result<Fragment, ExpandError> { | 87 | fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> Result<Fragment, ExpandError> { |
74 | let res: tt::TokenTree = match template { | 88 | let res = if v == "crate" { |
75 | crate::TokenTree::Subtree(subtree) => expand_subtree(subtree, ctx)?.into(), | 89 | // FIXME: Properly handle $crate token |
76 | crate::TokenTree::Repeat(repeat) => { | 90 | let tt = |
77 | let mut buf: Vec<tt::TokenTree> = Vec::new(); | 91 | tt::Leaf::from(tt::Ident { text: "$crate".into(), id: tt::TokenId::unspecified() }) |
78 | ctx.nesting.push(0); | 92 | .into(); |
79 | // Dirty hack to make macro-expansion terminate. | 93 | Fragment::Tokens(tt) |
80 | // This should be replaced by a propper macro-by-example implementation | 94 | } else if !ctx.bindings.contains(v) { |
81 | let mut limit = 65536; | 95 | // Note that it is possible to have a `$var` inside a macro which is not bound. |
82 | let mut has_seps = 0; | 96 | // For example: |
83 | let mut counter = 0; | 97 | // ``` |
84 | 98 | // macro_rules! foo { | |
85 | // We store the old var expanded value, and restore it later | 99 | // ($a:ident, $b:ident, $c:tt) => { |
86 | // It is because before this `$repeat`, | 100 | // macro_rules! bar { |
87 | // it is possible some variables already expanad in the same subtree | 101 | // ($bi:ident) => { |
88 | // | 102 | // fn $bi() -> u8 {$c} |
89 | // `some_var_expanded` keep check if the deeper subtree has expanded variables | 103 | // } |
90 | let mut some_var_expanded = false; | 104 | // } |
91 | let old_var_expanded = ctx.var_expanded; | 105 | // } |
92 | ctx.var_expanded = false; | 106 | // ``` |
93 | 107 | // We just treat it a normal tokens | |
94 | while let Ok(t) = expand_subtree(&repeat.subtree, ctx) { | 108 | let tt = tt::Subtree { |
95 | // if no var expanded in the child, we count it as a fail | 109 | delimiter: tt::Delimiter::None, |
96 | if !ctx.var_expanded { | 110 | token_trees: vec![ |
97 | break; | 111 | tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone }).into(), |
98 | } | 112 | tt::Leaf::from(tt::Ident { text: v.clone(), id: tt::TokenId::unspecified() }) |
113 | .into(), | ||
114 | ], | ||
115 | } | ||
116 | .into(); | ||
117 | Fragment::Tokens(tt) | ||
118 | } else { | ||
119 | let fragment = ctx.bindings.get(&v, &ctx.nesting)?.clone(); | ||
120 | ctx.var_expanded = true; | ||
121 | fragment | ||
122 | }; | ||
123 | Ok(res) | ||
124 | } | ||
99 | 125 | ||
100 | // Reset `ctx.var_expandeded` to see if there is other expanded variable | 126 | fn expand_repeat( |
101 | // in the next matching | 127 | ctx: &mut ExpandCtx, |
102 | some_var_expanded = true; | 128 | template: &tt::Subtree, |
103 | ctx.var_expanded = false; | 129 | kind: RepeatKind, |
104 | 130 | separator: Option<Separator>, | |
105 | counter += 1; | 131 | ) -> Result<Fragment, ExpandError> { |
106 | limit -= 1; | 132 | let mut buf: Vec<tt::TokenTree> = Vec::new(); |
107 | if limit == 0 { | 133 | ctx.nesting.push(0); |
108 | log::warn!( | 134 | // Dirty hack to make macro-expansion terminate. |
109 | "expand_tt excced in repeat pattern exceed limit => {:#?}\n{:#?}", | 135 | // This should be replaced by a propper macro-by-example implementation |
110 | template, | 136 | let mut limit = 65536; |
111 | ctx | 137 | let mut has_seps = 0; |
112 | ); | 138 | let mut counter = 0; |
113 | break; | 139 | |
114 | } | 140 | // We store the old var expanded value, and restore it later |
141 | // It is because before this `$repeat`, | ||
142 | // it is possible some variables already expanad in the same subtree | ||
143 | // | ||
144 | // `some_var_expanded` keep check if the deeper subtree has expanded variables | ||
145 | let mut some_var_expanded = false; | ||
146 | let old_var_expanded = ctx.var_expanded; | ||
147 | ctx.var_expanded = false; | ||
148 | |||
149 | while let Ok(mut t) = expand_subtree(ctx, template) { | ||
150 | t.delimiter = tt::Delimiter::None; | ||
151 | // if no var expanded in the child, we count it as a fail | ||
152 | if !ctx.var_expanded { | ||
153 | break; | ||
154 | } | ||
115 | 155 | ||
116 | let idx = ctx.nesting.pop().unwrap(); | 156 | // Reset `ctx.var_expandeded` to see if there is other expanded variable |
117 | ctx.nesting.push(idx + 1); | 157 | // in the next matching |
118 | push_subtree(&mut buf, t); | 158 | some_var_expanded = true; |
119 | 159 | ctx.var_expanded = false; | |
120 | if let Some(ref sep) = repeat.separator { | 160 | |
121 | match sep { | 161 | counter += 1; |
122 | crate::Separator::Ident(ident) => { | 162 | limit -= 1; |
123 | has_seps = 1; | 163 | if limit == 0 { |
124 | buf.push(tt::Leaf::from(ident.clone()).into()); | 164 | log::warn!( |
125 | } | 165 | "expand_tt excced in repeat pattern exceed limit => {:#?}\n{:#?}", |
126 | crate::Separator::Literal(lit) => { | 166 | template, |
127 | has_seps = 1; | 167 | ctx |
128 | buf.push(tt::Leaf::from(lit.clone()).into()); | 168 | ); |
129 | } | 169 | break; |
130 | 170 | } | |
131 | crate::Separator::Puncts(puncts) => { | 171 | |
132 | has_seps = puncts.len(); | 172 | let idx = ctx.nesting.pop().unwrap(); |
133 | for punct in puncts { | 173 | ctx.nesting.push(idx + 1); |
134 | buf.push(tt::Leaf::from(*punct).into()); | 174 | push_subtree(&mut buf, t); |
135 | } | 175 | |
136 | } | 176 | if let Some(ref sep) = separator { |
137 | } | 177 | match sep { |
178 | Separator::Ident(ident) => { | ||
179 | has_seps = 1; | ||
180 | buf.push(tt::Leaf::from(ident.clone()).into()); | ||
181 | } | ||
182 | Separator::Literal(lit) => { | ||
183 | has_seps = 1; | ||
184 | buf.push(tt::Leaf::from(lit.clone()).into()); | ||
138 | } | 185 | } |
139 | 186 | ||
140 | if let crate::RepeatKind::ZeroOrOne = repeat.kind { | 187 | Separator::Puncts(puncts) => { |
141 | break; | 188 | has_seps = puncts.len(); |
189 | for punct in puncts { | ||
190 | buf.push(tt::Leaf::from(*punct).into()); | ||
191 | } | ||
142 | } | 192 | } |
143 | } | 193 | } |
194 | } | ||
144 | 195 | ||
145 | // Restore the `var_expanded` by combining old one and the new one | 196 | if RepeatKind::ZeroOrOne == kind { |
146 | ctx.var_expanded = some_var_expanded || old_var_expanded; | 197 | break; |
198 | } | ||
199 | } | ||
147 | 200 | ||
148 | ctx.nesting.pop().unwrap(); | 201 | // Restore the `var_expanded` by combining old one and the new one |
149 | for _ in 0..has_seps { | 202 | ctx.var_expanded = some_var_expanded || old_var_expanded; |
150 | buf.pop(); | ||
151 | } | ||
152 | 203 | ||
153 | if crate::RepeatKind::OneOrMore == repeat.kind && counter == 0 { | 204 | ctx.nesting.pop().unwrap(); |
154 | return Err(ExpandError::UnexpectedToken); | 205 | for _ in 0..has_seps { |
155 | } | 206 | buf.pop(); |
207 | } | ||
156 | 208 | ||
157 | // Check if it is a single token subtree without any delimiter | 209 | if RepeatKind::OneOrMore == kind && counter == 0 { |
158 | // e.g {Delimiter:None> ['>'] /Delimiter:None>} | 210 | return Err(ExpandError::UnexpectedToken); |
159 | tt::Subtree { delimiter: tt::Delimiter::None, token_trees: buf }.into() | 211 | } |
160 | } | 212 | |
161 | crate::TokenTree::Leaf(leaf) => match leaf { | 213 | // Check if it is a single token subtree without any delimiter |
162 | crate::Leaf::Ident(ident) => tt::Leaf::from(tt::Ident { | 214 | // e.g {Delimiter:None> ['>'] /Delimiter:None>} |
163 | text: ident.text.clone(), | 215 | let tt = tt::Subtree { delimiter: tt::Delimiter::None, token_trees: buf }.into(); |
164 | id: tt::TokenId::unspecified(), | 216 | Ok(Fragment::Tokens(tt)) |
165 | }) | ||
166 | .into(), | ||
167 | crate::Leaf::Punct(punct) => tt::Leaf::from(*punct).into(), | ||
168 | crate::Leaf::Var(v) => { | ||
169 | if v.text == "crate" { | ||
170 | // FIXME: Properly handle $crate token | ||
171 | tt::Leaf::from(tt::Ident { | ||
172 | text: "$crate".into(), | ||
173 | id: tt::TokenId::unspecified(), | ||
174 | }) | ||
175 | .into() | ||
176 | } else if !ctx.bindings.contains(&v.text) { | ||
177 | // Note that it is possible to have a `$var` inside a macro which is not bound. | ||
178 | // For example: | ||
179 | // ``` | ||
180 | // macro_rules! foo { | ||
181 | // ($a:ident, $b:ident, $c:tt) => { | ||
182 | // macro_rules! bar { | ||
183 | // ($bi:ident) => { | ||
184 | // fn $bi() -> u8 {$c} | ||
185 | // } | ||
186 | // } | ||
187 | // } | ||
188 | // ``` | ||
189 | // We just treat it a normal tokens | ||
190 | tt::Subtree { | ||
191 | delimiter: tt::Delimiter::None, | ||
192 | token_trees: vec![ | ||
193 | tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone }) | ||
194 | .into(), | ||
195 | tt::Leaf::from(tt::Ident { | ||
196 | text: v.text.clone(), | ||
197 | id: tt::TokenId::unspecified(), | ||
198 | }) | ||
199 | .into(), | ||
200 | ], | ||
201 | } | ||
202 | .into() | ||
203 | } else { | ||
204 | let fragment = ctx.bindings.get(&v.text, &ctx.nesting)?.clone(); | ||
205 | ctx.var_expanded = true; | ||
206 | return Ok(fragment); | ||
207 | } | ||
208 | } | ||
209 | crate::Leaf::Literal(l) => tt::Leaf::from(tt::Literal { text: l.text.clone() }).into(), | ||
210 | }, | ||
211 | }; | ||
212 | Ok(Fragment::Tokens(res)) | ||
213 | } | 217 | } |
214 | 218 | ||
215 | fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) { | 219 | fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) { |