aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_mbe/src/mbe_expander.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_mbe/src/mbe_expander.rs')
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs167
1 files changed, 123 insertions, 44 deletions
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs
index 00fb09a3b..d5189b537 100644
--- a/crates/ra_mbe/src/mbe_expander.rs
+++ b/crates/ra_mbe/src/mbe_expander.rs
@@ -21,7 +21,10 @@ fn expand_rule(rule: &crate::Rule, input: &tt::Subtree) -> Result<tt::Subtree, E
21 if !input.is_eof() { 21 if !input.is_eof() {
22 return Err(ExpandError::UnexpectedToken); 22 return Err(ExpandError::UnexpectedToken);
23 } 23 }
24 expand_subtree(&rule.rhs, &bindings, &mut Vec::new()) 24
25 let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new(), var_expanded: false };
26
27 expand_subtree(&rule.rhs, &mut ctx)
25} 28}
26 29
27/// The actual algorithm for expansion is not too hard, but is pretty tricky. 30/// The actual algorithm for expansion is not too hard, but is pretty tricky.
@@ -179,10 +182,10 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
179 // Enable followiing code when everything is fixed 182 // Enable followiing code when everything is fixed
180 // At least we can dogfood itself to not stackoverflow 183 // At least we can dogfood itself to not stackoverflow
181 // 184 //
182 // "tt" => { 185 "tt" => {
183 // let token = input.eat().ok_or(ExpandError::UnexpectedToken)?.clone(); 186 let token = input.eat().ok_or(ExpandError::UnexpectedToken)?.clone();
184 // res.inner.insert(text.clone(), Binding::Simple(token.into())); 187 res.inner.insert(text.clone(), Binding::Simple(token.into()));
185 // } 188 }
186 "item" => { 189 "item" => {
187 let item = 190 let item =
188 input.eat_item().ok_or(ExpandError::UnexpectedToken)?.clone(); 191 input.eat_item().ok_or(ExpandError::UnexpectedToken)?.clone();
@@ -196,6 +199,7 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
196 "literal" => { 199 "literal" => {
197 let literal = 200 let literal =
198 input.eat_literal().ok_or(ExpandError::UnexpectedToken)?.clone(); 201 input.eat_literal().ok_or(ExpandError::UnexpectedToken)?.clone();
202
199 res.inner.insert( 203 res.inner.insert(
200 text.clone(), 204 text.clone(),
201 Binding::Simple(tt::Leaf::from(literal).into()), 205 Binding::Simple(tt::Leaf::from(literal).into()),
@@ -210,7 +214,7 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
210 } 214 }
211 } 215 }
212 crate::Leaf::Punct(punct) => { 216 crate::Leaf::Punct(punct) => {
213 if input.eat_punct() != Some(punct) { 217 if !input.eat_punct().map(|p| p.char == punct.char).unwrap_or(false) {
214 return Err(ExpandError::UnexpectedToken); 218 return Err(ExpandError::UnexpectedToken);
215 } 219 }
216 } 220 }
@@ -224,20 +228,54 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
224 crate::TokenTree::Repeat(crate::Repeat { subtree, kind, separator }) => { 228 crate::TokenTree::Repeat(crate::Repeat { subtree, kind, separator }) => {
225 // Dirty hack to make macro-expansion terminate. 229 // Dirty hack to make macro-expansion terminate.
226 // This should be replaced by a propper macro-by-example implementation 230 // This should be replaced by a propper macro-by-example implementation
227 let mut limit = 128; 231 let mut limit = 65536;
228 let mut counter = 0; 232 let mut counter = 0;
229 while let Ok(nested) = match_lhs(subtree, input) { 233
230 counter += 1; 234 let mut memento = input.save();
231 limit -= 1; 235
232 if limit == 0 { 236 loop {
233 break; 237 match match_lhs(subtree, input) {
234 } 238 Ok(nested) => {
235 res.push_nested(nested)?; 239 counter += 1;
236 if let Some(separator) = *separator { 240 limit -= 1;
237 if !input.is_eof() { 241 if limit == 0 {
238 if input.eat_punct().map(|p| p.char) != Some(separator) { 242 log::warn!("match_lhs excced in repeat pattern exceed limit => {:#?}\n{:#?}\n{:#?}\n{:#?}", subtree, input, kind, separator);
239 return Err(ExpandError::UnexpectedToken); 243 break;
244 }
245
246 memento = input.save();
247 res.push_nested(nested)?;
248 if counter == 1 {
249 if let crate::RepeatKind::ZeroOrOne = kind {
250 break;
251 }
240 } 252 }
253
254 if let Some(separator) = separator {
255 use crate::Separator::*;
256
257 if !input
258 .eat_seperator()
259 .map(|sep| match (sep, separator) {
260 (Ident(ref a), Ident(ref b)) => a.text == b.text,
261 (Literal(ref a), Literal(ref b)) => a.text == b.text,
262 (Puncts(ref a), Puncts(ref b)) if a.len() == b.len() => {
263 let a_iter = a.iter().map(|a| a.char);
264 let b_iter = b.iter().map(|b| b.char);
265 a_iter.eq(b_iter)
266 }
267 _ => false,
268 })
269 .unwrap_or(false)
270 {
271 input.rollback(memento);
272 break;
273 }
274 }
275 }
276 Err(_) => {
277 input.rollback(memento);
278 break;
241 } 279 }
242 } 280 }
243 } 281 }
@@ -246,10 +284,6 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
246 crate::RepeatKind::OneOrMore if counter == 0 => { 284 crate::RepeatKind::OneOrMore if counter == 0 => {
247 return Err(ExpandError::UnexpectedToken); 285 return Err(ExpandError::UnexpectedToken);
248 } 286 }
249 crate::RepeatKind::ZeroOrOne if counter > 1 => {
250 return Err(ExpandError::UnexpectedToken);
251 }
252
253 _ => {} 287 _ => {}
254 } 288 }
255 } 289 }
@@ -273,15 +307,21 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
273 Ok(res) 307 Ok(res)
274} 308}
275 309
310#[derive(Debug)]
311struct ExpandCtx<'a> {
312 bindings: &'a Bindings,
313 nesting: Vec<usize>,
314 var_expanded: bool,
315}
316
276fn expand_subtree( 317fn expand_subtree(
277 template: &crate::Subtree, 318 template: &crate::Subtree,
278 bindings: &Bindings, 319 ctx: &mut ExpandCtx,
279 nesting: &mut Vec<usize>,
280) -> Result<tt::Subtree, ExpandError> { 320) -> Result<tt::Subtree, ExpandError> {
281 let token_trees = template 321 let token_trees = template
282 .token_trees 322 .token_trees
283 .iter() 323 .iter()
284 .map(|it| expand_tt(it, bindings, nesting)) 324 .map(|it| expand_tt(it, ctx))
285 .collect::<Result<Vec<_>, ExpandError>>()?; 325 .collect::<Result<Vec<_>, ExpandError>>()?;
286 326
287 Ok(tt::Subtree { token_trees, delimiter: template.delimiter }) 327 Ok(tt::Subtree { token_trees, delimiter: template.delimiter })
@@ -303,43 +343,81 @@ fn reduce_single_token(mut subtree: tt::Subtree) -> tt::TokenTree {
303 343
304fn expand_tt( 344fn expand_tt(
305 template: &crate::TokenTree, 345 template: &crate::TokenTree,
306 bindings: &Bindings, 346 ctx: &mut ExpandCtx,
307 nesting: &mut Vec<usize>,
308) -> Result<tt::TokenTree, ExpandError> { 347) -> Result<tt::TokenTree, ExpandError> {
309 let res: tt::TokenTree = match template { 348 let res: tt::TokenTree = match template {
310 crate::TokenTree::Subtree(subtree) => expand_subtree(subtree, bindings, nesting)?.into(), 349 crate::TokenTree::Subtree(subtree) => expand_subtree(subtree, ctx)?.into(),
311 crate::TokenTree::Repeat(repeat) => { 350 crate::TokenTree::Repeat(repeat) => {
312 let mut token_trees: Vec<tt::TokenTree> = Vec::new(); 351 let mut token_trees: Vec<tt::TokenTree> = Vec::new();
313 nesting.push(0); 352 ctx.nesting.push(0);
314 // Dirty hack to make macro-expansion terminate. 353 // Dirty hack to make macro-expansion terminate.
315 // This should be replaced by a propper macro-by-example implementation 354 // This should be replaced by a propper macro-by-example implementation
316 let mut limit = 128; 355 let mut limit = 65536;
317 let mut has_sep = false; 356 let mut has_seps = 0;
357 let mut counter = 0;
318 358
319 while let Ok(t) = expand_subtree(&repeat.subtree, bindings, nesting) { 359 let mut some_var_expanded = false;
360 ctx.var_expanded = false;
361
362 while let Ok(t) = expand_subtree(&repeat.subtree, ctx) {
363 // if no var expaned in the child, we count it as a fail
364 if !ctx.var_expanded {
365 break;
366 }
367 some_var_expanded = true;
368 ctx.var_expanded = false;
369
370 counter += 1;
320 limit -= 1; 371 limit -= 1;
321 if limit == 0 { 372 if limit == 0 {
373 log::warn!(
374 "expand_tt excced in repeat pattern exceed limit => {:#?}\n{:#?}",
375 template,
376 ctx
377 );
322 break; 378 break;
323 } 379 }
324 let idx = nesting.pop().unwrap(); 380
325 nesting.push(idx + 1); 381 let idx = ctx.nesting.pop().unwrap();
382 ctx.nesting.push(idx + 1);
326 token_trees.push(reduce_single_token(t).into()); 383 token_trees.push(reduce_single_token(t).into());
327 384
328 if let Some(sep) = repeat.separator { 385 if let Some(ref sep) = repeat.separator {
329 let punct = 386 match sep {
330 tt::Leaf::from(tt::Punct { char: sep, spacing: tt::Spacing::Alone }); 387 crate::Separator::Ident(ident) => {
331 token_trees.push(punct.into()); 388 has_seps = 1;
332 has_sep = true; 389 token_trees.push(tt::Leaf::from(ident.clone()).into());
390 }
391 crate::Separator::Literal(lit) => {
392 has_seps = 1;
393 token_trees.push(tt::Leaf::from(lit.clone()).into());
394 }
395
396 crate::Separator::Puncts(puncts) => {
397 has_seps = puncts.len();
398 for punct in puncts {
399 token_trees.push(tt::Leaf::from(*punct).into());
400 }
401 }
402 }
403 }
404
405 if let crate::RepeatKind::ZeroOrOne = repeat.kind {
406 break;
333 } 407 }
334 } 408 }
335 nesting.pop().unwrap();
336 409
337 // Dirty hack for remove the last sep 410 ctx.var_expanded = some_var_expanded;
338 // if it is a "," undo the push 411
339 if has_sep && repeat.separator.unwrap() == ',' { 412 ctx.nesting.pop().unwrap();
413 for _ in 0..has_seps {
340 token_trees.pop(); 414 token_trees.pop();
341 } 415 }
342 416
417 if crate::RepeatKind::OneOrMore == repeat.kind && counter == 0 {
418 return Err(ExpandError::UnexpectedToken);
419 }
420
343 // Check if it is a singel token subtree without any delimiter 421 // Check if it is a singel token subtree without any delimiter
344 // e.g {Delimiter:None> ['>'] /Delimiter:None>} 422 // e.g {Delimiter:None> ['>'] /Delimiter:None>}
345 reduce_single_token(tt::Subtree { token_trees, delimiter: tt::Delimiter::None }) 423 reduce_single_token(tt::Subtree { token_trees, delimiter: tt::Delimiter::None })
@@ -356,7 +434,8 @@ fn expand_tt(
356 tt::Leaf::from(tt::Ident { text: "$crate".into(), id: TokenId::unspecified() }) 434 tt::Leaf::from(tt::Ident { text: "$crate".into(), id: TokenId::unspecified() })
357 .into() 435 .into()
358 } else { 436 } else {
359 let tkn = bindings.get(&v.text, nesting)?.clone(); 437 let tkn = ctx.bindings.get(&v.text, &ctx.nesting)?.clone();
438 ctx.var_expanded = true;
360 439
361 if let tt::TokenTree::Subtree(subtree) = tkn { 440 if let tt::TokenTree::Subtree(subtree) = tkn {
362 reduce_single_token(subtree) 441 reduce_single_token(subtree)