aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--askama_derive/src/generator.rs164
-rw-r--r--askama_derive/src/lib.rs68
-rw-r--r--askama_derive/src/path.rs42
3 files changed, 137 insertions, 137 deletions
diff --git a/askama_derive/src/generator.rs b/askama_derive/src/generator.rs
index 6c53a89..de2e6f2 100644
--- a/askama_derive/src/generator.rs
+++ b/askama_derive/src/generator.rs
@@ -9,6 +9,88 @@ use std::collections::HashSet;
use syn;
+pub fn generate(ast: &syn::DeriveInput, path: &str, mut nodes: Vec<Node>) -> String {
+ let mut base: Option<Expr> = None;
+ let mut blocks = Vec::new();
+ let mut block_names = Vec::new();
+ let mut content = Vec::new();
+ for n in nodes.drain(..) {
+ match n {
+ Node::Extends(path) => {
+ match base {
+ Some(_) => panic!("multiple extend blocks found"),
+ None => { base = Some(path); },
+ }
+ },
+ Node::BlockDef(ws1, name, _, ws2) => {
+ blocks.push(n);
+ block_names.push(name);
+ content.push(Node::Block(ws1, name, ws2));
+ },
+ _ => { content.push(n); },
+ }
+ }
+
+ let mut locals = HashSet::new();
+ let mut gen = Generator::default(&mut locals);
+ if !blocks.is_empty() {
+ let trait_name = trait_name_for_path(&base, path);
+ if base.is_none() {
+ gen.define_trait(&trait_name, &block_names);
+ } else {
+ gen.deref_to_parent(ast, &get_parent_type(ast).unwrap());
+ }
+
+ let trait_nodes = if base.is_none() { Some(&content[..]) } 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, &content);
+ }
+ gen.result()
+}
+
+fn trait_name_for_path(base: &Option<Expr>, path: &str) -> String {
+ let rooted_path = match *base {
+ Some(Expr::StrLit(user_path)) => {
+ path::find_template_from_path(user_path, Some(path))
+ },
+ _ => {
+ let mut path_buf = PathBuf::new();
+ path_buf.push(&path);
+ path_buf
+ },
+ };
+
+ let mut res = String::new();
+ res.push_str("TraitFrom");
+ for c in rooted_path.to_string_lossy().chars() {
+ if c.is_alphanumeric() {
+ res.push(c);
+ } else {
+ res.push_str(&format!("{:x}", c as u32));
+ }
+ }
+ res
+}
+
+fn get_parent_type(ast: &syn::DeriveInput) -> Option<&syn::Ty> {
+ match ast.body {
+ syn::Body::Struct(ref data) => {
+ data.fields().iter().filter_map(|f| {
+ f.ident.as_ref().and_then(|name| {
+ if name.as_ref() == "_parent" {
+ Some(&f.ty)
+ } else {
+ None
+ }
+ })
+ })
+ },
+ _ => panic!("derive(Template) only works for struct items"),
+ }.next()
+}
+
struct Generator<'a> {
buf: String,
indent: u8,
@@ -451,85 +533,3 @@ impl<'a> Generator<'a> {
}
}
-
-fn trait_name_for_path(base: &Option<Expr>, path: &str) -> String {
- let rooted_path = match *base {
- Some(Expr::StrLit(user_path)) => {
- path::find_template_from_path(user_path, Some(path))
- },
- _ => {
- let mut path_buf = PathBuf::new();
- path_buf.push(&path);
- path_buf
- },
- };
-
- let mut res = String::new();
- res.push_str("TraitFrom");
- for c in rooted_path.to_string_lossy().chars() {
- if c.is_alphanumeric() {
- res.push(c);
- } else {
- res.push_str(&format!("{:x}", c as u32));
- }
- }
- res
-}
-
-fn get_parent_type(ast: &syn::DeriveInput) -> Option<&syn::Ty> {
- match ast.body {
- syn::Body::Struct(ref data) => {
- data.fields().iter().filter_map(|f| {
- f.ident.as_ref().and_then(|name| {
- if name.as_ref() == "_parent" {
- Some(&f.ty)
- } else {
- None
- }
- })
- })
- },
- _ => panic!("derive(Template) only works for struct items"),
- }.next()
-}
-
-pub fn generate(ast: &syn::DeriveInput, path: &str, mut nodes: Vec<Node>) -> String {
- let mut base: Option<Expr> = None;
- let mut blocks = Vec::new();
- let mut block_names = Vec::new();
- let mut content = Vec::new();
- for n in nodes.drain(..) {
- match n {
- Node::Extends(path) => {
- match base {
- Some(_) => panic!("multiple extend blocks found"),
- None => { base = Some(path); },
- }
- },
- Node::BlockDef(ws1, name, _, ws2) => {
- blocks.push(n);
- block_names.push(name);
- content.push(Node::Block(ws1, name, ws2));
- },
- _ => { content.push(n); },
- }
- }
-
- let mut locals = HashSet::new();
- let mut gen = Generator::default(&mut locals);
- if !blocks.is_empty() {
- let trait_name = trait_name_for_path(&base, path);
- if base.is_none() {
- gen.define_trait(&trait_name, &block_names);
- } else {
- gen.deref_to_parent(ast, &get_parent_type(ast).unwrap());
- }
-
- let trait_nodes = if base.is_none() { Some(&content[..]) } 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, &content);
- }
- gen.result()
-}
diff --git a/askama_derive/src/lib.rs b/askama_derive/src/lib.rs
index 5ee5a4c..ad0e218 100644
--- a/askama_derive/src/lib.rs
+++ b/askama_derive/src/lib.rs
@@ -10,10 +10,36 @@ mod generator;
mod parser;
mod path;
-// Holds metadata for the template, based on the `template()` attribute.
-struct TemplateMeta {
- path: String,
- print: String,
+#[proc_macro_derive(Template, attributes(template))]
+pub fn derive_template(input: TokenStream) -> TokenStream {
+ let ast = syn::parse_derive_input(&input.to_string()).unwrap();
+ match ast.body {
+ syn::Body::Struct(ref data) => data,
+ _ => panic!("#[derive(Template)] can only be used with structs"),
+ };
+ build_template(&ast).parse().unwrap()
+}
+
+/// Takes a `syn::DeriveInput` and generates source code for it
+///
+/// Reads the metadata from the `template()` attribute to get the template
+/// metadata, then fetches the source from the filesystem. The source is
+/// parsed, and the parse tree is fed to the code generator. Will print
+/// the parse tree and/or generated source according to the `print` key's
+/// value as passed to the `template()` attribute.
+fn build_template(ast: &syn::DeriveInput) -> String {
+ let meta = get_template_meta(ast);
+ let path = path::find_template_from_path(&meta.path, None);
+ let src = path::get_template_source(&path);
+ let nodes = parser::parse(&src);
+ if meta.print == "ast" || meta.print == "all" {
+ println!("{:?}", nodes);
+ }
+ let code = generator::generate(ast, &meta.path, nodes);
+ if meta.print == "code" || meta.print == "all" {
+ println!("{}", code);
+ }
+ code
}
// Returns a `TemplateMeta` based on the `template()` attribute data found
@@ -57,34 +83,8 @@ fn get_template_meta(ast: &syn::DeriveInput) -> TemplateMeta {
TemplateMeta { path: path.unwrap(), print: print }
}
-/// Takes a `syn::DeriveInput` and generates source code for it
-///
-/// Reads the metadata from the `template()` attribute to get the template
-/// metadata, then fetches the source from the filesystem. The source is
-/// parsed, and the parse tree is fed to the code generator. Will print
-/// the parse tree and/or generated source according to the `print` key's
-/// value as passed to the `template()` attribute.
-fn build_template(ast: &syn::DeriveInput) -> String {
- let meta = get_template_meta(ast);
- let path = path::find_template_from_path(&meta.path, None);
- let src = path::get_template_source(&path);
- let nodes = parser::parse(&src);
- if meta.print == "ast" || meta.print == "all" {
- println!("{:?}", nodes);
- }
- let code = generator::generate(ast, &meta.path, nodes);
- if meta.print == "code" || meta.print == "all" {
- println!("{}", code);
- }
- code
-}
-
-#[proc_macro_derive(Template, attributes(template))]
-pub fn derive_template(input: TokenStream) -> TokenStream {
- let ast = syn::parse_derive_input(&input.to_string()).unwrap();
- match ast.body {
- syn::Body::Struct(ref data) => data,
- _ => panic!("#[derive(Template)] can only be used with structs"),
- };
- build_template(&ast).parse().unwrap()
+// Holds metadata for the template, based on the `template()` attribute.
+struct TemplateMeta {
+ path: String,
+ print: String,
}
diff --git a/askama_derive/src/path.rs b/askama_derive/src/path.rs
index b51f5f3..03ab20d 100644
--- a/askama_derive/src/path.rs
+++ b/askama_derive/src/path.rs
@@ -3,10 +3,23 @@ use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
-fn template_dir() -> PathBuf {
- let mut path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
- path.push("templates");
- path
+pub fn get_template_source(tpl_path: &Path) -> String {
+ let mut path = template_dir();
+ path.push(tpl_path);
+ let mut f = match File::open(&path) {
+ Err(_) => {
+ let msg = format!("unable to open template file '{}'",
+ &path.to_str().unwrap());
+ panic!(msg);
+ },
+ Ok(f) => f,
+ };
+ let mut s = String::new();
+ f.read_to_string(&mut s).unwrap();
+ if s.ends_with('\n') {
+ let _ = s.pop();
+ }
+ s
}
pub fn find_template_from_path<'a>(path: &str, start_at: Option<&str>) -> PathBuf {
@@ -33,23 +46,10 @@ pub fn find_template_from_path<'a>(path: &str, start_at: Option<&str>) -> PathBu
}
}
-pub fn get_template_source(tpl_path: &Path) -> String {
- let mut path = template_dir();
- path.push(tpl_path);
- let mut f = match File::open(&path) {
- Err(_) => {
- let msg = format!("unable to open template file '{}'",
- &path.to_str().unwrap());
- panic!(msg);
- },
- Ok(f) => f,
- };
- let mut s = String::new();
- f.read_to_string(&mut s).unwrap();
- if s.ends_with('\n') {
- let _ = s.pop();
- }
- s
+fn template_dir() -> PathBuf {
+ let mut path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
+ path.push("templates");
+ path
}
#[cfg(test)]