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"
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"

View file

@ -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);

View file

@ -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)
})
}