Merge #1041: Keep not <var> from reading back as a variable named 'not …' (@Silvertree2010)

This commit is contained in:
bflatastic
2026-10-24 09:23:02 +07:00
2 changed files with 30 additions and 1 deletions
+6 -1
View File
@@ -169,7 +169,12 @@ impl Expr {
}) })
.collect(); .collect();
match (op, parts.as_slice()) { match (op, parts.as_slice()) {
(ExprOp::Not, [x]) => format!("not {x}"), // `not done` reads as a variable named "not done" if there is one: then
// `not (done)`.
(ExprOp::Not, [x]) => {
let bare = format!("not {x}");
if x.starts_with('(') || Expr::parse(&bare, vars).is_ok_and(|e| e == *self) { bare } else { format!("not ({x})") }
}
(ExprOp::Negate, [x]) => format!("-{x}"), (ExprOp::Negate, [x]) => format!("-{x}"),
_ => parts.join(&format!(" {} ", op.symbol())), _ => parts.join(&format!(" {} ", op.symbol())),
} }
+24
View File
@@ -195,3 +195,27 @@ fn names_that_look_like_literals_read_back_as_variables() {
assert_eq!(parse("1"), n(1.0)); assert_eq!(parse("1"), n(1.0));
assert_eq!(parse("\"q\""), Expr::Value(VariableValue::String("q".into()))); assert_eq!(parse("\"q\""), Expr::Value(VariableValue::String("q".into())));
} }
#[test]
fn not_of_a_variable_reads_back_when_a_name_starts_with_not() {
use ExprOp::*;
let mut v = vars();
let b = v.variables.iter().find(|x| x.id == "b").unwrap().clone();
for (id, name) in [("done", "done"), ("nd", "not done")] {
let mut x = b.clone();
x.id = id.into();
x.name = name.into();
v.variables.push(x);
}
let not_done = Expr::op(Not, vec![Expr::var("done")]);
for e in [
not_done.clone(),
Expr::op(And, vec![Expr::var("b"), not_done.clone()]),
Expr::op(Equals, vec![not_done.clone(), Expr::Value(VariableValue::Boolean(true))]),
Expr::op(Not, vec![not_done.clone()]),
] {
let shown = e.display(&v);
assert_eq!(Expr::parse(&shown, &v), Ok(e.clone()), "shown as {shown:?}");
}
assert_eq!(Expr::op(Not, vec![Expr::var("b")]).display(&vars()), "not b-name", "plain names stay bare");
}