aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Anthony Nowell <anowell@gmail.com>2017-09-27 01:53:35 -0600
committerLibravatar Dirkjan Ochtman <dirkjan@ochtman.nl>2017-11-02 14:55:10 +0100
commit468f376bfc2cf3e09addac37cd144de56b5f93bf (patch)
tree3a6e127bac7e6a2193739902ff60a16b12c51c12
parent14beb21d0cef62ca47ad85617bd9460369a15b61 (diff)
downloadaskama-468f376bfc2cf3e09addac37cd144de56b5f93bf.tar.gz
askama-468f376bfc2cf3e09addac37cd144de56b5f93bf.tar.bz2
askama-468f376bfc2cf3e09addac37cd144de56b5f93bf.zip
implement basic match functionality
Diffstat (limited to '')
-rw-r--r--askama_shared/src/generator.rs42
-rw-r--r--askama_shared/src/parser.rs54
-rw-r--r--testing/templates/match.html6
-rw-r--r--testing/tests/matches.rs18
4 files changed, 119 insertions, 1 deletions
diff --git a/askama_shared/src/generator.rs b/askama_shared/src/generator.rs
index dcdea32..6fca3fb 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, WS};
+use parser::{self, Cond, Expr, Macro, Node, Target, When, WS};
use path;
use quote::{Tokens, ToTokens};
@@ -339,6 +339,9 @@ impl<'a> Generator<'a> {
Node::Cond(ref conds, ref ws) => {
self.write_cond(state, conds, ws);
},
+ Node::Match(ref ws1, ref expr, ref inter, ref arms, ref ws2) => {
+ self.write_match(state, ws1, expr, inter, arms, ws2);
+ },
Node::Loop(ref ws1, ref var, ref iter, ref body, ref ws2) => {
self.write_loop(state, ws1, var, iter, body, ws2);
},
@@ -428,6 +431,43 @@ impl<'a> Generator<'a> {
self.writeln("}");
}
+ fn write_match(&mut self, state: &'a State, ws1: &WS, expr: &Expr, inter: &'a str, arms:
+ &'a [When], ws2: &WS) {
+ self.flush_ws(ws1);
+ if !inter.is_empty() {
+ self.next_ws = Some(inter);
+ }
+
+ self.write("match ");
+ self.visit_expr(expr);
+ self.writeln(" {");
+
+ for arm in arms {
+ let &(ref ws, ref variant, ref params, ref body) = arm;
+ self.locals.push();
+ self.write(variant);
+ if params.len() > 0 {
+ self.write("(");
+ for (i, param) in params.iter().enumerate() {
+ self.locals.insert(param);
+ if i > 0 {
+ self.write(", ");
+ }
+ self.write(param);
+ }
+ self.write(")");
+ }
+ self.writeln(" => {");
+ self.handle_ws(ws);
+ self.handle(state, body, AstLevel::Nested);
+ self.writeln("}");
+ self.locals.pop();
+ }
+
+ self.writeln("}");
+ self.handle_ws(ws2);
+ }
+
fn write_loop(&mut self, state: &'a State, ws1: &WS, var: &'a Target, iter: &Expr,
body: &'a [Node], ws2: &WS) {
self.handle_ws(ws1);
diff --git a/askama_shared/src/parser.rs b/askama_shared/src/parser.rs
index 5bdcb9b..ec4dcbd 100644
--- a/askama_shared/src/parser.rs
+++ b/askama_shared/src/parser.rs
@@ -40,6 +40,7 @@ pub enum Node<'a> {
LetDecl(WS, Target<'a>),
Let(WS, Target<'a>, Expr<'a>),
Cond(Vec<(WS, Option<Expr<'a>>, Vec<Node<'a>>)>, WS),
+ Match(WS, Expr<'a>, &'a str, Vec<When<'a>>, WS),
Loop(WS, Target<'a>, Expr<'a>, Vec<Node<'a>>, WS),
Extends(Expr<'a>),
BlockDef(WS, &'a str, Vec<Node<'a>>, WS),
@@ -49,6 +50,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>>);
fn split_ws_parts(s: &[u8]) -> Node {
if s.is_empty() {
@@ -210,6 +212,12 @@ named!(parameters<Vec<&'a str>>, do_parse!(
(vals.unwrap_or_default())
));
+named!(with_parameters<Vec<&'a str>>, do_parse!(
+ tag_s!("with") >>
+ params: ws!(parameters) >>
+ (params)
+));
+
named!(expr_group<Expr>, map!(
delimited!(char!('('), expr_any, char!(')')),
|s| Expr::Group(Box::new(s))
@@ -359,6 +367,51 @@ named!(block_if<Node>, do_parse!(
})
));
+named!(when_block<When>, do_parse!(
+ tag_s!("{%") >>
+ pws: opt!(tag_s!("-")) >>
+ ws!(tag_s!("when")) >>
+ variant: ws!(identifier) >>
+ 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)
+));
+
+named!(block_match<Node>, do_parse!(
+ pws1: opt!(tag_s!("-")) >>
+ ws!(tag_s!("match")) >>
+ expr: ws!(expr_any) >>
+ nws1: opt!(tag_s!("-")) >>
+ tag_s!("%}") >>
+ inter: take_content >>
+ arms: many1!(when_block) >>
+ ws!(tag_s!("{%")) >>
+ pws2: opt!(tag_s!("-")) >>
+ ws!(tag_s!("endmatch")) >>
+ nws2: opt!(tag_s!("-")) >>
+ ({
+ let inter = match inter {
+ Node::Lit(lws, val, rws) => {
+ assert!(val.is_empty(),
+ "only whitespace allowed between match and first when, found {}", val);
+ assert!(rws.is_empty(),
+ "only whitespace allowed between match and first when, found {}", rws);
+ lws
+ },
+ _ => panic!("only literals allowed between match and first when"),
+ };
+ Node::Match(
+ WS(pws1.is_some(), nws1.is_some()),
+ expr,
+ inter,
+ arms,
+ WS(pws2.is_some(), nws2.is_some()),
+ )
+ })
+));
+
named!(block_let<Node>, do_parse!(
pws: opt!(tag_s!("-")) >>
ws!(tag_s!("let")) >>
@@ -471,6 +524,7 @@ named!(block_node<Node>, do_parse!(
block_let |
block_if |
block_for |
+ block_match |
block_extends |
block_include |
block_import |
diff --git a/testing/templates/match.html b/testing/templates/match.html
new file mode 100644
index 0000000..51950b4
--- /dev/null
+++ b/testing/templates/match.html
@@ -0,0 +1,6 @@
+{% match item %}
+{% when Some with (val) %}
+Found {{val}}
+{% when None %}
+Not Found
+{% endmatch %}
diff --git a/testing/tests/matches.rs b/testing/tests/matches.rs
new file mode 100644
index 0000000..4a55615
--- /dev/null
+++ b/testing/tests/matches.rs
@@ -0,0 +1,18 @@
+#[macro_use]
+extern crate askama;
+
+use askama::Template;
+
+#[derive(Template)]
+#[template(path = "match.html")]
+struct MatchTemplate<'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");
+}