diff --git a/src/uu/expr/src/syntax_tree.rs b/src/uu/expr/src/syntax_tree.rs index a5c453c1745..22d0bde13d5 100644 --- a/src/uu/expr/src/syntax_tree.rs +++ b/src/uu/expr/src/syntax_tree.rs @@ -624,9 +624,6 @@ pub struct AstNode { #[derive(Debug, Clone)] #[cfg_attr(test, derive(Eq, PartialEq))] pub enum AstNodeInner { - Evaluated { - value: NumOrStr, - }, Leaf { value: MaybeNonUtf8String, }, @@ -650,15 +647,6 @@ impl AstNode { Parser::new(input).parse() } - pub fn evaluated(self) -> ExprResult { - Ok(Self { - id: get_next_id(), - inner: AstNodeInner::Evaluated { - value: self.eval()?, - }, - }) - } - pub fn eval(&self) -> ExprResult { // This function implements a recursive tree-walking algorithm, but uses an explicit // stack approach instead of native recursion to avoid potential stack overflow @@ -669,9 +657,6 @@ impl AstNode { while let Some(node) = stack.pop() { match &node.inner { - AstNodeInner::Evaluated { value, .. } => { - result_stack.insert(node.id, Ok(value.clone())); - } AstNodeInner::Leaf { value, .. } => { result_stack.insert(node.id, Ok(value.to_owned().into())); } @@ -896,9 +881,7 @@ impl<'a, S: AsRef> Parser<'a, S> { value: self.next()?.into(), }, b"(" => { - // Evaluate the node just after parsing to we detect arithmetic - // errors before checking for the closing parenthesis. - let s = self.parse_expression()?.evaluated()?; + let s = self.parse_expression()?; match self.next() { Ok(b")") => {} @@ -1070,9 +1053,7 @@ mod test { AstNode::parse(&["(", "1", "+", "2", ")", "*", "3"]), Ok(op( BinOp::Numeric(NumericOp::Mul), - op(BinOp::Numeric(NumericOp::Add), "1", "2") - .evaluated() - .unwrap(), + op(BinOp::Numeric(NumericOp::Add), "1", "2"), "3" )) ); diff --git a/tests/by-util/test_expr.rs b/tests/by-util/test_expr.rs index ec1cf91598f..c95465af7a7 100644 --- a/tests/by-util/test_expr.rs +++ b/tests/by-util/test_expr.rs @@ -217,6 +217,29 @@ fn test_and() { new_ucmd!().args(&["", "&", ""]).fails().stdout_only("0\n"); } +#[test] +fn test_parenthesized_short_circuit_dead_branches() { + new_ucmd!() + .args(&["1", "|", "(", "1", "/", "0", ")"]) + .succeeds() + .stdout_only("1\n"); + + new_ucmd!() + .args(&["0", "&", "(", "1", "/", "0", ")"]) + .fails_with_code(1) + .stdout_only("0\n"); + + new_ucmd!() + .args(&["1", "|", "(", "0", "&", "(", "1", "/", "0", ")", ")"]) + .succeeds() + .stdout_only("1\n"); + + new_ucmd!() + .args(&["0", "&", "(", "1", "|", "(", "1", "/", "0", ")", ")"]) + .fails_with_code(1) + .stdout_only("0\n"); +} + #[test] fn test_length_fail() { new_ucmd!().args(&["length", "αbcdef", "1"]).fails(); @@ -580,11 +603,11 @@ fn test_num_str_comparison() { } #[test] -fn test_eager_evaluation() { +fn test_missing_closing_parenthesis_reports_syntax_error() { new_ucmd!() .args(&["(", "1", "/", "0"]) .fails() - .stderr_contains("division by zero"); + .stderr_contains("expecting ')' after '0'"); } #[test]