From 85f8a2669986c244f3a87951555795a546e45dde Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 16 Nov 2018 06:50:36 -0800 Subject: [PATCH] Add expression interpolation with `#{expr}` One annoyance I frequently run into with the `quote!` macro is that I need to lift out all variable bindings that are being interpolated. For example I'll often do: let name = &foo.name; let abi = &foo.abi; quote! { extern #abi fn #name() { /* ... */ } } but I've recently had the idea that in addition to lighteight `#name` interpolation there's also available syntax (I believe) to support expression interpolation as well, implemented in this PR. The above snippet could now be rewritten as: quote! { extern #{foo.abi} fn #{foo.name} { /* ... */ } } --- src/lib.rs | 9 +++++++++ tests/test.rs | 16 ++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 8f0203b..71b3b01 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -254,6 +254,10 @@ pub mod __rt { /// [`ToTokens`]: trait.ToTokens.html /// [Syn]: https://github.com/dtolnay/syn /// +/// You can also use `#{expr}` to interpolate an arbitrary expression, so long +/// as the result implements the [`ToTokens`] trait. For example `#{1 + 3}` will +/// interpolate `4i32`. +/// /// Repetition is done using `#(...)*` or `#(...),*` again similar to /// `macro_rules!`. This iterates through the elements of any variable /// interpolated within the repetition and inserts a copy of the repetition body @@ -579,6 +583,11 @@ macro_rules! quote_each_token { quote_each_token!($tokens $span $($rest)*); }; + ($tokens:ident $span:ident # { $val:expr } $($rest:tt)*) => { + $crate::ToTokens::to_tokens(&$val, &mut $tokens); + quote_each_token!($tokens $span $($rest)*); + }; + ($tokens:ident $span:ident # $first:ident $($rest:tt)*) => { $crate::ToTokens::to_tokens(&$first, &mut $tokens); quote_each_token!($tokens $span $($rest)*); diff --git a/tests/test.rs b/tests/test.rs index f832da5..5833bce 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -293,3 +293,19 @@ fn test_append_tokens() { a.append_all(b); assert_eq!("a b", a.to_string()); } + +#[test] +fn whole_exprs() { + let x = X; + let tokens = quote!(#{x}); + assert_eq!(tokens.to_string(), "X"); + + let tokens = quote!(#{1 + 2}); + assert_eq!(tokens.to_string(), "3i32"); + + struct A { b: X } + let x = A { b: X }; + + let tokens = quote!(#{x.b}); + assert_eq!(tokens.to_string(), "X"); +}