]> Repositorios git - scryer-prolog.git/commitdiff
Negative shifts (fixes #1719 and #1718)
authorAdrián Arroyo Calle <[email protected]>
Mon, 30 Jan 2023 17:56:37 +0000 (18:56 +0100)
committerAdrián Arroyo Calle <[email protected]>
Mon, 30 Jan 2023 17:56:37 +0000 (18:56 +0100)
src/machine/arithmetic_ops.rs

index 6e12b8c6a3944ee8c38128ebb4d0bc3372c9c319..87911d093ed5b1ba7acf30e1151458b72cade8f5 100644 (file)
@@ -633,7 +633,9 @@ pub(crate) fn shr(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
 
             if let Ok(n2) = u32::try_from(n2_i) {
                 return Ok(Number::arena_from(n1 >> n2, arena));
-            } else {
+            } else if let Ok(n2) = u32::try_from(n2_i * -1) {
+               return Ok(Number::arena_from(n1 << n2, arena));
+           } else {
                 return Ok(Number::arena_from(n1 >> u32::max_value(), arena));
             }
         }
@@ -642,22 +644,34 @@ pub(crate) fn shr(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
 
             match n2.to_u32() {
                 Some(n2) => Ok(Number::arena_from(n1 >> n2, arena)),
-                _ => Ok(Number::arena_from(n1 >> u32::max_value(), arena)),
+                _ => {
+                   if let Some(n2) = Integer::from(&*n2 * -1).to_u32() {
+                       Ok(Number::arena_from(n1 << n2, arena))
+                   } else {
+                       Ok(Number::arena_from(n1 >> u32::max_value(), arena))
+                   }
+               },
             }
         }
         (Number::Integer(n1), Number::Fixnum(n2)) => match u32::try_from(n2.get_num()) {
             Ok(n2) => Ok(Number::arena_from(Integer::from(&*n1 >> n2), arena)),
-            _ => Ok(Number::arena_from(
-                Integer::from(&*n1 >> u32::max_value()),
-                arena,
-            )),
+            _ => {
+               if let Ok(n2) = u32::try_from(n2.get_num() * -1) {
+                   Ok(Number::arena_from(Integer::from(&*n1 << n2), arena))
+               } else {
+                   Ok(Number::arena_from(Integer::from(&*n1 >> u32::max_value()),arena))
+               }
+           },
         },
         (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() {
             Some(n2) => Ok(Number::arena_from(Integer::from(&*n1 >> n2), arena)),
-            _ => Ok(Number::arena_from(
-                Integer::from(&*n1 >> u32::max_value()),
-                arena,
-            )),
+            _ => {
+               if let Some(n2) = Integer::from(&*n2 * -1).to_u32() {
+                   Ok(Number::arena_from(Integer::from(&*n1 << n2), arena))
+               } else {
+                   Ok(Number::arena_from(Integer::from(&*n1 >> u32::max_value()), arena))
+               }
+              },
         },
         (Number::Integer(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),
         (Number::Fixnum(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),
@@ -680,7 +694,9 @@ pub(crate) fn shl(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
 
             if let Ok(n2) = u32::try_from(n2_i) {
                 return Ok(Number::arena_from(n1 << n2, arena));
-            } else {
+            } else if let Ok(n2) = u32::try_from(n2_i * -1) {
+               return Ok(Number::arena_from(n1 >> n2, arena));
+           } else {
                 return Ok(Number::arena_from(n1 << u32::max_value(), arena));
             }
         }
@@ -689,22 +705,34 @@ pub(crate) fn shl(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
 
             match n2.to_u32() {
                 Some(n2) => Ok(Number::arena_from(n1 << n2, arena)),
-                _ => Ok(Number::arena_from(n1 << u32::max_value(), arena)),
+                _ => {
+                   if let Some(n2) = Integer::from(&*n2 * -1).to_u32() {
+                       Ok(Number::arena_from(n1 >> n2, arena))
+                   } else {
+                       Ok(Number::arena_from(n1 << u32::max_value(), arena))
+                   }
+               }
             }
         }
         (Number::Integer(n1), Number::Fixnum(n2)) => match u32::try_from(n2.get_num()) {
             Ok(n2) => Ok(Number::arena_from(Integer::from(&*n1 << n2), arena)),
-            _ => Ok(Number::arena_from(
-                Integer::from(&*n1 << u32::max_value()),
-                arena,
-            )),
+            _ => {
+               if let Ok(n2) = u32::try_from(n2.get_num() * -1) {
+                   Ok(Number::arena_from(Integer::from(&*n1 >> n2), arena))
+               } else {
+                   Ok(Number::arena_from(Integer::from(&*n1 << u32::max_value()),arena))
+               }
+           }
         },
         (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() {
             Some(n2) => Ok(Number::arena_from(Integer::from(&*n1 << n2), arena)),
-            _ => Ok(Number::arena_from(
-                Integer::from(&*n1 << u32::max_value()),
-                arena,
-            )),
+            _ => {
+               if let Some(n2) = Integer::from(&*n2 * -1).to_u32() {
+                   Ok(Number::arena_from(Integer::from(&*n1 >> n2), arena))
+               } else {
+                   Ok(Number::arena_from(Integer::from(&*n1 << u32::max_value()),arena))
+               }
+           }
         },
         (Number::Integer(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),
         (Number::Fixnum(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),