]> Repositorios git - scryer-prolog.git/commitdiff
separate handling of inlined query terms.
authorMark Thom <[email protected]>
Mon, 13 Nov 2017 20:18:05 +0000 (13:18 -0700)
committerMark Thom <[email protected]>
Mon, 13 Nov 2017 20:18:05 +0000 (13:18 -0700)
src/prolog/ast.rs
src/prolog/codegen.rs
src/prolog/iterators.rs
src/prolog/parser

index 2dd8acbab25a95090afda93716bb1041b7488175..e834a4b75adfc508bce45489f4dfb71c129cbd8d 100644 (file)
@@ -309,13 +309,26 @@ pub enum Term {
     Var(Cell<VarReg>, Var)
 }
 
+pub enum InlinedQueryTerm {    
+    Is(Vec<Box<Term>>),
+    IsAtomic(Vec<Box<Term>>),
+    IsVar(Vec<Box<Term>>)
+}    
+
+impl InlinedQueryTerm {
+    pub fn arity(&self) -> usize {
+        match self {
+            &InlinedQueryTerm::Is(_) => 2,
+            _ => 1
+        }
+    }
+}
+
 pub enum QueryTerm {
     CallN(Vec<Box<Term>>),
     Catch(Vec<Box<Term>>),
     Cut,
-    Is(Vec<Box<Term>>),
-    IsAtomic(Vec<Box<Term>>),
-    IsVar(Vec<Box<Term>>),
+    Inlined(InlinedQueryTerm),
     Term(Term),
     Throw(Vec<Box<Term>>)
 }
@@ -325,9 +338,7 @@ impl QueryTerm {
         match self {
             &QueryTerm::Catch(_) => 3,
             &QueryTerm::Throw(_) => 1,
-            &QueryTerm::Is(_) => 2,
-            &QueryTerm::IsAtomic(_) => 1,
-            &QueryTerm::IsVar(_) => 1,
+            &QueryTerm::Inlined(ref term) => term.arity(),
             &QueryTerm::CallN(ref terms) => terms.len(),
             &QueryTerm::Cut => 0,
             &QueryTerm::Term(ref term) => term.arity(),
index bafcea3ed5437d924b32ca4f4c19afd75aa7a263..9e332f3df21a1995a03eef504c48e5166ff8de57 100644 (file)
@@ -93,16 +93,16 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
             Some(&VarData::Perm(p)) if p != 0 => RegType::Perm(p),
             _ => {
                 let mut target = Vec::new();
-                                
+
                 self.marker.reset_arg(arity);
                 self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target);
-                
+
                 code.push(Line::Query(target));
                 vr.get().norm()
-            }   
+            }
         }
     }
-    
+
     fn add_or_increment_void_instr<Target>(target: &mut Vec<Target>)
         where Target: CompilationTarget<'a>
     {
@@ -231,27 +231,36 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
         ConjunctInfo::new(vs, num_of_chunks, has_deep_cut)
     }
 
-    fn add_conditional_call(compiled_query: &mut Code, qt: &QueryTerm, pvs: usize)
+    fn add_conditional_call_inlined(term: &InlinedQueryTerm, code: &mut Code)
+    {
+        match term {
+            &InlinedQueryTerm::IsAtomic(_) | &InlinedQueryTerm::IsVar(_) =>
+                code.push(proceed!()),
+            _ => {}
+        };
+    }
+    
+    fn add_conditional_call(code: &mut Code, qt: &QueryTerm, pvs: usize)
     {
         match qt {
             &QueryTerm::CallN(ref terms) => {
                 let call = ControlInstruction::CallN(terms.len());
-                compiled_query.push(Line::Control(call));
+                code.push(Line::Control(call));
             },
             &QueryTerm::Catch(_) =>
-                compiled_query.push(Line::Control(ControlInstruction::CatchCall)),
-            &QueryTerm::IsAtomic(_) | &QueryTerm::IsVar(_) =>
-                compiled_query.push(proceed!()),
+                code.push(Line::Control(ControlInstruction::CatchCall)),
+            &QueryTerm::Inlined(ref term) =>
+                Self::add_conditional_call_inlined(term, code),
             &QueryTerm::Term(Term::Constant(_, Constant::Atom(ref atom))) => {
                 let call = ControlInstruction::Call(atom.clone(), 0, pvs);
-                compiled_query.push(Line::Control(call));
+                code.push(Line::Control(call));
             },
             &QueryTerm::Term(Term::Clause(_, ref atom, ref terms)) => {
                 let call = ControlInstruction::Call(atom.clone(), terms.len(), pvs);
-                compiled_query.push(Line::Control(call));
+                code.push(Line::Control(call));
             },
             &QueryTerm::Throw(_) =>
-                compiled_query.push(Line::Control(ControlInstruction::ThrowCall)),
+                code.push(Line::Control(ControlInstruction::ThrowCall)),
             _ => {}
         }
     }
@@ -282,6 +291,87 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
         dealloc_index
     }
 
+    fn compile_inlined(&mut self, term: &'a InlinedQueryTerm, term_loc: GenContext, code: &mut Code)
+                       -> Result<(), ParserError>
+    {
+        match term {
+            &InlinedQueryTerm::Is(ref terms) => {
+                let mut arith_code = {
+                    let mut evaluator = ArithmeticEvaluator::new(self.marker.bindings());
+                    evaluator.eval(terms[1].as_ref())?
+                };
+
+                code.append(&mut arith_code);
+
+                match terms[0].as_ref() {
+                    &Term::Var(ref vr, ref name) => {
+                        let r = self.mark_non_callable(name,
+                                                       2,
+                                                       term_loc,
+                                                       vr,
+                                                       code);
+
+                        code.push(is_call!(r));
+                    },
+                    &Term::Constant(_, Constant::Float(fl)) => {
+                        code.push(query![put_constant!(Level::Shallow,
+                                                       Constant::Float(fl),
+                                                       temp_v!(1))]);
+                        code.push(is_call!(temp_v!(1)));
+                    },
+                    &Term::Constant(_, Constant::Integer(ref bi)) => {
+                        let bi = bi.clone();
+                        code.push(query![put_constant!(Level::Shallow,
+                                                       Constant::Integer(bi),
+                                                       temp_v!(1))]);
+                        code.push(is_call!(temp_v!(1)));
+                    },
+                    _ => {
+                        return Err(ParserError::from(ArithmeticError::InvalidTerm));
+                    }
+                }
+            },
+            &InlinedQueryTerm::IsAtomic(ref inner_term) =>
+                match inner_term[0].as_ref() {
+                    &Term::AnonVar | &Term::Clause(_, _, _) | &Term::Cons(_, _, _) => {
+                        code.push(fail!());
+                    },
+                    &Term::Constant(_, _) => {
+                        code.push(succeed!());
+                    },
+                    &Term::Var(ref vr, ref name) => {
+                        let r = self.mark_non_callable(name,
+                                                       1,
+                                                       term_loc,
+                                                       vr,
+                                                       code);
+
+                        code.push(is_atomic!(r));
+                    }
+                },
+            &InlinedQueryTerm::IsVar(ref inner_term) =>
+                match inner_term[0].as_ref() {
+                    &Term::Constant(_, _) | &Term::Clause(_, _, _) | &Term::Cons(_, _, _) => {
+                        code.push(fail!());
+                    },
+                    &Term::AnonVar => {
+                        code.push(succeed!());
+                    },
+                    &Term::Var(ref vr, ref name) => {
+                        let r = self.mark_non_callable(name,
+                                                       1,
+                                                       term_loc,
+                                                       vr,
+                                                       code);
+
+                        code.push(is_var!(r));
+                    }
+                }
+        }
+
+        Ok(())
+    }
+
     fn compile_seq(&mut self,
                    iter: ChunkedIterator<'a>,
                    conjunct_info: &ConjunctInfo<'a>,
@@ -300,90 +390,20 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
 
                 match *term {
                     &QueryTerm::Cut => {
-                        let term = if i + 1 < terms.len() {
+                        let is_terminal = if i + 1 < terms.len() {
                             Terminal::Non
                         } else {
                             Terminal::Terminal
                         };
 
                         code.push(if chunk_num == 0 {
-                            Line::Cut(CutInstruction::NeckCut(term))
+                            Line::Cut(CutInstruction::NeckCut(is_terminal))
                         } else {
-                            Line::Cut(CutInstruction::Cut(term))
+                            Line::Cut(CutInstruction::Cut(is_terminal))
                         });
                     },
-                    &QueryTerm::Is(ref terms) => {
-                        let mut arith_code = {
-                            let mut evaluator = ArithmeticEvaluator::new(self.marker.bindings());
-                             evaluator.eval(terms[1].as_ref())?
-                        };
-
-                        code.append(&mut arith_code);
-
-                        match terms[0].as_ref() {
-                            &Term::Var(ref vr, ref name) => {
-                                let r = self.mark_non_callable(name,
-                                                               term.arity(),
-                                                               term_loc,
-                                                               vr,
-                                                               code);
-                                
-                                code.push(is_call!(r));
-                            },
-                            &Term::Constant(_, Constant::Float(fl)) => {
-                                code.push(query![put_constant!(Level::Shallow,
-                                                               Constant::Float(fl),
-                                                               temp_v!(1))]);
-                                code.push(is_call!(temp_v!(1)));
-                            },
-                            &Term::Constant(_, Constant::Integer(ref bi)) => {
-                                let bi = bi.clone();
-                                code.push(query![put_constant!(Level::Shallow,
-                                                               Constant::Integer(bi),
-                                                               temp_v!(1))]);
-                                code.push(is_call!(temp_v!(1)));
-                            },
-                            _ => {
-                                return Err(ParserError::from(ArithmeticError::InvalidTerm));
-                            }
-                        }
-                    },
-                    &QueryTerm::IsAtomic(ref inner_term) =>
-                        match inner_term[0].as_ref() {
-                            &Term::AnonVar | &Term::Clause(_, _, _) | &Term::Cons(_, _, _) => {
-                                code.push(fail!());
-                            },
-                            &Term::Constant(_, _) => {
-                                code.push(succeed!());
-                            },
-                            &Term::Var(ref vr, ref name) => {
-                                let r = self.mark_non_callable(name,
-                                                               term.arity(),
-                                                               term_loc,
-                                                               vr,
-                                                               code);
-
-                                code.push(is_atomic!(r));
-                            }
-                        },
-                    &QueryTerm::IsVar(ref inner_term) =>
-                        match inner_term[0].as_ref() {
-                            &Term::Constant(_, _) | &Term::Clause(_, _, _) | &Term::Cons(_, _, _) => {
-                                code.push(fail!());
-                            },
-                            &Term::AnonVar => {
-                                code.push(succeed!());
-                            },
-                            &Term::Var(ref vr, ref name) => {
-                                let r = self.mark_non_callable(name,
-                                                               term.arity(),
-                                                               term_loc,
-                                                               vr,
-                                                               code);
-
-                                code.push(is_var!(r));
-                            }
-                        },
+                    &QueryTerm::Inlined(ref term) =>
+                        try!(self.compile_inlined(term, term_loc, code)),
                     _ if chunk_num == 0 => {
                         self.marker.reset_arg(term.arity());
 
@@ -419,12 +439,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
 
     fn compile_cleanup(code: &mut Code, conjunct_info: &ConjunctInfo, toc: &'a QueryTerm)
     {
-        //TODO: temporary workaround for inlined builtins.
         match toc {
-            &QueryTerm::IsAtomic(_) | &QueryTerm::IsVar(_) =>
-                code.push(proceed!()),
+            &QueryTerm::Inlined(ref term) =>
+                Self::add_conditional_call_inlined(term, code),
             _ => {}
-        }
+        };
 
         let dealloc_index = Self::lco(code);
 
@@ -444,12 +463,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
         self.marker.reset_arg(p0.arity());
         self.compile_seq_prelude(&conjunct_info, &mut code);
 
-        if let &QueryTerm::Term(ref term) = p0 {            
+        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 iter = ChunkedIterator::from_rule_body(p1, clauses);
             try!(self.compile_seq(iter, &conjunct_info, &mut code, false));
 
@@ -469,7 +488,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
             Ok(code)
         } else {
             Err(ParserError::InvalidRuleHead)
-        }        
+        }
     }
 
     fn mark_unsafe_fact_vars(&self, fact: &mut CompiledFact)
@@ -568,7 +587,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
         if let Some(query_term) = query.last() {
             Self::compile_cleanup(&mut code, &conjunct_info, query_term);
         }
-        
+
         Ok(code)
     }
 
index a2a96976e5e038a8884426375be99c58cf9f6cea..f8545cf95e012d7c1eb43aa4bd9b3f42bbd2871d 100644 (file)
@@ -40,11 +40,12 @@ impl<'a> QueryIterator<'a> {
                 let state = IteratorState::Clause(0, ClauseType::Catch, terms);
                 QueryIterator { state_stack: vec![state] }
             },
-            &QueryTerm::Is(ref terms) => {
+            &QueryTerm::Inlined(InlinedQueryTerm::Is(ref terms)) => {
                 let state = IteratorState::Clause(0, ClauseType::Is, terms);
                 QueryIterator { state_stack: vec![state] }
             },
-            &QueryTerm::IsAtomic(ref terms) | &QueryTerm::IsVar(ref terms) =>
+            &QueryTerm::Inlined(InlinedQueryTerm::IsAtomic(ref terms))
+          | &QueryTerm::Inlined(InlinedQueryTerm::IsVar(ref terms)) =>
                 Self::from_term(terms[0].as_ref()),
             &QueryTerm::Term(ref term) =>
                 Self::from_term(term),
@@ -269,12 +270,13 @@ impl<'a> ChunkedIterator<'a>
                     arity = child_terms.len();
                     break;
                 },
-                &QueryTerm::Is(_) => {
+                &QueryTerm::Inlined(InlinedQueryTerm::Is(_)) => {
                     result.push(term);
                     arity = 2;
                     break;
                 },
-                &QueryTerm::IsAtomic(_) | &QueryTerm::IsVar(_) =>
+                &QueryTerm::Inlined(InlinedQueryTerm::IsAtomic(_))
+              | &QueryTerm::Inlined(InlinedQueryTerm::IsVar(_)) =>
                     result.push(term),
                 &QueryTerm::Cut => {
                     result.push(term);
index f01fe4feab95bd50a3aefab448f540be5888a296..41d2d7d26fd855bcb4f486411333d3671c648aaa 160000 (submodule)
@@ -1 +1 @@
-Subproject commit f01fe4feab95bd50a3aefab448f540be5888a296
+Subproject commit 41d2d7d26fd855bcb4f486411333d3671c648aaa