From ee808da1f2599739e7cfb39dc4d16b6eefca352a Mon Sep 17 00:00:00 2001
From: yossyJ <28825627+yossyJ@users.noreply.github.com>
Date: Fri, 4 Jan 2019 23:12:44 +0900
Subject: [PATCH] Add support for tuple
---
askama_derive/src/generator.rs | 44 +++++++++++++++++++++++++---------
askama_derive/src/parser.rs | 24 +++++++++++++++++--
testing/templates/for.html | 3 +++
testing/templates/let.html | 1 +
testing/tests/loops.rs | 7 +++++-
testing/tests/vars.rs | 16 +++++++++++++
6 files changed, 81 insertions(+), 14 deletions(-)
diff --git a/askama_derive/src/generator.rs b/askama_derive/src/generator.rs
index 95a7d171e..67ec2c2f4 100644
--- a/askama_derive/src/generator.rs
+++ b/askama_derive/src/generator.rs
@@ -468,11 +468,7 @@ impl<'a> Generator<'a> {
self.write_buf_writable(buf);
buf.write("for (_loop_index, ");
- let targets = self.visit_target(var);
- for name in &targets {
- self.locals.insert(name);
- buf.write(name);
- }
+ self.visit_target(buf, var);
match iter {
Expr::Range(_, _, _) => buf.writeln(&format!(") in ({}).enumerate() {{", expr_code)),
_ => buf.writeln(&format!(") in (&{}).into_iter().enumerate() {{", expr_code)),
@@ -576,6 +572,15 @@ impl<'a> Generator<'a> {
self.locals.insert(name);
buf.write(name);
}
+ Target::Tuple(ref targets) => {
+ buf.write("(");
+ for name in targets {
+ self.locals.insert(name);
+ buf.write(name);
+ buf.write(",");
+ }
+ buf.write(")");
+ }
}
buf.writeln(";");
}
@@ -593,6 +598,15 @@ impl<'a> Generator<'a> {
}
buf.write(name);
}
+ Target::Tuple(ref targets) => {
+ buf.write("let (");
+ for name in targets {
+ self.locals.insert(name);
+ buf.write(name);
+ buf.write(",");
+ }
+ buf.write(")");
+ }
}
buf.writeln(&format!(" = {};", &expr_buf.buf));
}
@@ -1024,13 +1038,21 @@ impl<'a> Generator<'a> {
DisplayWrap::Unwrapped
}
- fn visit_target_single<'t>(&mut self, name: &'t str) -> Vec<&'t str> {
- vec![name]
- }
-
- fn visit_target<'t>(&mut self, target: &'t Target) -> Vec<&'t str> {
+ fn visit_target(&mut self, buf: &mut Buffer, target: &'a Target) {
match *target {
- Target::Name(s) => self.visit_target_single(s),
+ Target::Name(name) => {
+ self.locals.insert(name);
+ buf.write(name);
+ }
+ Target::Tuple(ref targets) => {
+ buf.write("(");
+ for name in targets {
+ self.locals.insert(name);
+ buf.write(name);
+ buf.write(",");
+ }
+ buf.write(")");
+ }
}
}
diff --git a/askama_derive/src/parser.rs b/askama_derive/src/parser.rs
index 81935f618..c5e610ede 100644
--- a/askama_derive/src/parser.rs
+++ b/askama_derive/src/parser.rs
@@ -42,6 +42,7 @@ pub enum MatchParameter<'a> {
#[derive(Debug)]
pub enum Target<'a> {
Name(&'a str),
+ Tuple(Vec<&'a str>),
}
#[derive(Clone, Copy, Debug)]
@@ -275,6 +276,25 @@ named!(target_single, map!(identifier,
|s| Target::Name(s)
));
+named!(target_tuple, do_parse!(
+ tag!("(") >>
+ args: opt!(do_parse!(
+ arg0: ws!(identifier) >>
+ args: many0!(do_parse!(
+ tag!(",") >>
+ argn: ws!(identifier) >>
+ (argn)
+ )) >>
+ ({
+ let mut res = vec![arg0];
+ res.extend(args);
+ res
+ })
+ )) >>
+ tag!(")") >>
+ (Target::Tuple(args.unwrap_or_default()))
+));
+
named!(variant_name, map!(identifier,
|s| MatchVariant::Name(s)
));
@@ -703,7 +723,7 @@ named_args!(block_match<'a>(s: &'a Syntax<'a>) , Node<'a>>, do_parse!(
named!(block_let, do_parse!(
pws: opt!(tag!("-")) >>
ws!(tag!("let")) >>
- var: ws!(target_single) >>
+ var: ws!(alt!(target_single | target_tuple)) >>
val: opt!(do_parse!(
ws!(tag!("=")) >>
val: ws!(expr_any) >>
@@ -720,7 +740,7 @@ named!(block_let, do_parse!(
named_args!(block_for<'a>(s: &'a Syntax<'a>) , Node<'a>>, do_parse!(
pws1: opt!(tag!("-")) >>
ws!(tag!("for")) >>
- var: ws!(target_single) >>
+ var: ws!(alt!(target_single | target_tuple)) >>
ws!(tag!("in")) >>
iter: ws!(expr_any) >>
nws1: opt!(tag!("-")) >>
diff --git a/testing/templates/for.html b/testing/templates/for.html
index 8b4032d9a..f74975293 100644
--- a/testing/templates/for.html
+++ b/testing/templates/for.html
@@ -1,3 +1,6 @@
{% for s in strings %}
{{- loop.index0 }}. {{ s }}{% if loop.first %} (first){% endif %}
{% endfor %}
+{% for (s1, s2) in tuple_strings %}
+ {{- loop.index0 }}. {{ s1 }},{{ s2 }}{% if loop.first %} (first){% endif %}
+{% endfor %}
diff --git a/testing/templates/let.html b/testing/templates/let.html
index 5b19255bb..034e8d458 100644
--- a/testing/templates/let.html
+++ b/testing/templates/let.html
@@ -1 +1,2 @@
{% let v = s %}{{ v }}
+{% let (v1,v2) = t %}{{ v1 }}{{ v2 }}
\ No newline at end of file
diff --git a/testing/tests/loops.rs b/testing/tests/loops.rs
index 3dfad38c9..b5fac7c76 100644
--- a/testing/tests/loops.rs
+++ b/testing/tests/loops.rs
@@ -4,14 +4,19 @@ use askama::Template;
#[template(path = "for.html")]
struct ForTemplate<'a> {
strings: Vec<&'a str>,
+ tuple_strings: Vec<(&'a str, &'a str)>,
}
#[test]
fn test_for() {
let s = ForTemplate {
strings: vec!["A", "alfa", "1"],
+ tuple_strings: vec![("B", "beta")],
};
- assert_eq!(s.render().unwrap(), "0. A (first)\n1. alfa\n2. 1\n");
+ assert_eq!(
+ s.render().unwrap(),
+ "0. A (first)\n1. alfa\n2. 1\n\n0. B,beta (first)\n"
+ );
}
#[derive(Template)]
diff --git a/testing/tests/vars.rs b/testing/tests/vars.rs
index 87af3f614..04f9ff2ee 100644
--- a/testing/tests/vars.rs
+++ b/testing/tests/vars.rs
@@ -12,6 +12,22 @@ fn test_let() {
assert_eq!(t.render().unwrap(), "foo");
}
+#[derive(Template)]
+#[template(path = "let.html")]
+struct LetTupleTemplate<'a> {
+ s: &'a str,
+ t: (&'a str, &'a str),
+}
+
+#[test]
+fn test_let_tuple() {
+ let t = LetTupleTemplate {
+ s: "foo",
+ t: ("bar", "bazz"),
+ };
+ assert_eq!(t.render().unwrap(), "foo\nbarbazz");
+}
+
#[derive(Template)]
#[template(path = "let-decl.html")]
struct LetDeclTemplate<'a> {