Add bit operator: bit-xor (#5940)

This commit is contained in:
Justin Ma 2022-07-03 19:45:20 +08:00 committed by GitHub
parent 3a38fb94f0
commit 4e90b478b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 59 additions and 20 deletions

View File

@ -119,6 +119,7 @@ impl CustomValue for ExprDb {
| Operator::NotIn | Operator::NotIn
| Operator::Pow | Operator::Pow
| Operator::BitOr | Operator::BitOr
| Operator::BitXor
| Operator::BitAnd | Operator::BitAnd
| Operator::ShiftLeft | Operator::ShiftLeft
| Operator::ShiftRight | Operator::ShiftRight

View File

@ -442,6 +442,10 @@ pub fn eval_expression(
let rhs = eval_expression(engine_state, stack, rhs)?; let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.bit_or(op_span, &rhs, expr.span) 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 => { Operator::BitAnd => {
let rhs = eval_expression(engine_state, stack, rhs)?; let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.bit_and(op_span, &rhs, expr.span) lhs.bit_and(op_span, &rhs, expr.span)

View File

@ -4107,6 +4107,7 @@ pub fn parse_operator(
b"not-in" => Operator::NotIn, b"not-in" => Operator::NotIn,
b"mod" => Operator::Modulo, b"mod" => Operator::Modulo,
b"bit-or" => Operator::BitOr, b"bit-or" => Operator::BitOr,
b"bit-xor" => Operator::BitXor,
b"bit-and" => Operator::BitAnd, b"bit-and" => Operator::BitAnd,
b"bit-shl" => Operator::ShiftLeft, b"bit-shl" => Operator::ShiftLeft,
b"bit-shr" => Operator::ShiftRight, b"bit-shr" => Operator::ShiftRight,

View File

@ -492,27 +492,29 @@ pub fn math_result_type(
) )
} }
}, },
Operator::ShiftLeft | Operator::ShiftRight | Operator::BitAnd | Operator::BitOr => { Operator::ShiftLeft
match (&lhs.ty, &rhs.ty) { | Operator::ShiftRight
(Type::Int, Type::Int) => (Type::Int, None), | 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),
(_, Type::Any) => (Type::Any, None), (_, Type::Any) => (Type::Any, None),
_ => { _ => {
*op = Expression::garbage(op.span); *op = Expression::garbage(op.span);
( (
Type::Any, Type::Any,
Some(ParseError::UnsupportedOperation( Some(ParseError::UnsupportedOperation(
op.span, op.span,
lhs.span, lhs.span,
lhs.ty.clone(), lhs.ty.clone(),
rhs.span, rhs.span,
rhs.ty.clone(), rhs.ty.clone(),
)), )),
) )
}
} }
} },
}, },
_ => { _ => {
*op = Expression::garbage(op.span); *op = Expression::garbage(op.span);

View File

@ -49,7 +49,7 @@ impl Expression {
| Operator::In | Operator::In
| Operator::NotIn => 80, | Operator::NotIn => 80,
Operator::BitAnd => 75, Operator::BitAnd => 75,
// Operator::BitXor => 70, Operator::BitXor => 70,
Operator::BitOr => 60, Operator::BitOr => 60,
Operator::And => 50, Operator::And => 50,
Operator::Or => 40, Operator::Or => 40,

View File

@ -27,6 +27,7 @@ pub enum Operator {
StartsWith, StartsWith,
EndsWith, EndsWith,
BitOr, BitOr,
BitXor,
BitAnd, BitAnd,
ShiftLeft, ShiftLeft,
ShiftRight, ShiftRight,
@ -53,6 +54,7 @@ impl Display for Operator {
Operator::Or => write!(f, "||"), Operator::Or => write!(f, "||"),
Operator::Pow => write!(f, "**"), Operator::Pow => write!(f, "**"),
Operator::BitOr => write!(f, "bit-or"), Operator::BitOr => write!(f, "bit-or"),
Operator::BitXor => write!(f, "bit-xor"),
Operator::BitAnd => write!(f, "bit-and"), Operator::BitAnd => write!(f, "bit-and"),
Operator::ShiftLeft => write!(f, "bit-shl"), Operator::ShiftLeft => write!(f, "bit-shl"),
Operator::ShiftRight => write!(f, "bit-shr"), Operator::ShiftRight => write!(f, "bit-shr"),

View File

@ -2297,6 +2297,25 @@ impl Value {
} }
} }
pub fn bit_xor(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
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<Value, ShellError> { pub fn bit_and(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
match (self, rhs) { match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Int { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Int {

View File

@ -55,6 +55,16 @@ fn or() -> TestResult {
run_test("true || false", "true") 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] #[test]
fn bit_and() -> TestResult { fn bit_and() -> TestResult {
run_test("2 bit-and 4", "0") run_test("2 bit-and 4", "0")