diff --git a/crates/nu-command/src/database/values/dsl/expression.rs b/crates/nu-command/src/database/values/dsl/expression.rs index d576044d1..a1447109b 100644 --- a/crates/nu-command/src/database/values/dsl/expression.rs +++ b/crates/nu-command/src/database/values/dsl/expression.rs @@ -119,6 +119,7 @@ impl CustomValue for ExprDb { | Operator::NotIn | Operator::Pow | Operator::BitOr + | Operator::BitXor | Operator::BitAnd | Operator::ShiftLeft | Operator::ShiftRight diff --git a/crates/nu-engine/src/eval.rs b/crates/nu-engine/src/eval.rs index 567b45665..339ca255c 100644 --- a/crates/nu-engine/src/eval.rs +++ b/crates/nu-engine/src/eval.rs @@ -442,6 +442,10 @@ pub fn eval_expression( let rhs = eval_expression(engine_state, stack, rhs)?; lhs.bit_or(op_span, &rhs, expr.span) } + Operator::BitXor => { + let rhs = eval_expression(engine_state, stack, rhs)?; + lhs.bit_xor(op_span, &rhs, expr.span) + } Operator::BitAnd => { let rhs = eval_expression(engine_state, stack, rhs)?; lhs.bit_and(op_span, &rhs, expr.span) diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index 4daa5075f..941ea396b 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -4107,6 +4107,7 @@ pub fn parse_operator( b"not-in" => Operator::NotIn, b"mod" => Operator::Modulo, b"bit-or" => Operator::BitOr, + b"bit-xor" => Operator::BitXor, b"bit-and" => Operator::BitAnd, b"bit-shl" => Operator::ShiftLeft, b"bit-shr" => Operator::ShiftRight, diff --git a/crates/nu-parser/src/type_check.rs b/crates/nu-parser/src/type_check.rs index 44cb30ce9..ac2a937f6 100644 --- a/crates/nu-parser/src/type_check.rs +++ b/crates/nu-parser/src/type_check.rs @@ -492,27 +492,29 @@ pub fn math_result_type( ) } }, - Operator::ShiftLeft | Operator::ShiftRight | Operator::BitAnd | Operator::BitOr => { - match (&lhs.ty, &rhs.ty) { - (Type::Int, Type::Int) => (Type::Int, None), + Operator::ShiftLeft + | Operator::ShiftRight + | Operator::BitOr + | Operator::BitXor + | Operator::BitAnd => match (&lhs.ty, &rhs.ty) { + (Type::Int, Type::Int) => (Type::Int, None), - (Type::Any, _) => (Type::Any, None), - (_, Type::Any) => (Type::Any, None), - _ => { - *op = Expression::garbage(op.span); - ( - Type::Any, - Some(ParseError::UnsupportedOperation( - op.span, - lhs.span, - lhs.ty.clone(), - rhs.span, - rhs.ty.clone(), - )), - ) - } + (Type::Any, _) => (Type::Any, None), + (_, Type::Any) => (Type::Any, None), + _ => { + *op = Expression::garbage(op.span); + ( + Type::Any, + Some(ParseError::UnsupportedOperation( + op.span, + lhs.span, + lhs.ty.clone(), + rhs.span, + rhs.ty.clone(), + )), + ) } - } + }, }, _ => { *op = Expression::garbage(op.span); diff --git a/crates/nu-protocol/src/ast/expression.rs b/crates/nu-protocol/src/ast/expression.rs index 11519e581..121a4337e 100644 --- a/crates/nu-protocol/src/ast/expression.rs +++ b/crates/nu-protocol/src/ast/expression.rs @@ -49,7 +49,7 @@ impl Expression { | Operator::In | Operator::NotIn => 80, Operator::BitAnd => 75, - // Operator::BitXor => 70, + Operator::BitXor => 70, Operator::BitOr => 60, Operator::And => 50, Operator::Or => 40, diff --git a/crates/nu-protocol/src/ast/operator.rs b/crates/nu-protocol/src/ast/operator.rs index a6a838322..e58ebe41f 100644 --- a/crates/nu-protocol/src/ast/operator.rs +++ b/crates/nu-protocol/src/ast/operator.rs @@ -27,6 +27,7 @@ pub enum Operator { StartsWith, EndsWith, BitOr, + BitXor, BitAnd, ShiftLeft, ShiftRight, @@ -53,6 +54,7 @@ impl Display for Operator { Operator::Or => write!(f, "||"), Operator::Pow => write!(f, "**"), Operator::BitOr => write!(f, "bit-or"), + Operator::BitXor => write!(f, "bit-xor"), Operator::BitAnd => write!(f, "bit-and"), Operator::ShiftLeft => write!(f, "bit-shl"), Operator::ShiftRight => write!(f, "bit-shr"), diff --git a/crates/nu-protocol/src/value/mod.rs b/crates/nu-protocol/src/value/mod.rs index 7b663b21e..628f65744 100644 --- a/crates/nu-protocol/src/value/mod.rs +++ b/crates/nu-protocol/src/value/mod.rs @@ -2297,6 +2297,25 @@ impl Value { } } + pub fn bit_xor(&self, op: Span, rhs: &Value, span: Span) -> Result { + match (self, rhs) { + (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Int { + span, + val: *lhs ^ rhs, + }), + (Value::CustomValue { val: lhs, span }, rhs) => { + lhs.operation(*span, Operator::BitXor, op, rhs) + } + _ => Err(ShellError::OperatorMismatch { + op_span: op, + lhs_ty: self.get_type(), + lhs_span: self.span()?, + rhs_ty: rhs.get_type(), + rhs_span: rhs.span()?, + }), + } + } + pub fn bit_and(&self, op: Span, rhs: &Value, span: Span) -> Result { match (self, rhs) { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Int { diff --git a/src/tests/test_math.rs b/src/tests/test_math.rs index f9219f4d9..75e1f8546 100644 --- a/src/tests/test_math.rs +++ b/src/tests/test_math.rs @@ -55,6 +55,16 @@ fn or() -> TestResult { run_test("true || false", "true") } +#[test] +fn bit_xor() -> TestResult { + run_test("4 bit-xor 4", "0") +} + +#[test] +fn bit_xor_add() -> TestResult { + run_test("4 bit-xor 2 + 2", "0") +} + #[test] fn bit_and() -> TestResult { run_test("2 bit-and 4", "0")