mirror of
https://github.com/askama-rs/askama.git
synced 2025-10-02 15:25:19 +00:00
Use ISO 646 alternative operators for bit ops
This change allows simplifying the use of filter expressions, because you won't have to care about spaces around the `|` pipe operator.
This commit is contained in:
parent
704c506770
commit
879d889bb2
@ -4,14 +4,14 @@ use std::str;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::{tag, take_till};
|
||||
use nom::character::complete::char;
|
||||
use nom::combinator::{cut, map, not, opt, peek, recognize};
|
||||
use nom::combinator::{cut, map, not, opt, peek, recognize, value};
|
||||
use nom::error::ErrorKind;
|
||||
use nom::error_position;
|
||||
use nom::multi::{fold_many0, many0, separated_list0};
|
||||
use nom::sequence::{pair, preceded, terminated, tuple};
|
||||
|
||||
use super::{
|
||||
char_lit, filter, identifier, not_ws, num_lit, path_or_identifier, str_lit, ws, Level,
|
||||
char_lit, filter, identifier, keyword, not_ws, num_lit, path_or_identifier, str_lit, ws, Level,
|
||||
PathOrIdentifier,
|
||||
};
|
||||
use crate::{ErrorContext, ParseResult, WithSpan};
|
||||
@ -22,10 +22,7 @@ macro_rules! expr_prec_layer {
|
||||
let (_, level) = level.nest(i)?;
|
||||
let start = i;
|
||||
let (i, left) = Self::$inner(i, level)?;
|
||||
let (i, right) = many0(pair(
|
||||
ws(tag($op)),
|
||||
|i| Self::$inner(i, level),
|
||||
))(i)?;
|
||||
let (i, right) = many0(pair(ws($op), |i| Self::$inner(i, level)))(i)?;
|
||||
Ok((
|
||||
i,
|
||||
right.into_iter().fold(left, |left, (op, right)| {
|
||||
@ -34,22 +31,28 @@ macro_rules! expr_prec_layer {
|
||||
))
|
||||
}
|
||||
};
|
||||
( $name:ident, $inner:ident, $( $op:expr ),+ ) => {
|
||||
fn $name(i: &'a str, level: Level) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||
let (_, level) = level.nest(i)?;
|
||||
let start = i;
|
||||
let (i, left) = Self::$inner(i, level)?;
|
||||
let (i, right) = many0(pair(
|
||||
ws(alt(($( tag($op) ),+,))),
|
||||
|i| Self::$inner(i, level),
|
||||
))(i)?;
|
||||
Ok((
|
||||
i,
|
||||
right.into_iter().fold(left, |left, (op, right)| {
|
||||
WithSpan::new(Self::BinOp(op, Box::new(left), Box::new(right)), start)
|
||||
}),
|
||||
))
|
||||
}
|
||||
|
||||
fn alternative_binop<'a>(
|
||||
rust: &'static str,
|
||||
dont_match: Option<&'static str>,
|
||||
rinja: &'static str,
|
||||
) -> impl Fn(&'a str) -> ParseResult<'a, &'static str> {
|
||||
move |i: &'a str| -> ParseResult<'a, &'static str> {
|
||||
let (_, fail) = opt(tag(rust))(i)?;
|
||||
if fail.is_some() {
|
||||
let succeed = match dont_match {
|
||||
Some(dont_match) => opt(tag(dont_match))(i)?.1.is_some(),
|
||||
None => false,
|
||||
};
|
||||
if !succeed {
|
||||
return Err(nom::Err::Failure(ErrorContext::new(
|
||||
format!("the binary operator '{rust}' is called '{rinja}' in rinja"),
|
||||
i,
|
||||
)));
|
||||
}
|
||||
}
|
||||
value(rust, keyword(rinja))(i)
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,15 +192,26 @@ 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, "*", "/", "%");
|
||||
expr_prec_layer!(or, and, tag("||"));
|
||||
expr_prec_layer!(and, compare, tag("&&"));
|
||||
expr_prec_layer!(
|
||||
compare,
|
||||
bor,
|
||||
alt((
|
||||
tag("=="),
|
||||
tag("!="),
|
||||
tag(">="),
|
||||
tag(">"),
|
||||
tag("<="),
|
||||
tag("<"),
|
||||
))
|
||||
);
|
||||
expr_prec_layer!(bor, bxor, alternative_binop("|", Some("||"), "bitor"));
|
||||
expr_prec_layer!(bxor, band, alternative_binop("^", None, "xor"));
|
||||
expr_prec_layer!(band, shifts, alternative_binop("&", Some("&&"), "bitand"));
|
||||
expr_prec_layer!(shifts, addsub, alt((tag(">>"), tag("<<"))));
|
||||
expr_prec_layer!(addsub, muldivmod, alt((tag("+"), tag("-"))));
|
||||
expr_prec_layer!(muldivmod, filtered, alt((tag("*"), tag("/"), tag("%"))));
|
||||
|
||||
fn filtered(i: &'a str, mut level: Level) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||
let start = i;
|
||||
|
@ -684,20 +684,6 @@ fn test_odd_calls() {
|
||||
})),
|
||||
)]
|
||||
);
|
||||
assert_eq!(
|
||||
Ast::from_str("{{ a(b) |c }}", None, &syntax).unwrap().nodes,
|
||||
vec![Node::Expr(
|
||||
Ws(None, None),
|
||||
WithSpan::no_span(Expr::BinOp(
|
||||
"|",
|
||||
Box::new(WithSpan::no_span(Expr::Call(
|
||||
Box::new(WithSpan::no_span(Expr::Var("a"))),
|
||||
vec![WithSpan::no_span(Expr::Var("b"))]
|
||||
))),
|
||||
Box::new(WithSpan::no_span(Expr::Var("c")))
|
||||
),)
|
||||
)]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -847,19 +833,6 @@ fn test_parse_tuple() {
|
||||
})),
|
||||
)],
|
||||
);
|
||||
assert_eq!(
|
||||
Ast::from_str("{{ () | abs }}", None, &syntax)
|
||||
.unwrap()
|
||||
.nodes,
|
||||
vec![Node::Expr(
|
||||
Ws(None, None),
|
||||
WithSpan::no_span(Expr::BinOp(
|
||||
"|",
|
||||
Box::new(WithSpan::no_span(Expr::Tuple(vec![]))),
|
||||
Box::new(WithSpan::no_span(Expr::Var("abs")))
|
||||
)),
|
||||
)],
|
||||
);
|
||||
assert_eq!(
|
||||
Ast::from_str("{{ (1)|abs }}", None, &syntax).unwrap().nodes,
|
||||
vec![Node::Expr(
|
||||
@ -872,21 +845,6 @@ fn test_parse_tuple() {
|
||||
})),
|
||||
)],
|
||||
);
|
||||
assert_eq!(
|
||||
Ast::from_str("{{ (1) | abs }}", None, &syntax)
|
||||
.unwrap()
|
||||
.nodes,
|
||||
vec![Node::Expr(
|
||||
Ws(None, None),
|
||||
WithSpan::no_span(Expr::BinOp(
|
||||
"|",
|
||||
Box::new(WithSpan::no_span(Expr::Group(Box::new(WithSpan::no_span(
|
||||
Expr::NumLit("1")
|
||||
))))),
|
||||
Box::new(WithSpan::no_span(Expr::Var("abs")))
|
||||
)),
|
||||
)],
|
||||
);
|
||||
assert_eq!(
|
||||
Ast::from_str("{{ (1,)|abs }}", None, &syntax)
|
||||
.unwrap()
|
||||
@ -901,21 +859,6 @@ fn test_parse_tuple() {
|
||||
})),
|
||||
)],
|
||||
);
|
||||
assert_eq!(
|
||||
Ast::from_str("{{ (1,) | abs }}", None, &syntax)
|
||||
.unwrap()
|
||||
.nodes,
|
||||
vec![Node::Expr(
|
||||
Ws(None, None),
|
||||
WithSpan::no_span(Expr::BinOp(
|
||||
"|",
|
||||
Box::new(WithSpan::no_span(Expr::Tuple(vec![WithSpan::no_span(
|
||||
Expr::NumLit("1")
|
||||
)]))),
|
||||
Box::new(WithSpan::no_span(Expr::Var("abs")))
|
||||
)),
|
||||
)],
|
||||
);
|
||||
assert_eq!(
|
||||
Ast::from_str("{{ (1, 2)|abs }}", None, &syntax)
|
||||
.unwrap()
|
||||
@ -931,22 +874,6 @@ fn test_parse_tuple() {
|
||||
})),
|
||||
)],
|
||||
);
|
||||
assert_eq!(
|
||||
Ast::from_str("{{ (1, 2) | abs }}", None, &syntax)
|
||||
.unwrap()
|
||||
.nodes,
|
||||
vec![Node::Expr(
|
||||
Ws(None, None),
|
||||
WithSpan::no_span(Expr::BinOp(
|
||||
"|",
|
||||
Box::new(WithSpan::no_span(Expr::Tuple(vec![
|
||||
WithSpan::no_span(Expr::NumLit("1")),
|
||||
WithSpan::no_span(Expr::NumLit("2"))
|
||||
]))),
|
||||
Box::new(WithSpan::no_span(Expr::Var("abs")))
|
||||
)),
|
||||
)],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1050,17 +977,6 @@ fn test_parse_array() {
|
||||
}))
|
||||
)],
|
||||
);
|
||||
assert_eq!(
|
||||
Ast::from_str("{{ [] |foo }}", None, &syntax).unwrap().nodes,
|
||||
vec![Node::Expr(
|
||||
Ws(None, None),
|
||||
WithSpan::no_span(Expr::BinOp(
|
||||
"|",
|
||||
Box::new(WithSpan::no_span(Expr::Array(vec![]))),
|
||||
Box::new(WithSpan::no_span(Expr::Var("foo")))
|
||||
)),
|
||||
)],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -34,8 +34,8 @@
|
||||
{{-1}}{{ -1 }}{{ - 1 }}
|
||||
{{1+2}}{{ 1+2 }}{{ 1 +2 }}{{ 1+ 2 }} {{ 1 + 2 }}
|
||||
{{1*2}}{{ 1*2 }}{{ 1 *2 }}{{ 1* 2 }} {{ 1 * 2 }}
|
||||
{{1&2}}{{ 1&2 }}{{ 1 &2 }}{{ 1& 2 }} {{ 1 & 2 }}
|
||||
{{1|2}}{{ 1|2 }}{{ 1 |2 }}{{ 1| 2 }} {{ 1 | 2 }}
|
||||
{{1 bitand 2}}{{ 1 bitand 2 }}{{ 1 bitand 2 }}{{ 1 bitand 2 }} {{ 1 bitand 2 }}
|
||||
{{1 bitor 2}}{{ 1 bitor 2 }}{{ 1 bitor 2}}{{1 bitor 2 }} {{1 bitor 2}}
|
||||
|
||||
{{true}}{{false}}
|
||||
{{!true}}{{ !true }}{{ ! true }}
|
||||
|
@ -16,13 +16,13 @@
|
||||
{% if c >> b == a -%}
|
||||
lsh
|
||||
{%- endif -%}
|
||||
{% if a & b == b -%}
|
||||
{% if a bitand b == b -%}
|
||||
band
|
||||
{%- endif -%}
|
||||
{% if b ^ c == a + c -%}
|
||||
{% if b xor c == a + c -%}
|
||||
bxor
|
||||
{%- endif -%}
|
||||
{% if (b | c) == a + c -%}
|
||||
{% if b bitor c == a + c -%}
|
||||
bor
|
||||
{%- endif -%}
|
||||
{% if a == b && a + b == c -%}
|
||||
|
@ -4,4 +4,4 @@
|
||||
{{ 1 * 2 + 4 -}}
|
||||
{{ 11 - 15 / 3 -}}
|
||||
{{ 4 + 5 % 3 -}}
|
||||
{{ 4 | 2 + 5 & 2 -}}
|
||||
{{ 4 bitor 2 + 5 bitand 2 -}}
|
||||
|
46
testing/tests/ui/iso646.rs
Normal file
46
testing/tests/ui/iso646.rs
Normal file
@ -0,0 +1,46 @@
|
||||
use rinja::Template;
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(ext = "txt", source = "{{ a & b }}")]
|
||||
struct BitAnd {
|
||||
a: u32,
|
||||
b: u32,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(ext = "txt", source = "{{ a bitand b }}")]
|
||||
struct BitAndIso646 {
|
||||
a: u32,
|
||||
b: u32,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(ext = "txt", source = "{{ a | b }}")]
|
||||
struct BitOr {
|
||||
a: u32,
|
||||
b: u32,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(ext = "txt", source = "{{ a bitor b }}")]
|
||||
struct BitOrIso646 {
|
||||
a: u32,
|
||||
b: u32,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(ext = "txt", source = "{{ a ^ b }}")]
|
||||
struct Xor {
|
||||
a: u32,
|
||||
b: u32,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(ext = "txt", source = "{{ a xor b }}")]
|
||||
struct XorIso646 {
|
||||
a: u32,
|
||||
b: u32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
29
testing/tests/ui/iso646.stderr
Normal file
29
testing/tests/ui/iso646.stderr
Normal file
@ -0,0 +1,29 @@
|
||||
error: the binary operator '&' is called 'bitand' in rinja
|
||||
failed to parse template source at row 1, column 5 near:
|
||||
"& b }}"
|
||||
--> tests/ui/iso646.rs:3:10
|
||||
|
|
||||
3 | #[derive(Template)]
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: the binary operator '|' is called 'bitor' in rinja
|
||||
failed to parse template source at row 1, column 5 near:
|
||||
"| b }}"
|
||||
--> tests/ui/iso646.rs:17:10
|
||||
|
|
||||
17 | #[derive(Template)]
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: the binary operator '^' is called 'xor' in rinja
|
||||
failed to parse template source at row 1, column 5 near:
|
||||
"^ b }}"
|
||||
--> tests/ui/iso646.rs:31:10
|
||||
|
|
||||
31 | #[derive(Template)]
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info)
|
Loading…
x
Reference in New Issue
Block a user