forked from mirrors/jj
templater: turn logical && and || into short-circuiting operators
Since the context (or self) property is no longer passed by argument, it's easy to implement short-circuiting behavior.
This commit is contained in:
parent
df7be43ab6
commit
96e0bc0bdd
2 changed files with 18 additions and 7 deletions
|
@ -495,16 +495,16 @@ fn build_binary_operation<'a, L: TemplateLanguage<'a> + ?Sized>(
|
||||||
) -> TemplateParseResult<L::Property> {
|
) -> TemplateParseResult<L::Property> {
|
||||||
match op {
|
match op {
|
||||||
BinaryOp::LogicalOr => {
|
BinaryOp::LogicalOr => {
|
||||||
// No short-circuiting supported
|
|
||||||
let lhs = expect_boolean_expression(language, build_ctx, lhs_node)?;
|
let lhs = expect_boolean_expression(language, build_ctx, lhs_node)?;
|
||||||
let rhs = expect_boolean_expression(language, build_ctx, rhs_node)?;
|
let rhs = expect_boolean_expression(language, build_ctx, rhs_node)?;
|
||||||
Ok(L::wrap_boolean((lhs, rhs).map(|(l, r)| l | r)))
|
let out = lhs.and_then(move |l| Ok(l || rhs.extract()?));
|
||||||
|
Ok(L::wrap_boolean(out))
|
||||||
}
|
}
|
||||||
BinaryOp::LogicalAnd => {
|
BinaryOp::LogicalAnd => {
|
||||||
// No short-circuiting supported
|
|
||||||
let lhs = expect_boolean_expression(language, build_ctx, lhs_node)?;
|
let lhs = expect_boolean_expression(language, build_ctx, lhs_node)?;
|
||||||
let rhs = expect_boolean_expression(language, build_ctx, rhs_node)?;
|
let rhs = expect_boolean_expression(language, build_ctx, rhs_node)?;
|
||||||
Ok(L::wrap_boolean((lhs, rhs).map(|(l, r)| l & r)))
|
let out = lhs.and_then(move |l| Ok(l && rhs.extract()?));
|
||||||
|
Ok(L::wrap_boolean(out))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1199,6 +1199,10 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_error_property<O>(message: &str) -> impl TemplateProperty<Output = O> + '_ {
|
||||||
|
Literal(()).and_then(|()| Err(TemplatePropertyError(message.into())))
|
||||||
|
}
|
||||||
|
|
||||||
fn new_signature(name: &str, email: &str) -> Signature {
|
fn new_signature(name: &str, email: &str) -> Signature {
|
||||||
Signature {
|
Signature {
|
||||||
name: name.to_owned(),
|
name: name.to_owned(),
|
||||||
|
@ -1490,7 +1494,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_logical_operation() {
|
fn test_logical_operation() {
|
||||||
let env = TestTemplateEnv::new();
|
let mut env = TestTemplateEnv::new();
|
||||||
|
|
||||||
insta::assert_snapshot!(env.render_ok(r#"!false"#), @"true");
|
insta::assert_snapshot!(env.render_ok(r#"!false"#), @"true");
|
||||||
insta::assert_snapshot!(env.render_ok(r#"false || !false"#), @"true");
|
insta::assert_snapshot!(env.render_ok(r#"false || !false"#), @"true");
|
||||||
|
@ -1498,6 +1502,13 @@ mod tests {
|
||||||
|
|
||||||
insta::assert_snapshot!(env.render_ok(r#" !"" "#), @"true");
|
insta::assert_snapshot!(env.render_ok(r#" !"" "#), @"true");
|
||||||
insta::assert_snapshot!(env.render_ok(r#" "" || "a".lines() "#), @"true");
|
insta::assert_snapshot!(env.render_ok(r#" "" || "a".lines() "#), @"true");
|
||||||
|
|
||||||
|
// Short-circuiting
|
||||||
|
env.add_keyword("bad_bool", || L::wrap_boolean(new_error_property("Bad")));
|
||||||
|
insta::assert_snapshot!(env.render_ok(r#"false && bad_bool"#), @"false");
|
||||||
|
insta::assert_snapshot!(env.render_ok(r#"true && bad_bool"#), @"<Error: Bad>");
|
||||||
|
insta::assert_snapshot!(env.render_ok(r#"false || bad_bool"#), @"<Error: Bad>");
|
||||||
|
insta::assert_snapshot!(env.render_ok(r#"true || bad_bool"#), @"true");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -31,8 +31,8 @@ The following operators are supported.
|
||||||
* `x.f()`: Method call.
|
* `x.f()`: Method call.
|
||||||
* `-x`: Negate integer value.
|
* `-x`: Negate integer value.
|
||||||
* `!x`: Logical not.
|
* `!x`: Logical not.
|
||||||
* `x && y`: Logical and.
|
* `x && y`: Logical and, short-circuiting.
|
||||||
* `x || y`: Logical or.
|
* `x || y`: Logical or, short-circuiting.
|
||||||
* `x ++ y`: Concatenate `x` and `y` templates.
|
* `x ++ y`: Concatenate `x` and `y` templates.
|
||||||
|
|
||||||
## Global functions
|
## Global functions
|
||||||
|
|
Loading…
Reference in a new issue