]> Repositorios git - scryer-prolog.git/commitdiff
add atom predicate.
authorMark Thom <[email protected]>
Sat, 10 Mar 2018 22:26:35 +0000 (15:26 -0700)
committerMark Thom <[email protected]>
Sat, 10 Mar 2018 22:26:35 +0000 (15:26 -0700)
README.md
src/main.rs
src/prolog/ast.rs
src/prolog/builtins.rs
src/prolog/codegen.rs
src/prolog/io.rs
src/prolog/machine/machine_state_impl.rs
src/prolog/macros.rs
src/test_utils.rs [deleted file]
src/tests.rs

index 9dd97819d1270c704a6bacbdfaf5c91d6b5783b5..7dfb1378c7f8bd56da400c5e5f4d4602ad7bdc98 100644 (file)
--- a/README.md
+++ b/README.md
@@ -123,6 +123,7 @@ The following predicates are built-in to rusty-wam.
 * `(;)/2`
 * `append/3`
 * `arg/3`
+* `atom/1`
 * `atomic/1`
 * `between/3`
 * `call/1..63`
index e08e5301ea350ddf5c23dae1bef0367d26b99b3c..cde9536e6e560cc9201c5030e4702411dda0aa0d 100644 (file)
@@ -3,7 +3,6 @@
 extern crate termion;
 
 mod prolog;
-#[macro_use] mod test_utils;
 
 use prolog::ast::*;
 use prolog::io::*;
index 45810283ffe8c3edb5e4e4e5a6adb42283ba9611..2ab59feb7b285e46618b8a6f140927f823175938 100644 (file)
@@ -551,6 +551,7 @@ pub enum Term {
 #[derive(Clone, Copy)]
 pub enum InlinedClauseType {
     CompareNumber(CompareNumberQT),
+    IsAtom,
     IsAtomic,
     IsCompound,
     IsInteger,
@@ -565,6 +566,7 @@ impl InlinedClauseType {
     pub fn name(&self) -> &'static str {
         match self {
             &InlinedClauseType::CompareNumber(qt) => qt.name(),
+            &InlinedClauseType::IsAtom => "atom",
             &InlinedClauseType::IsAtomic => "atomic",
             &InlinedClauseType::IsCompound => "compound",
             &InlinedClauseType::IsInteger  => "integer",
@@ -584,6 +586,7 @@ impl InlinedClauseType {
             ("<=", 2) => Some(InlinedClauseType::CompareNumber(CompareNumberQT::LessThanOrEqual)),
             ("=\\=", 2) => Some(InlinedClauseType::CompareNumber(CompareNumberQT::NotEqual)),
             ("=:=", 2) => Some(InlinedClauseType::CompareNumber(CompareNumberQT::Equal)),
+            ("atom", 1) => Some(InlinedClauseType::IsAtom),
             ("atomic", 1) => Some(InlinedClauseType::IsAtomic),
             ("compound", 1) => Some(InlinedClauseType::IsCompound),
             ("integer", 1) => Some(InlinedClauseType::IsInteger),
@@ -1203,6 +1206,7 @@ pub enum BuiltInInstruction {
     InstallInferenceCounter(RegType, RegType, RegType),
     InstallNewBlock,
     InternalCallN,
+    IsAtom(RegType),
     IsAtomic(RegType),
     IsCompound(RegType),
     IsFloat(RegType),
index 6f4572dd248e746a081310eddcb36868d88b5a39..5da939459b9e426eb5150da888de11926d8d48fb 100644 (file)
@@ -620,7 +620,9 @@ fn get_builtins() -> Code {
          query![put_value!(temp_v!(5), 1)],
          reset_block!(),
          fail!(),
-         compare_execute!() // compare/3, 464.
+         compare_execute!(), // compare/3, 464.
+         is_atom!(temp_v!(1)), // atom/1, 465.
+         proceed!()
     ]
 }
 
@@ -733,7 +735,8 @@ pub fn build_code_and_op_dirs() -> (CodeDir, OpDir)
     code_dir.insert((clause_name!("=@="), 2), (391, builtin.clone()));
     code_dir.insert((clause_name!("\\=@="), 2), (392, builtin.clone()));
     code_dir.insert((clause_name!("compare"), 3), (464, builtin.clone()));
-
+    code_dir.insert((clause_name!("atom"), 1), (465, builtin.clone()));
+    
     (code_dir, op_dir)
 }
 
index 15299edab782c501a54257ac3eac6e9f0750230c..b770a693478bcc623e27af9dc69186e55ce69480 100644 (file)
@@ -320,6 +320,19 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
                                                 at_1.unwrap_or(interm!(1)),
                                                 at_2.unwrap_or(interm!(2))));
             },
+            InlinedClauseType::IsAtom =>
+                match terms[0].as_ref() {
+                    &Term::Constant(_, Constant::Atom(_)) => {
+                        code.push(succeed!());
+                    },
+                    &Term::Var(ref vr, ref name) => {
+                        let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
+                        code.push(is_atom!(r));
+                    }
+                    _ => {
+                        code.push(fail!());
+                    }
+                },
             InlinedClauseType::IsAtomic =>
                 match terms[0].as_ref() {
                     &Term::AnonVar | &Term::Clause(..) | &Term::Cons(..) => {
@@ -608,12 +621,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
 
         vs.populate_restricting_sets();
         self.marker.drain_var_data(vs);
-        
+
         let mut code = Vec::new();
 
         if let &Term::Clause(_, _, ref args, _) = term {
             self.marker.reset_at_head(args);
-            
+
             let iter = FactInstruction::iter(term);
             let mut compiled_fact = self.compile_target(iter, GenContext::Head, false);
 
index 7fcdfe34595ecb3e2c9db7fdd3dfbf447da59f9a..912b605dd61d19569ed921a903689cc6868ef644 100644 (file)
@@ -249,6 +249,8 @@ impl fmt::Display for BuiltInInstruction {
                 write!(f, "unwind_stack"),
             &BuiltInInstruction::Unify =>
                 write!(f, "unify"),
+            &BuiltInInstruction::IsAtom(r) =>
+                write!(f, "is_atom {}", r),
             &BuiltInInstruction::IsAtomic(r) =>
                 write!(f, "is_atomic {}", r),
             &BuiltInInstruction::IsCompound(r) =>
index c8d169cd24aa08309bf9b24123cddb30d80a142b..39d1ad463a67d572063487231c6e4725e273c9e7 100644 (file)
@@ -1350,6 +1350,14 @@ impl MachineState {
                     _ => self.throw_exception(functor!("type_error", 1, [heap_atom!("integer_expected")]))
                 };
             },
+            &BuiltInInstruction::IsAtom(r) => {
+                let d = self.store(self.deref(self[r].clone()));
+
+                match d {
+                    Addr::Con(Constant::Atom(_)) => self.p += 1,
+                    _ => self.fail = true
+                };
+            },
             &BuiltInInstruction::IsAtomic(r) => {
                 let d = self.store(self.deref(self[r].clone()));
 
index 01e075f357a902b996a3873449ebcb7e8394d813..d78c7b76a8feba797626b6877512a6a907d32553 100644 (file)
@@ -167,6 +167,12 @@ macro_rules! retry_me_else {
     )
 }
 
+macro_rules! is_atom {
+    ($reg:expr) => (
+        Line::BuiltIn(BuiltInInstruction::IsAtom($reg))
+    )
+}
+
 macro_rules! is_atomic {
     ($reg:expr) => (
         Line::BuiltIn(BuiltInInstruction::IsAtomic($reg))
diff --git a/src/test_utils.rs b/src/test_utils.rs
deleted file mode 100644 (file)
index f464c07..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-use prolog::ast::*;
-use prolog::heap_print::*;
-use prolog::io::*;
-use prolog::machine::*;
-
-use std::collections::HashSet;
-use std::mem::swap;
-
-pub struct TestOutputter {
-    results: Vec<HashSet<String>>,
-    contents: HashSet<String>,
-    focus: String
-}
-
-impl TestOutputter {
-    fn cache(&mut self) {
-        self.begin_new_var();
-
-        let mut contents = HashSet::new();
-        swap(&mut contents, &mut self.contents);
-        
-        self.results.push(contents);
-    }
-}
-
-impl HeapCellValueOutputter for TestOutputter {
-    type Output = Vec<HashSet<String>>;
-
-    fn new() -> Self {
-        TestOutputter { results: vec![],
-                        contents: HashSet::new(),
-                        focus: String::new() }
-    }
-
-    fn append(&mut self, focus: &str) {        
-        self.focus += focus;        
-    }
-
-    fn begin_new_var(&mut self) {        
-        if !self.focus.is_empty() {
-            let mut focus = String::new();
-            swap(&mut focus, &mut self.focus);
-            
-            self.contents.insert(focus);
-        }
-    }
-
-    fn result(self) -> Self::Output {
-        self.results
-    }
-
-    fn ends_with(&self, s: &str) -> bool {
-        self.focus.ends_with(s)
-    }
-
-    fn len(&self) -> usize {
-        self.focus.len()
-    }
-
-    fn truncate(&mut self, len: usize) {
-        self.focus.truncate(len);
-    }
-}
-
-pub fn collect_test_output(wam: &mut Machine, alloc_locs: AllocVarDict, mut heap_locs: HeapVarDict)
-                           -> Vec<HashSet<String>>
-{
-    let mut output = TestOutputter::new();
-    
-    output = wam.heap_view(&heap_locs, output);
-    output.cache();
-    
-    while let EvalSession::SubsequentQuerySuccess = wam.continue_query(&alloc_locs, &mut heap_locs)
-    {
-        output = wam.heap_view(&heap_locs, output);
-        output.cache();
-    }
-
-    output.result()
-}
-
-pub fn collect_test_output_with_limit(wam: &mut Machine, alloc_locs: AllocVarDict,
-                                      mut heap_locs: HeapVarDict, limit: usize)
-                                      -> Vec<HashSet<String>>
-{
-    let mut output = TestOutputter::new();
-    
-    output = wam.heap_view(&heap_locs, output);
-    output.cache();
-    
-    let mut count  = 1;
-
-    if count == limit {
-        return output.result();
-    }
-
-    while let EvalSession::SubsequentQuerySuccess = wam.continue_query(&alloc_locs, &mut heap_locs)
-    {
-        output = wam.heap_view(&heap_locs, output);
-        output.cache();
-        
-        count += 1;
-
-        if count == limit {
-            break;
-        }
-    }
-
-    output.result()
-}
-
-#[allow(dead_code)]
-pub fn submit(wam: &mut Machine, buffer: &str) -> bool
-{
-    wam.reset();
-        
-    match parse_code(wam, buffer) {
-        Ok(tl) =>
-            match compile_packet(wam, tl) {
-                EvalSession::InitialQuerySuccess(_, _) |
-                EvalSession::EntrySuccess |
-                EvalSession::SubsequentQuerySuccess =>
-                    true,
-                _ => false
-            },
-        Err(e) => panic!("parse error: {:?}", e)
-    }
-}
-
-#[allow(dead_code)]
-pub fn submit_query(wam: &mut Machine, buffer: &str, result: Vec<HashSet<String>>) -> bool
-{
-    wam.reset();
-
-    match parse_code(wam, buffer) {
-        Ok(tl) =>
-            match compile_packet(wam, tl) {
-                EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) =>
-                    result == collect_test_output(wam, alloc_locs, heap_locs),
-                EvalSession::EntrySuccess => true,
-                _ => false
-            },
-        Err(e) => panic!("parse error: {:?}", e)
-    }
-}
-
-#[allow(dead_code)]
-pub fn submit_query_with_limit(wam: &mut Machine, buffer: &str,
-                               result: Vec<HashSet<String>>, limit: usize)
-                               -> bool
-{
-    wam.reset();
-
-    match parse_code(wam, buffer) {
-        Ok(tl) =>
-            match compile_packet(wam, tl) {
-                EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) =>
-                    result == collect_test_output_with_limit(wam, alloc_locs,
-                                                             heap_locs, limit),
-                EvalSession::EntrySuccess => true,
-                _ => false
-            },
-        Err(e) => panic!("parse error: {:?}", e)
-    }
-}
-
-#[allow(unused_macros)]
-macro_rules! expand_strs {
-    ($arr:expr) => (
-        $arr.into_iter().map(|s| String::from(*s)).collect()
-    )
-}
-
-#[allow(unused_macros)]
-macro_rules! assert_prolog_success_with_limit {
-    ($wam:expr, $buf:expr, [$($res:expr),*], $limit:expr) => (
-        assert!(submit_query_with_limit($wam, $buf, vec![$(expand_strs!($res)),*], $limit))
-    )
-}
-
-#[allow(unused_macros)]
-macro_rules! assert_prolog_failure {
-    ($wam: expr, $buf: expr) => (
-        assert_eq!(submit($wam, $buf), false)
-    )
-}
-
-#[allow(unused_macros)]
-macro_rules! assert_prolog_success {
-    ($wam:expr, $query:expr, [$($res:expr),*]) => (
-        assert!(submit_query($wam, $query, vec![$(expand_strs!($res)),*]))
-    );
-    ($wam:expr, $buf:expr) => (
-        assert_eq!(submit($wam, $buf), true)
-    )
-}
index 5b29072e54c4b8f2a6573afdd194f13235574f89..6640fd1bb2fadea87bc769c7f8d5f76f0df6867c 100644 (file)
@@ -1,5 +1,199 @@
-use super::*;
-use test_utils::*;
+use prolog::ast::*;
+use prolog::heap_print::*;
+use prolog::io::*;
+use prolog::machine::*;
+
+use std::collections::HashSet;
+use std::mem::swap;
+
+pub struct TestOutputter {
+    results: Vec<HashSet<String>>,
+    contents: HashSet<String>,
+    focus: String
+}
+
+impl TestOutputter {
+    fn cache(&mut self) {
+        self.begin_new_var();
+
+        let mut contents = HashSet::new();
+        swap(&mut contents, &mut self.contents);
+
+        self.results.push(contents);
+    }
+}
+
+impl HeapCellValueOutputter for TestOutputter {
+    type Output = Vec<HashSet<String>>;
+
+    fn new() -> Self {
+        TestOutputter { results: vec![],
+                        contents: HashSet::new(),
+                        focus: String::new() }
+    }
+
+    fn append(&mut self, focus: &str) {
+        self.focus += focus;
+    }
+
+    fn begin_new_var(&mut self) {
+        if !self.focus.is_empty() {
+            let mut focus = String::new();
+            swap(&mut focus, &mut self.focus);
+
+            self.contents.insert(focus);
+        }
+    }
+
+    fn result(self) -> Self::Output {
+        self.results
+    }
+
+    fn ends_with(&self, s: &str) -> bool {
+        self.focus.ends_with(s)
+    }
+
+    fn len(&self) -> usize {
+        self.focus.len()
+    }
+
+    fn truncate(&mut self, len: usize) {
+        self.focus.truncate(len);
+    }
+}
+
+pub fn collect_test_output(wam: &mut Machine, alloc_locs: AllocVarDict, mut heap_locs: HeapVarDict)
+                           -> Vec<HashSet<String>>
+{
+    let mut output = TestOutputter::new();
+
+    output = wam.heap_view(&heap_locs, output);
+    output.cache();
+
+    while let EvalSession::SubsequentQuerySuccess = wam.continue_query(&alloc_locs, &mut heap_locs)
+    {
+        output = wam.heap_view(&heap_locs, output);
+        output.cache();
+    }
+
+    output.result()
+}
+
+pub fn collect_test_output_with_limit(wam: &mut Machine, alloc_locs: AllocVarDict,
+                                      mut heap_locs: HeapVarDict, limit: usize)
+                                      -> Vec<HashSet<String>>
+{
+    let mut output = TestOutputter::new();
+
+    output = wam.heap_view(&heap_locs, output);
+    output.cache();
+
+    let mut count  = 1;
+
+    if count == limit {
+        return output.result();
+    }
+
+    while let EvalSession::SubsequentQuerySuccess = wam.continue_query(&alloc_locs, &mut heap_locs)
+    {
+        output = wam.heap_view(&heap_locs, output);
+        output.cache();
+
+        count += 1;
+
+        if count == limit {
+            break;
+        }
+    }
+
+    output.result()
+}
+
+#[allow(dead_code)]
+pub fn submit(wam: &mut Machine, buffer: &str) -> bool
+{
+    wam.reset();
+
+    match parse_code(wam, buffer) {
+        Ok(tl) =>
+            match compile_packet(wam, tl) {
+                EvalSession::InitialQuerySuccess(_, _) |
+                EvalSession::EntrySuccess |
+                EvalSession::SubsequentQuerySuccess =>
+                    true,
+                _ => false
+            },
+        Err(e) => panic!("parse error: {:?}", e)
+    }
+}
+
+#[allow(dead_code)]
+pub fn submit_query(wam: &mut Machine, buffer: &str, result: Vec<HashSet<String>>) -> bool
+{
+    wam.reset();
+
+    match parse_code(wam, buffer) {
+        Ok(tl) =>
+            match compile_packet(wam, tl) {
+                EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) =>
+                    result == collect_test_output(wam, alloc_locs, heap_locs),
+                EvalSession::EntrySuccess => true,
+                _ => false
+            },
+        Err(e) => panic!("parse error: {:?}", e)
+    }
+}
+
+#[allow(dead_code)]
+pub fn submit_query_with_limit(wam: &mut Machine, buffer: &str,
+                               result: Vec<HashSet<String>>, limit: usize)
+                               -> bool
+{
+    wam.reset();
+
+    match parse_code(wam, buffer) {
+        Ok(tl) =>
+            match compile_packet(wam, tl) {
+                EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) =>
+                    result == collect_test_output_with_limit(wam, alloc_locs,
+                                                             heap_locs, limit),
+                EvalSession::EntrySuccess => true,
+                _ => false
+            },
+        Err(e) => panic!("parse error: {:?}", e)
+    }
+}
+
+#[allow(unused_macros)]
+macro_rules! expand_strs {
+    ($arr:expr) => (
+        $arr.into_iter().map(|s| String::from(*s)).collect()
+    )
+}
+
+#[allow(unused_macros)]
+macro_rules! assert_prolog_success_with_limit {
+    ($wam:expr, $buf:expr, [$($res:expr),*], $limit:expr) => (
+        assert!(submit_query_with_limit($wam, $buf, vec![$(expand_strs!($res)),*], $limit))
+    )
+}
+
+#[allow(unused_macros)]
+macro_rules! assert_prolog_failure {
+    ($wam: expr, $buf: expr) => (
+        assert_eq!(submit($wam, $buf), false)
+    )
+}
+
+#[allow(unused_macros)]
+macro_rules! assert_prolog_success {
+    ($wam:expr, $query:expr, [$($res:expr),*]) => (
+        assert!(submit_query($wam, $query, vec![$(expand_strs!($res)),*]))
+    );
+    ($wam:expr, $buf:expr) => (
+        assert_eq!(submit($wam, $buf), true)
+    )
+}
 
 #[test]
 fn test_queries_on_facts()
@@ -1172,7 +1366,6 @@ fn test_queries_on_conditionals()
     assert_prolog_success!(&mut wam, "?- catch(test(a, [a]), type_error(E), true).",
                            [["E = _6"], ["E = _6"]]);
 
-    //TODO: write tests for calling ;, ->, to confirm behavior is correct.
     assert_prolog_success!(&mut wam, "?- f(X), call(->, atomic(X), true).",
                            [["X = a"], ["X = b"]]);
 }
@@ -1182,6 +1375,16 @@ fn test_queries_on_builtins()
 {
     let mut wam = Machine::new();
 
+    assert_prolog_failure!(&mut wam, "?- atom(X).");
+    assert_prolog_success!(&mut wam, "?- atom(a).");
+    assert_prolog_failure!(&mut wam, "?- atom(\"string\").");
+    assert_prolog_failure!(&mut wam, "?- atom([]).");
+    assert_prolog_failure!(&mut wam, "?- atom(1).");
+    assert_prolog_failure!(&mut wam, "?- atom(0).");
+    assert_prolog_failure!(&mut wam, "?- atom(0.0).");
+    assert_prolog_failure!(&mut wam, "?- atom([a,b,c]).");
+    assert_prolog_failure!(&mut wam, "?- atom(atop(the_trees)).");
+
     assert_prolog_failure!(&mut wam, "?- atomic(X).");
     assert_prolog_success!(&mut wam, "?- atomic(a).");
     assert_prolog_success!(&mut wam, "?- atomic(\"string\").");
@@ -1570,5 +1773,5 @@ fn test_queries_on_call_with_inference_limit()
                            [["R = !", "X = 6"]]);
     assert_prolog_success!(&mut wam, "?- call_with_inference_limit(g(X), 1, R), call_with_inference_limit(g(X), 1, R).",
                            [["R = inference_limit_exceeded", "X = _1"]]);
-    
+
 }