1use crate::error::{DogeError, DogeResult};
2use crate::value::Value;
3
4fn int_pair(sym: &str, a: &Value, b: &Value) -> DogeResult<(i64, i64)> {
7 match (a, b) {
8 (Value::Int(x), Value::Int(y)) => Ok((*x, *y)),
9 _ => Err(DogeError::type_error(format!(
10 "cannot {sym} {} and {} (bitwise operators need Ints)",
11 a.describe(),
12 b.describe()
13 ))),
14 }
15}
16
17fn shift_count(y: i64) -> DogeResult<u32> {
20 u32::try_from(y).map_err(|_| {
21 DogeError::value_error(format!(
22 "cannot shift by {y} — the shift count must be 0 or more"
23 ))
24 })
25}
26
27fn shift_overflow(x: i64, y: i64) -> DogeError {
28 DogeError::overflow(format!("{x} << {y} overflowed the Int range"))
29}
30
31pub fn bitand(a: Value, b: Value) -> DogeResult {
33 let (x, y) = int_pair("&", &a, &b)?;
34 Ok(Value::Int(x & y))
35}
36
37pub fn bitor(a: Value, b: Value) -> DogeResult {
39 let (x, y) = int_pair("|", &a, &b)?;
40 Ok(Value::Int(x | y))
41}
42
43pub fn bitxor(a: Value, b: Value) -> DogeResult {
45 let (x, y) = int_pair("^", &a, &b)?;
46 Ok(Value::Int(x ^ y))
47}
48
49pub fn shl(a: Value, b: Value) -> DogeResult {
52 let (x, y) = int_pair("<<", &a, &b)?;
53 let n = shift_count(y)?;
54 if n >= i64::BITS {
55 return Err(shift_overflow(x, y));
56 }
57 let result = x << n;
58 if result >> n != x {
60 return Err(shift_overflow(x, y));
61 }
62 Ok(Value::Int(result))
63}
64
65pub fn shr(a: Value, b: Value) -> DogeResult {
68 let (x, y) = int_pair(">>", &a, &b)?;
69 let n = shift_count(y)?;
70 let result = if n >= i64::BITS {
71 if x < 0 {
72 -1
73 } else {
74 0
75 }
76 } else {
77 x >> n
78 };
79 Ok(Value::Int(result))
80}
81
82pub fn bitnot(a: Value) -> DogeResult {
84 match &a {
85 Value::Int(n) => Ok(Value::Int(!n)),
86 _ => Err(DogeError::type_error(format!(
87 "cannot ~ {} (bitwise NOT needs an Int)",
88 a.describe()
89 ))),
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96 use crate::error::ErrorKind;
97
98 fn int(n: i64) -> Value {
99 Value::Int(n)
100 }
101
102 #[test]
103 fn basic_bitwise() {
104 assert!(matches!(
105 bitand(int(0b1100), int(0b1010)).unwrap(),
106 Value::Int(0b1000)
107 ));
108 assert!(matches!(
109 bitor(int(0b1100), int(0b1010)).unwrap(),
110 Value::Int(0b1110)
111 ));
112 assert!(matches!(
113 bitxor(int(0b1100), int(0b1010)).unwrap(),
114 Value::Int(0b0110)
115 ));
116 assert!(matches!(bitnot(int(0)).unwrap(), Value::Int(-1)));
117 assert!(matches!(bitnot(int(5)).unwrap(), Value::Int(-6)));
118 }
119
120 #[test]
121 fn shifts() {
122 assert!(matches!(shl(int(1), int(4)).unwrap(), Value::Int(16)));
123 assert!(matches!(shr(int(16), int(4)).unwrap(), Value::Int(1)));
124 assert!(matches!(shr(int(-8), int(1)).unwrap(), Value::Int(-4)));
126 assert!(matches!(shr(int(-8), int(200)).unwrap(), Value::Int(-1)));
128 assert!(matches!(shr(int(8), int(200)).unwrap(), Value::Int(0)));
129 }
130
131 #[test]
132 fn shift_errors() {
133 assert_eq!(shl(int(1), int(64)).unwrap_err().kind, ErrorKind::Overflow);
134 assert_eq!(shl(int(1), int(63)).unwrap_err().kind, ErrorKind::Overflow);
135 assert_eq!(
136 shl(int(-1), int(-1)).unwrap_err().kind,
137 ErrorKind::ValueError
138 );
139 assert_eq!(
140 shr(int(1), int(-1)).unwrap_err().kind,
141 ErrorKind::ValueError
142 );
143 }
144
145 #[test]
146 fn non_int_is_a_type_error() {
147 assert_eq!(
148 bitand(int(1), Value::str("x")).unwrap_err().kind,
149 ErrorKind::TypeError
150 );
151 assert_eq!(
152 bitnot(Value::str("x")).unwrap_err().kind,
153 ErrorKind::TypeError
154 );
155 }
156}