From a46966b4ad0f9223d7e5e12d675b337a048afd3e Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Sat, 23 Jun 2018 18:17:33 +0200 Subject: Add support for range operators (see #95) --- askama_derive/src/generator.rs | 18 ++++++++++++++++++ askama_derive/src/parser.rs | 22 +++++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) (limited to 'askama_derive/src') diff --git a/askama_derive/src/generator.rs b/askama_derive/src/generator.rs index 0e86a27..5ec2238 100644 --- a/askama_derive/src/generator.rs +++ b/askama_derive/src/generator.rs @@ -598,6 +598,7 @@ impl<'a> Generator<'a> { Expr::Filter(name, ref args) => self.visit_filter(name, args, code), Expr::Unary(op, ref inner) => self.visit_unary(op, inner, code), Expr::BinOp(op, ref left, ref right) => self.visit_binop(op, left, right, code), + Expr::Range(op, ref left, ref right) => self.visit_range(op, left, right, code), Expr::Group(ref inner) => self.visit_group(inner, code), Expr::MethodCall(ref obj, method, ref args) => { self.visit_method_call(obj, method, args, code) @@ -762,6 +763,23 @@ impl<'a> Generator<'a> { DisplayWrap::Unwrapped } + fn visit_range( + &mut self, + op: &str, + left: &Option>, + right: &Option>, + code: &mut String, + ) -> DisplayWrap { + if let Some(left) = left { + self.visit_expr(left, code); + } + code.push_str(op); + if let Some(right) = right { + self.visit_expr(right, code); + } + DisplayWrap::Unwrapped + } + fn visit_binop( &mut self, op: &str, diff --git a/askama_derive/src/parser.rs b/askama_derive/src/parser.rs index c8bbb96..5694d4e 100644 --- a/askama_derive/src/parser.rs +++ b/askama_derive/src/parser.rs @@ -16,6 +16,7 @@ pub enum Expr<'a> { Filter(&'a str, Vec>), Unary(&'a str, Box>), BinOp(&'a str, Box>, Box>), + Range(&'a str, Option>>, Option>>), Group(Box>), MethodCall(Box>, &'a str, Vec>), } @@ -422,7 +423,26 @@ expr_prec_layer!(expr_compare, expr_bor, "==", "!=", ">=", ">", "<=", "<" ); expr_prec_layer!(expr_and, expr_compare, "&&"); -expr_prec_layer!(expr_any, expr_and, "||"); +expr_prec_layer!(expr_or, expr_and, "||"); + +named!(range_right, do_parse!( + ws!(tag_s!("..")) >> + incl: opt!(ws!(tag_s!("="))) >> + right: opt!(expr_or) >> + (Expr::Range(if incl.is_some() { "..=" } else { ".." }, None, right.map(|v| Box::new(v)))) +)); + +named!(expr_any, alt!( + range_right | + do_parse!( + left: expr_or >> + rest: range_right >> (match rest { + Expr::Range(op, _, right) => Expr::Range(op, Some(Box::new(left)), right), + _ => unreachable!(), + }) + ) | + expr_or +)); named!(expr_node, do_parse!( tag_s!("{{") >> -- cgit