diff options
Diffstat (limited to 'askama_shared/src/generator.rs')
| -rw-r--r-- | askama_shared/src/generator.rs | 216 | 
1 files changed, 119 insertions, 97 deletions
diff --git a/askama_shared/src/generator.rs b/askama_shared/src/generator.rs index 2385784..af7c3e6 100644 --- a/askama_shared/src/generator.rs +++ b/askama_shared/src/generator.rs @@ -1,4 +1,5 @@  use filters; +use input::TemplateInput;  use parser::{self, Cond, Expr, Macro, Node, Target, WS};  use path; @@ -10,53 +11,78 @@ use std::collections::{HashMap, HashSet};  use syn; -pub fn generate(ast: &syn::DeriveInput, path: &Path, nodes: &[Node]) -> String { -    let mut base: Option<&Expr> = None; -    let mut blocks = Vec::new(); -    let mut macros = HashMap::new(); -    for n in nodes.iter() { -        match *n { -            Node::Extends(ref path) => { -                match base { -                    Some(_) => panic!("multiple extend blocks found"), -                    None => { base = Some(path); }, -                } -            }, -            ref def @ Node::BlockDef(_, _, _, _) => { -                blocks.push(def); -            }, -            Node::Macro(name, ref m) => { -                macros.insert(name, m); -            }, -            _ => {}, + +pub fn generate(input: &TemplateInput, nodes: &[Node]) -> String { +    State::new(input, nodes).generate() +} + +struct State<'a> { +    input: &'a TemplateInput<'a>, +    nodes: &'a [Node<'a>], +    blocks: Vec<&'a Node<'a>>, +    macros: MacroMap<'a>, +    trait_name: String, +    derived: bool, +} + +impl<'a> State<'a> { +    fn new<'n>(input: &'n TemplateInput, nodes: &'n [Node]) -> State<'n> { +        let mut base: Option<&Expr> = None; +        let mut blocks = Vec::new(); +        let mut macros = HashMap::new(); +        for n in nodes.iter() { +            match *n { +                Node::Extends(ref path) => { +                    match base { +                        Some(_) => panic!("multiple extend blocks found"), +                        None => { base = Some(path); }, +                    } +                }, +                ref def @ Node::BlockDef(_, _, _, _) => { +                    blocks.push(def); +                }, +                Node::Macro(name, ref m) => { +                    macros.insert(name, m); +                }, +                _ => {}, +            } +        } +        State { +            input, +            nodes, +            blocks, +            macros, +            trait_name: trait_name_for_path(&base, &input.path), +            derived: base.is_some(),          }      } -    let mut gen = Generator::default(¯os); -    if !blocks.is_empty() { -        let trait_name = trait_name_for_path(&base, path); -        if base.is_none() { -            gen.define_trait(&trait_name, &blocks); +    fn generate(&self) -> String { +        let mut gen = Generator::default(); +        if !self.blocks.is_empty() { +            if !self.derived { +                gen.define_trait(&self); +            } else { +                let parent_type = get_parent_type(self.input.ast) +                    .expect("expected field '_parent' in extending template struct"); +                gen.deref_to_parent(&self, &parent_type); +            } + +            let trait_nodes = if !self.derived { Some(&self.nodes[..]) } else { None }; +            gen.impl_trait(&self, trait_nodes); +            gen.impl_template_for_trait(&self);          } else { -            let parent_type = get_parent_type(ast) -                .expect("expected field '_parent' in extending template struct"); -            gen.deref_to_parent(ast, &parent_type); +            gen.impl_template(&self);          } - -        let trait_nodes = if base.is_none() { Some(&nodes[..]) } else { None }; -        gen.impl_trait(ast, &trait_name, &blocks, trait_nodes); -        gen.impl_template_for_trait(ast, base.is_some()); -    } else { -        gen.impl_template(ast, &nodes); -    } -    gen.impl_display(ast); -    if cfg!(feature = "iron") { -        gen.impl_modifier_response(ast); -    } -    if cfg!(feature = "rocket") { -        gen.impl_responder(ast, path); +        gen.impl_display(&self); +        if cfg!(feature = "iron") { +            gen.impl_modifier_response(&self); +        } +        if cfg!(feature = "rocket") { +            gen.impl_responder(&self); +        } +        gen.result()      } -    gen.result()  }  fn trait_name_for_path(base: &Option<&Expr>, path: &Path) -> String { @@ -103,12 +129,11 @@ struct Generator<'a> {      locals: SetChain<'a, &'a str>,      next_ws: Option<&'a str>,      skip_ws: bool, -    macros: &'a MacroMap<'a>,  }  impl<'a> Generator<'a> { -    fn new<'n>(macros: &'n MacroMap, locals: SetChain<'n, &'n str>, indent: u8) -> Generator<'n> { +    fn new<'n>(locals: SetChain<'n, &'n str>, indent: u8) -> Generator<'n> {          Generator {              buf: String::new(),              indent: indent, @@ -116,17 +141,16 @@ impl<'a> Generator<'a> {              locals: locals,              next_ws: None,              skip_ws: false, -            macros: macros,          }      } -    fn default<'n>(macros: &'n MacroMap) -> Generator<'n> { -        Self::new(macros, SetChain::new(), 0) +    fn default<'n>() -> Generator<'n> { +        Self::new(SetChain::new(), 0)      }      fn child<'n>(&'n mut self) -> Generator<'n> {          let locals = SetChain::with_parent(&self.locals); -        Self::new(self.macros, locals, self.indent) +        Self::new(locals, self.indent)      }      /* Helper methods for writing to internal buffer */ @@ -369,8 +393,8 @@ impl<'a> Generator<'a> {          self.writeln("))?;");      } -    fn write_call(&mut self, ws: &WS, name: &str, args: &[Expr]) { -        let def = self.macros.get(name).expect(&format!("macro '{}' not found", name)); +    fn write_call(&mut self, state: &'a State, ws: &WS, name: &str, args: &[Expr]) { +        let def = state.macros.get(name).expect(&format!("macro '{}' not found", name));          self.handle_ws(ws);          self.locals.push();          self.writeln("{"); @@ -382,7 +406,7 @@ impl<'a> Generator<'a> {                  .expect(&format!("macro '{}' takes more than {} arguments", name, i)));              self.writeln(";");          } -        self.handle(&def.nodes); +        self.handle(state, &def.nodes);          self.flush_ws(&def.ws2);          self.writeln("}");          self.locals.pop(); @@ -416,7 +440,7 @@ impl<'a> Generator<'a> {          self.writeln(";");      } -    fn write_cond(&mut self, conds: &'a [Cond], ws: &WS) { +    fn write_cond(&mut self, state: &'a State, conds: &'a [Cond], ws: &WS) {          for (i, &(ref cws, ref cond, ref nodes)) in conds.iter().enumerate() {              self.handle_ws(cws);              match *cond { @@ -436,14 +460,14 @@ impl<'a> Generator<'a> {              }              self.writeln(" {");              self.locals.push(); -            self.handle(nodes); +            self.handle(state, nodes);              self.locals.pop();          }          self.handle_ws(ws);          self.writeln("}");      } -    fn write_loop(&mut self, ws1: &WS, var: &'a Target, iter: &Expr, +    fn write_loop(&mut self, state: &'a State, ws1: &WS, var: &'a Target, iter: &Expr,                    body: &'a [Node], ws2: &WS) {          self.handle_ws(ws1);          self.locals.push(); @@ -457,7 +481,7 @@ impl<'a> Generator<'a> {          self.visit_expr(iter);          self.writeln(").into_iter().enumerate() {"); -        self.handle(body); +        self.handle(state, body);          self.handle_ws(ws2);          self.writeln("}");          self.locals.pop(); @@ -469,8 +493,8 @@ impl<'a> Generator<'a> {          self.prepare_ws(ws2);      } -    fn write_block_defs(&mut self, blocks: &'a [&'a Node]) { -        for b in blocks { +    fn write_block_defs(&mut self, state: &'a State) { +        for b in &state.blocks {              if let &&Node::BlockDef(ref ws1, ref name, ref nodes, ref ws2) = b {                  self.writeln("#[allow(unused_variables)]");                  self.writeln(&format!( @@ -480,7 +504,7 @@ impl<'a> Generator<'a> {                  self.prepare_ws(ws1);                  self.locals.push(); -                self.handle(nodes); +                self.handle(state, nodes);                  self.locals.pop();                  self.flush_ws(ws2); @@ -492,21 +516,21 @@ impl<'a> Generator<'a> {          }      } -    fn handle_include(&mut self, ws: &WS, path: &str) { +    fn handle_include(&mut self, state: &'a State, ws: &WS, path: &str) {          self.prepare_ws(ws);          let path = path::find_template_from_path(&path, None);          let src = path::get_template_source(&path);          let nodes = parser::parse(&src);          let nested = {              let mut gen = self.child(); -            gen.handle(&nodes); +            gen.handle(state, &nodes);              gen.result()          };          self.buf.push_str(&nested);          self.flush_ws(ws);      } -    fn handle(&mut self, nodes: &'a [Node]) { +    fn handle(&mut self, state: &'a State, nodes: &'a [Node]) {          for n in nodes {              match *n {                  Node::Lit(lws, val, rws) => { self.write_lit(lws, val, rws); } @@ -515,18 +539,18 @@ impl<'a> Generator<'a> {                  Node::LetDecl(ref ws, ref var) => { self.write_let_decl(ws, var); },                  Node::Let(ref ws, ref var, ref val) => { self.write_let(ws, var, val); },                  Node::Cond(ref conds, ref ws) => { -                    self.write_cond(conds, ws); +                    self.write_cond(state, conds, ws);                  },                  Node::Loop(ref ws1, ref var, ref iter, ref body, ref ws2) => { -                    self.write_loop(ws1, var, iter, body, ws2); +                    self.write_loop(state, ws1, var, iter, body, ws2);                  },                  Node::BlockDef(ref ws1, name, _, ref ws2) => {                      self.write_block(ws1, name, ws2);                  },                  Node::Include(ref ws, ref path) => { -                    self.handle_include(ws, path); +                    self.handle_include(state, ws, path);                  }, -                Node::Call(ref ws, name, ref args) => self.write_call(ws, name, args), +                Node::Call(ref ws, name, ref args) => self.write_call(state, ws, name, args),                  Node::Macro(_, _) |                  Node::Extends(_) => {},              } @@ -535,11 +559,11 @@ impl<'a> Generator<'a> {      // Writes header for the `impl` for `TraitFromPathName` or `Template`      // for the given context struct. -    fn write_header(&mut self, ast: &syn::DeriveInput, target: &str, extra_anno: &[&str]) { +    fn write_header(&mut self, state: &'a State, target: &str, extra_anno: &[&str]) {          let mut full_anno = Tokens::new();          let mut orig_anno = Tokens::new(); -        let need_anno = ast.generics.lifetimes.len() > 0 || -                        ast.generics.ty_params.len() > 0 || +        let need_anno = state.input.ast.generics.lifetimes.len() > 0 || +                        state.input.ast.generics.ty_params.len() > 0 ||                          extra_anno.len() > 0;          if need_anno {              full_anno.append("<"); @@ -547,7 +571,7 @@ impl<'a> Generator<'a> {          }          let (mut full_sep, mut orig_sep) = (false, false); -        for lt in &ast.generics.lifetimes { +        for lt in &state.input.ast.generics.lifetimes {              if full_sep {                  full_anno.append(",");              } @@ -568,7 +592,7 @@ impl<'a> Generator<'a> {              full_sep = true;          } -        for param in &ast.generics.ty_params { +        for param in &state.input.ast.generics.ty_params {              if full_sep {                  full_anno.append(",");              } @@ -589,18 +613,18 @@ impl<'a> Generator<'a> {          }          let mut where_clause = Tokens::new(); -        ast.generics.where_clause.to_tokens(&mut where_clause); +        state.input.ast.generics.where_clause.to_tokens(&mut where_clause);          self.writeln(&format!("impl{} {} for {}{}{} {{", -                              full_anno.as_str(), target, ast.ident.as_ref(), +                              full_anno.as_str(), target, state.input.ast.ident.as_ref(),                                orig_anno.as_str(), where_clause.as_str()));      }      // Implement `Template` for the given context struct. -    fn impl_template(&mut self, ast: &syn::DeriveInput, nodes: &'a [Node]) { -        self.write_header(ast, "::askama::Template", &vec![]); +    fn impl_template(&mut self, state: &'a State) { +        self.write_header(state, "::askama::Template", &vec![]);          self.writeln("fn render_into(&self, writer: &mut ::std::fmt::Write) -> \                        ::askama::Result<()> {"); -        self.handle(nodes); +        self.handle(state, state.nodes);          self.flush_ws(&WS(false, false));          self.writeln("Ok(())");          self.writeln("}"); @@ -608,8 +632,8 @@ impl<'a> Generator<'a> {      }      // Implement `Display` for the given context struct. -    fn impl_display(&mut self, ast: &syn::DeriveInput) { -        self.write_header(ast, "::std::fmt::Display", &vec![]); +    fn impl_display(&mut self, state: &'a State) { +        self.write_header(state, "::std::fmt::Display", &vec![]);          self.writeln("fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {");          self.writeln("self.render_into(f).map_err(|_| ::std::fmt::Error {})");          self.writeln("}"); @@ -617,8 +641,8 @@ impl<'a> Generator<'a> {      }      // Implement `Deref<Parent>` for an inheriting context struct. -    fn deref_to_parent(&mut self, ast: &syn::DeriveInput, parent_type: &syn::Ty) { -        self.write_header(ast, "::std::ops::Deref", &vec![]); +    fn deref_to_parent(&mut self, state: &'a State, parent_type: &syn::Ty) { +        self.write_header(state, "::std::ops::Deref", &vec![]);          let mut tokens = Tokens::new();          parent_type.to_tokens(&mut tokens);          self.writeln(&format!("type Target = {};", tokens.as_str())); @@ -629,19 +653,18 @@ impl<'a> Generator<'a> {      }      // Implement `TraitFromPathName` for the given context struct. -    fn impl_trait(&mut self, ast: &syn::DeriveInput, trait_name: &str, -                  blocks: &'a [&'a Node], nodes: Option<&'a [Node]>) { -        self.write_header(ast, &trait_name, &vec![]); -        self.write_block_defs(blocks); +    fn impl_trait(&mut self, state: &'a State, nodes: Option<&'a [Node]>) { +        self.write_header(state, &state.trait_name, &vec![]); +        self.write_block_defs(state);          self.writeln("#[allow(unused_variables)]");          self.writeln(&format!(              "fn render_trait_into(&self, timpl: &{}, writer: &mut ::std::fmt::Write) \               -> ::askama::Result<()> {{", -            trait_name)); +            state.trait_name));          if let Some(nodes) = nodes { -            self.handle(nodes); +            self.handle(state, nodes);              self.flush_ws(&WS(false, false));          } else {              self.writeln("self._parent.render_trait_into(self, writer)?;"); @@ -654,11 +677,11 @@ impl<'a> Generator<'a> {      }      // Implement `Template` for templates that implement a template trait. -    fn impl_template_for_trait(&mut self, ast: &syn::DeriveInput, derived: bool) { -        self.write_header(ast, "::askama::Template", &vec![]); +    fn impl_template_for_trait(&mut self, state: &'a State) { +        self.write_header(state, "::askama::Template", &vec![]);          self.writeln("fn render_into(&self, writer: &mut ::std::fmt::Write) \                        -> ::askama::Result<()> {"); -        if derived { +        if state.derived {              self.writeln("self._parent.render_trait_into(self, writer)?;");          } else {              self.writeln("self.render_trait_into(self, writer)?;"); @@ -669,19 +692,19 @@ impl<'a> Generator<'a> {      }      // Defines the `TraitFromPathName` trait. -    fn define_trait(&mut self, trait_name: &str, blocks: &'a [&'a Node]) { -        self.writeln(&format!("trait {} {{", &trait_name)); -        self.write_block_defs(blocks); +    fn define_trait(&mut self, state: &'a State) { +        self.writeln(&format!("trait {} {{", state.trait_name)); +        self.write_block_defs(state);          self.writeln(&format!(              "fn render_trait_into(&self, timpl: &{}, writer: &mut ::std::fmt::Write) \               -> ::askama::Result<()>;", -            trait_name)); +            state.trait_name));          self.writeln("}");      }      // Implement iron's Modifier<Response> if enabled -    fn impl_modifier_response(&mut self, ast: &syn::DeriveInput) { -        self.write_header(ast, "::askama::iron::Modifier<::askama::iron::Response>", &vec![]); +    fn impl_modifier_response(&mut self, state: &'a State) { +        self.write_header(state, "::askama::iron::Modifier<::askama::iron::Response>", &vec![]);          self.writeln("fn modify(self, res: &mut ::askama::iron::Response) {");          self.writeln("res.body = Some(Box::new(self.render().unwrap().into_bytes()));");          self.writeln("}"); @@ -689,8 +712,8 @@ impl<'a> Generator<'a> {      }      // Implement Rocket's `Responder`. -    fn impl_responder(&mut self, ast: &syn::DeriveInput, path: &Path) { -        self.write_header(ast, "::askama::rocket::Responder<'r>", &vec!["'r"]); +    fn impl_responder(&mut self, state: &'a State) { +        self.write_header(state, "::askama::rocket::Responder<'r>", &vec!["'r"]);          self.writeln("fn respond_to(self, _: &::askama::rocket::Request) \                        -> ::std::result::Result<\                           ::askama::rocket::Response<'r>, ::askama::rocket::Status> {"); @@ -699,7 +722,7 @@ impl<'a> Generator<'a> {          self.writeln("::askama::rocket::Response::build()");          self.indent(); -        let ext = match path.extension() { +        let ext = match state.input.path.extension() {              Some(s) => s.to_str().unwrap(),              None => "txt",          }; @@ -716,7 +739,6 @@ impl<'a> Generator<'a> {      fn result(self) -> String {          self.buf      } -  }  struct SetChain<'a, T: 'a> where T: cmp::Eq + hash::Hash {  | 
