diff options
Diffstat (limited to 'askama_parser/src/expr.rs')
-rw-r--r-- | askama_parser/src/expr.rs | 142 |
1 files changed, 71 insertions, 71 deletions
diff --git a/askama_parser/src/expr.rs b/askama_parser/src/expr.rs index 7896981..415b8f4 100644 --- a/askama_parser/src/expr.rs +++ b/askama_parser/src/expr.rs @@ -11,6 +11,39 @@ use nom::{error_position, IResult}; use super::{bool_lit, char_lit, identifier, not_ws, num_lit, path, str_lit, ws}; +macro_rules! expr_prec_layer { + ( $name:ident, $inner:ident, $op:expr ) => { + fn $name(i: &'a str) -> IResult<&'a str, Self> { + let (i, left) = Self::$inner(i)?; + let (i, right) = many0(pair( + ws(tag($op)), + Self::$inner, + ))(i)?; + Ok(( + i, + right.into_iter().fold(left, |left, (op, right)| { + Self::BinOp(op, Box::new(left), Box::new(right)) + }), + )) + } + }; + ( $name:ident, $inner:ident, $( $op:expr ),+ ) => { + fn $name(i: &'a str) -> IResult<&'a str, Self> { + let (i, left) = Self::$inner(i)?; + let (i, right) = many0(pair( + ws(alt(($( tag($op) ),+,))), + Self::$inner, + ))(i)?; + Ok(( + i, + right.into_iter().fold(left, |left, (op, right)| { + Self::BinOp(op, Box::new(left), Box::new(right)) + }), + )) + } + } +} + #[derive(Debug, PartialEq)] pub enum Expr<'a> { BoolLit(&'a str), @@ -43,13 +76,13 @@ impl<'a> Expr<'a> { } pub(super) fn parse(i: &'a str) -> IResult<&'a str, Self> { - let range_right = |i| pair(ws(alt((tag("..="), tag("..")))), opt(expr_or))(i); + let range_right = |i| pair(ws(alt((tag("..="), tag("..")))), opt(Self::or))(i); alt(( map(range_right, |(op, right)| { Self::Range(op, None, right.map(Box::new)) }), map( - pair(expr_or, opt(range_right)), + pair(Self::or, opt(range_right)), |(left, right)| match right { Some((op, right)) => Self::Range(op, Some(Box::new(left)), right.map(Box::new)), None => left, @@ -57,6 +90,42 @@ impl<'a> Expr<'a> { ), ))(i) } + + expr_prec_layer!(or, and, "||"); + expr_prec_layer!(and, compare, "&&"); + expr_prec_layer!(compare, bor, "==", "!=", ">=", ">", "<=", "<"); + expr_prec_layer!(bor, bxor, "|"); + expr_prec_layer!(bxor, band, "^"); + expr_prec_layer!(band, shifts, "&"); + expr_prec_layer!(shifts, addsub, ">>", "<<"); + expr_prec_layer!(addsub, muldivmod, "+", "-"); + expr_prec_layer!(muldivmod, filtered, "*", "/", "%"); + + fn filtered(i: &'a str) -> IResult<&'a str, Self> { + let (i, (obj, filters)) = tuple((Self::prefix, many0(filter)))(i)?; + + let mut res = obj; + for (fname, args) in filters { + res = Self::Filter(fname, { + let mut args = match args { + Some(inner) => inner, + None => Vec::new(), + }; + args.insert(0, res); + args + }); + } + + Ok((i, res)) + } + + fn prefix(i: &'a str) -> IResult<&'a str, Self> { + let (i, (ops, mut expr)) = pair(many0(ws(alt((tag("!"), tag("-"))))), Suffix::parse)(i)?; + for op in ops.iter().rev() { + expr = Self::Unary(op, Box::new(expr)); + } + Ok((i, expr)) + } } fn expr_bool_lit(i: &str) -> IResult<&str, Expr<'_>> { @@ -260,72 +329,3 @@ fn filter(i: &str) -> IResult<&str, (&str, Option<Vec<Expr<'_>>>)> { let (i, (_, fname, args)) = tuple((char('|'), ws(identifier), opt(Expr::arguments)))(i)?; Ok((i, (fname, args))) } - -fn expr_filtered(i: &str) -> IResult<&str, Expr<'_>> { - let (i, (obj, filters)) = tuple((expr_prefix, many0(filter)))(i)?; - - let mut res = obj; - for (fname, args) in filters { - res = Expr::Filter(fname, { - let mut args = match args { - Some(inner) => inner, - None => Vec::new(), - }; - args.insert(0, res); - args - }); - } - - Ok((i, res)) -} - -fn expr_prefix(i: &str) -> IResult<&str, Expr<'_>> { - let (i, (ops, mut expr)) = pair(many0(ws(alt((tag("!"), tag("-"))))), Suffix::parse)(i)?; - for op in ops.iter().rev() { - expr = Expr::Unary(op, Box::new(expr)); - } - Ok((i, expr)) -} - -macro_rules! expr_prec_layer { - ( $name:ident, $inner:ident, $op:expr ) => { - fn $name(i: &str) -> IResult<&str, Expr<'_>> { - let (i, left) = $inner(i)?; - let (i, right) = many0(pair( - ws(tag($op)), - $inner, - ))(i)?; - Ok(( - i, - right.into_iter().fold(left, |left, (op, right)| { - Expr::BinOp(op, Box::new(left), Box::new(right)) - }), - )) - } - }; - ( $name:ident, $inner:ident, $( $op:expr ),+ ) => { - fn $name(i: &str) -> IResult<&str, Expr<'_>> { - let (i, left) = $inner(i)?; - let (i, right) = many0(pair( - ws(alt(($( tag($op) ),+,))), - $inner, - ))(i)?; - Ok(( - i, - right.into_iter().fold(left, |left, (op, right)| { - Expr::BinOp(op, Box::new(left), Box::new(right)) - }), - )) - } - } -} - -expr_prec_layer!(expr_muldivmod, expr_filtered, "*", "/", "%"); -expr_prec_layer!(expr_addsub, expr_muldivmod, "+", "-"); -expr_prec_layer!(expr_shifts, expr_addsub, ">>", "<<"); -expr_prec_layer!(expr_band, expr_shifts, "&"); -expr_prec_layer!(expr_bxor, expr_band, "^"); -expr_prec_layer!(expr_bor, expr_bxor, "|"); -expr_prec_layer!(expr_compare, expr_bor, "==", "!=", ">=", ">", "<=", "<"); -expr_prec_layer!(expr_and, expr_compare, "&&"); -expr_prec_layer!(expr_or, expr_and, "||"); |