]> Repositorios git - scryer-prolog.git/commitdiff
add sign/1 (#216) and gcd/2 (#217) as evaluable functors, update the README
authorMark Thom <[email protected]>
Sun, 27 Oct 2019 19:05:05 +0000 (13:05 -0600)
committerMark Thom <[email protected]>
Sun, 27 Oct 2019 19:05:05 +0000 (13:05 -0600)
README.md
src/prolog/arithmetic.rs
src/prolog/instructions.rs
src/prolog/machine/machine_state_impl.rs
src/prolog/write.rs

index 28f254e260ec2bdefbeeaa08cc2ef811f2c5aad1..0b8b564ca07d6f28dff795047a00a1d9851a16a8 100644 (file)
--- a/README.md
+++ b/README.md
@@ -50,11 +50,11 @@ Extend Scryer Prolog to include the following, among other features:
 - [x] Backtrackable and non-backtrackable global variables via `bb_get/2`
       `bb_put/2` (non-backtrackable) and `bb_b_put/2`
       (backtrackable).
+- [ ] clp(B) and clp($\mathbb{Z}$) as builtin libraries (_in progress_).
 - [ ] Streams and predicates for stream control (_in progress_).
 - [ ] An incremental compacting garbage collector satisfying the five
       properties of "Precise Garbage Collection in Prolog."
 - [ ] Mode declarations.
-- [ ] Extensions for clp(FD).
 
 ## Phase 3
 
@@ -134,7 +134,7 @@ The following predicates are built-in to Scryer.
       `abs/1`, `sin/1`, `cos/1`, `tan/1`, `asin/1`, `acos/1`,
       `atan/1`, `atan2/2`, `log/1`, `exp/1`, `sqrt/1`, `float/1`,
       `truncate/1`, `round/1`, `floor/1`, `ceiling/1`, `pi/0`,
-      `min/1`, `max/1`      
+      `min/1`, `max/1`, `gcd/2`, `sign/1`
     * Comparison operators: `>`, `<`, `=<`, `>=`, `=:=`, `=\=`.
 * `(:)/2`
 * `(@>)/2`
index 5ed87051b226a81ef36b65821365a2962b63b374..4c126d774d530b317a0e24e75015b9595f48ad0a 100644 (file)
@@ -159,6 +159,7 @@ impl<'a> ArithmeticEvaluator<'a> {
             "round" => Ok(ArithmeticInstruction::Round(a1, t)),
             "ceiling" => Ok(ArithmeticInstruction::Ceiling(a1, t)),
             "floor" => Ok(ArithmeticInstruction::Floor(a1, t)),
+            "sign" => Ok(ArithmeticInstruction::Sign(a1, t)),
             "\\" => Ok(ArithmeticInstruction::BitwiseComplement(a1, t)),
             _ => Err(ArithmeticError::NonEvaluableFunctor(
                 Constant::Atom(name, None),
@@ -192,6 +193,7 @@ impl<'a> ArithmeticEvaluator<'a> {
             "xor" => Ok(ArithmeticInstruction::Xor(a1, a2, t)),
             "mod" => Ok(ArithmeticInstruction::Mod(a1, a2, t)),
             "rem" => Ok(ArithmeticInstruction::Rem(a1, a2, t)),
+            "gcd" => Ok(ArithmeticInstruction::Gcd(a1, a2, t)),
             "atan2" => Ok(ArithmeticInstruction::ATan2(a1, a2, t)),
             _ => Err(ArithmeticError::NonEvaluableFunctor(
                 Constant::Atom(name, None),
index f8ffd99c36c1b3c5fb6ad35ea5a40890bbcb500c..75a7d8935ab1efcf1f988df8f653d43ee8064f00 100644 (file)
@@ -189,6 +189,8 @@ pub enum ArithmeticInstruction {
     Or(ArithmeticTerm, ArithmeticTerm, usize),
     Mod(ArithmeticTerm, ArithmeticTerm, usize),
     Rem(ArithmeticTerm, ArithmeticTerm, usize),
+    Gcd(ArithmeticTerm, ArithmeticTerm, usize),
+    Sign(ArithmeticTerm, usize),
     Cos(ArithmeticTerm, usize),
     Sin(ArithmeticTerm, usize),
     Tan(ArithmeticTerm, usize),
@@ -314,6 +316,10 @@ impl ArithmeticInstruction {
             &ArithmeticInstruction::ATan2(ref at_1, ref at_2, t) => {
                 arith_instr_bin_functor(h, "rem", at_1, at_2, t)
             }
+            &ArithmeticInstruction::Gcd(ref at_1, ref at_2, t) => {
+                arith_instr_bin_functor(h, "gcd", at_1, at_2, t)
+            }
+            &ArithmeticInstruction::Sign(ref at, t) => arith_instr_unary_functor(h, "sign", at, t),
             &ArithmeticInstruction::Cos(ref at, t) => arith_instr_unary_functor(h, "cos", at, t),
             &ArithmeticInstruction::Sin(ref at, t) => arith_instr_unary_functor(h, "sin", at, t),
             &ArithmeticInstruction::Tan(ref at, t) => arith_instr_unary_functor(h, "tan", at, t),
index 16495c1e0e9bf901b683f5d32e6f5d0a0457cbf6..5d6b5fbcc5140815c83c177e26fd23a254da5150 100644 (file)
@@ -940,6 +940,7 @@ impl MachineState {
                         "mod" => interms.push(Number::Integer(self.modulus(a1, a2)?)),
                         "rem" => interms.push(Number::Integer(self.remainder(a1, a2)?)),
                         "atan2" => interms.push(Number::Float(OrderedFloat(self.atan2(a1, a2)?))),
+                        "gcd" => interms.push(Number::Integer(self.gcd(a1, a2)?)),
                         _ => {
                             return Err(self.error_form(MachineError::instantiation_error(), caller))
                         }
@@ -967,6 +968,7 @@ impl MachineState {
                         "ceiling" => interms.push(Number::Integer(self.ceiling(a1))),
                         "floor" => interms.push(Number::Integer(self.floor(a1))),
                         "\\" => interms.push(Number::Integer(self.bitwise_complement(a1)?)),
+                        "sign" => interms.push(Number::Integer(self.sign(a1))),
                         _ => {
                             return Err(self.error_form(MachineError::instantiation_error(), caller))
                         }
@@ -1099,6 +1101,26 @@ impl MachineState {
         }
     }
 
+    fn gcd(&self, n1: Number, n2: Number) -> Result<Integer, MachineStub> {
+        match (n1, n2) {
+            (Number::Integer(n1), Number::Integer(n2)) => {
+                Ok(n1.gcd(&n2))
+            }
+            (Number::Float(f), _) | (_, Number::Float(f)) => {
+                let n = Addr::Con(Constant::Float(f));
+                let stub = MachineError::functor_stub(clause_name!("gcd"), 2);
+                
+                Err(self.error_form(MachineError::type_error(ValidType::Integer, n), stub))
+            }
+            (Number::Rational(r), _) | (_, Number::Rational(r)) => {
+                let n = Addr::Con(Constant::Rational(r));
+                let stub = MachineError::functor_stub(clause_name!("gcd"), 2);
+                
+                Err(self.error_form(MachineError::type_error(ValidType::Integer, n), stub))
+            }
+        }
+    }
+    
     fn float_pow(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
         let f1 = result_f(&n1, rnd_f);
         let f2 = result_f(&n2, rnd_f);
@@ -1355,6 +1377,16 @@ impl MachineState {
         }
     }
 
+    fn sign(&self, n: Number) -> Integer {
+        if n.is_positive() {
+            Integer::from(1)
+        } else if n.is_negative() {
+            Integer::from(0)
+        } else {
+            Integer::from(-1)
+        }
+    }
+
     fn remainder(&self, n1: Number, n2: Number) -> Result<Integer, MachineStub> {
         let stub = MachineError::functor_stub(clause_name!("(rem)"), 2);
 
@@ -1440,6 +1472,13 @@ impl MachineState {
                 self.interms[t - 1] = try_or_fail!(self, self.int_pow(n1, n2));
                 self.p += 1;
             }
+            &ArithmeticInstruction::Gcd(ref a1, ref a2, t) => {
+                let n1 = try_or_fail!(self, self.get_number(a1));
+                let n2 = try_or_fail!(self, self.get_number(a2));
+
+                self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.gcd(n1, n2)));
+                self.p += 1;
+            }
             &ArithmeticInstruction::Pow(ref a1, ref a2, t) => {
                 let n1 = try_or_fail!(self, self.get_number(a1));
                 let n2 = try_or_fail!(self, self.get_number(a2));
@@ -1477,6 +1516,12 @@ impl MachineState {
                 self.interms[t - 1] = n1.abs();
                 self.p += 1;
             }
+            &ArithmeticInstruction::Sign(ref a1, t) => {
+                let n = try_or_fail!(self, self.get_number(a1));
+
+                self.interms[t - 1] = Number::Integer(self.sign(n));
+                self.p += 1;
+            }
             &ArithmeticInstruction::Neg(ref a1, t) => {
                 let n1 = try_or_fail!(self, self.get_number(a1));
 
index 84df600cbd06ef82bdab9647aee95703d211fcc3..03a884c8a3679e10589117933b3c4098c22175ba 100644 (file)
@@ -352,6 +352,9 @@ impl fmt::Display for ArithmeticInstruction {
             &ArithmeticInstruction::RDiv(ref a1, ref a2, ref t) => {
                 write!(f, "rdiv {}, {}, @{}", a1, a2, t)
             }
+            &ArithmeticInstruction::Gcd(ref a1, ref a2, ref t) => {
+                write!(f, "gcd {}, {}, @{}", a1, a2, t)
+            }
             &ArithmeticInstruction::Shl(ref a1, ref a2, ref t) => {
                 write!(f, "shl {}, {}, @{}", a1, a2, t)
             }
@@ -377,6 +380,7 @@ impl fmt::Display for ArithmeticInstruction {
                 write!(f, "atan2 {}, {}, @{}", a1, a2, t)
             }
             &ArithmeticInstruction::Plus(ref a, ref t) => write!(f, "plus {}, @{}", a, t),
+            &ArithmeticInstruction::Sign(ref a, ref t) => write!(f, "sign {}, @{}", a, t),
             &ArithmeticInstruction::Neg(ref a, ref t) => write!(f, "neg {}, @{}", a, t),
             &ArithmeticInstruction::Cos(ref a, ref t) => write!(f, "cos {}, @{}", a, t),
             &ArithmeticInstruction::Sin(ref a, ref t) => write!(f, "sin {}, @{}", a, t),