]> Repositorios git - scryer-prolog.git/commitdiff
add beginning support for ',', ';', '->'
authorMark Thom <[email protected]>
Sun, 24 Dec 2017 06:23:30 +0000 (23:23 -0700)
committerMark Thom <[email protected]>
Sun, 24 Dec 2017 06:23:30 +0000 (23:23 -0700)
Cargo.toml
README.md
src/prolog/ast.rs
src/prolog/builtins.rs
src/prolog/codegen.rs
src/prolog/io.rs
src/prolog/machine.rs
src/prolog/macros.rs

index 6a8c39d1f70b2aa03b8829c99c3a41fe2e2356dd..7d3168db86f572121a8bd875856661079669473f 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "rusty-wam"
-version = "0.7.3"
+version = "0.7.4"
 authors = ["Mark Thom"]
 
 [dependencies]
index 483c87f1a4134c0e511de0a66aca4bbedeeaaca3..5e81a8951285746ca4701c743af63a51f4078f2d 100644 (file)
--- a/README.md
+++ b/README.md
@@ -20,7 +20,7 @@ Extend rusty-wam to include the following, among other features:
 * Built-in and user-defined operators of all fixities, with custom
   associativity and precedence (_done_). 
 * Bignum, rational number and floating point arithmetic (_in progress_).
-* Built-in control operators (`,`, `;`, `->`, etc.).
+* Built-in control operators (`,`, `;`, `->`, etc.) (_in progress_).
 * Built-in predicates for list processing and top-level declarative
   control (`setup_call_control/3`, `call_with_inference_limit/3`,
   etc.)
index d8320d5abaf38e14f3ef3b528d76ffcfcac6054a..ee86c1b331fc8ca508adec65f17274a1e2e6fea6 100644 (file)
@@ -275,6 +275,12 @@ pub enum Constant {
     EmptyList
 }
 
+impl<'a> From<&'a str> for Constant {
+    fn from(input: &str) -> Constant {
+        Constant::Atom(String::from(input))
+    }
+}
+
 impl fmt::Display for Constant {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
@@ -416,6 +422,7 @@ pub enum ChoiceInstruction {
     TryMeElse(usize)
 }
 
+#[derive(Clone, Copy)]
 pub enum Terminal {
     Terminal, Non
 }
@@ -715,12 +722,15 @@ pub enum BuiltInInstruction {
     Fail,
     GetBall,
     GetCurrentBlock,
+    GetCutPoint,
     InstallNewBlock,
     InternalCallN,
     IsAtomic(RegType),
     IsVar(RegType),
     ResetBlock,
     SetBall,
+    SetNeckCutPoint(Terminal),
+    SetNonNeckCutPoint(Terminal),
     Succeed,
     Unify,
     UnwindStack
index 7c074e81fdea36c2776e600a3ed822d302ef4bb9..3dce6392bd7d36bc9202570376be2a055c45b7cb 100644 (file)
@@ -104,7 +104,90 @@ fn get_builtins() -> Code {
          proceed!(),
          fact![get_value!(temp_v!(1), 2)], // =/2, 73.
          proceed!(),
-         proceed!() // true/0, 75.
+         proceed!(), // true/0, 75.
+         try_me_else!(2), // ';'/2, 76.
+         execute_n!(1),
+         trust_me!(),
+         query![put_value!(temp_v!(2), 1)],
+         execute_n!(1),
+         allocate!(3), // ','/2, 81.
+         fact![get_var_in_fact!(perm_v!(2), 1),
+               get_var_in_fact!(perm_v!(1), 2)],
+         query![put_var!(perm_v!(3), 1)],         
+         get_cp!(),
+         query![put_value!(perm_v!(2), 1),
+                put_value!(perm_v!(1), 2),
+                put_unsafe_value!(3, 3)],
+         deallocate!(),
+         goto!(88, 3),
+         try_me_else!(25), // ','/3, 88.
+         switch_on_term!(4, 0, 0, 0),
+         indexed_try!(4),
+         retry!(11),
+         trust!(14),
+         try_me_else!(8),
+         allocate!(3),
+         fact![get_constant!(Constant::from("!"), temp_v!(1)),
+               get_structure!(String::from(","), 2, temp_v!(2)),
+               unify_variable!(perm_v!(2)),
+               unify_variable!(perm_v!(1)),
+               get_var_in_fact!(perm_v!(3), 3)],
+         query![put_value!(perm_v!(3), 1)],
+         set_non_neck_cp!(non_terminal!()),
+         query![put_unsafe_value!(2, 1),
+                put_unsafe_value!(1, 2),
+                put_value!(perm_v!(3), 3)],
+         deallocate!(),
+         goto!(88, 3),
+         retry_me_else!(4),
+         fact![get_constant!(Constant::from("!"), temp_v!(1)),
+               get_constant!(Constant::from("!"), temp_v!(2))],
+         query![put_value!(temp_v!(3), 1)],
+         set_neck_cp!(terminal!()),
+         trust_me!(),
+         allocate!(1),
+         fact![get_constant!(Constant::from("!"), temp_v!(1)),
+               get_var_in_fact!(perm_v!(1), 2)],
+         query![put_value!(temp_v!(3), 1)],
+         set_non_neck_cp!(non_terminal!()),
+         query![put_value!(perm_v!(1), 1)],
+         deallocate!(),
+         execute_n!(1),
+         retry_me_else!(7),
+         allocate!(1),
+         fact![get_constant!(Constant::from("!"), temp_v!(2)),
+               get_var_in_fact!(perm_v!(1), 3)],
+         call_n!(1),
+         query![put_value!(perm_v!(1), 1)],
+         deallocate!(),
+         set_non_neck_cp!(terminal!()),
+         retry_me_else!(7),
+         allocate!(3),
+         fact![get_structure!(String::from(","), 2, temp_v!(2)),
+               unify_variable!(perm_v!(2)),
+               unify_variable!(perm_v!(1)),
+               get_var_in_fact!(perm_v!(3), 3)],         
+         call_n!(1),
+         query![put_unsafe_value!(2, 1),
+                put_unsafe_value!(1, 2),
+                put_value!(perm_v!(3), 3)],
+         deallocate!(),
+         goto!(88, 3),
+         trust_me!(),
+         allocate!(1),
+         fact![get_var_in_fact!(perm_v!(1), 2)],
+         call_n!(1),
+         query![put_value!(perm_v!(1), 1)],
+         deallocate!(),
+         execute_n!(1),
+         allocate!(2), // (->)/2, 134.
+         get_level!(),
+         fact![get_var_in_fact!(perm_v!(2), 2)],
+         call_n!(1),
+         cut!(non_terminal!()),
+         query![put_value!(perm_v!(2), 1)],
+         deallocate!(),
+         execute_n!(1)
     ]
 }
 
@@ -148,6 +231,10 @@ pub fn build_code_dir() -> (Code, CodeDir, OpDir)
     op_dir.insert((String::from("=:="), Fixity::In), (XFX, 700));
     op_dir.insert((String::from(">="), Fixity::In), (XFX, 700));
     op_dir.insert((String::from("=<"), Fixity::In), (XFX, 700));
+
+    // control operators.
+    op_dir.insert((String::from(";"), Fixity::In), (XFY, 1100));
+    op_dir.insert((String::from("->"), Fixity::In), (XFY, 1050));
     
     // there are 63 registers in the VM, so call/N is defined for all 0 <= N <= 62
     // (an extra register is needed for the predicate name)
@@ -163,7 +250,11 @@ pub fn build_code_dir() -> (Code, CodeDir, OpDir)
     code_dir.insert((String::from("catch"), 3), (PredicateKeyType::BuiltIn, 5));
     code_dir.insert((String::from("throw"), 1), (PredicateKeyType::BuiltIn, 59));
     code_dir.insert((String::from("="), 2), (PredicateKeyType::BuiltIn, 73));
-    code_dir.insert((String::from("true"), 0), (PredicateKeyType::BuiltIn, 75));
+    code_dir.insert((String::from("true"), 0), (PredicateKeyType::BuiltIn, 75));    
 
+    code_dir.insert((String::from(";"), 2), (PredicateKeyType::BuiltIn, 76));
+    code_dir.insert((String::from(","), 2), (PredicateKeyType::BuiltIn, 81));    
+    code_dir.insert((String::from("->"), 2), (PredicateKeyType::BuiltIn, 134));
+    
     (builtin_code, code_dir, op_dir)
 }
index 213141e6ad6454a4e00096f1ac727f24984d98da..c21a1bc0408f58d7b11d8c84b65504c4dbf383e3 100644 (file)
@@ -65,8 +65,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
         self.marker.take_bindings()
     }
 
-    fn update_var_count<Iter>(&mut self, iter: Iter)
-        where Iter: Iterator<Item=TermRef<'a>>
+    fn update_var_count<Iter: Iterator<Item=TermRef<'a>>>(&mut self, iter: Iter)
     {
         for term in iter {
             if let TermRef::Var(_, _, var) = term {
@@ -96,7 +95,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
 
                 self.marker.reset_arg(arity);
                 self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target);
-                code.push(Line::Query(target));
+
+                if !target.is_empty() {
+                    code.push(Line::Query(target));
+                }
+                
                 vr.get().norm()
             }
         }
@@ -233,13 +236,6 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
     fn add_conditional_call_inlined(_: &InlinedQueryTerm, code: &mut Code)
     {
         code.push(proceed!());
-
-        /*
-        match term {
-            &InlinedQueryTerm::IsAtomic(_) | &InlinedQueryTerm::IsVar(_) =>
-                code.push(proceed!())
-        };
-         */
     }
 
     fn add_conditional_call(code: &mut Code, qt: &QueryTerm, pvs: usize)
@@ -340,7 +336,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
         Ok(())
     }
 
-    fn call_arith_eval(&self, term: &'a Term, target_int: usize) -> Result<ArithCont, ArithmeticError>
+    fn call_arith_eval(&self, term: &'a Term, target_int: usize)
+                       -> Result<ArithCont, ArithmeticError>
     {
         let mut evaluator = ArithmeticEvaluator::new(self.marker.bindings(), target_int);
         evaluator.eval(term)
@@ -421,7 +418,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
                         self.marker.reset_arg(term.arity());
 
                         let iter = term.post_order_iter();
-                        code.push(Line::Query(self.compile_target(iter, term_loc, is_exposed)));
+                        let query = self.compile_target(iter, term_loc, is_exposed);
+
+                        if !query.is_empty() {
+                            code.push(Line::Query(query));
+                        }
+                        
                         Self::add_conditional_call(code, term, conjunct_info.perm_vars());
                     },
                     _ => {
@@ -479,7 +481,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
         if let &QueryTerm::Term(ref term) = p0 {
             if let &Term::Clause(_, _, _) = term {
                 let iter = FactInstruction::iter(term);
-                code.push(Line::Fact(self.compile_target(iter, GenContext::Head, false)));
+                let fact = self.compile_target(iter, GenContext::Head, false);
+
+                if !fact.is_empty() {
+                    code.push(Line::Fact(fact));
+                }
             }
 
             let iter = ChunkedIterator::from_rule_body(p1, clauses);
@@ -550,7 +556,10 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
             let mut compiled_fact = self.compile_target(iter, GenContext::Head, false);
 
             self.mark_unsafe_fact_vars(&mut compiled_fact);
-            code.push(Line::Fact(compiled_fact));
+
+            if !compiled_fact.is_empty() {
+                code.push(Line::Fact(compiled_fact));
+            }
         }
 
         code.push(proceed!());
@@ -567,9 +576,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
         self.marker.reset_arg(term.arity());
 
         let iter = term.post_order_iter();
-        let compiled_query = Line::Query(self.compile_target(iter, term_loc, is_exposed));
+        let compiled_query = self.compile_target(iter, term_loc, is_exposed);
 
-        code.push(compiled_query);
+        if !compiled_query.is_empty() {
+            code.push(Line::Query(compiled_query));
+        }
 
         Self::add_conditional_call(code, term, index);
     }
index 4bb6a5a89ea75c169f524c19ab5b217e4e71707a..d63b700db0a956822028731c1266d24cc808521f 100644 (file)
@@ -141,6 +141,16 @@ impl fmt::Display for IndexedChoiceInstruction {
     }
 }
 
+impl fmt::Display for Terminal {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            &Terminal::Terminal =>
+                write!(f, "terminal"),
+            &Terminal::Non =>
+                write!(f, "non_terminal")
+        }
+    }
+}
 
 impl fmt::Display for BuiltInInstruction {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -159,6 +169,8 @@ impl fmt::Display for BuiltInInstruction {
                 write!(f, "get_ball X1"),
             &BuiltInInstruction::GetCurrentBlock =>
                 write!(f, "get_current_block X1"),
+            &BuiltInInstruction::GetCutPoint =>
+                write!(f, "get_cp"),
             &BuiltInInstruction::InstallNewBlock =>
                 write!(f, "install_new_block"),
             &BuiltInInstruction::InternalCallN =>
@@ -171,6 +183,10 @@ impl fmt::Display for BuiltInInstruction {
                 write!(f, "reset_block"),
             &BuiltInInstruction::SetBall =>
                 write!(f, "set_ball"),
+            &BuiltInInstruction::SetNeckCutPoint(terminal) =>
+                write!(f, "set_neck_cp {}", terminal),
+            &BuiltInInstruction::SetNonNeckCutPoint(terminal) =>
+                write!(f, "set_non_neck_cp {}", terminal),
             &BuiltInInstruction::Succeed =>
                 write!(f, "true"),
             &BuiltInInstruction::UnwindStack =>
index 7dcaba6df3d44c9379b584298b42874c2896d08a..047a05f154186c4018cc66e0eda9227debb91708 100644 (file)
@@ -1621,7 +1621,14 @@ impl MachineState {
 
                 self.write_constant_to_var(addr, &c);
                 self.p += 1;
-            },            
+            },
+            &BuiltInInstruction::GetCutPoint => {
+                let c = Constant::Usize(self.b);
+                let addr = self[temp_v!(1)].clone();
+
+                self.write_constant_to_var(addr, &c);
+                self.p += 1;
+            },
             &BuiltInInstruction::EraseBall => {
                 self.ball.0 = 0;
                 self.ball.1.truncate(0);
@@ -1659,6 +1666,28 @@ impl MachineState {
 
                 self.p += 1;
             },
+            &BuiltInInstruction::SetNeckCutPoint(terminal) => {
+                let nb = self.store(self.deref(self[temp_v!(1)].clone()));
+
+                match nb {
+                    Addr::Con(Constant::Usize(nb)) => {
+                        self.b = nb;
+                        self.neck_cut(terminal);
+                    },
+                    _ => self.fail = true
+                };
+            },
+            &BuiltInInstruction::SetNonNeckCutPoint(terminal) => {
+                let nb = self.store(self.deref(self[temp_v!(1)].clone()));
+
+                match nb {
+                    Addr::Con(Constant::Usize(nb)) => {
+                        self.b = nb;
+                        self.non_neck_cut(terminal);
+                    },
+                    _ => self.fail = true
+                };
+            },
             &BuiltInInstruction::CleanUpBlock => {
                 let nb = self.store(self.deref(self[temp_v!(1)].clone()));
 
@@ -1997,24 +2026,45 @@ impl MachineState {
         }
     }
 
-    fn execute_cut_instr(&mut self, instr: &CutInstruction) {
-        match instr {
-            &CutInstruction::Cut(ref term) => {
-                let b = self.b;
-                let e = self.e;
-                let b0 = self.and_stack[e].b0; // STACK[E+2+1]
+    fn non_neck_cut(&mut self, term: Terminal)
+    {
+        let b = self.b;
+        let e = self.e;
+        let b0 = self.and_stack[e].b0; // STACK[E+2+1]
 
-                if b > b0 {
-                    self.b = b0;
-                    self.tidy_trail();
-                }
+        if b > b0 {
+            self.b = b0;
+            self.tidy_trail();
+        }
 
-                if let &Terminal::Terminal = term {
-                    self.p = self.cp;
-                } else {
-                    self.p += 1;
-                }
-            },
+        if let Terminal::Terminal = term {
+            self.p = self.cp;
+        } else {
+            self.p += 1;
+        }
+    }
+
+    fn neck_cut(&mut self, term: Terminal)
+    {
+        let b = self.b;
+        let b0 = self.b0;
+
+        if b > b0 {
+            self.b = b0;
+            self.tidy_trail();
+        }
+
+        if let Terminal::Terminal = term {
+            self.p = self.cp;
+        } else {
+            self.p += 1;
+        }        
+    }
+    
+    fn execute_cut_instr(&mut self, instr: &CutInstruction) {
+        match instr {
+            &CutInstruction::Cut(term) =>
+                self.non_neck_cut(term),                
             &CutInstruction::GetLevel => {
                 let b0 = self.b0;
                 let e  = self.e;
@@ -2022,21 +2072,8 @@ impl MachineState {
                 self.and_stack[e].b0 = b0;
                 self.p += 1;
             },
-            &CutInstruction::NeckCut(ref term) => {
-                let b = self.b;
-                let b0 = self.b0;
-
-                if b > b0 {
-                    self.b = b0;
-                    self.tidy_trail();
-                }
-
-                if let &Terminal::Terminal = term {
-                    self.p = self.cp;
-                } else {
-                    self.p += 1;
-                }
-            }
+            &CutInstruction::NeckCut(term) =>
+                self.neck_cut(term)
         }
     }
 
index 130ac3c496279d5ba7739e37d38dd7316225c903..c31e5f59cd1850cccd4516ff593ff720199815c8 100644 (file)
@@ -123,6 +123,12 @@ macro_rules! try_me_else {
     )
 }
 
+macro_rules! retry_me_else {
+    ($o:expr) => (
+        Line::Choice(ChoiceInstruction::RetryMeElse($o))
+    )
+}
+
 macro_rules! is_atomic {
     ($reg:expr) => (
         Line::BuiltIn(BuiltInInstruction::IsAtomic($reg))
@@ -159,6 +165,12 @@ macro_rules! proceed {
     )
 }
 
+macro_rules! terminal {
+    () => (
+        Terminal::Terminal
+    )
+}
+
 macro_rules! non_terminal {
     () => (
         Terminal::Non
@@ -260,3 +272,63 @@ macro_rules! get_level {
         Line::Cut(CutInstruction::GetLevel)
     )
 }
+
+macro_rules! switch_on_term {
+    ($v:expr, $c:expr, $l:expr, $s:expr) => (
+        Line::Indexing(IndexingInstruction::SwitchOnTerm($v, $c, $l, $s))
+    )
+}
+
+macro_rules! indexed_try {
+    ($i:expr) => (
+        Line::IndexedChoice(IndexedChoiceInstruction::Try($i))
+    )
+}
+
+macro_rules! retry {
+    ($i:expr) => (
+        Line::IndexedChoice(IndexedChoiceInstruction::Retry($i))
+    )
+}
+
+macro_rules! trust {
+    ($i:expr) => (
+        Line::IndexedChoice(IndexedChoiceInstruction::Trust($i))
+    )
+}
+
+macro_rules! get_cp {
+    () => (
+        Line::BuiltIn(BuiltInInstruction::GetCutPoint)
+    )
+}
+
+macro_rules! set_neck_cp {
+    ($term:expr) => (
+        Line::BuiltIn(BuiltInInstruction::SetNeckCutPoint($term))
+    )
+}
+
+macro_rules! set_non_neck_cp {
+    ($term:expr) => (
+        Line::BuiltIn(BuiltInInstruction::SetNonNeckCutPoint($term))
+    )
+}
+
+macro_rules! get_constant {
+    ($c:expr, $r:expr) => (
+        FactInstruction::GetConstant(Level::Shallow, $c, $r)
+    )
+}
+
+macro_rules! get_structure {
+    ($atom:expr, $arity:expr, $r:expr) => (
+        FactInstruction::GetStructure(Level::Shallow, $atom, $arity, $r)
+    )
+}
+
+macro_rules! unify_variable {
+    ($r:expr) => (
+        FactInstruction::UnifyVariable($r)
+    )
+}