From a10130a9ac1188066dba08158ae093a4816a4aed Mon Sep 17 00:00:00 2001
From: Byte <28512568+HeapUnderfl0w@users.noreply.github.com>
Date: Sun, 12 Jul 2020 11:42:14 +0000
Subject: [PATCH] Switch to 3rd party `quote` macro (#201)

* Add proc_macro2 and quote dependencies

* Completly switch over to proc_macro2 where possible

* Remove unessesary ::from casts

* Remove pendantic cast that i missed

* Make Builder::push_tokens accept TokenStream

* Remove stray commented out code

* Reword unclear comment on `Span` to a todo item

* Move comment closer to its intended line

* Use into instead of explicit conversion
---
 maud_macros/Cargo.toml      |  2 ++
 maud_macros/src/generate.rs | 52 ++++++++++++++++++++-----------------
 maud_macros/src/lib.rs      | 25 +++++++++---------
 3 files changed, 43 insertions(+), 36 deletions(-)

diff --git a/maud_macros/Cargo.toml b/maud_macros/Cargo.toml
index 6245a0b..32bb0da 100644
--- a/maud_macros/Cargo.toml
+++ b/maud_macros/Cargo.toml
@@ -14,6 +14,8 @@ edition = "2018"
 syn = "1.0.8"
 matches = "0.1.8"
 maud_htmlescape = { version = "0.17.0", path = "../maud_htmlescape" }
+quote = "1.0.7"
+proc-macro2 = "1.0.18"
 
 [lib]
 name = "maud_macros"
diff --git a/maud_macros/src/generate.rs b/maud_macros/src/generate.rs
index f4c9d45..1261050 100644
--- a/maud_macros/src/generate.rs
+++ b/maud_macros/src/generate.rs
@@ -1,15 +1,15 @@
 use matches::matches;
 use maud_htmlescape::Escaper;
-use proc_macro::{
+use proc_macro2::{
     Delimiter,
     Group,
     Literal,
-    quote,
     Span,
     Ident,
     TokenStream,
     TokenTree,
 };
+use quote::quote;
 
 use crate::ast::*;
 
@@ -48,10 +48,10 @@ impl Generator {
                 }
             },
             Markup::Literal { content, .. } => build.push_escaped(&content),
-            Markup::Symbol { symbol } => self.name(symbol, build),
-            Markup::Splice { expr, .. } => build.push_tokens(self.splice(expr)),
-            Markup::Element { name, attrs, body } => self.element(name, attrs, body, build),
-            Markup::Let { tokens, .. } => build.push_tokens(tokens),
+            Markup::Symbol { symbol } => self.name(symbol.into(), build),
+            Markup::Splice { expr, .. } => build.push_tokens(self.splice(expr.into())),
+            Markup::Element { name, attrs, body } => self.element(name.into(), attrs, body, build),
+            Markup::Let { tokens, .. } => build.push_tokens(tokens.into()),
             Markup::Special { segments } => {
                 for segment in segments {
                     build.push_tokens(self.special(segment));
@@ -64,8 +64,9 @@ impl Generator {
                         .map(|arm| self.match_arm(arm))
                         .collect();
                     let mut body = TokenTree::Group(Group::new(Delimiter::Brace, body));
-                    body.set_span(arms_span);
-                    quote!($head $body)
+                    body.set_span(arms_span.into());
+                    let head: TokenStream = head.into();
+                    quote!(#head #body)
                 });
             },
         }
@@ -75,7 +76,7 @@ impl Generator {
         let mut build = self.builder();
         self.markups(markups, &mut build);
         let mut block = TokenTree::Group(Group::new(Delimiter::Brace, build.finish()));
-        block.set_span(outer_span);
+        block.set_span(outer_span.into());
         TokenStream::from(block)
     }
 
@@ -89,7 +90,7 @@ impl Generator {
                 }
             }
             impl<T: maud::Render> Render for T {}
-            $expr.__maud_render_to(&mut $output_ident);
+            #expr.__maud_render_to(&mut #output_ident);
         })
     }
 
@@ -122,23 +123,23 @@ impl Generator {
             match attr_type {
                 AttrType::Normal { value } => {
                     build.push_str(" ");
-                    self.name(name, build);
+                    self.name(name.into(), build);
                     build.push_str("=\"");
                     self.markup(value, build);
                     build.push_str("\"");
                 },
                 AttrType::Empty { toggler: None } => {
                     build.push_str(" ");
-                    self.name(name, build);
+                    self.name(name.into(), build);
                 },
                 AttrType::Empty { toggler: Some(toggler) } => {
                     let head = desugar_toggler(toggler);
                     build.push_tokens({
                         let mut build = self.builder();
                         build.push_str(" ");
-                        self.name(name, &mut build);
+                        self.name(name.into(), &mut build);
                         let body = build.finish();
-                        quote!($head { $body })
+                        quote!(#head { #body })
                     })
                 },
             }
@@ -147,12 +148,14 @@ impl Generator {
 
     fn special(&self, Special { head, body, .. }: Special) -> TokenStream {
         let body = self.block(body);
-        quote!($head $body)
+        let head: TokenStream = head.into();
+        quote!(#head #body)
     }
 
     fn match_arm(&self, MatchArm { head, body }: MatchArm) -> TokenStream {
         let body = self.block(body);
-        quote!($head $body)
+        let head: TokenStream = head.into();
+        quote!(#head #body)
     }
 }
 
@@ -201,15 +204,15 @@ fn desugar_classes_or_ids(
         };
         let head = desugar_toggler(toggler);
         markups.push(Markup::Special {
-            segments: vec![Special { at_span: Span::call_site(), head, body }],
+            segments: vec![Special { at_span: proc_macro::Span::call_site(), head: head.into(), body }],
         });
     }
     Some(Attribute {
-        name: TokenStream::from(TokenTree::Ident(Ident::new(attr_name, Span::call_site()))),
+        name: TokenStream::from(TokenTree::Ident(Ident::new(attr_name, Span::call_site()))).into(),
         attr_type: AttrType::Normal {
             value: Markup::Block(Block {
                 markups,
-                outer_span: Span::call_site(),
+                outer_span: proc_macro::Span::call_site(),
             }),
         },
     })
@@ -228,7 +231,8 @@ fn prepend_leading_space(name: Markup, leading_space: &mut bool) -> Vec<Markup>
     markups
 }
 
-fn desugar_toggler(Toggler { mut cond, cond_span }: Toggler) -> TokenStream {
+fn desugar_toggler(Toggler { cond, cond_span }: Toggler) -> TokenStream {
+    let mut cond = TokenStream::from(cond);
     // If the expression contains an opening brace `{`,
     // wrap it in parentheses to avoid parse errors
     if cond.clone().into_iter().any(|token| match token {
@@ -236,10 +240,10 @@ fn desugar_toggler(Toggler { mut cond, cond_span }: Toggler) -> TokenStream {
         _ => false,
     }) {
         let mut wrapped_cond = TokenTree::Group(Group::new(Delimiter::Parenthesis, cond));
-        wrapped_cond.set_span(cond_span);
+        wrapped_cond.set_span(cond_span.into());
         cond = TokenStream::from(wrapped_cond);
     }
-    quote!(if $cond)
+    quote!(if #cond)
 }
 
 ////////////////////////////////////////////////////////
@@ -268,7 +272,7 @@ impl Builder {
         Escaper::new(&mut self.tail).write_str(string).unwrap();
     }
 
-    fn push_tokens<T: IntoIterator<Item=TokenTree>>(&mut self, tokens: T) {
+    fn push_tokens(&mut self, tokens: TokenStream) {
         self.cut();
         self.tokens.extend(tokens);
     }
@@ -280,7 +284,7 @@ impl Builder {
         let push_str_expr = {
             let output_ident = self.output_ident.clone();
             let string = TokenTree::Literal(Literal::string(&self.tail));
-            quote!($output_ident.push_str($string);)
+            quote!(#output_ident.push_str(#string);)
         };
         self.tail.clear();
         self.tokens.extend(push_str_expr);
diff --git a/maud_macros/src/lib.rs b/maud_macros/src/lib.rs
index 08c683f..2cae866 100644
--- a/maud_macros/src/lib.rs
+++ b/maud_macros/src/lib.rs
@@ -15,38 +15,39 @@ mod ast;
 mod generate;
 mod parse;
 
-use proc_macro::{Literal, Span, Ident, TokenStream, TokenTree};
-use proc_macro::quote;
+use proc_macro2::{Literal, Ident, TokenStream, TokenTree};
+use quote::quote;
 
 type ParseResult<T> = Result<T, ()>;
 
 #[proc_macro]
-pub fn html(input: TokenStream) -> TokenStream {
-    expand(input)
+pub fn html(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    expand(input.into()).into()
 }
 
 #[proc_macro]
-pub fn html_debug(input: TokenStream) -> TokenStream {
-    let expr = expand(input);
+pub fn html_debug(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let expr = expand(input.into());
     println!("expansion:\n{}", expr);
-    expr
+    expr.into()
 }
 
 fn expand(input: TokenStream) -> TokenStream {
-    let output_ident = TokenTree::Ident(Ident::new("__maud_output", Span::mixed_site()));
+    // TODO: call `proc_macro2::Span::mixed_site()` directly when Rust 1.45 is stable
+    let output_ident = TokenTree::Ident(Ident::new("__maud_output", proc_macro::Span::mixed_site().into()));
     // Heuristic: the size of the resulting markup tends to correlate with the
     // code size of the template itself
     let size_hint = input.to_string().len();
     let size_hint = TokenTree::Literal(Literal::u64_unsuffixed(size_hint as u64));
-    let markups = match parse::parse(input) {
+    let markups = match parse::parse(input.into()) {
         Ok(markups) => markups,
         Err(()) => Vec::new(),
     };
     let stmts = generate::generate(markups, output_ident.clone());
     quote!({
         extern crate maud;
-        let mut $output_ident = ::std::string::String::with_capacity($size_hint);
-        $stmts
-        maud::PreEscaped($output_ident)
+        let mut #output_ident = ::std::string::String::with_capacity(#size_hint);
+        #stmts
+        maud::PreEscaped(#output_ident)
     })
 }