diff options
author | Dirkjan Ochtman <dirkjan@ochtman.nl> | 2017-01-06 11:22:49 +0100 |
---|---|---|
committer | Dirkjan Ochtman <dirkjan@ochtman.nl> | 2017-01-06 13:08:29 +0100 |
commit | 7904325c1613fa307bb9a0fb5a1d5751420a063e (patch) | |
tree | 8f6828b37f10ba61f5ff7b0272f2603a79aefc41 | |
parent | 856d2d7a27d9bb40aba0bcca60a9a5c82939bce2 (diff) | |
download | askama-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.rs | 7 | ||||
-rw-r--r-- | askama_derive/src/parser.rs | 34 |
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"), } } |