summaryrefslogtreecommitdiffstats
path: root/vendor/askama_derive/src/lib.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /vendor/askama_derive/src/lib.rs
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/askama_derive/src/lib.rs')
-rw-r--r--vendor/askama_derive/src/lib.rs121
1 files changed, 121 insertions, 0 deletions
diff --git a/vendor/askama_derive/src/lib.rs b/vendor/askama_derive/src/lib.rs
new file mode 100644
index 000000000..35070fe80
--- /dev/null
+++ b/vendor/askama_derive/src/lib.rs
@@ -0,0 +1,121 @@
+#![deny(elided_lifetimes_in_paths)]
+
+use askama_shared::heritage::{Context, Heritage};
+use askama_shared::input::{Print, Source, TemplateInput};
+use askama_shared::parser::{parse, Expr, Node};
+use askama_shared::{
+ generator, get_template_source, read_config_file, CompileError, Config, Integrations,
+};
+use proc_macro::TokenStream;
+use proc_macro2::Span;
+
+use std::collections::HashMap;
+use std::path::PathBuf;
+
+#[proc_macro_derive(Template, attributes(template))]
+pub fn derive_template(input: TokenStream) -> TokenStream {
+ let ast: syn::DeriveInput = syn::parse(input).unwrap();
+ match build_template(&ast) {
+ Ok(source) => source.parse().unwrap(),
+ Err(e) => syn::Error::new(Span::call_site(), e)
+ .to_compile_error()
+ .into(),
+ }
+}
+
+/// 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, 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];
+ 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]);
+ }
+
+ let code = generator::generate(&input, &contexts, &heritage, INTEGRATIONS)?;
+ 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(CompileError::String(format!(
+ "cyclic dependecy in graph {:#?}",
+ dependency_graph
+ .iter()
+ .map(|e| format!("{:#?} --> {:#?}", e.0, e.1))
+ .collect::<Vec<String>>()
+ )));
+ }
+ 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(())
+}
+
+const INTEGRATIONS: Integrations = Integrations {
+ actix: cfg!(feature = "actix-web"),
+ axum: cfg!(feature = "axum"),
+ gotham: cfg!(feature = "gotham"),
+ iron: cfg!(feature = "iron"),
+ mendes: cfg!(feature = "mendes"),
+ rocket: cfg!(feature = "rocket"),
+ tide: cfg!(feature = "tide"),
+ warp: cfg!(feature = "warp"),
+};