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.rs110
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(_) => {