Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-expand/src/builtin/quote.rs')
| -rw-r--r-- | crates/hir-expand/src/builtin/quote.rs | 250 |
1 files changed, 118 insertions, 132 deletions
diff --git a/crates/hir-expand/src/builtin/quote.rs b/crates/hir-expand/src/builtin/quote.rs index 418d8d9660..6c1abc2620 100644 --- a/crates/hir-expand/src/builtin/quote.rs +++ b/crates/hir-expand/src/builtin/quote.rs @@ -6,7 +6,7 @@ use span::Span; use syntax::ToSmolStr; use tt::IdentIsRaw; -use crate::name::Name; +use crate::{name::Name, tt::TopSubtreeBuilder}; pub(crate) fn dollar_crate(span: Span) -> tt::Ident<Span> { tt::Ident { sym: sym::dollar_crate.clone(), span, is_raw: tt::IdentIsRaw::No } @@ -20,119 +20,93 @@ pub(crate) fn dollar_crate(span: Span) -> tt::Ident<Span> { #[doc(hidden)] #[macro_export] macro_rules! quote_impl__ { - ($span:ident) => { - Vec::<$crate::tt::TokenTree>::new() - }; + ($span:ident $builder:ident) => {}; - ( @SUBTREE($span:ident) $delim:ident $($tt:tt)* ) => { + ( @SUBTREE($span:ident $builder:ident) $delim:ident $($tt:tt)* ) => { { - let children = $crate::builtin::quote::__quote!($span $($tt)*); - $crate::tt::Subtree { - delimiter: $crate::tt::Delimiter { - kind: $crate::tt::DelimiterKind::$delim, - open: $span, - close: $span, - }, - token_trees: $crate::builtin::quote::IntoTt::to_tokens(children).into_boxed_slice(), - } + $builder.open($crate::tt::DelimiterKind::$delim, $span); + $crate::builtin::quote::__quote!($span $builder $($tt)*); + $builder.close($span); } }; - ( @PUNCT($span:ident) $first:literal ) => { - { - vec![ - $crate::tt::Leaf::Punct($crate::tt::Punct { - char: $first, - spacing: $crate::tt::Spacing::Alone, - span: $span, - }).into() - ] - } + ( @PUNCT($span:ident $builder:ident) $first:literal ) => { + $builder.push( + $crate::tt::Leaf::Punct($crate::tt::Punct { + char: $first, + spacing: $crate::tt::Spacing::Alone, + span: $span, + }) + ); }; - ( @PUNCT($span:ident) $first:literal, $sec:literal ) => { - { - vec![ - $crate::tt::Leaf::Punct($crate::tt::Punct { - char: $first, - spacing: $crate::tt::Spacing::Joint, - span: $span, - }).into(), - $crate::tt::Leaf::Punct($crate::tt::Punct { - char: $sec, - spacing: $crate::tt::Spacing::Alone, - span: $span, - }).into() - ] - } + ( @PUNCT($span:ident $builder:ident) $first:literal, $sec:literal ) => { + $builder.extend([ + $crate::tt::Leaf::Punct($crate::tt::Punct { + char: $first, + spacing: $crate::tt::Spacing::Joint, + span: $span, + }), + $crate::tt::Leaf::Punct($crate::tt::Punct { + char: $sec, + spacing: $crate::tt::Spacing::Alone, + span: $span, + }) + ]); }; // hash variable - ($span:ident # $first:ident $($tail:tt)* ) => { - { - let token = $crate::builtin::quote::ToTokenTree::to_token($first, $span); - let mut tokens = vec![token.into()]; - let mut tail_tokens = $crate::builtin::quote::IntoTt::to_tokens($crate::builtin::quote::__quote!($span $($tail)*)); - tokens.append(&mut tail_tokens); - tokens - } + ($span:ident $builder:ident # $first:ident $($tail:tt)* ) => { + $crate::builtin::quote::ToTokenTree::to_tokens($first, $span, $builder); + $crate::builtin::quote::__quote!($span $builder $($tail)*); }; - ($span:ident ## $first:ident $($tail:tt)* ) => { - { - let mut tokens = $first.into_iter().map(|it| $crate::builtin::quote::ToTokenTree::to_token(it, $span)).collect::<Vec<crate::tt::TokenTree>>(); - let mut tail_tokens = $crate::builtin::quote::IntoTt::to_tokens($crate::builtin::quote::__quote!($span $($tail)*)); - tokens.append(&mut tail_tokens); - tokens - } - }; + ($span:ident $builder:ident ## $first:ident $($tail:tt)* ) => {{ + ::std::iter::IntoIterator::into_iter($first).for_each(|it| $crate::builtin::quote::ToTokenTree::to_tokens(it, $span, $builder)); + $crate::builtin::quote::__quote!($span $builder $($tail)*); + }}; // Brace - ($span:ident { $($tt:tt)* } ) => { $crate::builtin::quote::__quote!(@SUBTREE($span) Brace $($tt)*) }; + ($span:ident $builder:ident { $($tt:tt)* } ) => { $crate::builtin::quote::__quote!(@SUBTREE($span $builder) Brace $($tt)*) }; // Bracket - ($span:ident [ $($tt:tt)* ] ) => { $crate::builtin::quote::__quote!(@SUBTREE($span) Bracket $($tt)*) }; + ($span:ident $builder:ident [ $($tt:tt)* ] ) => { $crate::builtin::quote::__quote!(@SUBTREE($span $builder) Bracket $($tt)*) }; // Parenthesis - ($span:ident ( $($tt:tt)* ) ) => { $crate::builtin::quote::__quote!(@SUBTREE($span) Parenthesis $($tt)*) }; + ($span:ident $builder:ident ( $($tt:tt)* ) ) => { $crate::builtin::quote::__quote!(@SUBTREE($span $builder) Parenthesis $($tt)*) }; // Literal - ($span:ident $tt:literal ) => { vec![$crate::builtin::quote::ToTokenTree::to_token($tt, $span).into()] }; + ($span:ident $builder:ident $tt:literal ) => { $crate::builtin::quote::ToTokenTree::to_tokens($tt, $span, $builder) }; // Ident - ($span:ident $tt:ident ) => { - vec![ { + ($span:ident $builder:ident $tt:ident ) => { + $builder.push( $crate::tt::Leaf::Ident($crate::tt::Ident { sym: intern::Symbol::intern(stringify!($tt)), span: $span, is_raw: tt::IdentIsRaw::No, - }).into() - }] + }) + ); }; // Puncts // FIXME: Not all puncts are handled - ($span:ident -> ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '-', '>')}; - ($span:ident => ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '=', '>')}; - ($span:ident & ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '&')}; - ($span:ident , ) => {$crate::builtin::quote::__quote!(@PUNCT($span) ',')}; - ($span:ident : ) => {$crate::builtin::quote::__quote!(@PUNCT($span) ':')}; - ($span:ident ; ) => {$crate::builtin::quote::__quote!(@PUNCT($span) ';')}; - ($span:ident :: ) => {$crate::builtin::quote::__quote!(@PUNCT($span) ':', ':')}; - ($span:ident . ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '.')}; - ($span:ident < ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '<')}; - ($span:ident > ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '>')}; - ($span:ident ! ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '!')}; - ($span:ident # ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '#')}; - ($span:ident $ ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '$')}; - ($span:ident * ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '*')}; - - ($span:ident $first:tt $($tail:tt)+ ) => { - { - let mut tokens = $crate::builtin::quote::IntoTt::to_tokens($crate::builtin::quote::__quote!($span $first )); - let mut tail_tokens = $crate::builtin::quote::IntoTt::to_tokens($crate::builtin::quote::__quote!($span $($tail)*)); - - tokens.append(&mut tail_tokens); - tokens - } - }; + ($span:ident $builder:ident -> ) => {$crate::builtin::quote::__quote!(@PUNCT($span $builder) '-', '>')}; + ($span:ident $builder:ident => ) => {$crate::builtin::quote::__quote!(@PUNCT($span $builder) '=', '>')}; + ($span:ident $builder:ident & ) => {$crate::builtin::quote::__quote!(@PUNCT($span $builder) '&')}; + ($span:ident $builder:ident , ) => {$crate::builtin::quote::__quote!(@PUNCT($span $builder) ',')}; + ($span:ident $builder:ident : ) => {$crate::builtin::quote::__quote!(@PUNCT($span $builder) ':')}; + ($span:ident $builder:ident ; ) => {$crate::builtin::quote::__quote!(@PUNCT($span $builder) ';')}; + ($span:ident $builder:ident :: ) => {$crate::builtin::quote::__quote!(@PUNCT($span $builder) ':', ':')}; + ($span:ident $builder:ident . ) => {$crate::builtin::quote::__quote!(@PUNCT($span $builder) '.')}; + ($span:ident $builder:ident < ) => {$crate::builtin::quote::__quote!(@PUNCT($span $builder) '<')}; + ($span:ident $builder:ident > ) => {$crate::builtin::quote::__quote!(@PUNCT($span $builder) '>')}; + ($span:ident $builder:ident ! ) => {$crate::builtin::quote::__quote!(@PUNCT($span $builder) '!')}; + ($span:ident $builder:ident # ) => {$crate::builtin::quote::__quote!(@PUNCT($span $builder) '#')}; + ($span:ident $builder:ident $ ) => {$crate::builtin::quote::__quote!(@PUNCT($span $builder) '$')}; + ($span:ident $builder:ident * ) => {$crate::builtin::quote::__quote!(@PUNCT($span $builder) '*')}; + + ($span:ident $builder:ident $first:tt $($tail:tt)+ ) => {{ + $crate::builtin::quote::__quote!($span $builder $first); + $crate::builtin::quote::__quote!($span $builder $($tail)*); + }}; } pub use quote_impl__ as __quote; @@ -141,52 +115,68 @@ pub use quote_impl__ as __quote; #[macro_export] macro_rules! quote { ($span:ident=> $($tt:tt)* ) => { - $crate::builtin::quote::IntoTt::to_subtree($crate::builtin::quote::__quote!($span $($tt)*), $span) + { + let mut builder = $crate::tt::TopSubtreeBuilder::new($crate::tt::Delimiter { + kind: $crate::tt::DelimiterKind::Invisible, + open: $span, + close: $span, + }); + #[allow(unused)] + let builder_ref = &mut builder; + $crate::builtin::quote::__quote!($span builder_ref $($tt)*); + builder.build_skip_top_subtree() + } } } pub(super) use quote; -pub trait IntoTt { - fn to_subtree(self, span: Span) -> crate::tt::Subtree; - fn to_tokens(self) -> Vec<crate::tt::TokenTree>; +pub trait ToTokenTree { + fn to_tokens(self, span: Span, builder: &mut TopSubtreeBuilder); } -impl IntoTt for Vec<crate::tt::TokenTree> { - fn to_subtree(self, span: Span) -> crate::tt::Subtree { - crate::tt::Subtree { - delimiter: crate::tt::Delimiter::invisible_spanned(span), - token_trees: self.into_boxed_slice(), - } - } - - fn to_tokens(self) -> Vec<crate::tt::TokenTree> { - self - } +/// Wraps `TokenTreesView` with a delimiter (a subtree, but without allocating). +pub struct WithDelimiter<'a> { + pub delimiter: crate::tt::Delimiter, + pub token_trees: crate::tt::TokenTreesView<'a>, } -impl IntoTt for crate::tt::Subtree { - fn to_subtree(self, _: Span) -> crate::tt::Subtree { - self +impl ToTokenTree for WithDelimiter<'_> { + fn to_tokens(self, span: Span, builder: &mut TopSubtreeBuilder) { + builder.open(self.delimiter.kind, self.delimiter.open); + self.token_trees.to_tokens(span, builder); + builder.close(self.delimiter.close); } +} - fn to_tokens(self) -> Vec<crate::tt::TokenTree> { - vec![crate::tt::TokenTree::Subtree(self)] +impl ToTokenTree for crate::tt::TokenTreesView<'_> { + fn to_tokens(self, _: Span, builder: &mut TopSubtreeBuilder) { + builder.extend_with_tt(self); } } -pub trait ToTokenTree { - fn to_token(self, span: Span) -> crate::tt::TokenTree; +impl ToTokenTree for crate::tt::SubtreeView<'_> { + fn to_tokens(self, _: Span, builder: &mut TopSubtreeBuilder) { + builder.extend_with_tt(self.as_token_trees()); + } } -impl ToTokenTree for crate::tt::TokenTree { - fn to_token(self, _: Span) -> crate::tt::TokenTree { - self +impl ToTokenTree for crate::tt::TopSubtree { + fn to_tokens(self, _: Span, builder: &mut TopSubtreeBuilder) { + builder.extend_tt_dangerous(self.0); } } -impl ToTokenTree for crate::tt::Subtree { - fn to_token(self, _: Span) -> crate::tt::TokenTree { - self.into() +impl ToTokenTree for crate::tt::TtElement<'_> { + fn to_tokens(self, _: Span, builder: &mut TopSubtreeBuilder) { + match self { + crate::tt::TtElement::Leaf(leaf) => builder.push(leaf.clone()), + crate::tt::TtElement::Subtree(subtree, subtree_iter) => { + builder.extend_tt_dangerous( + std::iter::once(crate::tt::TokenTree::Subtree(subtree.clone())) + .chain(subtree_iter.remaining().flat_tokens().iter().cloned()), + ); + } + } } } @@ -194,18 +184,17 @@ macro_rules! impl_to_to_tokentrees { ($($span:ident: $ty:ty => $this:ident $im:block;)*) => { $( impl ToTokenTree for $ty { - fn to_token($this, $span: Span) -> crate::tt::TokenTree { + fn to_tokens($this, $span: Span, builder: &mut TopSubtreeBuilder) { let leaf: crate::tt::Leaf = $im.into(); - leaf.into() + builder.push(leaf); } } )* } } - impl<T: ToTokenTree + Clone> ToTokenTree for &T { - fn to_token(self, span: Span) -> crate::tt::TokenTree { - self.clone().to_token(span) + fn to_tokens(self, span: Span, builder: &mut TopSubtreeBuilder) { + self.clone().to_tokens(span, builder); } } @@ -316,18 +305,15 @@ mod tests { // } let struct_name = mk_ident("Foo"); let fields = [mk_ident("name"), mk_ident("id")]; - let fields = fields - .iter() - .flat_map(|it| quote!(DUMMY =>#it: self.#it.clone(), ).token_trees.into_vec()); - - let list = crate::tt::Subtree { - delimiter: crate::tt::Delimiter { - kind: crate::tt::DelimiterKind::Brace, - open: DUMMY, - close: DUMMY, - }, - token_trees: fields.collect(), - }; + let fields = fields.iter().map(|it| quote!(DUMMY =>#it: self.#it.clone(), )); + + let mut builder = tt::TopSubtreeBuilder::new(crate::tt::Delimiter { + kind: crate::tt::DelimiterKind::Brace, + open: DUMMY, + close: DUMMY, + }); + fields.for_each(|field| builder.extend_with_tt(field.view().as_token_trees())); + let list = builder.build(); let quoted = quote! {DUMMY => impl Clone for #struct_name { |