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> {
|
||||
match op {
|
||||
BinaryOp::LogicalOr => {
|
||||
// No short-circuiting supported
|
||||
let lhs = expect_boolean_expression(language, build_ctx, lhs_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 => {
|
||||
// No short-circuiting supported
|
||||
let lhs = expect_boolean_expression(language, build_ctx, lhs_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 {
|
||||
Signature {
|
||||
name: name.to_owned(),
|
||||
|
@ -1490,7 +1494,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
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 || !false"#), @"true");
|
||||
|
@ -1498,6 +1502,13 @@ mod tests {
|
|||
|
||||
insta::assert_snapshot!(env.render_ok(r#" !"" "#), @"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]
|
||||
|
|
|
@ -31,8 +31,8 @@ The following operators are supported.
|
|||
* `x.f()`: Method call.
|
||||
* `-x`: Negate integer value.
|
||||
* `!x`: Logical not.
|
||||
* `x && y`: Logical and.
|
||||
* `x || y`: Logical or.
|
||||
* `x && y`: Logical and, short-circuiting.
|
||||
* `x || y`: Logical or, short-circuiting.
|
||||
* `x ++ y`: Concatenate `x` and `y` templates.
|
||||
|
||||
## Global functions
|
||||
|
|
Loading…
Reference in a new issue