aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_mbe/src/mbe_expander
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-09-17 13:53:01 +0100
committerGitHub <[email protected]>2019-09-17 13:53:01 +0100
commit9421d2a953516b392ae35446bc4f2206dd993c84 (patch)
treee6c7b46cabe1f10f7da28f3db209df2260045fa8 /crates/ra_mbe/src/mbe_expander
parent8eb2697b7d2a98c952b3acd1711829a13e13cab1 (diff)
parent4551182f94fe81c314f79ddf8916a5520cfd03b0 (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.rs361
-rw-r--r--crates/ra_mbe/src/mbe_expander/transcriber.rs288
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 @@
1use crate::{ 1use 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
7use ra_parser::FragmentKind::*; 9use ra_parser::{FragmentKind::*, TreeSink};
8use ra_syntax::SmolStr; 10use ra_syntax::{SmolStr, SyntaxKind};
11use tt::buffer::{Cursor, TokenBuffer};
9 12
10impl Bindings { 13impl 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) { 50macro_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
51pub(super) fn match_lhs( 59macro_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
65pub(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
80fn 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
134impl<'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
230pub(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
159fn match_meta_var(kind: &str, input: &mut TtCursor) -> Result<Option<Fragment>, ExpandError> { 288fn 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
196fn collect_vars(subtree: &crate::Subtree) -> Vec<SmolStr> { 328fn 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
1use ra_syntax::SmolStr; 4use ra_syntax::SmolStr;
2 5
3use crate::{ 6use 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
8impl Bindings { 12impl 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
45pub(super) fn transcribe( 49pub(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
60fn expand_subtree( 65fn 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
73fn expand_tt(template: &crate::TokenTree, ctx: &mut ExpandCtx) -> Result<Fragment, ExpandError> { 87fn 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 126fn 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
215fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) { 219fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) {