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:
René Kijewski 2024-06-19 10:58:43 +02:00
parent 704c506770
commit 879d889bb2
7 changed files with 125 additions and 120 deletions

View File

@ -4,14 +4,14 @@ use std::str;
use nom::branch::alt; use nom::branch::alt;
use nom::bytes::complete::{tag, take_till}; use nom::bytes::complete::{tag, take_till};
use nom::character::complete::char; 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::ErrorKind;
use nom::error_position; use nom::error_position;
use nom::multi::{fold_many0, many0, separated_list0}; use nom::multi::{fold_many0, many0, separated_list0};
use nom::sequence::{pair, preceded, terminated, tuple}; use nom::sequence::{pair, preceded, terminated, tuple};
use super::{ 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, PathOrIdentifier,
}; };
use crate::{ErrorContext, ParseResult, WithSpan}; use crate::{ErrorContext, ParseResult, WithSpan};
@ -22,10 +22,7 @@ macro_rules! expr_prec_layer {
let (_, level) = level.nest(i)?; let (_, level) = level.nest(i)?;
let start = i; let start = i;
let (i, left) = Self::$inner(i, level)?; let (i, left) = Self::$inner(i, level)?;
let (i, right) = many0(pair( let (i, right) = many0(pair(ws($op), |i| Self::$inner(i, level)))(i)?;
ws(tag($op)),
|i| Self::$inner(i, level),
))(i)?;
Ok(( Ok((
i, i,
right.into_iter().fold(left, |left, (op, right)| { 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)?; fn alternative_binop<'a>(
let start = i; rust: &'static str,
let (i, left) = Self::$inner(i, level)?; dont_match: Option<&'static str>,
let (i, right) = many0(pair( rinja: &'static str,
ws(alt(($( tag($op) ),+,))), ) -> impl Fn(&'a str) -> ParseResult<'a, &'static str> {
|i| Self::$inner(i, level), move |i: &'a str| -> ParseResult<'a, &'static str> {
))(i)?; let (_, fail) = opt(tag(rust))(i)?;
Ok(( if fail.is_some() {
i, let succeed = match dont_match {
right.into_iter().fold(left, |left, (op, right)| { Some(dont_match) => opt(tag(dont_match))(i)?.1.is_some(),
WithSpan::new(Self::BinOp(op, Box::new(left), Box::new(right)), start) 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) ))(i)
} }
expr_prec_layer!(or, and, "||"); expr_prec_layer!(or, and, tag("||"));
expr_prec_layer!(and, compare, "&&"); expr_prec_layer!(and, compare, tag("&&"));
expr_prec_layer!(compare, bor, "==", "!=", ">=", ">", "<=", "<"); expr_prec_layer!(
expr_prec_layer!(bor, bxor, "|"); compare,
expr_prec_layer!(bxor, band, "^"); bor,
expr_prec_layer!(band, shifts, "&"); alt((
expr_prec_layer!(shifts, addsub, ">>", "<<"); tag("=="),
expr_prec_layer!(addsub, muldivmod, "+", "-"); tag("!="),
expr_prec_layer!(muldivmod, filtered, "*", "/", "%"); 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>> { fn filtered(i: &'a str, mut level: Level) -> ParseResult<'a, WithSpan<'a, Self>> {
let start = i; let start = i;

View File

@ -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] #[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!( assert_eq!(
Ast::from_str("{{ (1)|abs }}", None, &syntax).unwrap().nodes, Ast::from_str("{{ (1)|abs }}", None, &syntax).unwrap().nodes,
vec![Node::Expr( 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!( assert_eq!(
Ast::from_str("{{ (1,)|abs }}", None, &syntax) Ast::from_str("{{ (1,)|abs }}", None, &syntax)
.unwrap() .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!( assert_eq!(
Ast::from_str("{{ (1, 2)|abs }}", None, &syntax) Ast::from_str("{{ (1, 2)|abs }}", None, &syntax)
.unwrap() .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] #[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] #[test]

View File

@ -34,8 +34,8 @@
{{-1}}{{ -1 }}{{ - 1 }} {{-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&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|2}}{{ 1|2 }}{{ 1 |2 }}{{ 1| 2 }} {{ 1 | 2 }} {{1 bitor 2}}{{ 1 bitor 2 }}{{ 1 bitor 2}}{{1 bitor 2 }} {{1 bitor 2}}
{{true}}{{false}} {{true}}{{false}}
{{!true}}{{ !true }}{{ ! true }} {{!true}}{{ !true }}{{ ! true }}

View File

@ -16,13 +16,13 @@
{% if c >> b == a -%} {% if c >> b == a -%}
lsh lsh
{%- endif -%} {%- endif -%}
{% if a & b == b -%} {% if a bitand b == b -%}
band band
{%- endif -%} {%- endif -%}
{% if b ^ c == a + c -%} {% if b xor c == a + c -%}
bxor bxor
{%- endif -%} {%- endif -%}
{% if (b | c) == a + c -%} {% if b bitor c == a + c -%}
bor bor
{%- endif -%} {%- endif -%}
{% if a == b && a + b == c -%} {% if a == b && a + b == c -%}

View File

@ -4,4 +4,4 @@
{{ 1 * 2 + 4 -}} {{ 1 * 2 + 4 -}}
{{ 11 - 15 / 3 -}} {{ 11 - 15 / 3 -}}
{{ 4 + 5 % 3 -}} {{ 4 + 5 % 3 -}}
{{ 4 | 2 + 5 & 2 -}} {{ 4 bitor 2 + 5 bitand 2 -}}

View 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() {
}

View 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)