Skip to content

Commit 34764cf

Browse files
committed
fix caller logic
Signed-off-by: Michael Pollind <[email protected]>
1 parent c79da0a commit 34764cf

File tree

4 files changed

+42
-25
lines changed

4 files changed

+42
-25
lines changed

askama_derive/src/generator.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,9 @@ struct Generator<'a, 'h> {
8585
/// Used in blocks to check if we are inside a filter block.
8686
is_in_filter_block: usize,
8787
/// Set of called macros we are currently in. Used to prevent (indirect) recursions.
88-
seen_macros: Vec<(&'a Macro<'a>, Option<FileInfo<'a>>)>,
89-
/// Set of callers to forward into the macro.
90-
current_caller: Option<&'a Call<'a>>,
88+
seen_callers: Vec<(&'a Call<'a>, &'a Macro<'a>, Option<FileInfo<'a>>)>,
89+
/// the active caller within the macro.
90+
active_caller: Option<&'a Call<'a>>,
9191
}
9292

9393
impl<'a, 'h> Generator<'a, 'h> {
@@ -112,8 +112,8 @@ impl<'a, 'h> Generator<'a, 'h> {
112112
..Default::default()
113113
},
114114
is_in_filter_block,
115-
seen_macros: Vec::new(),
116-
current_caller: None,
115+
seen_callers: Vec::new(),
116+
active_caller: None,
117117
}
118118
}
119119

askama_derive/src/generator/node.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -624,9 +624,9 @@ impl<'a> Generator<'a, '_> {
624624
(*def, ctx)
625625
};
626626

627-
if self.seen_macros.iter().any(|(s, _)| std::ptr::eq(*s, def)) {
627+
if self.seen_callers.iter().any(|(_, s, _)| std::ptr::eq(*s, def)) {
628628
let mut message = "Found recursion in macro calls:".to_owned();
629-
for (m, f) in &self.seen_macros {
629+
for (_, m, f) in &self.seen_callers {
630630
if let Some(f) = f {
631631
write!(message, "{f}").unwrap();
632632
} else {
@@ -635,9 +635,10 @@ impl<'a> Generator<'a, '_> {
635635
}
636636
return Err(ctx.generate_error(message, call.span()));
637637
} else {
638-
self.seen_macros.push((def, ctx.file_info_of(call.span())));
638+
self.seen_callers
639+
.push((call, def, ctx.file_info_of(call.span())));
639640
}
640-
self.current_caller = Some(call);
641+
self.active_caller = self.seen_callers.last().map(|v| v.0);
641642
self.flush_ws(ws1); // Cannot handle_ws() here: whitespace from macro definition comes first
642643
let size_hint = self.push_locals(|this| {
643644
macro_call_ensure_arg_count(call, def, ctx)?;
@@ -760,8 +761,9 @@ impl<'a> Generator<'a, '_> {
760761
Ok(size_hint)
761762
})?;
762763
self.prepare_ws(ws1);
763-
self.seen_macros.pop();
764-
self.current_caller = None;
764+
self.seen_callers.pop();
765+
self.seen_callers.pop();
766+
self.active_caller = None;
765767
Ok(size_hint)
766768
}
767769

@@ -1107,11 +1109,11 @@ impl<'a> Generator<'a, '_> {
11071109
if ***path == Expr::Var("super") {
11081110
return self.write_block(ctx, buf, None, ws, s.span());
11091111
} else if ***path == Expr::Var("caller") {
1110-
let def = self.current_caller.ok_or_else(|| {
1112+
let def = self.active_caller.ok_or_else(|| {
11111113
ctx.generate_error(format_args!("block is not defined for caller"), s.span())
11121114
})?;
1113-
self.current_caller = None;
1114-
self.handle_ws(ws);
1115+
self.active_caller = None;
1116+
self.handle_ws(ws);
11151117
let size_hint = self.push_locals(|this| {
11161118
this.write_buf_writable(ctx, buf)?;
11171119
buf.write('{');
@@ -1171,13 +1173,13 @@ impl<'a> Generator<'a, '_> {
11711173
}
11721174
}
11731175
let mut size_hint = this.handle(ctx, &def.nodes, buf, AstLevel::Nested)?;
1174-
1176+
11751177
this.flush_ws(def.ws2);
11761178
size_hint += this.write_buf_writable(ctx, buf)?;
11771179
buf.write('}');
11781180
Ok(size_hint)
11791181
})?;
1180-
self.current_caller = Some(def);
1182+
self.active_caller = self.seen_callers.last().map(|v| v.0);
11811183
return Ok(size_hint);
11821184
}
11831185
}

testing/tests/calls.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@ nested
125125
assert_eq!(x.render().unwrap(), "nested");
126126
}
127127

128-
129128
#[test]
130129
fn test_caller_struct() {
131130
struct TestInput<'a> {

testing/tests/macro.rs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,6 @@ fn test_caller_expr() {
252252
)]
253253
struct MacroCallerExpr;
254254
assert_eq!(MacroCallerExpr.render().unwrap(), "20 1 35\n");
255-
256255
}
257256

258257
#[test]
@@ -261,25 +260,42 @@ fn test_caller_in_caller() {
261260
#[template(
262261
source = r#"
263262
{%- macro test2() -%}
264-
{{~ caller("bb") ~}}
263+
{{ caller("bb") }}
265264
{%- endmacro -%}
266265
{%- macro test() -%}
267-
{{~ caller("a") ~}}
266+
{{ caller("a") }}
267+
{%- call(b) test2() -%}
268+
five: {{ b }}
269+
{%~ endcall -%}
270+
{%- endmacro -%}
271+
{%- macro test3() -%}
272+
{{ caller("cc") }}
273+
{%- endmacro -%}
274+
{%- macro test4() -%}
275+
{{ caller("dd") }}
268276
{%- endmacro -%}
269277
{%- call(a) test() -%}
270278
{%- call(b) test2() -%}
271279
one: {{ b }}
280+
{%~ endcall -%}
281+
{%- call(b) test3() -%}
282+
two: {{ b }}
283+
{%~ call(b) test4() -%}
284+
three: {{ b }}
285+
{%~ endcall -%}
272286
{%- endcall -%}
273-
two: {{- a -}}
274-
{%- endcall -%}
287+
four: {{ a }}
288+
{%~ endcall -%}
275289
"#,
276290
ext = "txt"
277291
)]
278-
struct CallerInCaller;
279-
assert_eq!(CallerInCaller.render().unwrap(), "one: bbtwo:a");
292+
struct CallerInCaller;
293+
assert_eq!(
294+
CallerInCaller.render().unwrap(),
295+
"one: bb\ntwo: cc\nthree: dd\nfour: a\nfive: bb\n"
296+
);
280297
}
281298

282-
283299
// This test ensures that we can use declared variables as default value for
284300
// macro arguments.
285301
#[test]

0 commit comments

Comments
 (0)