aboutsummaryrefslogtreecommitdiffstats
path: root/askama_shared
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--askama_shared/src/derive.rs106
-rw-r--r--askama_shared/src/generator.rs110
-rw-r--r--askama_shared/src/lib.rs3
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;