mirror of
https://github.com/askama-rs/askama.git
synced 2025-09-30 22:41:13 +00:00
Reorganize code order in askama_derive modules
This commit is contained in:
parent
946e8c7587
commit
d40f5a3ea6
@ -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()
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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)]
|
||||
|
Loading…
x
Reference in New Issue
Block a user