]> Repositorios git - scryer-prolog.git/commitdiff
add cyclic_term
authorMark Thom <[email protected]>
Thu, 29 Mar 2018 05:41:19 +0000 (23:41 -0600)
committerMark Thom <[email protected]>
Thu, 29 Mar 2018 05:41:19 +0000 (23:41 -0600)
README.md
src/prolog/ast.rs
src/prolog/builtins.rs
src/prolog/codegen.rs
src/prolog/io.rs
src/prolog/machine/machine_state.rs
src/prolog/machine/machine_state_impl.rs
src/prolog/machine/mod.rs
src/prolog/macros.rs

index d723b8e5b71ade119e63cc23f065153d12d24c2e..3c74cb1892895729f972811866bd9d7a312b8fe0 100644 (file)
--- a/README.md
+++ b/README.md
@@ -134,6 +134,7 @@ The following predicates are built-in to rusty-wam.
 * `catch/3`
 * `compare/3`
 * `compound/1`
+* `cyclic_term/1`
 * `display/1`
 * `duplicate_term/2`
 * `false/0`
index a43fb4548c4d8f2f983234815da6596483ebcf0d..89857418b4687ef009b5222ed947ef0cb98b054f 100644 (file)
@@ -132,11 +132,14 @@ impl PredicateClause {
 }
 
 pub type OpDirKey = (ClauseName, Fixity);
+
 // name and fixity -> operator type and precedence.
 pub type OpDir = HashMap<OpDirKey, (Specifier, usize, ClauseName)>;
 
 pub type CodeDir = HashMap<PredicateKey, (usize, ClauseName)>;
 
+pub type TermDir = HashMap<PredicateKey, Predicate>;
+
 pub type PredicateKey = (ClauseName, usize); // name, arity.
 
 pub struct ModuleDecl {
@@ -249,11 +252,7 @@ impl TopLevel {
             &TopLevel::Declaration(_) => None,
             &TopLevel::Fact(ref term) => term.name(),
             &TopLevel::Predicate(ref clauses) =>
-                if let Some(ref term) = clauses.first() {
-                    term.name()
-                } else {
-                    None
-                },
+                clauses.first().and_then(|ref term| term.name()),
             &TopLevel::Query(_) => None,
             &TopLevel::Rule(Rule { ref head, .. }) =>
                 Some(head.0.clone())
@@ -270,6 +269,15 @@ impl TopLevel {
             &TopLevel::Rule(Rule { ref head, .. }) => head.1.len()
         }
     }
+
+    pub fn as_predicate(self) -> Option<Predicate> {
+        match self {
+            TopLevel::Fact(term) => Some(vec![PredicateClause::Fact(term)]),
+            TopLevel::Rule(rule) => Some(vec![PredicateClause::Rule(rule)]),
+            TopLevel::Predicate(pred) => Some(pred),
+            _ => None
+        }
+    }
 }
 
 #[derive(Clone, Copy)]
@@ -680,6 +688,7 @@ pub enum ClauseType {
     Catch,
     Compare,
     CompareTerm(CompareTermQT),
+    CyclicTerm,
     Display,
     DuplicateTerm,
     Eq,
@@ -775,12 +784,13 @@ impl ClauseType {
     pub fn name(&self) -> ClauseName {
         match self {
             &ClauseType::AcyclicTerm => clause_name!("acyclic_term"),
-            &ClauseType::Arg => clause_name!("arg"),            
+            &ClauseType::Arg => clause_name!("arg"),
             &ClauseType::CallN => clause_name!("call"),
             &ClauseType::CallWithInferenceLimit => clause_name!("call_with_inference_limit"),
             &ClauseType::Catch => clause_name!("catch"),
             &ClauseType::Compare => clause_name!("compare"),
             &ClauseType::CompareTerm(qt) => clause_name!(qt.name()),
+            &ClauseType::CyclicTerm => clause_name!("cyclic_term"),
             &ClauseType::Display => clause_name!("display"),
             &ClauseType::DuplicateTerm => clause_name!("duplicate_term"),
             &ClauseType::Eq => clause_name!("=="),
@@ -806,6 +816,7 @@ impl ClauseType {
             ("call_with_inference_limit", 3) => ClauseType::CallWithInferenceLimit,
             ("catch", 3) => ClauseType::Catch,
             ("compare", 3) => ClauseType::Compare,
+            ("cyclic_term", 1) => ClauseType::CyclicTerm,
             ("@>", 2) => ClauseType::CompareTerm(CompareTermQT::GreaterThan),
             ("@<", 2) => ClauseType::CompareTerm(CompareTermQT::LessThan),
             ("@>=", 2) => ClauseType::CompareTerm(CompareTermQT::GreaterThanOrEqual),
@@ -1200,7 +1211,7 @@ pub enum BuiltInInstruction {
     CompareNumber(CompareNumberQT, ArithmeticTerm, ArithmeticTerm),
     DefaultRetryMeElse(usize),
     DefaultSetCutPoint(RegType),
-    DefaultTrustMe,    
+    DefaultTrustMe,
     EraseBall,
     Fail,
     GetArg(bool), // last call.
@@ -1211,7 +1222,7 @@ pub enum BuiltInInstruction {
     InstallCleaner,
     InstallInferenceCounter(RegType, RegType, RegType),
     InstallNewBlock,
-    InternalCallN,        
+    InternalCallN,
     RemoveCallPolicyCheck,
     RemoveInferenceCounter(RegType, RegType),
     ResetBlock,
index 6d3e678c9492fc6c6cd35ea5ea954b3f2c4f8994..88c5a5b3e2d15f19e421ea1018e4f33145630f53 100644 (file)
@@ -626,6 +626,7 @@ fn get_builtins() -> Code {
          sort_execute!(), // sort/2, 467.
          keysort_execute!(), // keysort/2, 468.
          acyclic_term_execute!(), // acyclic_term/1, 469.
+         cyclic_term_execute!(), // cyclic_term/1, 470.
     ]
 }
 
@@ -742,6 +743,7 @@ pub fn build_code_and_op_dirs() -> (CodeDir, OpDir)
     code_dir.insert((clause_name!("sort"), 2), (467, builtin.clone()));
     code_dir.insert((clause_name!("keysort"), 2), (468, builtin.clone()));
     code_dir.insert((clause_name!("acyclic_term"), 1), (469, builtin.clone()));
+    code_dir.insert((clause_name!("cyclic_term"), 1), (470, builtin.clone()));
     
     (code_dir, op_dir)
 }
@@ -804,7 +806,8 @@ pub fn builtin_module() -> Module
                                             (clause_name!("atom"), 1),
                                             (clause_name!("sort"), 2),
                                             (clause_name!("keysort"), 2),
-                                            (clause_name!("acyclic_term"), 1)]);
+                                            (clause_name!("acyclic_term"), 1),
+                                            (clause_name!("cyclic_term"), 1)]);
 
     for arity in 0 .. 63 {
         module_decl.exports.push((clause_name!("call"), arity));
index 84a9ac6a0b0b0a04f40d4bd5c956214c9940c6f1..e10d9fd9f08ad76946f680b267cbbf9469e422bd 100644 (file)
@@ -7,7 +7,7 @@ use prolog::iterators::*;
 use prolog::targets::*;
 
 use std::cell::Cell;
-use std::collections::HashMap;
+use std::collections::{HashMap};
 use std::rc::Rc;
 use std::vec::Vec;
 
index 66c6cf136c86ffc2d95e80e0087a6d8da45a3b43..76e1b8f110d8579a7b0170f5733f4f66f355fddf 100644 (file)
@@ -496,7 +496,7 @@ fn compile_decl(wam: &mut Machine, tl: TopLevel, queue: Vec<TopLevel>) -> EvalSe
 
             if !code.is_empty() {
                 if let Some(name) = tl.name() {
-                    wam.add_user_code(name, tl.arity(), code)
+                    wam.add_user_code(name, tl.arity(), code, tl.as_predicate().unwrap())
                 } else {
                     EvalSession::from(EvalError::NamelessEntry)
                 }
index 1a31351fb8e20dc3a40284f3e181e95a31dd9f78..a0893580e16a468e8bb45a18c807cf28bb6aebca 100644 (file)
@@ -1,7 +1,6 @@
 use prolog::and_stack::*;
 use prolog::ast::*;
 use prolog::copier::*;
-use prolog::heap_iter::*;
 use prolog::num::{BigInt, BigUint, Zero, One};
 use prolog::or_stack::*;
 use prolog::heap_print::*;
@@ -10,7 +9,7 @@ use prolog::tabled_rc::*;
 use downcast::Any;
 
 use std::cmp::Ordering;
-use std::collections::{HashMap, HashSet};
+use std::collections::HashMap;
 use std::mem::swap;
 use std::ops::{Index, IndexMut};
 use std::rc::Rc;
@@ -397,30 +396,8 @@ pub(crate) trait CallPolicy: Any {
     {
         match ct {
             &ClauseType::AcyclicTerm => {
-                let addr = machine_st[temp_v!(1)].clone();
-                let mut seen = HashSet::new();
-                let mut fail = false;
-                
-                {
-                    let mut iter = machine_st.pre_order_iter(addr);
-
-                    loop {
-                        if let Some(addr) = iter.stack().last() {
-                            if !seen.contains(addr) {                            
-                                seen.insert(addr.clone());
-                            } else {
-                                fail = true;
-                                break;
-                            }                            
-                        }
-
-                        if iter.next().is_none() {
-                            break;
-                        }
-                    }
-                }
-
-                machine_st.fail = fail;
+                let addr = machine_st[temp_v!(1)].clone();                
+                machine_st.fail = machine_st.is_cyclic_term(addr);
                 return_from_clause!(lco, machine_st)
             },
             &ClauseType::Arg => {
@@ -476,6 +453,11 @@ pub(crate) trait CallPolicy: Any {
 
                 return_from_clause!(lco, machine_st)
             },
+            &ClauseType::CyclicTerm => {
+                let addr = machine_st[temp_v!(1)].clone();                
+                machine_st.fail = !machine_st.is_cyclic_term(addr);
+                return_from_clause!(lco, machine_st)
+            },
             &ClauseType::Display => {
                 let output = machine_st.print_term(machine_st[temp_v!(1)].clone(),
                                                    DisplayFormatter {},
index 73ae9e152c0a9a638905a74cbcaf7659de1456eb..5b97e455fcc8cb6da7c4c80d117e9b412c4f5176 100644 (file)
@@ -11,7 +11,7 @@ use prolog::or_stack::*;
 use prolog::tabled_rc::*;
 
 use std::cmp::{max, Ordering};
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
 use std::rc::Rc;
 
 macro_rules! try_or_fail {
@@ -1001,6 +1001,30 @@ impl MachineState {
         }
     }
 
+    pub(super) fn is_cyclic_term(&self, addr: Addr) -> bool {
+        let mut seen = HashSet::new();
+        let mut fail = false;
+        
+        let mut iter = self.pre_order_iter(addr);
+
+        loop {
+            if let Some(addr) = iter.stack().last() {
+                if !seen.contains(addr) {                            
+                    seen.insert(addr.clone());
+                } else {
+                    fail = true;
+                    break;
+                }                            
+            }
+
+            if iter.next().is_none() {
+                break;
+            }
+        }
+
+        fail
+    }
+    
     fn try_get_arg(&mut self) -> Result<(), Vec<HeapCellValue>>
     {
         let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
index c94b8a067ec2c74e1ca74310a284bfbd7d9a3d66..6e6bc1ece393e9ea77bb6cf9a9e62dd6c2b1a2cc 100644 (file)
@@ -25,8 +25,9 @@ pub struct Machine {
     call_policy: Box<CallPolicy>,
     cut_policy: Box<CutPolicy>,
     code: Code,
-    code_dir: CodeDir,
+    code_dir: CodeDir,    
     pub op_dir: OpDir,
+    term_dir: TermDir,
     modules: HashMap<ClauseName, Module>,
     cached_query: Option<Code>
 }
@@ -68,6 +69,7 @@ impl Machine {
             cut_policy: Box::new(DefaultCutPolicy {}),
             code,
             code_dir,
+            term_dir: TermDir::new(),
             op_dir,
             modules: HashMap::new(),
             cached_query: None
@@ -173,7 +175,8 @@ impl Machine {
         self.code.extend(code.into_iter());
     }
 
-    pub fn add_user_code(&mut self, name: ClauseName, arity: usize, code: Code) -> EvalSession
+    pub fn add_user_code(&mut self, name: ClauseName, arity: usize, code: Code, pred: Predicate)
+                         -> EvalSession
     {
         match self.code_dir.get(&(name.clone(), arity)) {
             Some(&(_, ref mod_name)) if mod_name == &clause_name!("builtin") =>
@@ -184,8 +187,9 @@ impl Machine {
         let offset = self.code.len();
 
         self.code.extend(code.into_iter());
+        self.term_dir.insert((name.clone(), arity), pred);
         self.code_dir.insert((name, arity), (offset, clause_name!("user")));
-
+        
         EvalSession::EntrySuccess
     }
 
index 90ec275aa6d46b17fd518a35058bb3e583c9e842..85a2576051f63de9f0b372617bf6245c23517dbe 100644 (file)
@@ -734,6 +734,12 @@ macro_rules! acyclic_term_execute {
     )
 }
 
+macro_rules! cyclic_term_execute {
+    () => (
+        Line::Control(ControlInstruction::CallClause(ClauseType::CyclicTerm, 1, 0, true))
+    )
+}
+
 macro_rules! return_from_clause {
     ($lco:expr, $machine_st:expr) => {{
         if $lco {