diff options
-rw-r--r-- | askama_derive/src/generator.rs | 45 | ||||
-rw-r--r-- | askama_derive/src/parser.rs | 54 | ||||
-rw-r--r-- | testing/templates/match-custom-enum.html | 4 | ||||
-rw-r--r-- | testing/tests/matches.rs | 8 |
4 files changed, 93 insertions, 18 deletions
diff --git a/askama_derive/src/generator.rs b/askama_derive/src/generator.rs index b30b040..047e975 100644 --- a/askama_derive/src/generator.rs +++ b/askama_derive/src/generator.rs @@ -1,6 +1,6 @@ use super::{get_template_source, Context, Heritage}; use crate::input::TemplateInput; -use crate::parser::{Cond, Expr, MatchParameter, MatchVariant, Node, Target, When, WS}; +use crate::parser::{Cond, Expr, MatchParameter, MatchParameters, MatchVariant, Node, Target, When, WS}; use askama_shared::filters; use proc_macro2::Span; @@ -399,18 +399,43 @@ impl<'a> Generator<'a> { } None => buf.write("_"), }; - if !params.is_empty() { - buf.write("("); - for (i, param) in params.iter().enumerate() { - if let MatchParameter::Name(p) = *param { - self.locals.insert(p); + + match params { + MatchParameters::Simple(params) => { + if !params.is_empty() { + buf.write("("); + for (i, param) in params.iter().enumerate() { + if let MatchParameter::Name(p) = *param { + self.locals.insert(p); + } + if i > 0 { + buf.write(", "); + } + self.visit_match_param(buf, param); + } + buf.write(")"); } - if i > 0 { - buf.write(", "); + } + MatchParameters::Named(params) => { + buf.write("{"); + for (i, param) in params.iter().enumerate() { + if let Some(MatchParameter::Name(p)) = param.1 { + self.locals.insert(p); + } else { + self.locals.insert(param.0); + } + + if i > 0 { + buf.write(", "); + } + buf.write(param.0); + if let Some(param) = ¶m.1 { + buf.write(":"); + self.visit_match_param(buf, ¶m); + } } - self.visit_match_param(buf, param); + buf.write("}"); } - buf.write(")"); } buf.writeln(" => {"); self.handle_ws(ws); diff --git a/askama_derive/src/parser.rs b/askama_derive/src/parser.rs index e1a7fc0..7968ac1 100644 --- a/askama_derive/src/parser.rs +++ b/askama_derive/src/parser.rs @@ -77,10 +77,22 @@ pub type Cond<'a> = (WS, Option<Expr<'a>>, Vec<Node<'a>>); pub type When<'a> = ( WS, Option<MatchVariant<'a>>, - Vec<MatchParameter<'a>>, + MatchParameters<'a>, Vec<Node<'a>>, ); +#[derive(Debug)] +pub enum MatchParameters<'a> { + Simple(Vec<MatchParameter<'a>>), + Named(Vec<(&'a str, Option<MatchParameter<'a>>)>), +} + +impl<'a> Default for MatchParameters<'a> { + fn default() -> Self { + MatchParameters::Simple(vec![]) + } +} + type Input<'a> = nom::types::CompleteByteSlice<'a>; #[allow(non_snake_case)] fn Input(input: &[u8]) -> Input { @@ -309,8 +321,13 @@ named!(parameters<Input, Vec<&str>>, do_parse!( (vals.unwrap_or_default()) )); -named!(with_parameters<Input, Vec<MatchParameter>>, do_parse!( +named!(with_parameters<Input, MatchParameters>, do_parse!( tag!("with") >> + value: alt!(match_simple_parameters | match_named_parameters) >> + (value) +)); + +named!(match_simple_parameters<Input, MatchParameters>, do_parse!( ws!(tag!("(")) >> vals: opt!(do_parse!( arg0: ws!(match_parameter) >> @@ -326,7 +343,26 @@ named!(with_parameters<Input, Vec<MatchParameter>>, do_parse!( }) )) >> tag!(")") >> - (vals.unwrap_or_default()) + (MatchParameters::Simple(vals.unwrap_or_default())) +)); + +named!(match_named_parameters<Input, MatchParameters>, do_parse!( + ws!(tag!("{")) >> + vals: opt!(do_parse!( + arg0: ws!(match_named_parameter) >> + args: many0!(do_parse!( + tag!(",") >> + argn: ws!(match_named_parameter) >> + (argn) + )) >> + ({ + let mut res = vec![arg0]; + res.extend(args); + res + }) + )) >> + tag!("}") >> + (MatchParameters::Named(vals.unwrap_or_default())) )); named!(expr_group<Input, Expr>, map!( @@ -356,6 +392,16 @@ named!(match_parameter<Input, MatchParameter>, alt!( param_str_lit )); +named!(match_named_parameter<Input, (&str, Option<MatchParameter>)>, do_parse!( + name: identifier >> + param: opt!(do_parse!( + ws!(tag!(":")) >> + param: match_parameter >> + (param) + )) >> + ((name, param)) +)); + named!(attr<Input, (&str, Option<Vec<Expr>>)>, do_parse!( tag!(".") >> attr: alt!(num_lit | identifier) >> @@ -549,7 +595,7 @@ named_args!(match_else_block<'a>(s: &'a Syntax<'a>) <Input<'a>, When<'a>>, do_pa nws: opt!(tag!("-")) >> call!(tag_block_end, s) >> block: call!(parse_template, s) >> - (WS(pws.is_some(), nws.is_some()), None, vec![], block) + (WS(pws.is_some(), nws.is_some()), None, MatchParameters::Simple(vec![]), block) )); named_args!(when_block<'a>(s: &'a Syntax<'a>) <Input<'a>, When<'a>>, do_parse!( diff --git a/testing/templates/match-custom-enum.html b/testing/templates/match-custom-enum.html index cb45b8f..bec38b9 100644 --- a/testing/templates/match-custom-enum.html +++ b/testing/templates/match-custom-enum.html @@ -1,6 +1,6 @@ {% match color %} -{% when Color::Rgb with (r, g, b) %} -Colorful: #{{ "{:02X}"|format(r) }}{{ "{:02X}"|format(g) }}{{ "{:02X}"|format(b) }} +{% when Color::Rgb with {r, g: g, b: blue} %} +Colorful: #{{ "{:02X}"|format(r) }}{{ "{:02X}"|format(g) }}{{ "{:02X}"|format(blue) }} {% when Color::GrayScale with (val) %} Gray: #{{ "{:02X}"|format(val) }}{{ "{:02X}"|format(val) }}{{ "{:02X}"|format(val) }} {% else %} diff --git a/testing/tests/matches.rs b/testing/tests/matches.rs index 89082ef..8657fa5 100644 --- a/testing/tests/matches.rs +++ b/testing/tests/matches.rs @@ -62,7 +62,7 @@ fn test_match_literal_num() { #[allow(dead_code)] enum Color { - Rgb(u32, u32, u32), + Rgb { r: u32, g: u32, b: u32 }, GrayScale(u32), Cmyk(u32, u32, u32, u32), } @@ -76,7 +76,11 @@ struct MatchCustomEnumTemplate { #[test] fn test_match_custom_enum() { let s = MatchCustomEnumTemplate { - color: Color::Rgb(160, 0, 255), + color: Color::Rgb { + r: 160, + g: 0, + b: 255, + }, }; assert_eq!(s.render().unwrap(), "\n\nColorful: #A000FF\n"); } |