Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/mbe/src/expander/transcriber.rs')
| -rw-r--r-- | crates/mbe/src/expander/transcriber.rs | 110 |
1 files changed, 78 insertions, 32 deletions
diff --git a/crates/mbe/src/expander/transcriber.rs b/crates/mbe/src/expander/transcriber.rs index 7a3e8653c2..6e79cdaa0b 100644 --- a/crates/mbe/src/expander/transcriber.rs +++ b/crates/mbe/src/expander/transcriber.rs @@ -59,12 +59,12 @@ impl<S: Span> Bindings<S> { token_trees: token_trees.clone(), }; Ok(match f { - Fragment::Tokens(_) => unreachable!(), + Fragment::Tokens(_) | Fragment::Empty => unreachable!(), Fragment::Expr(_) => Fragment::Expr, Fragment::Path(_) => Fragment::Path, }(subtree)) } - Binding::Fragment(it @ Fragment::Tokens(_)) => Ok(it.clone()), + Binding::Fragment(it @ (Fragment::Tokens(_) | Fragment::Empty)) => Ok(it.clone()), // emit some reasonable default expansion for missing bindings, // this gives better recovery than emitting the `$fragment-name` verbatim Binding::Missing(it) => Ok({ @@ -87,10 +87,7 @@ impl<S: Span> Bindings<S> { })), // FIXME: Meta and Item should get proper defaults MetaVarKind::Meta | MetaVarKind::Item | MetaVarKind::Tt | MetaVarKind::Vis => { - Fragment::Tokens(tt::TokenTree::Subtree(tt::Subtree { - delimiter: tt::Delimiter::DUMMY_INVISIBLE, - token_trees: vec![], - })) + Fragment::Empty } MetaVarKind::Path | MetaVarKind::Ty @@ -131,8 +128,10 @@ pub(super) fn transcribe<S: Span>( template: &MetaTemplate<S>, bindings: &Bindings<S>, marker: impl Fn(&mut S) + Copy, + new_meta_vars: bool, + call_site: S, ) -> ExpandResult<tt::Subtree<S>> { - let mut ctx = ExpandCtx { bindings, nesting: Vec::new() }; + let mut ctx = ExpandCtx { bindings, nesting: Vec::new(), new_meta_vars, call_site }; let mut arena: Vec<tt::TokenTree<S>> = Vec::new(); expand_subtree(&mut ctx, template, None, &mut arena, marker) } @@ -152,6 +151,8 @@ struct NestingState { struct ExpandCtx<'a, S> { bindings: &'a Bindings<S>, nesting: Vec<NestingState>, + new_meta_vars: bool, + call_site: S, } fn expand_subtree<S: Span>( @@ -206,13 +207,13 @@ fn expand_subtree<S: Span>( Op::Var { name, id, .. } => { let ExpandResult { value: fragment, err: e } = expand_var(ctx, name, *id, marker); err = err.or(e); - push_fragment(arena, fragment); + push_fragment(ctx, arena, fragment); } Op::Repeat { tokens: subtree, kind, separator } => { let ExpandResult { value: fragment, err: e } = expand_repeat(ctx, subtree, *kind, separator, arena, marker); err = err.or(e); - push_fragment(arena, fragment) + push_fragment(ctx, arena, fragment) } Op::Ignore { name, id } => { // Expand the variable, but ignore the result. This registers the repetition count. @@ -225,8 +226,20 @@ fn expand_subtree<S: Span>( arena.push( tt::Leaf::Literal(tt::Literal { text: index.to_string().into(), - // FIXME - span: S::DUMMY, + span: ctx.call_site, + }) + .into(), + ); + } + Op::Length { depth } => { + let length = ctx.nesting.get(ctx.nesting.len() - 1 - depth).map_or(0, |_nest| { + // FIXME: to be implemented + 0 + }); + arena.push( + tt::Leaf::Literal(tt::Literal { + text: length.to_string().into(), + span: ctx.call_site, }) .into(), ); @@ -268,7 +281,13 @@ fn expand_subtree<S: Span>( } } - let c = match count(ctx, binding, 0, *depth) { + let res = if ctx.new_meta_vars { + count(ctx, binding, 0, depth.unwrap_or(0)) + } else { + count_old(ctx, binding, 0, *depth) + }; + + let c = match res { Ok(c) => c, Err(e) => { // XXX: It *might* make sense to emit a dummy integer value like `0` here. @@ -285,8 +304,7 @@ fn expand_subtree<S: Span>( arena.push( tt::Leaf::Literal(tt::Literal { text: c.to_string().into(), - // FIXME - span: S::DUMMY, + span: ctx.call_site, }) .into(), ); @@ -297,7 +315,7 @@ fn expand_subtree<S: Span>( let tts = arena.drain(start_elements..).collect(); ExpandResult { value: tt::Subtree { - delimiter: delimiter.unwrap_or_else(tt::Delimiter::dummy_invisible), + delimiter: delimiter.unwrap_or_else(|| tt::Delimiter::invisible_spanned(ctx.call_site)), token_trees: tts, }, err, @@ -330,7 +348,7 @@ fn expand_var<S: Span>( // ``` // We just treat it a normal tokens let tt = tt::Subtree { - delimiter: tt::Delimiter::DUMMY_INVISIBLE, + delimiter: tt::Delimiter::invisible_spanned(id), token_trees: vec![ tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone, span: id }) .into(), @@ -342,10 +360,8 @@ fn expand_var<S: Span>( } Err(e) => ExpandResult { value: Fragment::Tokens(tt::TokenTree::Subtree(tt::Subtree::empty(tt::DelimSpan { - // FIXME - open: S::DUMMY, - // FIXME - close: S::DUMMY, + open: ctx.call_site, + close: ctx.call_site, }))), err: Some(e), }, @@ -389,7 +405,7 @@ fn expand_repeat<S: Span>( return ExpandResult { value: Fragment::Tokens( tt::Subtree { - delimiter: tt::Delimiter::dummy_invisible(), + delimiter: tt::Delimiter::invisible_spanned(ctx.call_site), token_trees: vec![], } .into(), @@ -403,7 +419,7 @@ fn expand_repeat<S: Span>( continue; } - t.delimiter = tt::Delimiter::DUMMY_INVISIBLE; + t.delimiter.kind = tt::DelimiterKind::Invisible; push_subtree(&mut buf, t); if let Some(sep) = separator { @@ -437,7 +453,11 @@ fn expand_repeat<S: Span>( // Check if it is a single token subtree without any delimiter // e.g {Delimiter:None> ['>'] /Delimiter:None>} - let tt = tt::Subtree { delimiter: tt::Delimiter::DUMMY_INVISIBLE, token_trees: buf }.into(); + let tt = tt::Subtree { + delimiter: tt::Delimiter::invisible_spanned(ctx.call_site), + token_trees: buf, + } + .into(); if RepeatKind::OneOrMore == kind && counter == 0 { return ExpandResult { @@ -448,14 +468,19 @@ fn expand_repeat<S: Span>( ExpandResult { value: Fragment::Tokens(tt), err } } -fn push_fragment<S: Span>(buf: &mut Vec<tt::TokenTree<S>>, fragment: Fragment<S>) { +fn push_fragment<S: Span>( + ctx: &ExpandCtx<'_, S>, + buf: &mut Vec<tt::TokenTree<S>>, + fragment: Fragment<S>, +) { match fragment { Fragment::Tokens(tt::TokenTree::Subtree(tt)) => push_subtree(buf, tt), Fragment::Expr(sub) => { push_subtree(buf, sub); } - Fragment::Path(tt) => fix_up_and_push_path_tt(buf, tt), + Fragment::Path(tt) => fix_up_and_push_path_tt(ctx, buf, tt), Fragment::Tokens(tt) => buf.push(tt), + Fragment::Empty => (), } } @@ -469,7 +494,11 @@ fn push_subtree<S>(buf: &mut Vec<tt::TokenTree<S>>, tt: tt::Subtree<S>) { /// Inserts the path separator `::` between an identifier and its following generic /// argument list, and then pushes into the buffer. See [`Fragment::Path`] for why /// we need this fixup. -fn fix_up_and_push_path_tt<S: Span>(buf: &mut Vec<tt::TokenTree<S>>, subtree: tt::Subtree<S>) { +fn fix_up_and_push_path_tt<S: Span>( + ctx: &ExpandCtx<'_, S>, + buf: &mut Vec<tt::TokenTree<S>>, + subtree: tt::Subtree<S>, +) { stdx::always!(matches!(subtree.delimiter.kind, tt::DelimiterKind::Invisible)); let mut prev_was_ident = false; // Note that we only need to fix up the top-level `TokenTree`s because the @@ -486,8 +515,7 @@ fn fix_up_and_push_path_tt<S: Span>(buf: &mut Vec<tt::TokenTree<S>>, subtree: tt tt::Leaf::Punct(tt::Punct { char: ':', spacing: tt::Spacing::Joint, - // FIXME - span: S::DUMMY, + span: ctx.call_site, }) .into(), ); @@ -495,8 +523,7 @@ fn fix_up_and_push_path_tt<S: Span>(buf: &mut Vec<tt::TokenTree<S>>, subtree: tt tt::Leaf::Punct(tt::Punct { char: ':', spacing: tt::Spacing::Alone, - // FIXME - span: S::DUMMY, + span: ctx.call_site, }) .into(), ); @@ -512,14 +539,33 @@ fn fix_up_and_push_path_tt<S: Span>(buf: &mut Vec<tt::TokenTree<S>>, subtree: tt fn count<S>( ctx: &ExpandCtx<'_, S>, binding: &Binding<S>, + depth_curr: usize, + depth_max: usize, +) -> Result<usize, CountError> { + match binding { + Binding::Nested(bs) => { + if depth_curr == depth_max { + Ok(bs.len()) + } else { + bs.iter().map(|b| count(ctx, b, depth_curr + 1, depth_max)).sum() + } + } + Binding::Empty => Ok(0), + Binding::Fragment(_) | Binding::Missing(_) => Ok(1), + } +} + +fn count_old<S>( + ctx: &ExpandCtx<'_, S>, + binding: &Binding<S>, our_depth: usize, count_depth: Option<usize>, ) -> Result<usize, CountError> { match binding { Binding::Nested(bs) => match count_depth { - None => bs.iter().map(|b| count(ctx, b, our_depth + 1, None)).sum(), + None => bs.iter().map(|b| count_old(ctx, b, our_depth + 1, None)).sum(), Some(0) => Ok(bs.len()), - Some(d) => bs.iter().map(|b| count(ctx, b, our_depth + 1, Some(d - 1))).sum(), + Some(d) => bs.iter().map(|b| count_old(ctx, b, our_depth + 1, Some(d - 1))).sum(), }, Binding::Empty => Ok(0), Binding::Fragment(_) | Binding::Missing(_) => { |