diff --git a/crates/deno_task_shell/src/grammar.pest b/crates/deno_task_shell/src/grammar.pest index 68657bf..6289e84 100644 --- a/crates/deno_task_shell/src/grammar.pest +++ b/crates/deno_task_shell/src/grammar.pest @@ -202,34 +202,33 @@ bitwise_or = { "|" } logical_and = { "&&" } logical_or = { "||" } +unary_plus = { "+" } +unary_minus = { "-" } +logical_not = { "!" } +bitwise_not = { "~" } +increment = { "++" } +decrement = { "--" } + unary_arithmetic_expr = !{ unary_pre_arithmetic_expr | unary_post_arithmetic_expr } unary_pre_arithmetic_expr = !{ - (post_arithmetic_op | pre_arithmetic_op) ~ (parentheses_expr | VARIABLE | NUMBER) + pre_arithmetic_op ~ (parentheses_expr | VARIABLE | NUMBER) } unary_post_arithmetic_expr = !{ (parentheses_expr | VARIABLE | NUMBER) ~ post_arithmetic_op } -pre_arithmetic_op= _{ - unary_plus | unary_minus | logical_not | bitwise_not +pre_arithmetic_op= !{ + increment | decrement | unary_plus | unary_minus | logical_not | bitwise_not } -unary_plus = { "+" } -unary_minus = { "-" } -logical_not = { "!" } -bitwise_not = { "~" } - post_arithmetic_op = !{ increment | decrement } -increment = { "++" } -decrement = { "--" } - assignment_operator = _{ assign | multiply_assign | divide_assign | modulo_assign | add_assign | subtract_assign | left_shift_assign | right_shift_assign | bitwise_and_assign | bitwise_xor_assign | bitwise_or_assign diff --git a/crates/deno_task_shell/src/parser.rs b/crates/deno_task_shell/src/parser.rs index 2e4fb0d..9a3cbf8 100644 --- a/crates/deno_task_shell/src/parser.rs +++ b/crates/deno_task_shell/src/parser.rs @@ -1469,9 +1469,9 @@ fn unary_pre_arithmetic_expr(pair: Pair) -> Result { }) } Rule::post_arithmetic_op => { - let op = parse_pre_arithmetic_op(first)?; + let op = parse_post_arithmetic_op(first)?; Ok(ArithmeticPart::UnaryArithmeticExpr { - operator: UnaryArithmeticOp::Pre(op), + operator: UnaryArithmeticOp::Post(op), operand: Box::new(operand), }) } @@ -1519,12 +1519,12 @@ fn parse_pre_arithmetic_op(pair: Pair) -> Result { match first.as_rule() { Rule::increment => Ok(PreArithmeticOp::Increment), Rule::decrement => Ok(PreArithmeticOp::Decrement), - Rule::add => Ok(PreArithmeticOp::Plus), - Rule::subtract => Ok(PreArithmeticOp::Minus), + Rule::unary_plus => Ok(PreArithmeticOp::Plus), + Rule::unary_minus => Ok(PreArithmeticOp::Minus), Rule::logical_not => Ok(PreArithmeticOp::LogicalNot), Rule::bitwise_not => Ok(PreArithmeticOp::BitwiseNot), _ => Err(miette!( - "Unexpected rule in post arithmetic operator: {:?}", + "Unexpected rule in pre arithmetic operator: {:?}", first.as_rule() )), } diff --git a/crates/deno_task_shell/src/shell/types.rs b/crates/deno_task_shell/src/shell/types.rs index 1ca905b..f8db925 100644 --- a/crates/deno_task_shell/src/shell/types.rs +++ b/crates/deno_task_shell/src/shell/types.rs @@ -636,17 +636,19 @@ impl ArithmeticResult { ArithmeticValue::Integer(val) => match operand { ArithmeticPart::Variable(name) => { let mut new_changes = self.changes.clone(); - new_changes.push(EnvChange::SetShellVar( - name.to_string(), - match op_type { - PreArithmeticOp::Increment => (*val + 1).to_string(), - PreArithmeticOp::Decrement => (*val - 1).to_string(), - _ => todo!( - "Unary arithmetic operation not implemented {:?}", - op_type - ), - }, - )); + if op_type == PreArithmeticOp::Increment + || op_type == PreArithmeticOp::Decrement + { + new_changes.push(EnvChange::SetShellVar( + name.to_string(), + match op_type { + PreArithmeticOp::Increment => (*val + 1).to_string(), + PreArithmeticOp::Decrement => (*val - 1).to_string(), + _ => Err(miette!("No change to ENV need for: {}", self))?, + }, + )); + } + Ok(ArithmeticResult { value: match op_type { PreArithmeticOp::Increment => { @@ -655,10 +657,14 @@ impl ArithmeticResult { PreArithmeticOp::Decrement => { ArithmeticValue::Integer(*val - 1) } - _ => todo!( - "Unary arithmetic operation not implemented {:?}", - op_type - ), + PreArithmeticOp::Plus => ArithmeticValue::Integer((*val).abs()), + PreArithmeticOp::Minus => { + ArithmeticValue::Integer(-(*val).abs()) + } + PreArithmeticOp::BitwiseNot => ArithmeticValue::Integer(!*val), + PreArithmeticOp::LogicalNot => { + ArithmeticValue::Integer(if *val == 0 { 1 } else { 0 }) + } }, changes: new_changes, }) @@ -671,17 +677,19 @@ impl ArithmeticResult { ArithmeticValue::Float(val) => match operand { ArithmeticPart::Variable(name) => { let mut new_changes = self.changes.clone(); - new_changes.push(EnvChange::SetShellVar( - name.to_string(), - match op_type { - PreArithmeticOp::Increment => (*val + 1.0).to_string(), - PreArithmeticOp::Decrement => (*val - 1.0).to_string(), - _ => todo!( - "Unary arithmetic operation not implemented {:?}", - op_type - ), - }, - )); + if op_type == PreArithmeticOp::Increment + || op_type == PreArithmeticOp::Decrement + { + new_changes.push(EnvChange::SetShellVar( + name.to_string(), + match op_type { + PreArithmeticOp::Increment => (*val + 1.0).to_string(), + PreArithmeticOp::Decrement => (*val - 1.0).to_string(), + _ => Err(miette!("No change to ENV need for: {}", self))?, + }, + )); + } + Ok(ArithmeticResult { value: match op_type { PreArithmeticOp::Increment => { @@ -690,10 +698,14 @@ impl ArithmeticResult { PreArithmeticOp::Decrement => { ArithmeticValue::Float(*val - 1.0) } - _ => todo!( - "Unary arithmetic operation not implemented {:?}", - op_type - ), + PreArithmeticOp::Plus => ArithmeticValue::Float((*val).abs()), + PreArithmeticOp::Minus => ArithmeticValue::Float(-(*val).abs()), + PreArithmeticOp::BitwiseNot => { + ArithmeticValue::Integer(!(*val as i64)) + } + PreArithmeticOp::LogicalNot => { + ArithmeticValue::Float(if *val == 0.0 { 1.0 } else { 0.0 }) + } }, changes: new_changes, }) diff --git a/crates/tests/src/lib.rs b/crates/tests/src/lib.rs index a489b98..6c73b7e 100644 --- a/crates/tests/src/lib.rs +++ b/crates/tests/src/lib.rs @@ -904,6 +904,30 @@ async fn arithmetic() { .assert_stdout("0\n") .run() .await; + + TestBuilder::new() + .command("echo $((a=1, +a))") + .assert_stdout("1\n") + .run() + .await; + + TestBuilder::new() + .command("echo $((a=1, -a))") + .assert_stdout("-1\n") + .run() + .await; + + TestBuilder::new() + .command("echo $((a=3, ~a))") + .assert_stdout("-4\n") + .run() + .await; + + TestBuilder::new() + .command("echo $((a=0, !a))") + .assert_stdout("1\n") + .run() + .await; } #[tokio::test]