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> {