#![deny(elided_lifetimes_in_paths)] #![deny(unreachable_pub)] use std::borrow::Cow; use std::fmt; use proc_macro::TokenStream; use proc_macro2::Span; use parser::ParseError; mod config; mod generator; mod heritage; mod input; #[proc_macro_derive(Template, attributes(template))] pub fn derive_template(input: TokenStream) -> TokenStream { let ast = syn::parse::(input).unwrap(); match generator::build_template(&ast) { Ok(source) => source.parse().unwrap(), Err(e) => e.into_compile_error(), } } #[derive(Debug, Clone)] struct CompileError { msg: Cow<'static, str>, span: Span, } impl CompileError { fn new>>(s: S, span: Span) -> Self { Self { msg: s.into(), span, } } fn into_compile_error(self) -> TokenStream { syn::Error::new(self.span, self.msg) .to_compile_error() .into() } } impl std::error::Error for CompileError {} impl fmt::Display for CompileError { #[inline] fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.write_str(&self.msg) } } impl From for CompileError { #[inline] fn from(e: ParseError) -> Self { Self::new(e.to_string(), Span::call_site()) } } impl From<&'static str> for CompileError { #[inline] fn from(s: &'static str) -> Self { Self::new(s, Span::call_site()) } } impl From for CompileError { #[inline] fn from(s: String) -> Self { Self::new(s, Span::call_site()) } } // This is used by the code generator to decide whether a named filter is part of // Askama or should refer to a local `filters` module. It should contain all the // filters shipped with Askama, even the optional ones (since optional inclusion // in the const vector based on features seems impossible right now). const BUILT_IN_FILTERS: &[&str] = &[ "abs", "capitalize", "center", "e", "escape", "filesizeformat", "fmt", "format", "indent", "into_f64", "into_isize", "join", "linebreaks", "linebreaksbr", "paragraphbreaks", "lower", "lowercase", "safe", "trim", "truncate", "upper", "uppercase", "urlencode", "urlencode_strict", "wordcount", // optional features, reserve the names anyway: "json", "markdown", "yaml", ];