diff options
author | Anthony Nowell <anowell@gmail.com> | 2017-10-05 02:47:36 -0600 |
---|---|---|
committer | Dirkjan Ochtman <dirkjan@ochtman.nl> | 2017-11-02 14:58:46 +0100 |
commit | cc51d201ab9e7ba958363d1f74b7bfd4dd12fecf (patch) | |
tree | f7c0c5ba23f1a6125846e248b73a8d273ebd7979 | |
parent | 751dee3fbabb35a8ad30ebdaee8e4dd4120c289a (diff) | |
download | askama-cc51d201ab9e7ba958363d1f74b7bfd4dd12fecf.tar.gz askama-cc51d201ab9e7ba958363d1f74b7bfd4dd12fecf.tar.bz2 askama-cc51d201ab9e7ba958363d1f74b7bfd4dd12fecf.zip |
support literals in match arms
-rw-r--r-- | askama_shared/src/generator.rs | 24 | ||||
-rw-r--r-- | askama_shared/src/parser.rs | 54 | ||||
-rw-r--r-- | testing/templates/match-literal.html | 8 | ||||
-rw-r--r-- | testing/templates/match-opt.html (renamed from testing/templates/match.html) | 2 | ||||
-rw-r--r-- | testing/tests/matches.rs | 32 |
5 files changed, 103 insertions, 17 deletions
diff --git a/askama_shared/src/generator.rs b/askama_shared/src/generator.rs index 6fca3fb..0c8b1e2 100644 --- a/askama_shared/src/generator.rs +++ b/askama_shared/src/generator.rs @@ -1,6 +1,6 @@ use filters; use input::TemplateInput; -use parser::{self, Cond, Expr, Macro, Node, Target, When, WS}; +use parser::{self, Cond, Expr, Macro, MatchParameter, Node, Target, When, WS}; use path; use quote::{Tokens, ToTokens}; @@ -445,15 +445,20 @@ impl<'a> Generator<'a> { for arm in arms { let &(ref ws, ref variant, ref params, ref body) = arm; self.locals.push(); - self.write(variant); + match *variant { + Some(ref param) => { self.visit_match_param(param); }, + None => self.write("_"), + }; if params.len() > 0 { self.write("("); for (i, param) in params.iter().enumerate() { - self.locals.insert(param); + if let MatchParameter::Name(ref p) = *param { + self.locals.insert(p); + } if i > 0 { self.write(", "); } - self.write(param); + self.visit_match_param(param); } self.write(")"); } @@ -624,6 +629,17 @@ impl<'a> Generator<'a> { } } + fn visit_match_param(&mut self, param: &MatchParameter) -> DisplayWrap { + match *param { + MatchParameter::NumLit(s) => self.visit_num_lit(s), + MatchParameter::StrLit(s) => self.visit_str_lit(s), + MatchParameter::Name(s) => { + self.write(s); + DisplayWrap::Unwrapped + } + } + } + fn visit_filter(&mut self, name: &str, args: &[Expr]) -> DisplayWrap { if name == "format" { self._visit_format_filter(args); diff --git a/askama_shared/src/parser.rs b/askama_shared/src/parser.rs index 6ea5ffd..76125ef 100644 --- a/askama_shared/src/parser.rs +++ b/askama_shared/src/parser.rs @@ -16,6 +16,13 @@ pub enum Expr<'a> { } #[derive(Debug)] +pub enum MatchParameter<'a> { + Name(&'a str), + NumLit(&'a str), + StrLit(&'a str), +} + +#[derive(Debug)] pub enum Target<'a> { Name(&'a str), } @@ -50,7 +57,7 @@ pub enum Node<'a> { } pub type Cond<'a> = (WS, Option<Expr<'a>>, Vec<Node<'a>>); -pub type When<'a> = (WS, &'a str, Vec<&'a str>, Vec<Node<'a>>); +pub type When<'a> = (WS, Option<MatchParameter<'a>>, Vec<MatchParameter<'a>>, Vec<Node<'a>>); fn split_ws_parts(s: &[u8]) -> Node { if s.is_empty() { @@ -147,11 +154,20 @@ named!(expr_array_lit<Expr>, do_parse!( }) )); +named!(param_num_lit<MatchParameter>, map!(num_lit, + |s| MatchParameter::NumLit(s) +)); + named!(expr_str_lit<Expr>, map!( delimited!(char!('"'), take_until!("\""), char!('"')), |s| Expr::StrLit(str::from_utf8(s).unwrap()) )); +named!(param_str_lit<MatchParameter>, map!( + delimited!(char!('"'), is_not!("\""), char!('"')), + |s| MatchParameter::StrLit(str::from_utf8(s).unwrap()) +)); + named!(expr_var<Expr>, map!(identifier, |s| Expr::Var(s)) ); @@ -174,6 +190,10 @@ named!(target_single<Target>, map!(identifier, |s| Target::Name(s) )); +named!(param_name<MatchParameter>, map!(identifier, + |s| MatchParameter::Name(s) +)); + named!(arguments<Vec<Expr>>, do_parse!( tag_s!("(") >> args: opt!(do_parse!( @@ -212,10 +232,24 @@ named!(parameters<Vec<&'a str>>, do_parse!( (vals.unwrap_or_default()) )); -named!(with_parameters<Vec<&'a str>>, do_parse!( +named!(with_parameters<Vec<MatchParameter>>, do_parse!( tag_s!("with") >> - params: ws!(parameters) >> - (params) + ws!(tag_s!("(")) >> + vals: opt!(do_parse!( + arg0: ws!(match_parameter) >> + args: many0!(do_parse!( + tag_s!(",") >> + argn: ws!(match_parameter) >> + (argn) + )) >> + ({ + let mut res = vec![arg0]; + res.extend(args); + res + }) + )) >> + tag_s!(")") >> + (vals.unwrap_or_default()) )); named!(expr_group<Expr>, map!( @@ -232,6 +266,12 @@ named!(expr_single<Expr>, alt!( expr_group )); +named!(match_parameter<MatchParameter>, alt!( + param_name | + param_num_lit | + param_str_lit +)); + named!(attr<(&str, Option<Vec<Expr>>)>, do_parse!( tag_s!(".") >> attr: alt!(num_lit | identifier) >> @@ -374,19 +414,19 @@ named!(match_else_block<When>, do_parse!( nws: opt!(tag_s!("-")) >> tag_s!("%}") >> block: parse_template >> - (WS(pws.is_some(), nws.is_some()), "_", vec![], block) + (WS(pws.is_some(), nws.is_some()), None, vec![], block) )); named!(when_block<When>, do_parse!( tag_s!("{%") >> pws: opt!(tag_s!("-")) >> ws!(tag_s!("when")) >> - variant: ws!(identifier) >> + variant: ws!(match_parameter) >> params: opt!(ws!(with_parameters)) >> nws: opt!(tag_s!("-")) >> tag_s!("%}") >> block: parse_template >> - (WS(pws.is_some(), nws.is_some()), variant, params.unwrap_or_default(), block) + (WS(pws.is_some(), nws.is_some()), Some(variant), params.unwrap_or_default(), block) )); named!(block_match<Node>, do_parse!( diff --git a/testing/templates/match-literal.html b/testing/templates/match-literal.html new file mode 100644 index 0000000..22203f4 --- /dev/null +++ b/testing/templates/match-literal.html @@ -0,0 +1,8 @@ +{% match item %} +{% when "foo" %} +Found literal foo +{% when "bar" %} +Found literal bar +{% else %} +Else found {{item}} +{% endmatch %} diff --git a/testing/templates/match.html b/testing/templates/match-opt.html index 51950b4..c77a2a6 100644 --- a/testing/templates/match.html +++ b/testing/templates/match-opt.html @@ -1,4 +1,6 @@ {% match item %} +{% when Some with ("foo") %} +Found literal foo {% when Some with (val) %} Found {{val}} {% when None %} diff --git a/testing/tests/matches.rs b/testing/tests/matches.rs index 4a55615..4f159ab 100644 --- a/testing/tests/matches.rs +++ b/testing/tests/matches.rs @@ -4,15 +4,35 @@ extern crate askama; use askama::Template; #[derive(Template)] -#[template(path = "match.html")] -struct MatchTemplate<'a> { +#[template(path = "match-opt.html")] +struct MatchOptTemplate<'a> { item: Option<&'a str>, } #[test] fn test_match_option() { - let s = MatchTemplate { - item: Some("foo"), - }; - assert_eq!(s.render().unwrap(), "\n\nFound foo\n"); + let s = MatchOptTemplate { item: Some("foo") }; + assert_eq!(s.render().unwrap(), "\n\nFound literal foo\n"); + + let s = MatchOptTemplate { item: Some("bar") }; + assert_eq!(s.render().unwrap(), "\n\nFound bar\n"); + + let s = MatchOptTemplate { item: None }; + assert_eq!(s.render().unwrap(), "\n\nNot Found\n"); +} + + +#[derive(Template)] +#[template(path = "match-literal.html")] +struct MatchLitTemplate<'a> { + item: &'a str, +} + +#[test] +fn test_match_literal() { + let s = MatchLitTemplate { item: "bar" }; + assert_eq!(s.render().unwrap(), "\n\nFound literal bar\n"); + + let s = MatchLitTemplate { item: "qux" }; + assert_eq!(s.render().unwrap(), "\n\nElse found qux\n"); } |