aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--askama_derive/src/lib.rs154
-rw-r--r--askama_shared/Cargo.toml1
-rw-r--r--askama_shared/src/generator.rs (renamed from askama_derive/src/generator.rs)39
-rw-r--r--askama_shared/src/heritage.rs111
-rw-r--r--askama_shared/src/lib.rs39
-rw-r--r--askama_shared/templates/b.html (renamed from askama_derive/templates/b.html)0
6 files changed, 188 insertions, 156 deletions
diff --git a/askama_derive/src/lib.rs b/askama_derive/src/lib.rs
index 0b64057..fcd857d 100644
--- a/askama_derive/src/lib.rs
+++ b/askama_derive/src/lib.rs
@@ -1,17 +1,13 @@
extern crate proc_macro;
-#[macro_use]
-extern crate quote;
-
-mod generator;
+use askama_shared::heritage::{Context, Heritage};
use askama_shared::input::{Print, Source, TemplateInput};
-use askama_shared::parser::{parse, Expr, Macro, Node};
-use askama_shared::{read_config_file, Config};
+use askama_shared::parser::{parse, Expr, Node};
+use askama_shared::{generator, get_template_source, read_config_file, Config, Integrations};
use proc_macro::TokenStream;
use std::collections::HashMap;
-use std::fs;
-use std::path::{Path, PathBuf};
+use std::path::PathBuf;
#[proc_macro_derive(Template, attributes(template))]
pub fn derive_template(input: TokenStream) -> TokenStream {
@@ -59,7 +55,7 @@ fn build_template(ast: &syn::DeriveInput) -> String {
eprintln!("{:?}", parsed[&input.path]);
}
- let code = generator::generate(&input, &contexts, &heritage);
+ let code = generator::generate(&input, &contexts, &heritage, INTEGRATIONS);
if input.print == Print::Code || input.print == Print::All {
eprintln!("{}", code);
}
@@ -88,136 +84,10 @@ fn find_used_templates(input: &TemplateInput, map: &mut HashMap<PathBuf, String>
}
}
-pub(crate) struct Heritage<'a> {
- root: &'a Context<'a>,
- blocks: BlockAncestry<'a>,
-}
-
-impl<'a> Heritage<'a> {
- fn new<'n>(
- mut ctx: &'n Context<'n>,
- contexts: &'n HashMap<&'n PathBuf, Context<'n>>,
- ) -> Heritage<'n> {
- let mut blocks: BlockAncestry<'n> = ctx
- .blocks
- .iter()
- .map(|(name, def)| (*name, vec![(ctx, *def)]))
- .collect();
-
- while let Some(ref path) = ctx.extends {
- ctx = &contexts[&path];
- for (name, def) in &ctx.blocks {
- blocks
- .entry(name)
- .or_insert_with(|| vec![])
- .push((ctx, def));
- }
- }
-
- Heritage { root: ctx, blocks }
- }
-}
-
-type BlockAncestry<'a> = HashMap<&'a str, Vec<(&'a Context<'a>, &'a Node<'a>)>>;
-
-pub(crate) struct Context<'a> {
- nodes: &'a [Node<'a>],
- extends: Option<PathBuf>,
- blocks: HashMap<&'a str, &'a Node<'a>>,
- macros: HashMap<&'a str, &'a Macro<'a>>,
- imports: HashMap<&'a str, PathBuf>,
-}
-
-impl<'a> Context<'a> {
- fn new<'n>(config: &Config, path: &Path, nodes: &'n [Node<'n>]) -> Context<'n> {
- let mut extends = None;
- let mut blocks = Vec::new();
- let mut macros = HashMap::new();
- let mut imports = HashMap::new();
-
- for n in nodes {
- match n {
- Node::Extends(Expr::StrLit(extends_path)) => match extends {
- Some(_) => panic!("multiple extend blocks found"),
- None => {
- extends = Some(config.find_template(extends_path, Some(path)));
- }
- },
- def @ Node::BlockDef(_, _, _, _) => {
- blocks.push(def);
- }
- Node::Macro(name, m) => {
- macros.insert(*name, m);
- }
- Node::Import(_, import_path, scope) => {
- let path = config.find_template(import_path, Some(path));
- imports.insert(*scope, path);
- }
- _ => {}
- }
- }
-
- let mut check_nested = 0;
- let mut nested_blocks = Vec::new();
- while check_nested < blocks.len() {
- if let Node::BlockDef(_, _, ref nodes, _) = blocks[check_nested] {
- for n in nodes {
- if let def @ Node::BlockDef(_, _, _, _) = n {
- nested_blocks.push(def);
- }
- }
- } else {
- panic!("non block found in list of blocks");
- }
- blocks.append(&mut nested_blocks);
- check_nested += 1;
- }
-
- let blocks: HashMap<_, _> = blocks
- .iter()
- .map(|def| {
- if let Node::BlockDef(_, name, _, _) = def {
- (*name, *def)
- } else {
- unreachable!()
- }
- })
- .collect();
-
- Context {
- nodes,
- extends,
- blocks,
- macros,
- imports,
- }
- }
-}
-
-#[allow(clippy::match_wild_err_arm)]
-fn get_template_source(tpl_path: &Path) -> String {
- match fs::read_to_string(tpl_path) {
- Err(_) => panic!(
- "unable to open template file '{}'",
- tpl_path.to_str().unwrap()
- ),
- Ok(mut source) => {
- if source.ends_with('\n') {
- let _ = source.pop();
- }
- source
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::get_template_source;
- use crate::Config;
-
- #[test]
- fn get_source() {
- let path = Config::new("").find_template("b.html", None);
- assert_eq!(get_template_source(&path), "bar");
- }
-}
+const INTEGRATIONS: Integrations = Integrations {
+ actix: cfg!(feature = "actix-web"),
+ gotham: cfg!(feature = "gotham"),
+ iron: cfg!(feature = "iron"),
+ rocket: cfg!(feature = "rocket"),
+ warp: cfg!(feature = "warp"),
+};
diff --git a/askama_shared/Cargo.toml b/askama_shared/Cargo.toml
index f82f026..d9faf2f 100644
--- a/askama_shared/Cargo.toml
+++ b/askama_shared/Cargo.toml
@@ -22,6 +22,7 @@ humansize = { version = "1.1.0", optional = true }
# https://github.com/rust-lang/rust/issues/62146
nom = { version = "5", default-features = false, features = ["std"] }
num-traits = { version = "0.2.6", optional = true }
+proc-macro2 = "1"
quote = "1"
serde = { version = "1.0", optional = true, features = ["derive"] }
serde_derive = { version = "1.0", optional = true }
diff --git a/askama_derive/src/generator.rs b/askama_shared/src/generator.rs
index a12b1f0..3171c38 100644
--- a/askama_derive/src/generator.rs
+++ b/askama_shared/src/generator.rs
@@ -1,13 +1,14 @@
-use super::{get_template_source, Context, Heritage};
-use askama_shared::filters;
-use askama_shared::input::{Source, TemplateInput};
-use askama_shared::parser::{
+use super::{get_template_source, Integrations};
+use crate::filters;
+use crate::heritage::{Context, Heritage};
+use crate::input::{Source, TemplateInput};
+use crate::parser::{
parse, Cond, Expr, MatchParameter, MatchParameters, MatchVariant, Node, Target, When, WS,
};
use proc_macro2::Span;
-use quote::ToTokens;
+use quote::{quote, ToTokens};
use std::collections::{HashMap, HashSet};
use std::path::PathBuf;
@@ -15,12 +16,14 @@ use std::{cmp, hash, mem, str};
use syn;
-pub(crate) fn generate(
+pub fn generate(
input: &TemplateInput,
contexts: &HashMap<&PathBuf, Context>,
heritage: &Option<Heritage>,
+ integrations: Integrations,
) -> String {
- Generator::new(input, contexts, heritage, SetChain::new()).build(&contexts[&input.path])
+ Generator::new(input, contexts, heritage, integrations, SetChain::new())
+ .build(&contexts[&input.path])
}
struct Generator<'a> {
@@ -30,6 +33,8 @@ struct Generator<'a> {
contexts: &'a HashMap<&'a PathBuf, Context<'a>>,
// The heritage contains references to blocks and their ancestry
heritage: &'a Option<Heritage<'a>>,
+ // What integrations need to be generated
+ integrations: Integrations,
// Variables accessible directly from the current scope (not redirected to context)
locals: SetChain<'a, &'a str>,
// Suffix whitespace from the previous literal. Will be flushed to the
@@ -52,12 +57,14 @@ impl<'a> Generator<'a> {
input: &'n TemplateInput,
contexts: &'n HashMap<&'n PathBuf, Context<'n>>,
heritage: &'n Option<Heritage>,
+ integrations: Integrations,
locals: SetChain<'n, &'n str>,
) -> Generator<'n> {
Generator {
input,
contexts,
heritage,
+ integrations,
locals,
next_ws: None,
skip_ws: false,
@@ -69,7 +76,13 @@ impl<'a> Generator<'a> {
fn child(&mut self) -> Generator {
let locals = SetChain::with_parent(&self.locals);
- Self::new(self.input, self.contexts, self.heritage, locals)
+ Self::new(
+ self.input,
+ self.contexts,
+ self.heritage,
+ self.integrations,
+ locals,
+ )
}
// Takes a Context and generates the relevant implementations.
@@ -83,19 +96,19 @@ impl<'a> Generator<'a> {
self.impl_template(ctx, &mut buf);
self.impl_display(&mut buf);
- if cfg!(feature = "iron") {
+ if self.integrations.iron {
self.impl_modifier_response(&mut buf);
}
- if cfg!(feature = "rocket") {
+ if self.integrations.rocket {
self.impl_rocket_responder(&mut buf);
}
- if cfg!(feature = "actix-web") {
+ if self.integrations.actix {
self.impl_actix_web_responder(&mut buf);
}
- if cfg!(feature = "gotham") {
+ if self.integrations.gotham {
self.impl_gotham_into_response(&mut buf);
}
- if cfg!(feature = "warp") {
+ if self.integrations.warp {
self.impl_warp_reply(&mut buf);
}
buf.buf
diff --git a/askama_shared/src/heritage.rs b/askama_shared/src/heritage.rs
new file mode 100644
index 0000000..97580d5
--- /dev/null
+++ b/askama_shared/src/heritage.rs
@@ -0,0 +1,111 @@
+use std::collections::HashMap;
+use std::path::{Path, PathBuf};
+
+use crate::parser::{Expr, Macro, Node};
+use crate::Config;
+
+pub struct Heritage<'a> {
+ pub root: &'a Context<'a>,
+ pub blocks: BlockAncestry<'a>,
+}
+
+impl<'a> Heritage<'a> {
+ pub fn new<'n>(
+ mut ctx: &'n Context<'n>,
+ contexts: &'n HashMap<&'n PathBuf, Context<'n>>,
+ ) -> Heritage<'n> {
+ let mut blocks: BlockAncestry<'n> = ctx
+ .blocks
+ .iter()
+ .map(|(name, def)| (*name, vec![(ctx, *def)]))
+ .collect();
+
+ while let Some(ref path) = ctx.extends {
+ ctx = &contexts[&path];
+ for (name, def) in &ctx.blocks {
+ blocks
+ .entry(name)
+ .or_insert_with(|| vec![])
+ .push((ctx, def));
+ }
+ }
+
+ Heritage { root: ctx, blocks }
+ }
+}
+
+type BlockAncestry<'a> = HashMap<&'a str, Vec<(&'a Context<'a>, &'a Node<'a>)>>;
+
+pub struct Context<'a> {
+ pub nodes: &'a [Node<'a>],
+ pub extends: Option<PathBuf>,
+ pub blocks: HashMap<&'a str, &'a Node<'a>>,
+ pub macros: HashMap<&'a str, &'a Macro<'a>>,
+ pub imports: HashMap<&'a str, PathBuf>,
+}
+
+impl<'a> Context<'a> {
+ pub fn new<'n>(config: &Config, path: &Path, nodes: &'n [Node<'n>]) -> Context<'n> {
+ let mut extends = None;
+ let mut blocks = Vec::new();
+ let mut macros = HashMap::new();
+ let mut imports = HashMap::new();
+
+ for n in nodes {
+ match n {
+ Node::Extends(Expr::StrLit(extends_path)) => match extends {
+ Some(_) => panic!("multiple extend blocks found"),
+ None => {
+ extends = Some(config.find_template(extends_path, Some(path)));
+ }
+ },
+ def @ Node::BlockDef(_, _, _, _) => {
+ blocks.push(def);
+ }
+ Node::Macro(name, m) => {
+ macros.insert(*name, m);
+ }
+ Node::Import(_, import_path, scope) => {
+ let path = config.find_template(import_path, Some(path));
+ imports.insert(*scope, path);
+ }
+ _ => {}
+ }
+ }
+
+ let mut check_nested = 0;
+ let mut nested_blocks = Vec::new();
+ while check_nested < blocks.len() {
+ if let Node::BlockDef(_, _, ref nodes, _) = blocks[check_nested] {
+ for n in nodes {
+ if let def @ Node::BlockDef(_, _, _, _) = n {
+ nested_blocks.push(def);
+ }
+ }
+ } else {
+ panic!("non block found in list of blocks");
+ }
+ blocks.append(&mut nested_blocks);
+ check_nested += 1;
+ }
+
+ let blocks: HashMap<_, _> = blocks
+ .iter()
+ .map(|def| {
+ if let Node::BlockDef(_, name, _, _) = def {
+ (*name, *def)
+ } else {
+ unreachable!()
+ }
+ })
+ .collect();
+
+ Context {
+ nodes,
+ extends,
+ blocks,
+ macros,
+ imports,
+ }
+ }
+}
diff --git a/askama_shared/src/lib.rs b/askama_shared/src/lib.rs
index fa4a9a0..0e8664d 100644
--- a/askama_shared/src/lib.rs
+++ b/askama_shared/src/lib.rs
@@ -15,8 +15,14 @@ pub use askama_escape::MarkupDisplay;
mod error;
pub use crate::error::{Error, Result};
pub mod filters;
+#[doc(hidden)]
+pub mod generator;
pub mod helpers;
+#[doc(hidden)]
+pub mod heritage;
+#[doc(hidden)]
pub mod input;
+#[doc(hidden)]
pub mod parser;
#[derive(Debug)]
@@ -240,6 +246,31 @@ where
vals.iter().map(|s| s.to_string()).collect()
}
+#[allow(clippy::match_wild_err_arm)]
+pub fn get_template_source(tpl_path: &Path) -> String {
+ match fs::read_to_string(tpl_path) {
+ Err(_) => panic!(
+ "unable to open template file '{}'",
+ tpl_path.to_str().unwrap()
+ ),
+ Ok(mut source) => {
+ if source.ends_with('\n') {
+ let _ = source.pop();
+ }
+ source
+ }
+ }
+}
+
+#[derive(Clone, Copy, Debug)]
+pub struct Integrations {
+ pub actix: bool,
+ pub gotham: bool,
+ pub iron: bool,
+ pub rocket: bool,
+ pub warp: bool,
+}
+
static CONFIG_FILE_NAME: &str = "askama.toml";
static DEFAULT_SYNTAX_NAME: &str = "default";
static DEFAULT_ESCAPERS: &[(&[&str], &str)] = &[
@@ -256,6 +287,12 @@ mod tests {
use std::path::{Path, PathBuf};
#[test]
+ fn get_source() {
+ let path = Config::new("").find_template("b.html", None);
+ assert_eq!(get_template_source(&path), "bar");
+ }
+
+ #[test]
fn test_default_config() {
let mut root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
root.push("templates");
@@ -293,7 +330,7 @@ mod tests {
fn find_relative_nonexistent() {
let config = Config::new("");
let root = config.find_template("a.html", None);
- config.find_template("b.html", Some(&root));
+ config.find_template("c.html", Some(&root));
}
#[test]
diff --git a/askama_derive/templates/b.html b/askama_shared/templates/b.html
index 5716ca5..5716ca5 100644
--- a/askama_derive/templates/b.html
+++ b/askama_shared/templates/b.html