diff options
Diffstat (limited to '')
-rw-r--r-- | askama_derive/src/lib.rs | 154 | ||||
-rw-r--r-- | askama_shared/Cargo.toml | 1 | ||||
-rw-r--r-- | askama_shared/src/generator.rs (renamed from askama_derive/src/generator.rs) | 39 | ||||
-rw-r--r-- | askama_shared/src/heritage.rs | 111 | ||||
-rw-r--r-- | askama_shared/src/lib.rs | 39 | ||||
-rw-r--r-- | askama_shared/templates/b.html (renamed from askama_derive/templates/b.html) | 0 |
6 files changed, 188 insertions, 156 deletions
diff --git a/askama_derive/src/lib.rs b/askama_derive/src/lib.rs index 0b64057..fcd857d 100644 --- a/askama_derive/src/lib.rs +++ b/askama_derive/src/lib.rs @@ -1,17 +1,13 @@ extern crate proc_macro; -#[macro_use] -extern crate quote; - -mod generator; +use askama_shared::heritage::{Context, Heritage}; use askama_shared::input::{Print, Source, TemplateInput}; -use askama_shared::parser::{parse, Expr, Macro, Node}; -use askama_shared::{read_config_file, Config}; +use askama_shared::parser::{parse, Expr, Node}; +use askama_shared::{generator, get_template_source, read_config_file, Config, Integrations}; use proc_macro::TokenStream; use std::collections::HashMap; -use std::fs; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; #[proc_macro_derive(Template, attributes(template))] pub fn derive_template(input: TokenStream) -> TokenStream { @@ -59,7 +55,7 @@ fn build_template(ast: &syn::DeriveInput) -> String { eprintln!("{:?}", parsed[&input.path]); } - let code = generator::generate(&input, &contexts, &heritage); + let code = generator::generate(&input, &contexts, &heritage, INTEGRATIONS); if input.print == Print::Code || input.print == Print::All { eprintln!("{}", code); } @@ -88,136 +84,10 @@ fn find_used_templates(input: &TemplateInput, map: &mut HashMap<PathBuf, String> } } -pub(crate) struct Heritage<'a> { - root: &'a Context<'a>, - blocks: BlockAncestry<'a>, -} - -impl<'a> Heritage<'a> { - fn new<'n>( - mut ctx: &'n Context<'n>, - contexts: &'n HashMap<&'n PathBuf, Context<'n>>, - ) -> Heritage<'n> { - let mut blocks: BlockAncestry<'n> = ctx - .blocks - .iter() - .map(|(name, def)| (*name, vec![(ctx, *def)])) - .collect(); - - while let Some(ref path) = ctx.extends { - ctx = &contexts[&path]; - for (name, def) in &ctx.blocks { - blocks - .entry(name) - .or_insert_with(|| vec![]) - .push((ctx, def)); - } - } - - Heritage { root: ctx, blocks } - } -} - -type BlockAncestry<'a> = HashMap<&'a str, Vec<(&'a Context<'a>, &'a Node<'a>)>>; - -pub(crate) struct Context<'a> { - nodes: &'a [Node<'a>], - extends: Option<PathBuf>, - blocks: HashMap<&'a str, &'a Node<'a>>, - macros: HashMap<&'a str, &'a Macro<'a>>, - imports: HashMap<&'a str, PathBuf>, -} - -impl<'a> Context<'a> { - fn new<'n>(config: &Config, path: &Path, nodes: &'n [Node<'n>]) -> Context<'n> { - let mut extends = None; - let mut blocks = Vec::new(); - let mut macros = HashMap::new(); - let mut imports = HashMap::new(); - - for n in nodes { - match n { - Node::Extends(Expr::StrLit(extends_path)) => match extends { - Some(_) => panic!("multiple extend blocks found"), - None => { - extends = Some(config.find_template(extends_path, Some(path))); - } - }, - def @ Node::BlockDef(_, _, _, _) => { - blocks.push(def); - } - Node::Macro(name, m) => { - macros.insert(*name, m); - } - Node::Import(_, import_path, scope) => { - let path = config.find_template(import_path, Some(path)); - imports.insert(*scope, path); - } - _ => {} - } - } - - let mut check_nested = 0; - let mut nested_blocks = Vec::new(); - while check_nested < blocks.len() { - if let Node::BlockDef(_, _, ref nodes, _) = blocks[check_nested] { - for n in nodes { - if let def @ Node::BlockDef(_, _, _, _) = n { - nested_blocks.push(def); - } - } - } else { - panic!("non block found in list of blocks"); - } - blocks.append(&mut nested_blocks); - check_nested += 1; - } - - let blocks: HashMap<_, _> = blocks - .iter() - .map(|def| { - if let Node::BlockDef(_, name, _, _) = def { - (*name, *def) - } else { - unreachable!() - } - }) - .collect(); - - Context { - nodes, - extends, - blocks, - macros, - imports, - } - } -} - -#[allow(clippy::match_wild_err_arm)] -fn get_template_source(tpl_path: &Path) -> String { - match fs::read_to_string(tpl_path) { - Err(_) => panic!( - "unable to open template file '{}'", - tpl_path.to_str().unwrap() - ), - Ok(mut source) => { - if source.ends_with('\n') { - let _ = source.pop(); - } - source - } - } -} - -#[cfg(test)] -mod tests { - use super::get_template_source; - use crate::Config; - - #[test] - fn get_source() { - let path = Config::new("").find_template("b.html", None); - assert_eq!(get_template_source(&path), "bar"); - } -} +const INTEGRATIONS: Integrations = Integrations { + actix: cfg!(feature = "actix-web"), + gotham: cfg!(feature = "gotham"), + iron: cfg!(feature = "iron"), + rocket: cfg!(feature = "rocket"), + warp: cfg!(feature = "warp"), +}; diff --git a/askama_shared/Cargo.toml b/askama_shared/Cargo.toml index f82f026..d9faf2f 100644 --- a/askama_shared/Cargo.toml +++ b/askama_shared/Cargo.toml @@ -22,6 +22,7 @@ humansize = { version = "1.1.0", optional = true } # https://github.com/rust-lang/rust/issues/62146 nom = { version = "5", default-features = false, features = ["std"] } num-traits = { version = "0.2.6", optional = true } +proc-macro2 = "1" quote = "1" serde = { version = "1.0", optional = true, features = ["derive"] } serde_derive = { version = "1.0", optional = true } diff --git a/askama_derive/src/generator.rs b/askama_shared/src/generator.rs index a12b1f0..3171c38 100644 --- a/askama_derive/src/generator.rs +++ b/askama_shared/src/generator.rs @@ -1,13 +1,14 @@ -use super::{get_template_source, Context, Heritage}; -use askama_shared::filters; -use askama_shared::input::{Source, TemplateInput}; -use askama_shared::parser::{ +use super::{get_template_source, Integrations}; +use crate::filters; +use crate::heritage::{Context, Heritage}; +use crate::input::{Source, TemplateInput}; +use crate::parser::{ parse, Cond, Expr, MatchParameter, MatchParameters, MatchVariant, Node, Target, When, WS, }; use proc_macro2::Span; -use quote::ToTokens; +use quote::{quote, ToTokens}; use std::collections::{HashMap, HashSet}; use std::path::PathBuf; @@ -15,12 +16,14 @@ use std::{cmp, hash, mem, str}; use syn; -pub(crate) fn generate( +pub fn generate( input: &TemplateInput, contexts: &HashMap<&PathBuf, Context>, heritage: &Option<Heritage>, + integrations: Integrations, ) -> String { - Generator::new(input, contexts, heritage, SetChain::new()).build(&contexts[&input.path]) + Generator::new(input, contexts, heritage, integrations, SetChain::new()) + .build(&contexts[&input.path]) } struct Generator<'a> { @@ -30,6 +33,8 @@ struct Generator<'a> { contexts: &'a HashMap<&'a PathBuf, Context<'a>>, // The heritage contains references to blocks and their ancestry heritage: &'a Option<Heritage<'a>>, + // What integrations need to be generated + integrations: Integrations, // Variables accessible directly from the current scope (not redirected to context) locals: SetChain<'a, &'a str>, // Suffix whitespace from the previous literal. Will be flushed to the @@ -52,12 +57,14 @@ impl<'a> Generator<'a> { input: &'n TemplateInput, contexts: &'n HashMap<&'n PathBuf, Context<'n>>, heritage: &'n Option<Heritage>, + integrations: Integrations, locals: SetChain<'n, &'n str>, ) -> Generator<'n> { Generator { input, contexts, heritage, + integrations, locals, next_ws: None, skip_ws: false, @@ -69,7 +76,13 @@ impl<'a> Generator<'a> { fn child(&mut self) -> Generator { let locals = SetChain::with_parent(&self.locals); - Self::new(self.input, self.contexts, self.heritage, locals) + Self::new( + self.input, + self.contexts, + self.heritage, + self.integrations, + locals, + ) } // Takes a Context and generates the relevant implementations. @@ -83,19 +96,19 @@ impl<'a> Generator<'a> { self.impl_template(ctx, &mut buf); self.impl_display(&mut buf); - if cfg!(feature = "iron") { + if self.integrations.iron { self.impl_modifier_response(&mut buf); } - if cfg!(feature = "rocket") { + if self.integrations.rocket { self.impl_rocket_responder(&mut buf); } - if cfg!(feature = "actix-web") { + if self.integrations.actix { self.impl_actix_web_responder(&mut buf); } - if cfg!(feature = "gotham") { + if self.integrations.gotham { self.impl_gotham_into_response(&mut buf); } - if cfg!(feature = "warp") { + if self.integrations.warp { self.impl_warp_reply(&mut buf); } buf.buf diff --git a/askama_shared/src/heritage.rs b/askama_shared/src/heritage.rs new file mode 100644 index 0000000..97580d5 --- /dev/null +++ b/askama_shared/src/heritage.rs @@ -0,0 +1,111 @@ +use std::collections::HashMap; +use std::path::{Path, PathBuf}; + +use crate::parser::{Expr, Macro, Node}; +use crate::Config; + +pub struct Heritage<'a> { + pub root: &'a Context<'a>, + pub blocks: BlockAncestry<'a>, +} + +impl<'a> Heritage<'a> { + pub fn new<'n>( + mut ctx: &'n Context<'n>, + contexts: &'n HashMap<&'n PathBuf, Context<'n>>, + ) -> Heritage<'n> { + let mut blocks: BlockAncestry<'n> = ctx + .blocks + .iter() + .map(|(name, def)| (*name, vec![(ctx, *def)])) + .collect(); + + while let Some(ref path) = ctx.extends { + ctx = &contexts[&path]; + for (name, def) in &ctx.blocks { + blocks + .entry(name) + .or_insert_with(|| vec![]) + .push((ctx, def)); + } + } + + Heritage { root: ctx, blocks } + } +} + +type BlockAncestry<'a> = HashMap<&'a str, Vec<(&'a Context<'a>, &'a Node<'a>)>>; + +pub struct Context<'a> { + pub nodes: &'a [Node<'a>], + pub extends: Option<PathBuf>, + pub blocks: HashMap<&'a str, &'a Node<'a>>, + pub macros: HashMap<&'a str, &'a Macro<'a>>, + pub imports: HashMap<&'a str, PathBuf>, +} + +impl<'a> Context<'a> { + pub fn new<'n>(config: &Config, path: &Path, nodes: &'n [Node<'n>]) -> Context<'n> { + let mut extends = None; + let mut blocks = Vec::new(); + let mut macros = HashMap::new(); + let mut imports = HashMap::new(); + + for n in nodes { + match n { + Node::Extends(Expr::StrLit(extends_path)) => match extends { + Some(_) => panic!("multiple extend blocks found"), + None => { + extends = Some(config.find_template(extends_path, Some(path))); + } + }, + def @ Node::BlockDef(_, _, _, _) => { + blocks.push(def); + } + Node::Macro(name, m) => { + macros.insert(*name, m); + } + Node::Import(_, import_path, scope) => { + let path = config.find_template(import_path, Some(path)); + imports.insert(*scope, path); + } + _ => {} + } + } + + let mut check_nested = 0; + let mut nested_blocks = Vec::new(); + while check_nested < blocks.len() { + if let Node::BlockDef(_, _, ref nodes, _) = blocks[check_nested] { + for n in nodes { + if let def @ Node::BlockDef(_, _, _, _) = n { + nested_blocks.push(def); + } + } + } else { + panic!("non block found in list of blocks"); + } + blocks.append(&mut nested_blocks); + check_nested += 1; + } + + let blocks: HashMap<_, _> = blocks + .iter() + .map(|def| { + if let Node::BlockDef(_, name, _, _) = def { + (*name, *def) + } else { + unreachable!() + } + }) + .collect(); + + Context { + nodes, + extends, + blocks, + macros, + imports, + } + } +} diff --git a/askama_shared/src/lib.rs b/askama_shared/src/lib.rs index fa4a9a0..0e8664d 100644 --- a/askama_shared/src/lib.rs +++ b/askama_shared/src/lib.rs @@ -15,8 +15,14 @@ pub use askama_escape::MarkupDisplay; mod error; pub use crate::error::{Error, Result}; pub mod filters; +#[doc(hidden)] +pub mod generator; pub mod helpers; +#[doc(hidden)] +pub mod heritage; +#[doc(hidden)] pub mod input; +#[doc(hidden)] pub mod parser; #[derive(Debug)] @@ -240,6 +246,31 @@ where vals.iter().map(|s| s.to_string()).collect() } +#[allow(clippy::match_wild_err_arm)] +pub fn get_template_source(tpl_path: &Path) -> String { + match fs::read_to_string(tpl_path) { + Err(_) => panic!( + "unable to open template file '{}'", + tpl_path.to_str().unwrap() + ), + Ok(mut source) => { + if source.ends_with('\n') { + let _ = source.pop(); + } + source + } + } +} + +#[derive(Clone, Copy, Debug)] +pub struct Integrations { + pub actix: bool, + pub gotham: bool, + pub iron: bool, + pub rocket: bool, + pub warp: bool, +} + static CONFIG_FILE_NAME: &str = "askama.toml"; static DEFAULT_SYNTAX_NAME: &str = "default"; static DEFAULT_ESCAPERS: &[(&[&str], &str)] = &[ @@ -256,6 +287,12 @@ mod tests { use std::path::{Path, PathBuf}; #[test] + fn get_source() { + let path = Config::new("").find_template("b.html", None); + assert_eq!(get_template_source(&path), "bar"); + } + + #[test] fn test_default_config() { let mut root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); root.push("templates"); @@ -293,7 +330,7 @@ mod tests { fn find_relative_nonexistent() { let config = Config::new(""); let root = config.find_template("a.html", None); - config.find_template("b.html", Some(&root)); + config.find_template("c.html", Some(&root)); } #[test] diff --git a/askama_derive/templates/b.html b/askama_shared/templates/b.html index 5716ca5..5716ca5 100644 --- a/askama_derive/templates/b.html +++ b/askama_shared/templates/b.html |