aboutsummaryrefslogtreecommitdiffstats
path: root/askama_shared/src/generator.rs
diff options
context:
space:
mode:
Diffstat (limited to 'askama_shared/src/generator.rs')
-rw-r--r--askama_shared/src/generator.rs60
1 files changed, 38 insertions, 22 deletions
diff --git a/askama_shared/src/generator.rs b/askama_shared/src/generator.rs
index 3b73170..146f9db 100644
--- a/askama_shared/src/generator.rs
+++ b/askama_shared/src/generator.rs
@@ -444,8 +444,8 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
Node::Cond(ref conds, ws) => {
self.write_cond(ctx, buf, conds, ws)?;
}
- Node::Match(ws1, ref expr, inter, ref arms, ws2) => {
- self.write_match(ctx, buf, ws1, expr, inter, arms, ws2)?;
+ Node::Match(ws1, ref expr, ref arms, ws2) => {
+ self.write_match(ctx, buf, ws1, expr, arms, ws2)?;
}
Node::Loop(ws1, ref var, ref iter, ref body, ws2) => {
self.write_loop(ctx, buf, ws1, var, iter, body, ws2)?;
@@ -505,8 +505,9 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
let mut has_else = false;
for (i, &(cws, ref cond, ref nodes)) in conds.iter().enumerate() {
self.handle_ws(cws);
- if arm_sizes.is_empty() {
- flushed += self.write_buf_writable(buf)?;
+ flushed += self.write_buf_writable(buf)?;
+ if i > 0 {
+ self.locals.pop();
}
let mut arm_size = 0;
@@ -518,8 +519,15 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
buf.dedent()?;
buf.write("} else if ");
}
+ // The following syntax `*(&(...) as &bool)` is used to
+ // trigger Rust's automatic dereferencing, to coerce
+ // e.g. `&&&&&bool` to `bool`. First `&(...) as &bool`
+ // coerces e.g. `&&&bool` to `&bool`. Then `*(&bool)`
+ // finally dereferences it to `bool`.
+ buf.write("*(&(");
let expr_code = self.visit_expr_root(expr)?;
buf.write(&expr_code);
+ buf.write(") as &bool)");
}
None => {
buf.dedent()?;
@@ -532,14 +540,14 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
self.locals.push();
arm_size += self.handle(ctx, nodes, buf, AstLevel::Nested)?;
- arm_size += self.write_buf_writable(buf)?;
arm_sizes.push(arm_size);
-
- self.locals.pop();
}
self.handle_ws(ws);
+ flushed += self.write_buf_writable(buf)?;
buf.writeln("}")?;
+ self.locals.pop();
+
if !has_else {
arm_sizes.push(0);
}
@@ -553,23 +561,28 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
buf: &mut Buffer,
ws1: WS,
expr: &Expr,
- inter: Option<&'a str>,
arms: &'a [When],
ws2: WS,
) -> Result<usize, CompileError> {
self.flush_ws(ws1);
let flushed = self.write_buf_writable(buf)?;
let mut arm_sizes = Vec::new();
- if let Some(inter) = inter {
- if !inter.is_empty() {
- self.next_ws = Some(inter);
- }
- }
let expr_code = self.visit_expr_root(expr)?;
buf.writeln(&format!("match &{} {{", expr_code))?;
- for arm in arms {
+
+ let mut arm_size = 0;
+ for (i, arm) in arms.iter().enumerate() {
let &(ws, ref variant, ref params, ref body) = arm;
+ self.handle_ws(ws);
+
+ if i > 0 {
+ arm_sizes.push(arm_size + self.write_buf_writable(buf)?);
+
+ buf.writeln("}")?;
+ self.locals.pop();
+ }
+
self.locals.push();
match *variant {
Some(ref param) => {
@@ -616,15 +629,17 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
}
}
buf.writeln(" => {")?;
- self.handle_ws(ws);
- let arm_size = self.handle(ctx, body, buf, AstLevel::Nested)?;
- arm_sizes.push(arm_size + self.write_buf_writable(buf)?);
- buf.writeln("}")?;
- self.locals.pop();
+
+ arm_size = self.handle(ctx, body, buf, AstLevel::Nested)?;
}
- buf.writeln("}")?;
self.handle_ws(ws2);
+ arm_sizes.push(arm_size + self.write_buf_writable(buf)?);
+ buf.writeln("}")?;
+ self.locals.pop();
+
+ buf.writeln("}")?;
+
Ok(flushed + median(&mut arm_sizes))
}
@@ -717,10 +732,11 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
}
names.write(arg);
- values.write("&");
+ values.write("&(");
values.write(&self.visit_expr_root(args.get(i).ok_or_else(|| {
CompileError::String(format!("macro '{}' takes more than {} arguments", name, i))
})?)?);
+ values.write(")");
self.locals.insert(arg);
}
@@ -944,7 +960,7 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
let expression = match wrapped {
Wrapped => expr_buf.buf,
Unwrapped => format!(
- "::askama::MarkupDisplay::new_unsafe(&{}, {})",
+ "::askama::MarkupDisplay::new_unsafe(&({}), {})",
expr_buf.buf, self.input.escaper
),
};