aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Dirkjan Ochtman <dirkjan@ochtman.nl>2017-01-06 11:22:49 +0100
committerLibravatar Dirkjan Ochtman <dirkjan@ochtman.nl>2017-01-06 13:08:29 +0100
commit7904325c1613fa307bb9a0fb5a1d5751420a063e (patch)
tree8f6828b37f10ba61f5ff7b0272f2603a79aefc41
parent856d2d7a27d9bb40aba0bcca60a9a5c82939bce2 (diff)
downloadaskama-7904325c1613fa307bb9a0fb5a1d5751420a063e.tar.gz
askama-7904325c1613fa307bb9a0fb5a1d5751420a063e.tar.bz2
askama-7904325c1613fa307bb9a0fb5a1d5751420a063e.zip
Add parser and code generator support for Filter expressions
-rw-r--r--askama_derive/src/generator.rs7
-rw-r--r--askama_derive/src/parser.rs34
2 files changed, 37 insertions, 4 deletions
diff --git a/askama_derive/src/generator.rs b/askama_derive/src/generator.rs
index 3fa5b9f..0e80265 100644
--- a/askama_derive/src/generator.rs
+++ b/askama_derive/src/generator.rs
@@ -54,9 +54,16 @@ impl Generator {
self.write(&format!("self.{}", str::from_utf8(s).unwrap()));
}
+ fn visit_filter(&mut self, name: &str, val: &Expr) {
+ self.write(&format!("askama::filters::{}(&", name));
+ self.visit_expr(val);
+ self.write(")");
+ }
+
fn visit_expr(&mut self, expr: &Expr) {
match expr {
&Expr::Var(s) => self.visit_var(s),
+ &Expr::Filter(name, ref val) => self.visit_filter(name, &val),
}
}
diff --git a/askama_derive/src/parser.rs b/askama_derive/src/parser.rs
index 5f3f8c5..cd93971 100644
--- a/askama_derive/src/parser.rs
+++ b/askama_derive/src/parser.rs
@@ -1,7 +1,9 @@
use nom::{self, IResult};
+use std::str;
pub enum Expr<'a> {
Var(&'a [u8]),
+ Filter(&'a str, Box<Expr<'a>>),
}
pub enum Node<'a> {
@@ -27,17 +29,41 @@ fn take_content(i: &[u8]) -> IResult<&[u8], Node> {
IResult::Done(&i[..0], Node::Lit(&i[..]))
}
-named!(expr_var<Expr>, map!(ws!(nom::alphanumeric), Expr::Var));
+named!(expr_var<Expr>, map!(nom::alphanumeric, Expr::Var));
-named!(any_expr<Expr>, delimited!(tag!("{{"), expr_var, tag!("}}")));
+fn expr_filtered(i: &[u8]) -> IResult<&[u8], Expr> {
+ let (mut left, mut expr) = match expr_var(i) {
+ IResult::Error(err) => { return IResult::Error(err); },
+ IResult::Incomplete(needed) => { return IResult::Incomplete(needed); },
+ IResult::Done(left, res) => (left, res),
+ };
+ while left[0] == b'|' {
+ match nom::alphanumeric(&left[1..]) {
+ IResult::Error(err) => {
+ return IResult::Error(err);
+ },
+ IResult::Incomplete(needed) => {
+ return IResult::Incomplete(needed);
+ },
+ IResult::Done(new_left, res) => {
+ left = new_left;
+ expr = Expr::Filter(str::from_utf8(res).unwrap(), Box::new(expr));
+ },
+ };
+ }
+ return IResult::Done(left, expr);
+}
-named!(expr_node<Node>, map!(any_expr, Node::Expr));
+named!(expr_node<Node>, map!(
+ delimited!(tag_s!("{{"), ws!(expr_filtered), tag_s!("}}")),
+ Node::Expr));
named!(parse_template< Vec<Node> >, many1!(alt!(take_content | expr_node)));
pub fn parse<'a>(src: &'a str) -> Vec<Node> {
match parse_template(src.as_bytes()) {
IResult::Done(_, res) => res,
- _ => panic!("problems parsing template source"),
+ IResult::Error(err) => panic!("problems parsing template source: {}", err),
+ IResult::Incomplete(_) => panic!("parsing incomplete"),
}
}