diff options
Diffstat (limited to '')
| -rw-r--r-- | askama_shared/src/parser.rs | 206 | 
1 files changed, 173 insertions, 33 deletions
diff --git a/askama_shared/src/parser.rs b/askama_shared/src/parser.rs index 9344c07..7224d02 100644 --- a/askama_shared/src/parser.rs +++ b/askama_shared/src/parser.rs @@ -573,36 +573,32 @@ fn expr_rust_macro(i: &[u8]) -> IResult<&[u8], Expr> {  macro_rules! expr_prec_layer {      ( $name:ident, $inner:ident, $op:expr ) => {          fn $name(i: &[u8]) -> IResult<&[u8], Expr> { -            let (i, (left, op_and_right)) = tuple(( +            let (i, left) = $inner(i)?; +            let (i, right) = many0(pair( +                ws(tag($op)),                  $inner, -                opt(pair( -                    ws(tag($op)), -                    expr_any, -                ))              ))(i)?; -            Ok((i, match op_and_right { -                Some((op, right)) => Expr::BinOp( -                    str::from_utf8(op).unwrap(), Box::new(left), Box::new(right) -                ), -                None => left, -            })) +            Ok(( +                i, +                right.into_iter().fold(left, |left, (op, right)| { +                    Expr::BinOp(str::from_utf8(op).unwrap(), Box::new(left), Box::new(right)) +                }), +            ))          }      };      ( $name:ident, $inner:ident, $( $op:expr ),+ ) => {          fn $name(i: &[u8]) -> IResult<&[u8], Expr> { -            let (i, (left, op_and_right)) = tuple(( +            let (i, left) = $inner(i)?; +            let (i, right) = many0(pair( +                ws(alt(($( tag($op) ),*,))),                  $inner, -                opt(pair( -                    ws(alt(($( tag($op) ),*,))), -                    expr_any -                ))              ))(i)?; -            Ok((i, match op_and_right { -                Some((op, right)) => Expr::BinOp( -                    str::from_utf8(op).unwrap(), Box::new(left), Box::new(right) -                ), -                None => left, -            })) +            Ok(( +                i, +                right.into_iter().fold(left, |left, (op, right)| { +                    Expr::BinOp(str::from_utf8(op).unwrap(), Box::new(left), Box::new(right)) +                }), +            ))          }      }  } @@ -1078,12 +1074,13 @@ pub fn parse<'a>(src: &'a str, syntax: &'a Syntax<'a>) -> Result<Vec<Node<'a>>,  #[cfg(test)]  mod tests { +    use super::{Expr, Node, WS};      use crate::Syntax;      fn check_ws_split(s: &str, res: &(&str, &str, &str)) {          let node = super::split_ws_parts(s.as_bytes());          match node { -            super::Node::Lit(lws, s, rws) => { +            Node::Lit(lws, s, rws) => {                  assert_eq!(lws, res.0);                  assert_eq!(s, res.1);                  assert_eq!(rws, res.2); @@ -1118,12 +1115,9 @@ mod tests {      fn test_parse_var_call() {          assert_eq!(              super::parse("{{ function(\"123\", 3) }}", &Syntax::default()).unwrap(), -            vec![super::Node::Expr( -                super::WS(false, false), -                super::Expr::VarCall( -                    "function", -                    vec![super::Expr::StrLit("123"), super::Expr::NumLit("3")] -                ), +            vec![Node::Expr( +                WS(false, false), +                Expr::VarCall("function", vec![Expr::StrLit("123"), Expr::NumLit("3")]),              )],          );      } @@ -1132,11 +1126,11 @@ mod tests {      fn test_parse_path_call() {          assert_eq!(              super::parse("{{ self::function(\"123\", 3) }}", &Syntax::default()).unwrap(), -            vec![super::Node::Expr( -                super::WS(false, false), -                super::Expr::PathCall( +            vec![Node::Expr( +                WS(false, false), +                Expr::PathCall(                      vec!["self", "function"], -                    vec![super::Expr::StrLit("123"), super::Expr::NumLit("3")], +                    vec![Expr::StrLit("123"), Expr::NumLit("3")],                  ),              )],          ); @@ -1152,6 +1146,152 @@ mod tests {          super::parse("{~ strvar|e ~}", &syntax).unwrap();      } + +    #[test] +    fn test_precedence() { +        use Expr::*; +        let syntax = Syntax::default(); +        assert_eq!( +            super::parse("{{ a + b == c }}", &syntax).unwrap(), +            vec![Node::Expr( +                WS(false, false), +                BinOp( +                    "==", +                    BinOp("+", Var("a").into(), Var("b").into()).into(), +                    Var("c").into(), +                ) +            )], +        ); +        assert_eq!( +            super::parse("{{ a + b * c - d / e }}", &syntax).unwrap(), +            vec![Node::Expr( +                WS(false, false), +                BinOp( +                    "-", +                    BinOp( +                        "+", +                        Var("a").into(), +                        BinOp("*", Var("b").into(), Var("c").into()).into(), +                    ) +                    .into(), +                    BinOp("/", Var("d").into(), Var("e").into()).into(), +                ) +            )], +        ); +        assert_eq!( +            super::parse("{{ a * (b + c) / -d }}", &syntax).unwrap(), +            vec![Node::Expr( +                WS(false, false), +                BinOp( +                    "/", +                    BinOp( +                        "*", +                        Var("a").into(), +                        Group(BinOp("+", Var("b").into(), Var("c").into()).into()).into() +                    ) +                    .into(), +                    Unary("-", Var("d").into()).into() +                ) +            )], +        ); +        assert_eq!( +            super::parse("{{ a || b && c || d && e }}", &syntax).unwrap(), +            vec![Node::Expr( +                WS(false, false), +                BinOp( +                    "||", +                    BinOp( +                        "||", +                        Var("a").into(), +                        BinOp("&&", Var("b").into(), Var("c").into()).into(), +                    ) +                    .into(), +                    BinOp("&&", Var("d").into(), Var("e").into()).into(), +                ) +            )], +        ); +    } + +    #[test] +    fn test_associativity() { +        use Expr::*; +        let syntax = Syntax::default(); +        assert_eq!( +            super::parse("{{ a + b + c }}", &syntax).unwrap(), +            vec![Node::Expr( +                WS(false, false), +                BinOp( +                    "+", +                    BinOp("+", Var("a").into(), Var("b").into()).into(), +                    Var("c").into() +                ) +            )], +        ); +        assert_eq!( +            super::parse("{{ a * b * c }}", &syntax).unwrap(), +            vec![Node::Expr( +                WS(false, false), +                BinOp( +                    "*", +                    BinOp("*", Var("a").into(), Var("b").into()).into(), +                    Var("c").into() +                ) +            )], +        ); +        assert_eq!( +            super::parse("{{ a && b && c }}", &syntax).unwrap(), +            vec![Node::Expr( +                WS(false, false), +                BinOp( +                    "&&", +                    BinOp("&&", Var("a").into(), Var("b").into()).into(), +                    Var("c").into() +                ) +            )], +        ); +        assert_eq!( +            super::parse("{{ a + b - c + d }}", &syntax).unwrap(), +            vec![Node::Expr( +                WS(false, false), +                BinOp( +                    "+", +                    BinOp( +                        "-", +                        BinOp("+", Var("a").into(), Var("b").into()).into(), +                        Var("c").into() +                    ) +                    .into(), +                    Var("d").into() +                ) +            )], +        ); +        assert_eq!( +            super::parse("{{ a == b != c > d > e == f }}", &syntax).unwrap(), +            vec![Node::Expr( +                WS(false, false), +                BinOp( +                    "==", +                    BinOp( +                        ">", +                        BinOp( +                            ">", +                            BinOp( +                                "!=", +                                BinOp("==", Var("a").into(), Var("b").into()).into(), +                                Var("c").into() +                            ) +                            .into(), +                            Var("d").into() +                        ) +                        .into(), +                        Var("e").into() +                    ) +                    .into(), +                    Var("f").into() +                ) +            )], +        ); +    }  }  type ParserError<'a, T> = Result<(&'a [u8], T), nom::Err<nom::error::Error<&'a [u8]>>>;  | 
