Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Spans to report better error locations #612

Closed
wants to merge 9 commits into from
Closed
49 changes: 29 additions & 20 deletions askama_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@
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 askama_shared::{generator, get_template_source, read_config_file, Config, Integrations};
use proc_macro::TokenStream;
use proc_macro2::Span;

use std::borrow::Cow;
use std::collections::HashMap;
use std::path::PathBuf;

Expand All @@ -19,9 +18,7 @@ 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(),
Err(err) => err.to_compile_error().into(),
}
}

Expand All @@ -32,26 +29,36 @@ pub fn derive_template(input: TokenStream) -> TokenStream {
/// 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)?;
fn build_template(ast: &syn::DeriveInput) -> Result<String, syn::Error> {
let config_toml = read_config_file().map_err(|msg| syn::Error::new(Span::call_site(), msg))?;
let config =
Config::new(&config_toml).map_err(|msg| syn::Error::new(Span::call_site(), msg))?;
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 (source, span) = match &input.source {
Source::Source(s, span) => (s.clone(), *span),
Source::Path(_, span) => {
let s = get_template_source(&input.path).map_err(|msg| syn::Error::new(*span, msg))?;
(s, *span)
}
};

let mut sources = HashMap::new();
find_used_templates(&input, &mut sources, source)?;
find_used_templates(&input, &mut sources, source).map_err(|msg| syn::Error::new(span, msg))?;

let mut parsed = HashMap::new();
for (path, src) in &sources {
parsed.insert(path.as_path(), parse(src, input.syntax)?);
parsed.insert(
path.as_path(),
parse(src, input.syntax).map_err(|msg| syn::Error::new(span, msg))?,
);
}

let mut contexts = HashMap::new();
for (path, nodes) in &parsed {
contexts.insert(*path, Context::new(input.config, path, nodes)?);
contexts.insert(
*path,
Context::new(input.config, path, nodes).map_err(|msg| syn::Error::new(span, msg))?,
);
}

let ctx = &contexts[input.path.as_path()];
Expand All @@ -65,7 +72,8 @@ fn build_template(ast: &syn::DeriveInput) -> Result<String, CompileError> {
eprintln!("{:?}", parsed[input.path.as_path()]);
}

let code = generator::generate(&input, &contexts, heritage.as_ref(), INTEGRATIONS)?;
let code = generator::generate(&input, &contexts, heritage.as_ref(), INTEGRATIONS)
.map_err(|msg| syn::Error::new(span, msg))?;
if input.print == Print::Code || input.print == Print::All {
eprintln!("{}", code);
}
Expand All @@ -76,7 +84,7 @@ fn find_used_templates(
input: &TemplateInput<'_>,
map: &mut HashMap<PathBuf, String>,
source: String,
) -> Result<(), CompileError> {
) -> Result<(), Cow<'static, str>> {
let mut dependency_graph = Vec::new();
let mut check = vec![(input.path.clone(), source)];
while let Some((path, source)) = check.pop() {
Expand All @@ -86,13 +94,14 @@ fn find_used_templates(
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!(
return Err(format!(
"cyclic dependecy in graph {:#?}",
dependency_graph
.iter()
.map(|e| format!("{:#?} --> {:#?}", e.0, e.1))
.collect::<Vec<String>>()
)));
.collect::<Vec<String>>(),
)
.into());
}
dependency_graph.push(dependency_path);
let source = get_template_source(&extends)?;
Expand Down
Loading