]> Repositorios git - scryer-prolog.git/commitdiff
inline and expand conditionals whenever possible
authorMark Thom <[email protected]>
Wed, 24 Jan 2018 04:01:53 +0000 (21:01 -0700)
committerMark Thom <[email protected]>
Wed, 24 Jan 2018 04:01:53 +0000 (21:01 -0700)
12 files changed:
Cargo.lock
src/main.rs
src/prolog/ast.rs
src/prolog/builtins.rs
src/prolog/codegen.rs
src/prolog/io.rs
src/prolog/iterators.rs
src/prolog/machine/machine_state.rs
src/prolog/machine/mod.rs
src/prolog/macros.rs
src/prolog/parser
src/test_utils.rs

index 966a4013a8773999e7a9d9292340f899087cc992..ddb719f8afde5f2f486ebaf477a3ab21dfbba559 100644 (file)
@@ -171,7 +171,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "rusty-wam"
-version = "0.7.4"
+version = "0.7.5"
 dependencies = [
  "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
index 6ea09b5718a3588b0e6b8d802ae6a93b99f3afce..c9ce711c2b15e04537e46623b9db412b4d2eb5f7 100644 (file)
@@ -6,16 +6,15 @@ mod prolog;
 
 use prolog::io::*;
 use prolog::machine::*;
-use prolog::parser::toplevel::*;
 
 #[cfg(test)]
 mod tests;
 
 fn process_buffer(wam: &mut Machine, buffer: &str)
 {
-    match parse_code(buffer, wam.atom_tbl(), wam.op_dir()) {
+    match parse_code(wam, buffer) {
         Ok(tl) => {
-            let result = eval(wam, &tl);
+            let result = compile(wam, &tl);
             print(wam, result);
         },
         Err(s) => println!("{:?}", s)
index 103f769af6725c309f7ec4eaff3f5bae6fae8602..7f5087d5c995adf08d7c4db692c7c9d0bc7a19ab 100644 (file)
@@ -85,6 +85,42 @@ pub enum TopLevel {
     Rule(Rule)
 }
 
+impl TopLevel {
+    pub fn name(&self) -> Option<TabledRc<Atom>> {
+        match self {
+            &TopLevel::Declaration(_) => None,
+            &TopLevel::Fact(ref term) => term.name(),
+            &TopLevel::Predicate(ref clauses) =>
+                if let Some(ref term) = clauses.first() {
+                    term.name()
+                } else {
+                    None
+                },
+            &TopLevel::Query(_) => None,
+            &TopLevel::Rule(Rule { head: (QueryTerm::Term(ref term), _), .. }) =>
+                match term {
+                    &Term::Clause(_, ref name, ..)
+                  | &Term::Constant(_, Constant::Atom(ref name)) =>
+                        Some(name.clone()),
+                    _ =>
+                        None
+                },
+            _ => None
+        }
+    }
+
+    pub fn arity(&self) -> usize {
+        match self {
+            &TopLevel::Declaration(_) => 0,
+            &TopLevel::Fact(ref term) => term.arity(),
+            &TopLevel::Predicate(ref clauses) =>
+                clauses.first().map(|t| t.arity()).unwrap_or(0),
+            &TopLevel::Query(_) => 0,
+            &TopLevel::Rule(Rule { head: (ref qt, _), ..}) => qt.arity(),
+        }
+    }
+}
+
 #[derive(Clone, Copy)]
 pub enum Level {
     Deep, Shallow
@@ -220,10 +256,11 @@ tokens exceeding 4096 chars in length. */
 pub enum ParserError
 {
     Arithmetic(ArithmeticError),
-    CommaArityMismatch,
+    BuiltInArityMismatch(&'static str),
     UnexpectedEOF,
     FailedMatch(String),
     IO(IOError),
+    ExpectedRel,
     InadmissibleFact,
     InadmissibleQueryTerm,
     IncompleteReduction,
@@ -291,6 +328,7 @@ impl fmt::Display for Constant {
     }
 }
 
+#[derive(Clone)]
 pub enum Term {
     AnonVar,
     Clause(Cell<RegType>, TabledRc<Atom>, Vec<Box<Term>>, Option<Fixity>),
@@ -303,7 +341,7 @@ pub enum InlinedQueryTerm {
     CompareNumber(CompareNumberQT, Vec<Box<Term>>),    
     IsAtomic(Vec<Box<Term>>),
     IsVar(Vec<Box<Term>>),
-    IsInteger(Vec<Box<Term>>)
+    IsInteger(Vec<Box<Term>>)    
 }
 
 impl InlinedQueryTerm {
@@ -312,7 +350,7 @@ impl InlinedQueryTerm {
             &InlinedQueryTerm::CompareNumber(_, _) => 2,            
             &InlinedQueryTerm::IsAtomic(_) => 1,
             &InlinedQueryTerm::IsInteger(_) => 1,
-            &InlinedQueryTerm::IsVar(_) => 1,
+            &InlinedQueryTerm::IsVar(_) => 1,            
         }
     }
 }
@@ -327,6 +365,10 @@ pub enum CompareNumberQT {
     Equal
 }
 
+// vars of predicate, toplevel offset.  Vec<Term> is always a vector
+// of vars (we get their adjoining cells this way).
+pub type JumpStub = (Vec<Term>, Rc<Cell<usize>>);
+
 pub enum QueryTerm {
     Arg(Vec<Box<Term>>),
     CallN(Vec<Box<Term>>),
@@ -337,6 +379,7 @@ pub enum QueryTerm {
     Functor(Vec<Box<Term>>),
     Inlined(InlinedQueryTerm),
     Is(Vec<Box<Term>>),
+    Jump(JumpStub),
     Term(Term),
     Throw(Vec<Box<Term>>)
 }
@@ -352,6 +395,7 @@ impl QueryTerm {
             &QueryTerm::Functor(_) => 3,
             &QueryTerm::Inlined(ref term) => term.arity(),
             &QueryTerm::Is(_) => 2,
+            &QueryTerm::Jump((ref vars, _)) => vars.len(),
             &QueryTerm::CallN(ref terms) => terms.len(),
             &QueryTerm::Cut => 0,
             &QueryTerm::Term(ref term) => term.arity(),
@@ -387,7 +431,7 @@ impl<'a> ClauseType<'a> {
             &ClauseType::Display => "display",
             &ClauseType::Deep(_, _, name, _) => name.as_str(),            
             &ClauseType::DuplicateTerm => "duplicate_term",
-            &ClauseType::Functor => "functor",
+            &ClauseType::Functor => "functor",            
             &ClauseType::Is => "is",
             &ClauseType::Root(name) => name.as_str(),
             &ClauseType::Throw => "throw"
@@ -774,7 +818,10 @@ pub enum ControlInstruction {
     ExecuteN(usize),
     FunctorCall,
     FunctorExecute,
-    Goto(usize, usize), // p, arity.
+    JmpByCall(usize, Rc<Cell<usize>>),    // arity, global_offset.
+    JmpByExecute(usize, Rc<Cell<usize>>), 
+    // GotoCall(usize, usize),    // p, arity.
+    GotoExecute(usize, usize), // p, arity.
     IsCall(RegType, ArithmeticTerm),
     IsExecute(RegType, ArithmeticTerm),
     Proceed,
@@ -801,10 +848,12 @@ impl ControlInstruction {
             &ControlInstruction::FunctorExecute => true,
             &ControlInstruction::ThrowCall => true,
             &ControlInstruction::ThrowExecute => true,
-            &ControlInstruction::Goto(_, _) => true,
+            &ControlInstruction::GotoExecute(..) => true,
             &ControlInstruction::Proceed => true,
-            &ControlInstruction::IsCall(_, _) => true,
-            &ControlInstruction::IsExecute(_, _) => true,
+            &ControlInstruction::IsCall(..) => true,
+            &ControlInstruction::IsExecute(..) => true,
+            &ControlInstruction::JmpByCall(..) => true,
+            &ControlInstruction::JmpByExecute(..) => true,
             _ => false
         }
     }
index 58e37a25778fc5f4b00a7e6ac2d70d48d2ba4b5f..bb7610277e1733edb18e3aa07d546d0a17f85924 100644 (file)
@@ -36,7 +36,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
                 put_value!(perm_v!(1), 3),
                 put_unsafe_value!(4, 4)],
          deallocate!(),
-         goto!(12, 4), // goto catch/4.
+         goto_execute!(12, 4), // goto catch/4.
          try_me_else!(10), // catch/4, 12.
          allocate!(3),
          fact![get_var_in_fact!(perm_v!(3), 1),
@@ -48,7 +48,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
          query![put_value!(perm_v!(2), 1),
                 put_unsafe_value!(1, 2)],
          deallocate!(),
-         goto!(44, 2), //21: goto end_block/2.
+         goto_execute!(44, 2), //21: goto end_block/2.
          trust_me!(),
          allocate!(3),
          fact![get_var_in_fact!(perm_v!(2), 2),
@@ -62,7 +62,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
                 put_value!(perm_v!(2), 2),
                 put_value!(perm_v!(1), 3)],
          deallocate!(),
-         goto!(32, 2), // goto handle_ball/2.
+         goto_execute!(32, 2), // goto handle_ball/2.
          try_me_else!(10), // handle_ball/2, 32.
          allocate!(2),
          get_level!(),
@@ -90,7 +90,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
                 put_value!(temp_v!(2), 1)],
          reset_block!(),
          deallocate!(),
-         goto!(61, 0),
+         goto_execute!(61, 0),
          set_ball!(), // throw/1, 59.
          unwind_stack!(),
          fail!(), // false/0, 61.
@@ -100,7 +100,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
          call_n!(1),
          cut!(),
          deallocate!(),
-         goto!(61, 0),
+         goto_execute!(61, 0),
          trust_me!(),
          proceed!(),
          duplicate_term!(), // duplicate_term/2, 71.
@@ -120,7 +120,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
                unify_variable!(temp_v!(1)),
                unify_variable!(temp_v!(2))],
          set_cp!(temp_v!(3)),
-         goto!(83, 3),
+         goto_execute!(83, 3),
          retry_me_else!(4),
          fact![get_constant!(atom!("!", atom_tbl), temp_v!(1)),
                get_constant!(atom!("!", atom_tbl), temp_v!(2))],
@@ -143,7 +143,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
                 put_unsafe_value!(1, 2),
                 put_value!(perm_v!(3), 3)],
          deallocate!(),
-         goto!(83, 3),
+         goto_execute!(83, 3),
          retry_me_else!(10),
          allocate!(1),
          get_level!(),
@@ -171,7 +171,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
          fact![get_structure!(atom_tbl, "->", 2, temp_v!(1), Some(infix!())),
                unify_variable!(temp_v!(1)),
                unify_variable!(temp_v!(2))],
-         goto!(139, 3),
+         goto_execute!(139, 3),
          trust_me!(),
          fact![get_structure!(atom_tbl, "->", 2, temp_v!(1), Some(infix!())),
                unify_void!(2)],
@@ -213,7 +213,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
                 put_value!(perm_v!(2), 4),
                 put_value!(perm_v!(4), 5)],
          deallocate!(),
-         goto!(173, 5), // goto arg_/3.
+         goto_execute!(173, 5), // goto arg_/3.
          retry_me_else!(10),
          allocate!(3),
          fact![get_var_in_fact!(perm_v!(1), 1),
@@ -229,7 +229,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
                 put_value!(perm_v!(2), 2),
                 put_value!(perm_v!(3), 3)],
          deallocate!(),
-         goto!(149, 3), // goto get_arg/3.
+         goto_execute!(149, 3), // goto get_arg/3.
          trust_me!(),
          query![get_var_in_query!(temp_v!(4), 1),
                 put_structure!(atom_tbl,
@@ -239,20 +239,20 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
                                temp_v!(1),
                                None),
                 set_constant!(atom!("integer_expected", atom_tbl))],
-         goto!(59, 1), // goto throw/1.
+         goto_execute!(59, 1), // goto throw/1.
          try_me_else!(5), // arg_/3, 173.
          fact![get_value!(temp_v!(1), 2),
                get_value!(temp_v!(1), 3)],
          neck_cut!(),
          query![put_value!(temp_v!(4), 2),
                 put_value!(temp_v!(5), 3)],
-         goto!(149, 3), // goto get_arg/3.
+         goto_execute!(149, 3), // goto get_arg/3.
          retry_me_else!(4),
          fact![get_value!(temp_v!(1), 2)],
          query![put_value!(temp_v!(4), 2),
                 get_var_in_query!(temp_v!(6), 3),
                 put_value!(temp_v!(5), 3)],
-         goto!(149, 3), // goto get_arg/3
+         goto_execute!(149, 3), // goto get_arg/3
          trust_me!(),
          allocate!(5),
          fact![get_var_in_fact!(perm_v!(2), 1),
@@ -273,7 +273,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
                 put_value!(perm_v!(3), 4),
                 put_value!(perm_v!(5), 5)],
          deallocate!(),
-         goto!(173, 3), // goto arg_/3.
+         goto_execute!(173, 3), // goto arg_/3.
          display!(), // display/1, 192.
          proceed!(),
          dynamic_is!(), // is/2, 194.
index 34d90b93be08b59eee76533265e96c0ad55cf425..5f3b248233b4594db66f74f881e77746433d6b27 100644 (file)
@@ -28,6 +28,12 @@ pub enum EvalSession<'a> {
     SubsequentQuerySuccess,
 }
 
+impl<'a> From<ParserError> for EvalSession<'a> {
+    fn from(err: ParserError) -> Self {
+        EvalSession::ParserError(err)
+    }
+}
+
 pub struct ConjunctInfo<'a> {
     pub perm_vs: VariableFixtures<'a>,
     pub num_of_chunks: usize,
@@ -79,12 +85,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
         *self.var_count.get(var).unwrap()
     }
 
-    fn mark_non_callable(&mut self,
-                         name: &'a Atom,
-                         arity: usize,
-                         term_loc: GenContext,
-                         vr: &'a Cell<VarReg>,
-                         code: &mut Code)
+    fn mark_non_callable(&mut self, name: &'a Atom, arity: usize, term_loc: GenContext,
+                         vr: &'a Cell<VarReg>, code: &mut Code)
                          -> RegType
     {
         match self.marker.bindings().get(name) {
@@ -145,11 +147,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
         };
     }
 
-    fn compile_clause<Target>(&mut self,
-                              ct: ClauseType<'a>,
-                              term_loc: GenContext,
-                              is_exposed: bool,
-                              terms: &'a Vec<Box<Term>>,
+    fn compile_clause<Target>(&mut self, ct: ClauseType<'a>, term_loc: GenContext,
+                              is_exposed: bool, terms: &'a Vec<Box<Term>>,
                               target: &mut Vec<Target>)
         where Target: CompilationTarget<'a>
     {
@@ -252,9 +251,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
             &QueryTerm::DuplicateTerm(_) =>
                 code.push(Line::Control(ControlInstruction::DuplicateTermCall)),
             &QueryTerm::Functor(_) =>
-                code.push(Line::Control(ControlInstruction::FunctorCall)),            
+                code.push(Line::Control(ControlInstruction::FunctorCall)),
             &QueryTerm::Inlined(_) =>
                 code.push(proceed!()),
+            &QueryTerm::Jump((ref vars, ref offset)) => {
+                code.push(jmp_call!(vars.len(), offset.clone()));
+            },
             &QueryTerm::Term(Term::Constant(_, Constant::Atom(ref atom))) => {
                 let call = ControlInstruction::Call(atom.clone(), 0, pvs);
                 code.push(Line::Control(call));
@@ -291,6 +293,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
                         *ctrl = ControlInstruction::DuplicateTermExecute,
                     ControlInstruction::FunctorCall =>
                         *ctrl = ControlInstruction::FunctorExecute,
+                    ControlInstruction::JmpByCall(arity, offset) =>
+                        *ctrl = ControlInstruction::JmpByExecute(arity, offset),
                     ControlInstruction::CatchCall =>
                         *ctrl = ControlInstruction::CatchExecute,
                     ControlInstruction::ThrowCall =>
@@ -323,7 +327,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
                 code.push(compare_number_instr!(cmp,
                                                 at_1.unwrap_or(interm!(1)),
                                                 at_2.unwrap_or(interm!(2))));
-            },            
+            },
             &InlinedQueryTerm::IsAtomic(ref inner_term) =>
                 match inner_term[0].as_ref() {
                     &Term::AnonVar | &Term::Clause(..) | &Term::Cons(..) => {
@@ -338,7 +342,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
                     }
                 },
             &InlinedQueryTerm::IsInteger(ref inner_term) =>
-                match inner_term[0].as_ref() {                    
+                match inner_term[0].as_ref() {
                     &Term::Constant(_, Constant::Number(Number::Integer(_))) => {
                         code.push(succeed!());
                     },
@@ -362,7 +366,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
                         let r = self.mark_non_callable(name, 1, term_loc, vr, code);
                         code.push(is_var!(r));
                     }
-                }        
+                }
         }
 
         Ok(())
@@ -375,11 +379,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
         evaluator.eval(term)
     }
 
-    fn compile_seq(&mut self,
-                   iter: ChunkedIterator<'a>,
-                   conjunct_info: &ConjunctInfo<'a>,
-                   code: &mut Code,
-                   is_exposed: bool)
+    fn compile_seq(&mut self, iter: ChunkedIterator<'a>, conjunct_info: &ConjunctInfo<'a>,
+                   code: &mut Code, is_exposed: bool)
                    -> Result<(), ParserError>
     {
         for (chunk_num, _, terms) in iter {
@@ -405,12 +406,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
 
                         match terms[0].as_ref() {
                             &Term::Var(ref vr, ref name) => {
-                                let r = self.mark_non_callable(name,
-                                                               2,
-                                                               term_loc,
-                                                               vr,
-                                                               code);
-
+                                let r = self.mark_non_callable(name, 2, term_loc, vr, code);
                                 code.push(is_call!(r, at.unwrap_or(interm!(1))));
                             },
                             &Term::Constant(_, ref c @ Constant::Number(_)) => {
@@ -466,17 +462,23 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
 
     fn compile_cleanup(code: &mut Code, conjunct_info: &ConjunctInfo, toc: &'a QueryTerm)
     {
+        // add a proceed to bookend any trailing inlines or cuts.
         match toc {
             &QueryTerm::Inlined(_) | &QueryTerm::Cut =>
                 code.push(proceed!()),
             _ => {}
         };
 
+        // perform lco.
         let dealloc_index = Self::lco(code);
 
         if conjunct_info.allocates() {
             code.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate));
         }
+
+        // mark the first uninitialized jmp command (if there is one)
+        // by code.len() - index.
+        //TODO
     }
 
     pub fn compile_rule<'b: 'a>(&mut self, rule: &'b Rule) -> Result<Code, ParserError>
index 276a531edbb5af55a467bc7f3d71bbc9c6581164..248b28637fdce79eea59a889c4db1005fcb422f5 100644 (file)
@@ -1,8 +1,10 @@
 use prolog::ast::*;
 use prolog::codegen::*;
 use prolog::debray_allocator::*;
+use prolog::fixtures::*;
 use prolog::heap_print::*;
 use prolog::machine::*;
+use prolog::parser::toplevel::*;
 
 use termion::raw::IntoRawMode;
 use termion::input::TermRead;
@@ -89,7 +91,7 @@ impl fmt::Display for CompareNumberQT {
             &CompareNumberQT::LessThan => write!(f, "<"),
             &CompareNumberQT::LessThanOrEqual => write!(f, "<="),
             &CompareNumberQT::NotEqual => write!(f, "=\\="),
-            &CompareNumberQT::Equal => write!(f, "=:="),            
+            &CompareNumberQT::Equal => write!(f, "=:="),
         }
     }
 }
@@ -129,12 +131,16 @@ impl fmt::Display for ControlInstruction {
                 write!(f, "deallocate"),
             &ControlInstruction::Execute(ref name, arity) =>
                 write!(f, "execute {}/{}", name, arity),
-            &ControlInstruction::Goto(p, arity) =>
-                write!(f, "goto {}/{}", p, arity),
+            &ControlInstruction::GotoExecute(p, arity) =>
+                write!(f, "goto_execute {}/{}", p, arity),
             &ControlInstruction::IsCall(r, ref at) =>
                 write!(f, "is_call {}, {}", r, at),
             &ControlInstruction::IsExecute(r, ref at) =>
                 write!(f, "is_execute {}, {}", r, at),
+            &ControlInstruction::JmpByCall(arity, ref offset) =>
+                write!(f, "jmp_by_call {}/{}", offset.get(), arity),
+            &ControlInstruction::JmpByExecute(arity, ref offset) =>
+                write!(f, "jmp_by_execute {}/{}", offset.get(), arity),
             &ControlInstruction::Proceed =>
                 write!(f, "proceed"),
             &ControlInstruction::ThrowCall =>
@@ -164,7 +170,7 @@ impl fmt::Display for BuiltInInstruction {
             &BuiltInInstruction::CleanUpBlock =>
                 write!(f, "clean_up_block"),
             &BuiltInInstruction::CompareNumber(cmp, ref at_1, ref at_2) =>
-                write!(f, "number_test {}, {}, {} ", cmp, at_1, at_2),            
+                write!(f, "number_test {}, {}, {} ", cmp, at_1, at_2),
             &BuiltInInstruction::DynamicCompareNumber(cmp) =>
                 write!(f, "dynamic_number_test {}", cmp),
             &BuiltInInstruction::EraseBall =>
@@ -188,9 +194,9 @@ impl fmt::Display for BuiltInInstruction {
             &BuiltInInstruction::IsInteger(r) =>
                 write!(f, "is_integer {}", r),
             &BuiltInInstruction::DynamicIs =>
-                write!(f, "call_is"),  
+                write!(f, "call_is"),
             &BuiltInInstruction::IsVar(r) =>
-                write!(f, "is_var {}", r),            
+                write!(f, "is_var {}", r),
             &BuiltInInstruction::ResetBlock =>
                 write!(f, "reset_block"),
             &BuiltInInstruction::SetBall =>
@@ -354,6 +360,12 @@ pub fn print_code(code: &Code) {
     }
 }
 
+pub fn parse_code(wam: &mut Machine, buffer: &str) -> Result<TopLevelPacket, ParserError>
+{
+    let mut worker = TopLevelWorker::new(wam.atom_tbl(), wam.op_dir());
+    worker.parse_code(buffer)
+}
+
 pub fn read() -> String {
     let _ = stdout().flush();
 
@@ -380,46 +392,90 @@ pub fn read() -> String {
     result
 }
 
-pub fn eval<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel) -> EvalSession<'b>
+// throw errors if declaration or query found.
+fn compile_relation(tl: &TopLevel) -> Result<Code, ParserError>
 {
+    let mut cg = CodeGenerator::<DebrayAllocator>::new();
+
     match tl {
-        &TopLevel::Declaration(ref decl) =>
-            wam.submit_decl(decl),
-        &TopLevel::Predicate(ref clauses) => {
-            let mut cg = CodeGenerator::<DebrayAllocator>::new();
+        &TopLevel::Declaration(_) | &TopLevel::Query(_) =>
+            Err(ParserError::ExpectedRel),
+        &TopLevel::Predicate(ref clauses) =>
+            cg.compile_predicate(clauses),
+        &TopLevel::Fact(ref fact) =>
+            Ok(cg.compile_fact(fact)),
+        &TopLevel::Rule(ref rule) =>
+            cg.compile_rule(rule)
+    }
+}
 
-            let compiled_pred = match cg.compile_predicate(clauses) {
-                Ok(pred) => pred,
-                Err(e)   => return EvalSession::ParserError(e)
-            };
+// set first jmp_by_call or jmp_by_index instruction to code.len() - idx,
+// where idx is the place it occurs. It only does this to the *first* uninitialized
+// jmp index it encounters, then returns.
+fn set_first_index(code: &Code)
+{
+    for (idx, line) in code.iter().enumerate() {
+        match line {
+            &Line::Control(ControlInstruction::JmpByExecute(_, ref offset))
+          | &Line::Control(ControlInstruction::JmpByCall(_, ref offset)) if offset.get() == 0 => {
+              offset.set(code.len() - idx);
+              break;
+            },
+            _ => {}
+        };
+    }
+}
 
-            wam.add_predicate(clauses, compiled_pred)
-        },
-        &TopLevel::Fact(ref fact) => {
-            let mut cg = CodeGenerator::<DebrayAllocator>::new();
+fn compile_appendix(code: &mut Code, queue: &Vec<TopLevel>) -> Result<(), ParserError>
+{
+    for tl in queue.iter() {
+        set_first_index(code);
+        code.append(&mut compile_relation(tl)?);
+    }
 
-            let compiled_fact = cg.compile_fact(fact);
-            wam.add_fact(fact, compiled_fact)
-        },
-        &TopLevel::Rule(ref rule) => {
-            let mut cg = CodeGenerator::<DebrayAllocator>::new();
+    Ok(())
+}
 
-            let compiled_rule = match cg.compile_rule(rule) {
-                Ok(rule) => rule,
-                Err(e) => return EvalSession::ParserError(e)                
-            };
+fn compile_query<'a>(terms: &'a Vec<QueryTerm>, queue: &'a Vec<TopLevel>)
+                     -> Result<(Code, AllocVarDict<'a>), ParserError>
+{
+    let mut cg = CodeGenerator::<DebrayAllocator>::new();
+    let mut code = try!(cg.compile_query(terms));    
+    
+    compile_appendix(&mut code, queue)?;
 
-            wam.add_rule(rule, compiled_rule)
-        },
-        &TopLevel::Query(ref query) => {
-            let mut cg = CodeGenerator::<DebrayAllocator>::new();
+    Ok((code, cg.take_vars()))
+}
 
-            let compiled_query = match cg.compile_query(query) {
-                Ok(query) => query,
+pub fn compile<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevelPacket) -> EvalSession<'b>
+{
+    match tl {
+        &TopLevelPacket::Query(ref terms, ref queue) =>
+            match compile_query(terms, queue) {
+                Ok((code, vars)) => wam.submit_query(code, vars),
+                Err(e) => EvalSession::from(e)
+            },
+        &TopLevelPacket::Decl(TopLevel::Declaration(ref decl), _) =>
+            wam.submit_decl(decl),
+        &TopLevelPacket::Decl(ref tl, ref queue) => {
+            let mut code = match compile_relation(tl) {
+                Ok(code) => code,
                 Err(e) => return EvalSession::ParserError(e)
             };
 
-            wam.submit_query(compiled_query, cg.take_vars())
+            if let Err(e) = compile_appendix(&mut code, queue) {
+                return EvalSession::from(e);
+            };
+
+            if !code.is_empty() {
+                if let Some(name) = tl.name() {
+                    wam.add_user_code(name, tl.arity(), code)
+                } else {
+                    EvalSession::NamelessEntry
+                }
+            } else {
+                EvalSession::ImpermissibleEntry(String::from("no code generated."))
+            }
         }
     }
 }
@@ -446,7 +502,7 @@ pub fn print(wam: &mut Machine, result: EvalSession) {
             loop {
                 let mut result = EvalSession::QueryFailure;
                 let mut output = PrinterOutputter::new();
-                
+
                 let bindings = wam.heap_view(&heap_locs, output).result();
 
                 let stdin = stdin();
index 8db60dccde4eac9e4dd9c5d4b06c3353079d66c2..06f4301a856cae082d09f884fd316ec92ac27117 100644 (file)
@@ -71,7 +71,14 @@ impl<'a> QueryIterator<'a> {
                 let state = TermIterState::Clause(0, ClauseType::Throw, term);
                 QueryIterator { state_stack: vec![state] }
             },
-            &QueryTerm::Cut => QueryIterator { state_stack: vec![] }
+            &QueryTerm::Cut => QueryIterator { state_stack: vec![] },
+            &QueryTerm::Jump((ref vars, _)) => {
+                let state_stack = vars.iter().rev().map(|t| {
+                    TermIterState::to_state(Level::Shallow, t)
+                }).collect();
+
+                QueryIterator { state_stack }
+            }
         }
     }
 }
@@ -266,6 +273,11 @@ impl<'a> ChunkedIterator<'a>
 
         while let Some(term) = item {
             match term {
+                &QueryTerm::Jump((ref vars, _)) => {
+                    result.push(term);
+                    arity = vars.len();
+                    break;
+                },
                 &QueryTerm::Term(ref inner_term) =>
                     if let GenContext::Head = self.term_loc {
                         result.push(term);
index d50a1c001e2c81f76253d3ce6143dd5cd1a215f7..55b63f9e20f6a4905a04f30bf27157372f8ae404 100644 (file)
@@ -1672,8 +1672,8 @@ impl MachineState {
                     let val = self.try_functor();
                     self.p = self.cp;
                     val
-                }),
-            &ControlInstruction::Goto(p, arity) => {
+                }),            
+            &ControlInstruction::GotoExecute(p, arity) => {
                 self.num_of_args = arity;
                 self.b0 = self.b;
                 self.p  = CodePtr::DirEntry(p);
@@ -1692,6 +1692,17 @@ impl MachineState {
                 self.unify(a1, Addr::Con(Constant::Number(a2)));
                 self.p = self.cp;
             },
+            &ControlInstruction::JmpByCall(arity, ref offset) => {
+                self.cp = self.p + 1;
+                self.num_of_args = arity;
+                self.b0 = self.b;
+                self.p += offset.get();
+            },
+            &ControlInstruction::JmpByExecute(arity, ref offset) => {                
+                self.num_of_args = arity;
+                self.b0 = self.b;
+                self.p += offset.get();
+            },
             &ControlInstruction::Proceed =>
                 self.p = self.cp,
             &ControlInstruction::ThrowCall => {
index 536c7ab01a5e2058685675af0e4cfed5670c908c..8d9e43f0b3b98ddb2561a9217e0344e33389ed1d 100644 (file)
@@ -12,7 +12,6 @@ use std::collections::{HashMap, HashSet};
 use std::mem::swap;
 use std::ops::Index;
 use std::rc::Rc;
-use std::vec::Vec;
 
 pub struct Machine {
     ms: machine_state::MachineState,
@@ -60,9 +59,8 @@ impl Machine {
         self.ms.atom_tbl.clone()
     }
 
-    fn add_user_code<'a>(&mut self, name: TabledRc<Atom>,
-                         arity: usize, offset: usize)
-                         -> EvalSession<'a>
+    pub fn add_user_code<'a>(&mut self, name: TabledRc<Atom>, arity: usize, mut code: Code)
+                             -> EvalSession<'a>
     {
         match self.code_dir.get(&(name.clone(), arity)) {
             Some(&(PredicateKeyType::BuiltIn, _)) =>
@@ -70,58 +68,14 @@ impl Machine {
             _ => {}
         };
 
+        let offset = self.code.len();
+
+        self.code.append(&mut code);
         self.code_dir.insert((name, arity), (PredicateKeyType::User, offset));
+        
         EvalSession::EntrySuccess
     }
 
-    pub fn add_fact<'a>(&mut self, fact: &Term, mut code: Code) -> EvalSession<'a>
-    {
-        match fact {
-            &Term::Clause(_, ref name, ..) | &Term::Constant(_, Constant::Atom(ref name)) => {
-                let p = self.code.len();
-                let arity = fact.arity();
-
-                self.code.append(&mut code);
-                self.add_user_code(name.clone(), arity, p)
-            },
-            _ => EvalSession::NamelessEntry
-        }
-    }
-
-    pub fn add_rule<'a>(&mut self, rule: &Rule, mut code: Code) -> EvalSession<'a>
-    {
-        match &rule.head.0 {
-            &QueryTerm::Term(Term::Clause(_, ref name, ..))
-          | &QueryTerm::Term(Term::Constant(_, Constant::Atom(ref name))) => {
-                let p = self.code.len();
-                let arity = rule.head.0.arity();
-
-                self.code.append(&mut code);
-                self.add_user_code(name.clone(), arity, p)
-            },
-            _ => EvalSession::NamelessEntry
-        }
-    }
-
-    pub fn add_predicate<'a>(&mut self, clauses: &Vec<PredicateClause>, mut code: Code)
-                             -> EvalSession<'a>
-    {
-        let p = self.code.len();
-
-        if let Some(ref clause) = clauses.first() {
-            if let Some(name) = clause.name() {
-                let arity = clause.arity();
-
-                self.code.append(&mut code);
-                self.add_user_code(name.clone(), arity, p)
-            } else {
-                EvalSession::NamelessEntry
-            }
-        } else {
-            EvalSession::ImpermissibleEntry(String::from("predicate must have clauses."))
-        }
-    }
-
     fn cached_query_size(&self) -> usize {
         match &self.cached_query {
             &Some(ref query) => query.len(),
@@ -255,7 +209,7 @@ impl Machine {
                     },
                     _ => {}
                 }
-
+                
                 self.ms.p = CodePtr::TopLevel(cn, p);
             }
 
index 6ad024a5fac48c4ec488a1dd55b792e2936b43a0..50ebd44329c053dffce7b23effe8eebfabc09825 100644 (file)
@@ -28,12 +28,6 @@ macro_rules! deallocate {
     )
 }
 
-macro_rules! compare_number {
-    ($cmp: expr, $terms: expr) => (
-        QueryTerm::Inlined(InlinedQueryTerm::CompareNumber($cmp, $terms))
-    )
-}
-
 macro_rules! compare_number_instr {
     ($cmp: expr, $at_1: expr, $at_2: expr) => (
         Line::BuiltIn(BuiltInInstruction::CompareNumber($cmp, $at_1, $at_2))
@@ -222,9 +216,9 @@ macro_rules! install_new_block {
     )
 }
 
-macro_rules! goto {
+macro_rules! goto_execute {
     ($line:expr, $arity:expr) => (
-        Line::Control(ControlInstruction::Goto($line, $arity))
+        Line::Control(ControlInstruction::GotoExecute($line, $arity))
     )
 }
 
@@ -465,3 +459,9 @@ macro_rules! cmp_eq {
         CompareNumberQT::Equal
     )
 }
+
+macro_rules! jmp_call {
+    ($arity:expr, $offset:expr) => (
+        Line::Control(ControlInstruction::JmpByCall($arity, $offset))
+    )
+}
index aa164cabe63b508a1227f15e4bb40b517717a2f3..9e80f2bd8268425c2128772b336f616be8d2c5d8 160000 (submodule)
@@ -1 +1 @@
-Subproject commit aa164cabe63b508a1227f15e4bb40b517717a2f3
+Subproject commit 9e80f2bd8268425c2128772b336f616be8d2c5d8
index 8507ff37f716d205f9228310fd74c15c52a26f0f..bb31d99e0d2f6f2a81684fe56343e672e55f3a6b 100644 (file)
@@ -3,7 +3,6 @@ use prolog::fixtures::*;
 use prolog::heap_print::*;
 use prolog::io::*;
 use prolog::machine::*;
-use prolog::parser::toplevel::*;
 
 use std::collections::HashSet;
 use std::mem::swap;
@@ -69,6 +68,7 @@ pub fn collect_test_output<'a>(wam: &mut Machine, alloc_locs: AllocVarDict<'a>,
                                -> Vec<HashSet<String>>
 {
     let mut output = TestOutputter::new();
+    
     output = wam.heap_view(&heap_locs, output);
     output.cache();
     
@@ -86,6 +86,7 @@ pub fn collect_test_output_with_limit<'a>(wam: &mut Machine, alloc_locs: AllocVa
                                           -> Vec<HashSet<String>>
 {
     let mut output = TestOutputter::new();
+    
     output = wam.heap_view(&heap_locs, output);
     output.cache();
     
@@ -114,10 +115,10 @@ pub fn collect_test_output_with_limit<'a>(wam: &mut Machine, alloc_locs: AllocVa
 pub fn submit(wam: &mut Machine, buffer: &str) -> bool
 {
     wam.reset();
-
-    match parse_code(buffer.trim(), wam.atom_tbl(), wam.op_dir()) {
+        
+    match parse_code(wam, buffer) {
         Ok(tl) =>
-            match eval(wam, &tl) {
+            match compile(wam, &tl) {
                 EvalSession::InitialQuerySuccess(_, _) |
                 EvalSession::EntrySuccess |
                 EvalSession::SubsequentQuerySuccess =>
@@ -133,9 +134,9 @@ pub fn submit_query(wam: &mut Machine, buffer: &str, result: Vec<HashSet<String>
 {
     wam.reset();
 
-    match parse_code(buffer.trim(), wam.atom_tbl(), wam.op_dir()) {
+    match parse_code(wam, buffer) {
         Ok(tl) =>
-            match eval(wam, &tl) {
+            match compile(wam, &tl) {
                 EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) =>
                     result == collect_test_output(wam, alloc_locs, heap_locs),
                 EvalSession::EntrySuccess => true,
@@ -152,9 +153,9 @@ pub fn submit_query_with_limit(wam: &mut Machine, buffer: &str,
 {
     wam.reset();
 
-    match parse_code(buffer.trim(), wam.atom_tbl(), wam.op_dir()) {
+    match parse_code(wam, buffer) {
         Ok(tl) =>
-            match eval(wam, &tl) {
+            match compile(wam, &tl) {
                 EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) =>
                     result == collect_test_output_with_limit(wam, alloc_locs,
                                                              heap_locs, limit),