diff options
Diffstat (limited to '')
| -rw-r--r-- | askama_shared/src/derive.rs | 106 | ||||
| -rw-r--r-- | askama_shared/src/generator.rs | 110 | ||||
| -rw-r--r-- | askama_shared/src/lib.rs | 3 | 
3 files changed, 100 insertions, 119 deletions
| diff --git a/askama_shared/src/derive.rs b/askama_shared/src/derive.rs deleted file mode 100644 index b8f0a2f..0000000 --- a/askama_shared/src/derive.rs +++ /dev/null @@ -1,106 +0,0 @@ -use std::collections::HashMap; -use std::path::PathBuf; - -use proc_macro2::TokenStream; - -use crate::heritage::{Context, Heritage}; -use crate::input::{Print, Source, TemplateInput}; -use crate::parser::{parse, Expr, Node}; -use crate::{generator, get_template_source, read_config_file, CompileError, Config}; - -/// The actual implementation for askama_derive::Template -#[doc(hidden)] -pub fn derive_template(input: TokenStream) -> TokenStream { -    let ast: syn::DeriveInput = syn::parse2(input).unwrap(); -    match build_template(&ast) { -        Ok(source) => source.parse().unwrap(), -        Err(e) => e.into_compile_error(), -    } -} - -/// 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) -> Result<String, CompileError> { -    let config_toml = read_config_file()?; -    let config = Config::new(&config_toml)?; -    let input = TemplateInput::new(ast, &config)?; -    let source: String = match input.source { -        Source::Source(ref s) => s.clone(), -        Source::Path(_) => get_template_source(&input.path)?, -    }; - -    let mut sources = HashMap::new(); -    find_used_templates(&input, &mut sources, source)?; - -    let mut parsed = HashMap::new(); -    for (path, src) in &sources { -        parsed.insert(path.as_path(), parse(src, input.syntax)?); -    } - -    let mut contexts = HashMap::new(); -    for (path, nodes) in &parsed { -        contexts.insert(*path, Context::new(input.config, path, nodes)?); -    } - -    let ctx = &contexts[input.path.as_path()]; -    let heritage = if !ctx.blocks.is_empty() || ctx.extends.is_some() { -        Some(Heritage::new(ctx, &contexts)) -    } else { -        None -    }; - -    if input.print == Print::Ast || input.print == Print::All { -        eprintln!("{:?}", parsed[input.path.as_path()]); -    } - -    let code = generator::generate(&input, &contexts, heritage.as_ref())?; -    if input.print == Print::Code || input.print == Print::All { -        eprintln!("{}", code); -    } -    Ok(code) -} - -fn find_used_templates( -    input: &TemplateInput<'_>, -    map: &mut HashMap<PathBuf, String>, -    source: String, -) -> Result<(), CompileError> { -    let mut dependency_graph = Vec::new(); -    let mut check = vec![(input.path.clone(), source)]; -    while let Some((path, source)) = check.pop() { -        for n in parse(&source, input.syntax)? { -            match n { -                Node::Extends(Expr::StrLit(extends)) => { -                    let extends = input.config.find_template(extends, Some(&path))?; -                    let dependency_path = (path.clone(), extends.clone()); -                    if dependency_graph.contains(&dependency_path) { -                        return Err(format!( -                            "cyclic dependecy in graph {:#?}", -                            dependency_graph -                                .iter() -                                .map(|e| format!("{:#?} --> {:#?}", e.0, e.1)) -                                .collect::<Vec<String>>() -                        ) -                        .into()); -                    } -                    dependency_graph.push(dependency_path); -                    let source = get_template_source(&extends)?; -                    check.push((extends, source)); -                } -                Node::Import(_, import, _) => { -                    let import = input.config.find_template(import, Some(&path))?; -                    let source = get_template_source(&import)?; -                    check.push((import, source)); -                } -                _ => {} -            } -        } -        map.insert(path, source); -    } -    Ok(()) -} diff --git a/askama_shared/src/generator.rs b/askama_shared/src/generator.rs index f7783af..c9e482d 100644 --- a/askama_shared/src/generator.rs +++ b/askama_shared/src/generator.rs @@ -1,24 +1,112 @@ -use super::{get_template_source, CompileError}; -use crate::filters;  use crate::heritage::{Context, Heritage}; -use crate::input::{Source, TemplateInput}; +use crate::input::{Print, Source, TemplateInput};  use crate::parser::{parse, Cond, CondTest, Expr, Loop, Node, Target, When, Ws}; +use crate::{filters, get_template_source, read_config_file, CompileError, Config}; +use proc_macro2::TokenStream;  use quote::{quote, ToTokens};  use std::collections::HashMap; -use std::path::Path; +use std::path::{Path, PathBuf};  use std::{cmp, hash, mem, str}; -pub(crate) fn generate<S: std::hash::BuildHasher>( -    input: &TemplateInput<'_>, -    contexts: &HashMap<&Path, Context<'_>, S>, -    heritage: Option<&Heritage<'_>>, -) -> Result<String, CompileError> { -    Generator::new(input, contexts, heritage, MapChain::new()) -        .build(&contexts[input.path.as_path()]) +/// The actual implementation for askama_derive::Template +#[doc(hidden)] +pub fn derive_template(input: TokenStream) -> TokenStream { +    let ast: syn::DeriveInput = syn::parse2(input).unwrap(); +    match build_template(&ast) { +        Ok(source) => source.parse().unwrap(), +        Err(e) => e.into_compile_error(), +    } +} + +/// 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) -> Result<String, CompileError> { +    let config_toml = read_config_file()?; +    let config = Config::new(&config_toml)?; +    let input = TemplateInput::new(ast, &config)?; +    let source: String = match input.source { +        Source::Source(ref s) => s.clone(), +        Source::Path(_) => get_template_source(&input.path)?, +    }; + +    let mut sources = HashMap::new(); +    find_used_templates(&input, &mut sources, source)?; + +    let mut parsed = HashMap::new(); +    for (path, src) in &sources { +        parsed.insert(path.as_path(), parse(src, input.syntax)?); +    } + +    let mut contexts = HashMap::new(); +    for (path, nodes) in &parsed { +        contexts.insert(*path, Context::new(input.config, path, nodes)?); +    } + +    let ctx = &contexts[input.path.as_path()]; +    let heritage = if !ctx.blocks.is_empty() || ctx.extends.is_some() { +        Some(Heritage::new(ctx, &contexts)) +    } else { +        None +    }; + +    if input.print == Print::Ast || input.print == Print::All { +        eprintln!("{:?}", parsed[input.path.as_path()]); +    } + +    let code = Generator::new(&input, &contexts, heritage.as_ref(), MapChain::new()) +        .build(&contexts[input.path.as_path()])?; +    if input.print == Print::Code || input.print == Print::All { +        eprintln!("{}", code); +    } +    Ok(code)  } +fn find_used_templates( +    input: &TemplateInput<'_>, +    map: &mut HashMap<PathBuf, String>, +    source: String, +) -> Result<(), CompileError> { +    let mut dependency_graph = Vec::new(); +    let mut check = vec![(input.path.clone(), source)]; +    while let Some((path, source)) = check.pop() { +        for n in parse(&source, input.syntax)? { +            match n { +                Node::Extends(Expr::StrLit(extends)) => { +                    let extends = input.config.find_template(extends, Some(&path))?; +                    let dependency_path = (path.clone(), extends.clone()); +                    if dependency_graph.contains(&dependency_path) { +                        return Err(format!( +                            "cyclic dependecy in graph {:#?}", +                            dependency_graph +                                .iter() +                                .map(|e| format!("{:#?} --> {:#?}", e.0, e.1)) +                                .collect::<Vec<String>>() +                        ) +                        .into()); +                    } +                    dependency_graph.push(dependency_path); +                    let source = get_template_source(&extends)?; +                    check.push((extends, source)); +                } +                Node::Import(_, import, _) => { +                    let import = input.config.find_template(import, Some(&path))?; +                    let source = get_template_source(&import)?; +                    check.push((import, source)); +                } +                _ => {} +            } +        } +        map.insert(path, source); +    } +    Ok(()) +}  struct Generator<'a, S: std::hash::BuildHasher> {      // The template input state: original struct AST and attributes      input: &'a TemplateInput<'a>, diff --git a/askama_shared/src/lib.rs b/askama_shared/src/lib.rs index 61ddb00..81500e1 100644 --- a/askama_shared/src/lib.rs +++ b/askama_shared/src/lib.rs @@ -13,11 +13,10 @@ use proc_macro2::{Span, TokenStream};  #[cfg(feature = "serde")]  use serde::Deserialize; -pub use crate::derive::derive_template; +pub use crate::generator::derive_template;  pub use crate::input::extension_to_mime_type;  pub use askama_escape::MarkupDisplay; -mod derive;  mod error;  pub use crate::error::{Error, Result};  pub mod filters; | 
