diff options
-rw-r--r-- | askama_shared/src/generator.rs | 10 | ||||
-rw-r--r-- | askama_shared/src/lib.rs | 43 | ||||
-rw-r--r-- | askama_shared/src/parser.rs | 13 | ||||
-rw-r--r-- | testing/templates/import.html | 2 | ||||
-rw-r--r-- | testing/tests/macro.rs | 12 |
5 files changed, 76 insertions, 4 deletions
diff --git a/askama_shared/src/generator.rs b/askama_shared/src/generator.rs index e92a2c6..e135c13 100644 --- a/askama_shared/src/generator.rs +++ b/askama_shared/src/generator.rs @@ -12,8 +12,8 @@ use std::collections::{HashMap, HashSet}; use syn; -pub fn generate(input: &TemplateInput, nodes: &[Node]) -> String { - Generator::default().build(&State::new(input, nodes)) +pub fn generate(input: &TemplateInput, nodes: &[Node], imported: &HashMap<&str, Macro>) -> String { + Generator::default().build(&State::new(input, nodes, imported)) } struct State<'a> { @@ -26,7 +26,7 @@ struct State<'a> { } impl<'a> State<'a> { - fn new<'n>(input: &'n TemplateInput, nodes: &'n [Node]) -> State<'n> { + fn new<'n>(input: &'n TemplateInput, nodes: &'n [Node], imported: &'n HashMap<&'n str, Macro<'n>>) -> State<'n> { let mut base: Option<&Expr> = None; let mut blocks = Vec::new(); let mut macros = HashMap::new(); @@ -47,6 +47,9 @@ impl<'a> State<'a> { _ => {}, } } + for (name, ref m) in imported { + macros.insert(name, m); + } State { input, nodes, @@ -351,6 +354,7 @@ impl<'a> Generator<'a> { }, Node::Call(ref ws, name, ref args) => self.write_call(state, ws, name, args), Node::Macro(_, _) | + Node::Import(_, _) | Node::Extends(_) => { if let AstLevel::Nested = level { panic!("macro or extend blocks only allowed at the top level"); diff --git a/askama_shared/src/lib.rs b/askama_shared/src/lib.rs index 066faca..a7deaff 100644 --- a/askama_shared/src/lib.rs +++ b/askama_shared/src/lib.rs @@ -21,7 +21,11 @@ mod input; mod parser; use input::Print; +use parser::{Node, Macro}; +use std::borrow::Cow; +use std::collections::HashMap; +use std::path::Path; /// Takes a `syn::DeriveInput` and generates source code for it /// @@ -33,16 +37,53 @@ use input::Print; pub fn build_template(ast: &syn::DeriveInput) -> String { let data = input::TemplateInput::new(ast); let nodes = parser::parse(data.source.as_ref()); + let imports = Imports::new(&nodes, &data.path); + let imported = imports.parse(); if data.meta.print == Print::Ast || data.meta.print == Print::All { println!("{:?}", nodes); } - let code = generator::generate(&data, &nodes); + let code = generator::generate(&data, &nodes, &imported); if data.meta.print == Print::Code || data.meta.print == Print::All { println!("{}", code); } code } + +pub struct Imports<'a> { + pub sources: Vec<Cow<'a, str>> +} + +impl <'a> Imports<'a> { + pub fn new(parent_nodes: &'a [Node], parent_path: &'a Path) -> Imports<'a> { + let sources = parent_nodes.iter().filter_map(|n| { + match *n { + Node::Import(_, ref import_path) => { + let path = path::find_template_from_path(import_path, Some(parent_path)); + let src = path::get_template_source(&path); + Some(Cow::Owned(src)) + }, + _ => None, + } + }).collect(); + Imports { + sources, + } + } + + pub fn parse(&'a self) -> HashMap<&'a str, Macro<'a>> { + self.sources.iter() + .flat_map(|s| parser::parse(s.as_ref())) + .filter_map(|n| { + match n { + Node::Macro(name, m) => Some((name, m)), + _ => None, + }}) + .collect() + } +} + + mod errors { error_chain! { foreign_links { diff --git a/askama_shared/src/parser.rs b/askama_shared/src/parser.rs index ab79a31..083e96b 100644 --- a/askama_shared/src/parser.rs +++ b/askama_shared/src/parser.rs @@ -42,6 +42,7 @@ pub enum Node<'a> { Extends(Expr<'a>), BlockDef(WS, &'a str, Vec<Node<'a>>, WS), Include(WS, &'a str), + Import(WS, &'a str), Macro(&'a str, Macro<'a>), } @@ -388,6 +389,17 @@ named!(block_include<Node>, do_parse!( })) )); +named!(block_import<Node>, do_parse!( + pws: opt!(tag_s!("-")) >> + ws!(tag_s!("import")) >> + name: ws!(expr_str_lit) >> + nws: opt!(tag_s!("-")) >> + (Node::Import(WS(pws.is_some(), nws.is_some()), match name { + Expr::StrLit(s) => s, + _ => panic!("import path must be a string literal"), + })) +)); + named!(block_macro<Node>, do_parse!( pws1: opt!(tag_s!("-")) >> ws!(tag_s!("macro")) >> @@ -420,6 +432,7 @@ named!(block_node<Node>, do_parse!( block_for | block_extends | block_include | + block_import | block_block | block_macro ) >> diff --git a/testing/templates/import.html b/testing/templates/import.html new file mode 100644 index 0000000..87d7969 --- /dev/null +++ b/testing/templates/import.html @@ -0,0 +1,2 @@ +{% import "macro.html" -%} +{%- call thrice(s) %} diff --git a/testing/tests/macro.rs b/testing/tests/macro.rs index 72f578e..25d95d8 100644 --- a/testing/tests/macro.rs +++ b/testing/tests/macro.rs @@ -14,3 +14,15 @@ fn test_macro() { let t = MacroTemplate { s: "foo" }; assert_eq!(t.render().unwrap(), "foo foo foo"); } + +#[derive(Template)] +#[template(path = "import.html")] +struct ImportTemplate<'a> { + s: &'a str, +} + +#[test] +fn test_import() { + let t = ImportTemplate { s: "foo" }; + assert_eq!(t.render().unwrap(), "foo foo foo"); +} |