Switch to 3rd party quote macro ()

* 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
This commit is contained in:
Byte 2020-07-12 11:42:14 +00:00 committed by GitHub
parent ee82847d8f
commit a10130a9ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 43 additions and 36 deletions

View file

@ -14,6 +14,8 @@ edition = "2018"
syn = "1.0.8" syn = "1.0.8"
matches = "0.1.8" matches = "0.1.8"
maud_htmlescape = { version = "0.17.0", path = "../maud_htmlescape" } maud_htmlescape = { version = "0.17.0", path = "../maud_htmlescape" }
quote = "1.0.7"
proc-macro2 = "1.0.18"
[lib] [lib]
name = "maud_macros" name = "maud_macros"

View file

@ -1,15 +1,15 @@
use matches::matches; use matches::matches;
use maud_htmlescape::Escaper; use maud_htmlescape::Escaper;
use proc_macro::{ use proc_macro2::{
Delimiter, Delimiter,
Group, Group,
Literal, Literal,
quote,
Span, Span,
Ident, Ident,
TokenStream, TokenStream,
TokenTree, TokenTree,
}; };
use quote::quote;
use crate::ast::*; use crate::ast::*;
@ -48,10 +48,10 @@ impl Generator {
} }
}, },
Markup::Literal { content, .. } => build.push_escaped(&content), Markup::Literal { content, .. } => build.push_escaped(&content),
Markup::Symbol { symbol } => self.name(symbol, build), Markup::Symbol { symbol } => self.name(symbol.into(), build),
Markup::Splice { expr, .. } => build.push_tokens(self.splice(expr)), Markup::Splice { expr, .. } => build.push_tokens(self.splice(expr.into())),
Markup::Element { name, attrs, body } => self.element(name, attrs, body, build), Markup::Element { name, attrs, body } => self.element(name.into(), attrs, body, build),
Markup::Let { tokens, .. } => build.push_tokens(tokens), Markup::Let { tokens, .. } => build.push_tokens(tokens.into()),
Markup::Special { segments } => { Markup::Special { segments } => {
for segment in segments { for segment in segments {
build.push_tokens(self.special(segment)); build.push_tokens(self.special(segment));
@ -64,8 +64,9 @@ impl Generator {
.map(|arm| self.match_arm(arm)) .map(|arm| self.match_arm(arm))
.collect(); .collect();
let mut body = TokenTree::Group(Group::new(Delimiter::Brace, body)); let mut body = TokenTree::Group(Group::new(Delimiter::Brace, body));
body.set_span(arms_span); body.set_span(arms_span.into());
quote!($head $body) let head: TokenStream = head.into();
quote!(#head #body)
}); });
}, },
} }
@ -75,7 +76,7 @@ impl Generator {
let mut build = self.builder(); let mut build = self.builder();
self.markups(markups, &mut build); self.markups(markups, &mut build);
let mut block = TokenTree::Group(Group::new(Delimiter::Brace, build.finish())); 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) TokenStream::from(block)
} }
@ -89,7 +90,7 @@ impl Generator {
} }
} }
impl<T: maud::Render> Render for T {} 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 { match attr_type {
AttrType::Normal { value } => { AttrType::Normal { value } => {
build.push_str(" "); build.push_str(" ");
self.name(name, build); self.name(name.into(), build);
build.push_str("=\""); build.push_str("=\"");
self.markup(value, build); self.markup(value, build);
build.push_str("\""); build.push_str("\"");
}, },
AttrType::Empty { toggler: None } => { AttrType::Empty { toggler: None } => {
build.push_str(" "); build.push_str(" ");
self.name(name, build); self.name(name.into(), build);
}, },
AttrType::Empty { toggler: Some(toggler) } => { AttrType::Empty { toggler: Some(toggler) } => {
let head = desugar_toggler(toggler); let head = desugar_toggler(toggler);
build.push_tokens({ build.push_tokens({
let mut build = self.builder(); let mut build = self.builder();
build.push_str(" "); build.push_str(" ");
self.name(name, &mut build); self.name(name.into(), &mut build);
let body = build.finish(); let body = build.finish();
quote!($head { $body }) quote!(#head { #body })
}) })
}, },
} }
@ -147,12 +148,14 @@ impl Generator {
fn special(&self, Special { head, body, .. }: Special) -> TokenStream { fn special(&self, Special { head, body, .. }: Special) -> TokenStream {
let body = self.block(body); 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 { fn match_arm(&self, MatchArm { head, body }: MatchArm) -> TokenStream {
let body = self.block(body); 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); let head = desugar_toggler(toggler);
markups.push(Markup::Special { 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 { 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 { attr_type: AttrType::Normal {
value: Markup::Block(Block { value: Markup::Block(Block {
markups, 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 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 `{`, // If the expression contains an opening brace `{`,
// wrap it in parentheses to avoid parse errors // wrap it in parentheses to avoid parse errors
if cond.clone().into_iter().any(|token| match token { if cond.clone().into_iter().any(|token| match token {
@ -236,10 +240,10 @@ fn desugar_toggler(Toggler { mut cond, cond_span }: Toggler) -> TokenStream {
_ => false, _ => false,
}) { }) {
let mut wrapped_cond = TokenTree::Group(Group::new(Delimiter::Parenthesis, cond)); 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); 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(); 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.cut();
self.tokens.extend(tokens); self.tokens.extend(tokens);
} }
@ -280,7 +284,7 @@ impl Builder {
let push_str_expr = { let push_str_expr = {
let output_ident = self.output_ident.clone(); let output_ident = self.output_ident.clone();
let string = TokenTree::Literal(Literal::string(&self.tail)); let string = TokenTree::Literal(Literal::string(&self.tail));
quote!($output_ident.push_str($string);) quote!(#output_ident.push_str(#string);)
}; };
self.tail.clear(); self.tail.clear();
self.tokens.extend(push_str_expr); self.tokens.extend(push_str_expr);

View file

@ -15,38 +15,39 @@ mod ast;
mod generate; mod generate;
mod parse; mod parse;
use proc_macro::{Literal, Span, Ident, TokenStream, TokenTree}; use proc_macro2::{Literal, Ident, TokenStream, TokenTree};
use proc_macro::quote; use quote::quote;
type ParseResult<T> = Result<T, ()>; type ParseResult<T> = Result<T, ()>;
#[proc_macro] #[proc_macro]
pub fn html(input: TokenStream) -> TokenStream { pub fn html(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
expand(input) expand(input.into()).into()
} }
#[proc_macro] #[proc_macro]
pub fn html_debug(input: TokenStream) -> TokenStream { pub fn html_debug(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let expr = expand(input); let expr = expand(input.into());
println!("expansion:\n{}", expr); println!("expansion:\n{}", expr);
expr expr.into()
} }
fn expand(input: TokenStream) -> TokenStream { 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 // Heuristic: the size of the resulting markup tends to correlate with the
// code size of the template itself // code size of the template itself
let size_hint = input.to_string().len(); let size_hint = input.to_string().len();
let size_hint = TokenTree::Literal(Literal::u64_unsuffixed(size_hint as u64)); 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, Ok(markups) => markups,
Err(()) => Vec::new(), Err(()) => Vec::new(),
}; };
let stmts = generate::generate(markups, output_ident.clone()); let stmts = generate::generate(markups, output_ident.clone());
quote!({ quote!({
extern crate maud; extern crate maud;
let mut $output_ident = ::std::string::String::with_capacity($size_hint); let mut #output_ident = ::std::string::String::with_capacity(#size_hint);
$stmts #stmts
maud::PreEscaped($output_ident) maud::PreEscaped(#output_ident)
}) })
} }