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
This commit is contained in:
parent
ee82847d8f
commit
a10130a9ac
3 changed files with 43 additions and 36 deletions
maud_macros
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue