diff options
Diffstat (limited to 'askama_derive/src')
-rw-r--r-- | askama_derive/src/generator.rs | 71 | ||||
-rw-r--r-- | askama_derive/src/lib.rs | 40 |
2 files changed, 60 insertions, 51 deletions
diff --git a/askama_derive/src/generator.rs b/askama_derive/src/generator.rs index 2f6c875..6f17db2 100644 --- a/askama_derive/src/generator.rs +++ b/askama_derive/src/generator.rs @@ -1,4 +1,4 @@ -use super::{get_template_source, Context}; +use super::{get_template_source, Context, Heritage}; use input::TemplateInput; use parser::{self, Cond, Expr, MatchParameter, MatchVariant, Node, Target, When, WS}; use shared::filters; @@ -13,8 +13,12 @@ use std::{cmp, hash, str}; use syn; -pub(crate) fn generate(input: &TemplateInput, contexts: &HashMap<&PathBuf, Context>) -> String { - Generator::new(input, contexts, SetChain::new()).build(&contexts[&input.path]) +pub(crate) fn generate( + input: &TemplateInput, + contexts: &HashMap<&PathBuf, Context>, + heritage: &Option<Heritage>, +) -> String { + Generator::new(input, contexts, heritage, SetChain::new()).build(&contexts[&input.path]) } struct Generator<'a> { @@ -22,6 +26,8 @@ struct Generator<'a> { input: &'a TemplateInput<'a>, // All contexts, keyed by the package-relative template path contexts: &'a HashMap<&'a PathBuf, Context<'a>>, + // The heritage contains references to blocks and their ancestry + heritage: &'a Option<Heritage<'a>>, // 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 @@ -42,11 +48,13 @@ impl<'a> Generator<'a> { fn new<'n>( input: &'n TemplateInput, contexts: &'n HashMap<&'n PathBuf, Context<'n>>, + heritage: &'n Option<Heritage>, locals: SetChain<'n, &'n str>, ) -> Generator<'n> { Generator { input, contexts, + heritage, locals, next_ws: None, skip_ws: false, @@ -57,24 +65,20 @@ impl<'a> Generator<'a> { fn child(&mut self) -> Generator { let locals = SetChain::with_parent(&self.locals); - Self::new(self.input, self.contexts, locals) + Self::new(self.input, self.contexts, self.heritage, locals) } // Takes a Context and generates the relevant implementations. fn build(mut self, ctx: &'a Context) -> String { let mut buf = Buffer::new(0); - let heritage = if !ctx.blocks.is_empty() { + if !ctx.blocks.is_empty() { if let Some(parent) = self.input.parent { self.deref_to_parent(&mut buf, parent); } - let heritage = Heritage::new(ctx, self.contexts); - self.trait_blocks(&heritage, &mut buf); - Some(heritage) - } else { - None + self.trait_blocks(&mut buf); }; - self.impl_template(ctx, &heritage, &mut buf); + self.impl_template(ctx, &mut buf); self.impl_display(&mut buf); if cfg!(feature = "iron") { self.impl_modifier_response(&mut buf); @@ -89,19 +93,14 @@ impl<'a> Generator<'a> { } // Implement `Template` for the given context struct. - fn impl_template( - &mut self, - ctx: &'a Context, - heritage: &Option<Heritage<'a>>, - buf: &mut Buffer, - ) { + fn impl_template(&mut self, ctx: &'a Context, buf: &mut Buffer) { self.write_header(buf, "::askama::Template", None); buf.writeln( "fn render_into(&self, writer: &mut ::std::fmt::Write) -> \ ::askama::Result<()> {", ); - if let Some(heritage) = heritage { + if let Some(heritage) = self.heritage { self.handle(heritage.root, heritage.root.nodes, buf, AstLevel::Top); } else { self.handle(ctx, &ctx.nodes, buf, AstLevel::Top); @@ -121,9 +120,12 @@ impl<'a> Generator<'a> { buf.writeln("}"); } - fn trait_blocks(&mut self, heritage: &Heritage<'a>, buf: &mut Buffer) { + fn trait_blocks(&mut self, buf: &mut Buffer) { let trait_name = format!("{}Blocks", self.input.ast.ident); let mut methods = vec![]; + let heritage = self.heritage + .as_ref() + .expect("need heritage for blocks trait"); self.write_header(buf, &trait_name, None); for blocks in heritage.blocks.values() { @@ -1021,35 +1023,6 @@ where } } -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 } - } -} - #[derive(Clone, PartialEq)] enum AstLevel { Top, @@ -1066,5 +1039,3 @@ enum DisplayWrap { } impl Copy for DisplayWrap {} - -type BlockAncestry<'a> = HashMap<&'a str, Vec<(&'a Context<'a>, &'a Node<'a>)>>; diff --git a/askama_derive/src/lib.rs b/askama_derive/src/lib.rs index 1fd7570..f977b19 100644 --- a/askama_derive/src/lib.rs +++ b/askama_derive/src/lib.rs @@ -53,11 +53,18 @@ fn build_template(ast: &syn::DeriveInput) -> String { contexts.insert(*path, Context::new(&input.config, path, nodes)); } + let ctx = &contexts[&input.path]; + let heritage = if !ctx.blocks.is_empty() { + Some(Heritage::new(ctx, &contexts)) + } else { + None + }; + if input.print == Print::Ast || input.print == Print::All { println!("{:?}", parsed[&input.path]); } - let code = generator::generate(&input, &contexts); + let code = generator::generate(&input, &contexts, &heritage); if input.print == Print::Code || input.print == Print::All { println!("{}", code); } @@ -86,6 +93,37 @@ 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>, |