]> Repositorios git - scryer-prolog.git/commitdiff
compile special instructions for partial strings when recognized
authorMark Thom <[email protected]>
Sun, 12 Apr 2020 03:53:28 +0000 (21:53 -0600)
committerMark Thom <[email protected]>
Sun, 12 Apr 2020 03:53:28 +0000 (21:53 -0600)
16 files changed:
src/prolog/codegen.rs
src/prolog/heap_print.rs
src/prolog/instructions.rs
src/prolog/iterators.rs
src/prolog/machine/code_repo.rs
src/prolog/machine/heap.rs
src/prolog/machine/machine_indices.rs
src/prolog/machine/machine_state.rs
src/prolog/machine/machine_state_impl.rs
src/prolog/machine/mod.rs
src/prolog/machine/partial_string.rs
src/prolog/machine/toplevel.rs
src/prolog/macros.rs
src/prolog/read.rs
src/prolog/targets.rs
src/prolog/write.rs

index 944e1c9ed1378c95d6d6dc12a6c3e6576ee02396..35430cef2ce9ee402c4a5bdc74b8b8f41ffbc17a 100644 (file)
@@ -163,40 +163,49 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
         target.push(Target::to_void(1));
     }
 
-    fn subterm_to_instr<Target>(
+    fn deep_var_instr<Target: CompilationTarget<'a>>(
+        &mut self,
+        cell: &'a Cell<VarReg>,
+        var: &'a Rc<Var>,
+        term_loc: GenContext,
+        is_exposed: bool,
+        target: &mut Vec<Target>,
+    ) {
+        if is_exposed || self.get_var_count(var.as_ref()) > 1 {
+            self.marker.mark_var(var.clone(), Level::Deep, cell, term_loc, target);
+        } else {
+            Self::add_or_increment_void_instr(target);
+        }
+    }
+
+    fn subterm_to_instr<Target: CompilationTarget<'a>>(
         &mut self,
         subterm: &'a Term,
         term_loc: GenContext,
         is_exposed: bool,
         target: &mut Vec<Target>,
-    ) where
-        Target: CompilationTarget<'a>,
-    {
+    ) {
         match subterm {
             &Term::AnonVar if is_exposed => {
-                self.marker.mark_anon_var(Level::Deep, term_loc, target)
+                self.marker.mark_anon_var(Level::Deep, term_loc, target);
+            }
+            &Term::AnonVar => {
+                Self::add_or_increment_void_instr(target);
             }
-            &Term::AnonVar => Self::add_or_increment_void_instr(target),
             &Term::Cons(ref cell, _, _) | &Term::Clause(ref cell, _, _, _) => {
-                self.marker
-                    .mark_non_var(Level::Deep, term_loc, cell, target);
+                self.marker.mark_non_var(Level::Deep, term_loc, cell, target);
                 target.push(Target::clause_arg_to_instr(cell.get()));
             }
             &Term::Constant(_, ref constant) => {
-                target.push(Target::constant_subterm(constant.clone()))
+                target.push(Target::constant_subterm(constant.clone()));
             }
             &Term::Var(ref cell, ref var) => {
-                if is_exposed || self.get_var_count(var) > 1 {
-                    self.marker
-                        .mark_var(var.clone(), Level::Deep, cell, term_loc, target);
-                } else {
-                    Self::add_or_increment_void_instr(target);
-                }
+                self.deep_var_instr(cell, var, term_loc, is_exposed, target);
             }
         };
     }
 
-    fn compile_target<Target, Iter>(
+     fn compile_target<Target, Iter>(
         &mut self,
         iter: Iter,
         term_loc: GenContext,
@@ -210,6 +219,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
 
         for term in iter {
             match term {
+                TermRef::AnonVar(lvl @ Level::Shallow) => {
+                    if let GenContext::Head = term_loc {
+                        self.marker.advance_arg();
+                    } else {
+                        self.marker.mark_anon_var(lvl, term_loc, &mut target);
+                    }
+                }
                 TermRef::Clause(lvl, cell, ct, terms) => {
                     self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
                     target.push(Target::to_structure(ct, terms.len(), cell.get()));
@@ -225,15 +241,22 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
                     self.subterm_to_instr(head, term_loc, is_exposed, &mut target);
                     self.subterm_to_instr(tail, term_loc, is_exposed, &mut target);
                 }
+                TermRef::Constant(lvl @ Level::Shallow, cell, Constant::String(ref string)) => {
+                    self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
+                    target.push(Target::to_pstr(lvl, string.to_string(), cell.get(), false));
+                }
                 TermRef::Constant(lvl @ Level::Shallow, cell, constant) => {
                     self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
                     target.push(Target::to_constant(lvl, constant.clone(), cell.get()));
                 }
-                TermRef::AnonVar(lvl @ Level::Shallow) => {
-                    if let GenContext::Head = term_loc {
-                        self.marker.advance_arg();
+                TermRef::PartialString(lvl, cell, string, tail) => {
+                    self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
+
+                    if let Some(tail) = tail {
+                        target.push(Target::to_pstr(lvl, string, cell.get(), true));
+                        self.subterm_to_instr(tail, term_loc, is_exposed, &mut target);
                     } else {
-                        self.marker.mark_anon_var(lvl, term_loc, &mut target);
+                        target.push(Target::to_pstr(lvl, string, cell.get(), false));
                     }
                 }
                 TermRef::Var(lvl @ Level::Shallow, cell, ref var) if var.as_str() == "!" => {
@@ -252,14 +275,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
                         }
                     }
 
-                    self.marker
-                        .mark_var(var.clone(), lvl, cell, term_loc, &mut target);
+                    self.marker.mark_var(var.clone(), lvl, cell, term_loc, &mut target);
                 }
                 TermRef::Var(lvl @ Level::Shallow, cell, var) => {
-                    self.marker
-                        .mark_var(var.clone(), lvl, cell, term_loc, &mut target)
+                    self.marker.mark_var(var.clone(), lvl, cell, term_loc, &mut target);
+                }
+                _ => {
                 }
-                _ => {}
             };
         }
 
index 6d252695562021c35859984231f51c5eb6f78c2a..91757052dafe69ccb8e4ad0d2d6b051447a9bb0c 100644 (file)
@@ -578,7 +578,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
             self.state_stack.push(TokenOrRedirect::CompositeRedirect(max_depth, left_directed_op));
             self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec));
         } else {
-            // if is_infix!(spec.assoc())
             match ct.name().as_str() {
                 "|" => {
                     self.format_bar_separator_op(iter, max_depth, ct.name(), spec);
@@ -1031,8 +1030,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
         mut max_depth: usize,
         h: usize,
         n: usize,
-    )
-    {
+    ) {
         iter.stack().pop();
         iter.stack().pop();
 
@@ -1044,24 +1042,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
         let mut heap_pstr_iter =
             self.machine_st.heap_pstr_iter(Addr::PStrLocation(h, n));
 
-        let mut buf = String::new();
-
-        while let Some(Some(c)) = heap_pstr_iter.next() {
-            buf.push(c);
-        }
-
-        let end_addr =
-            if let &HeapCellValue::PartialString(_, has_tail) = &self.machine_st.heap[h] {
-                if has_tail {
-                    self.machine_st.store(self.machine_st.deref(heap_pstr_iter.focus()))
-                } else {
-                    Addr::EmptyList
-                }
-            } else {
-                unreachable!()
-            };
+        let buf = heap_pstr_iter.to_string();
+        let end_addr = heap_pstr_iter.focus();
 
-        if let Addr::EmptyList = end_addr {
+        if Addr::EmptyList == end_addr {
             if !self.machine_st.flags.double_quotes.is_codes() {
                 self.push_char('"');
 
index d12cb7521571a8960345013be31e48368a38d795..6b88c52fd7be547c3b10b8faecbc52dba91dfae1 100644 (file)
@@ -225,7 +225,7 @@ fn arith_instr_unary_functor(
     t: usize,
 ) -> MachineStub {
     let at_stub = at.into_functor();
-    
+
     functor!(
         name,
         [aux(h, 0), integer(t)],
@@ -244,7 +244,7 @@ fn arith_instr_bin_functor(
     let at_2_stub = at_2.into_functor();
 
     functor!(
-        name,        
+        name,
         [aux(h, 0), aux(h, 1), integer(t)],
         [at_1_stub, at_2_stub]
     )
@@ -313,7 +313,7 @@ impl ArithmeticInstruction {
             &ArithmeticInstruction::Gcd(ref at_1, ref at_2, t) => {
                 arith_instr_bin_functor(h, "gcd", at_1, at_2, t)
             }
-            &ArithmeticInstruction::Sign(ref at, t) => { 
+            &ArithmeticInstruction::Sign(ref at, t) => {
                 arith_instr_unary_functor(h, "sign", at, t)
             }
             &ArithmeticInstruction::Cos(ref at, t)  => {
@@ -463,6 +463,7 @@ impl IndexingInstruction {
 pub enum FactInstruction {
     GetConstant(Level, Constant, RegType),
     GetList(Level, RegType),
+    GetPartialString(Level, String, RegType, bool),
     GetStructure(ClauseType, usize, RegType),
     GetValue(RegType, usize),
     GetVariable(RegType, usize),
@@ -479,7 +480,7 @@ impl FactInstruction {
             &FactInstruction::GetConstant(lvl, ref c, r) => {
                 let lvl_stub = lvl.into_functor();
                 let rt_stub  = reg_type_into_functor(r);
-                
+
                 functor!(
                     "get_constant",
                     [aux(h, 0), constant(h, c), aux(h, 1)],
@@ -496,6 +497,16 @@ impl FactInstruction {
                     [lvl_stub, rt_stub]
                 )
             }
+            &FactInstruction::GetPartialString(lvl, ref s, r, has_tail) => {
+                let lvl_stub = lvl.into_functor();
+                let rt_stub  = reg_type_into_functor(r);
+
+                functor!(
+                    "get_partial_string",
+                    [aux(h, 0), string(h, s), aux(h, 1), boolean(has_tail)],
+                    [lvl_stub, rt_stub]
+                )
+            }
             &FactInstruction::GetStructure(ref ct, arity, r) => {
                 let rt_stub = reg_type_into_functor(r);
 
@@ -528,7 +539,7 @@ impl FactInstruction {
             }
             &FactInstruction::UnifyLocalValue(r) => {
                 let rt_stub = reg_type_into_functor(r);
-                
+
                 functor!(
                     "unify_local_value",
                     [aux(h, 0)],
@@ -546,7 +557,7 @@ impl FactInstruction {
             }
             &FactInstruction::UnifyValue(r) => {
                 let rt_stub = reg_type_into_functor(r);
-                
+
                 functor!(
                     "unify_value",
                     [aux(h, 0)],
@@ -565,6 +576,7 @@ pub enum QueryInstruction {
     GetVariable(RegType, usize),
     PutConstant(Level, Constant, RegType),
     PutList(Level, RegType),
+    PutPartialString(Level, String, RegType, bool),
     PutStructure(ClauseType, usize, RegType),
     PutUnsafeValue(usize, usize),
     PutValue(RegType, usize),
@@ -596,13 +608,23 @@ impl QueryInstruction {
             &QueryInstruction::PutList(lvl, r) => {
                 let lvl_stub = lvl.into_functor();
                 let rt_stub  = reg_type_into_functor(r);
-                
+
                 functor!(
                     "put_list",
                     [aux(h, 0), aux(h, 1)],
                     [lvl_stub, rt_stub]
                 )
             }
+            &QueryInstruction::PutPartialString(lvl, ref s, r, has_tail) => {
+                let lvl_stub = lvl.into_functor();
+                let rt_stub  = reg_type_into_functor(r);
+
+                functor!(
+                    "put_partial_string",
+                    [aux(h, 0), string(h, s), aux(h, 1), boolean(has_tail)],
+                    [lvl_stub, rt_stub]
+                )
+            }
             &QueryInstruction::PutStructure(ref ct, arity, r) => {
                 let rt_stub = reg_type_into_functor(r);
 
@@ -616,7 +638,7 @@ impl QueryInstruction {
                 let rt_stub = reg_type_into_functor(r);
 
                 functor!(
-                    "put_value",                
+                    "put_value",
                     [aux(h, 0), integer(arg)],
                     [rt_stub]
                 )
@@ -644,7 +666,7 @@ impl QueryInstruction {
             }
             &QueryInstruction::SetLocalValue(r) => {
                 let rt_stub = reg_type_into_functor(r);
-                
+
                 functor!(
                     "set_local_value",
                     [aux(h, 0)],
index 183f28d5a8d0b5663defa74600b888ea5dce2f5d..83c6fab26f4716e669fd62ac75a4a0d0c75dc994 100644 (file)
@@ -16,6 +16,7 @@ pub enum TermRef<'a> {
     Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
     Constant(Level, &'a Cell<RegType>, &'a Constant),
     Clause(Level, &'a Cell<RegType>, ClauseType, &'a Vec<Box<Term>>),
+    PartialString(Level, &'a Cell<RegType>, String, Option<&'a Term>),
     Var(Level, &'a Cell<VarReg>, Rc<Var>),
 }
 
@@ -27,6 +28,7 @@ impl<'a> TermRef<'a> {
           | TermRef::Constant(lvl, ..)
           | TermRef::Var(lvl, ..)
           | TermRef::Clause(lvl, ..) => lvl,
+          | TermRef::PartialString(lvl, ..) => lvl,
         }
     }
 }
@@ -43,13 +45,63 @@ pub enum TermIterState<'a> {
     ),
     InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
     FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
+    PartialString(Level, &'a Cell<RegType>, String, Option<&'a Term>),
     Var(Level, &'a Cell<VarReg>, Rc<Var>),
 }
 
+fn is_partial_string<'a>(
+    head: &'a Term,
+    mut tail: &'a Term,
+) -> Option<(String, Option<&'a Term>)>
+{
+    let mut string =
+        match head {
+            &Term::Constant(_, Constant::Atom(ref atom, _)) if atom.is_char() => {
+                atom.as_str().chars().next().unwrap().to_string()
+            }
+            &Term::Constant(_, Constant::Char(c)) => {
+                c.to_string()
+            }
+            _ => {
+                return None;
+            }
+        };
+
+    while let Term::Cons(_, ref head, ref succ) = tail {
+        match head.as_ref() {
+            &Term::Constant(_, Constant::Atom(ref atom, _)) if atom.is_char() => {
+                string.push(atom.as_str().chars().next().unwrap());
+            }
+            &Term::Constant(_, Constant::Char(c)) => {
+                string.push(c);
+            }
+            _ => {
+                return None;
+            }
+        };
+
+        tail = succ.as_ref();
+    }
+
+    match tail {
+        Term::AnonVar | Term::Var(..) => {
+            return Some((string, Some(tail)));
+        }
+        Term::Constant(_, Constant::EmptyList) => {
+            return Some((string, None));
+        }
+        _ => {
+            return None;
+        }
+    }
+}
+
 impl<'a> TermIterState<'a> {
     pub fn subterm_to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> {
         match term {
-            &Term::AnonVar => TermIterState::AnonVar(lvl),
+            &Term::AnonVar => {
+                TermIterState::AnonVar(lvl)
+            }
             &Term::Clause(ref cell, ref name, ref subterms, ref spec) => {
                 let ct = if let Some(spec) = spec {
                     ClauseType::Op(name.clone(), spec.clone(), CodeIndex::default())
@@ -62,8 +114,12 @@ impl<'a> TermIterState<'a> {
             &Term::Cons(ref cell, ref head, ref tail) => {
                 TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref())
             }
-            &Term::Constant(ref cell, ref constant) => TermIterState::Constant(lvl, cell, constant),
-            &Term::Var(ref cell, ref var) => TermIterState::Var(lvl, cell, var.clone()),
+            &Term::Constant(ref cell, ref constant) => {
+                TermIterState::Constant(lvl, cell, constant)
+            }
+            &Term::Var(ref cell, ref var) => {
+                TermIterState::Var(lvl, cell, var.clone())
+            }
         }
     }
 }
@@ -128,7 +184,7 @@ impl<'a> QueryIterator<'a> {
                 QueryIterator {
                     state_stack: vec![state],
                 }
-            }            
+            }
             &QueryTerm::Clause(ref cell, ref ct, ref terms, _) => {
                 let state = TermIterState::Clause(Level::Root, 0, cell, ct.clone(), terms);
                 QueryIterator {
@@ -169,7 +225,9 @@ impl<'a> Iterator for QueryIterator<'a> {
     fn next(&mut self) -> Option<Self::Item> {
         while let Some(iter_state) = self.state_stack.pop() {
             match iter_state {
-                TermIterState::AnonVar(lvl) => return Some(TermRef::AnonVar(lvl)),
+                TermIterState::AnonVar(lvl) => {
+                    return Some(TermRef::AnonVar(lvl));
+                }
                 TermIterState::Clause(lvl, child_num, cell, ct, child_terms) => {
                     if child_num == child_terms.len() {
                         match ct {
@@ -182,7 +240,9 @@ impl<'a> Iterator for QueryIterator<'a> {
                                     lvl => Some(TermRef::Clause(lvl, cell, ct, child_terms)),
                                 }
                             }
-                            _ => return None,
+                            _ => {
+                                return None;
+                            }
                         };
                     } else {
                         self.state_stack.push(TermIterState::Clause(
@@ -192,23 +252,41 @@ impl<'a> Iterator for QueryIterator<'a> {
                             ct,
                             child_terms,
                         ));
+
                         self.push_subterm(lvl.child_level(), child_terms[child_num].as_ref());
                     }
                 }
                 TermIterState::InitialCons(lvl, cell, head, tail) => {
-                    self.state_stack
-                        .push(TermIterState::FinalCons(lvl, cell, head, tail));
+                    if let Some((string, tail)) = is_partial_string(head, tail) {
+                        self.state_stack.push(TermIterState::PartialString(
+                            lvl,
+                            cell,
+                            string,
+                            tail,
+                        ));
+
+                        if let Some(tail) = tail {
+                            self.push_subterm(lvl.child_level(), tail);
+                        }
+                    } else {
+                        self.state_stack.push(TermIterState::FinalCons(lvl, cell, head, tail));
 
-                    self.push_subterm(lvl.child_level(), tail);
-                    self.push_subterm(lvl.child_level(), head);
+                        self.push_subterm(lvl.child_level(), tail);
+                        self.push_subterm(lvl.child_level(), head);
+                    }
+                }
+                TermIterState::PartialString(lvl, cell, string, tail) => {
+                    return Some(TermRef::PartialString(lvl, cell, string, tail));
                 }
                 TermIterState::FinalCons(lvl, cell, head, tail) => {
-                    return Some(TermRef::Cons(lvl, cell, head, tail))
+                    return Some(TermRef::Cons(lvl, cell, head, tail));
                 }
                 TermIterState::Constant(lvl, cell, constant) => {
-                    return Some(TermRef::Constant(lvl, cell, constant))
+                    return Some(TermRef::Constant(lvl, cell, constant));
+                }
+                TermIterState::Var(lvl, cell, var) => {
+                    return Some(TermRef::Var(lvl, cell, var));
                 }
-                TermIterState::Var(lvl, cell, var) => return Some(TermRef::Var(lvl, cell, var)),
             };
         }
 
@@ -223,8 +301,7 @@ pub struct FactIterator<'a> {
 
 impl<'a> FactIterator<'a> {
     fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
-        self.state_queue
-            .push_back(TermIterState::subterm_to_state(lvl, term));
+        self.state_queue.push_back(TermIterState::subterm_to_state(lvl, term));
     }
 
     pub fn from_rule_head_clause(terms: &'a Vec<Box<Term>>) -> Self {
@@ -241,7 +318,9 @@ impl<'a> FactIterator<'a> {
 
     fn new(term: &'a Term, iterable_root: bool) -> Self {
         let states = match term {
-            &Term::AnonVar => vec![TermIterState::AnonVar(Level::Root)],
+            &Term::AnonVar => {
+                vec![TermIterState::AnonVar(Level::Root)]
+            }
             &Term::Clause(ref cell, ref name, ref terms, ref fixity) => {
                 let ct = ClauseType::from(name.clone(), terms.len(), fixity.clone());
                 vec![TermIterState::Clause(Level::Root, 0, cell, ct, terms)]
@@ -273,7 +352,9 @@ impl<'a> Iterator for FactIterator<'a> {
     fn next(&mut self) -> Option<Self::Item> {
         while let Some(state) = self.state_queue.pop_front() {
             match state {
-                TermIterState::AnonVar(lvl) => return Some(TermRef::AnonVar(lvl)),
+                TermIterState::AnonVar(lvl) => {
+                    return Some(TermRef::AnonVar(lvl));
+                }
                 TermIterState::Clause(lvl, _, cell, ct, child_terms) => {
                     for child_term in child_terms {
                         self.push_subterm(lvl.child_level(), child_term);
@@ -285,16 +366,27 @@ impl<'a> Iterator for FactIterator<'a> {
                     };
                 }
                 TermIterState::InitialCons(lvl, cell, head, tail) => {
-                    self.push_subterm(Level::Deep, head);
-                    self.push_subterm(Level::Deep, tail);
+                    if let Some((string, tail)) = is_partial_string(head, tail) {
+                        if let Some(tail) = tail {
+                            self.push_subterm(Level::Deep, tail);
+                        }
 
-                    return Some(TermRef::Cons(lvl, cell, head, tail));
+                        return Some(TermRef::PartialString(lvl, cell, string, tail));
+                    } else {
+                        self.push_subterm(Level::Deep, head);
+                        self.push_subterm(Level::Deep, tail);
+
+                        return Some(TermRef::Cons(lvl, cell, head, tail));
+                    }
                 }
                 TermIterState::Constant(lvl, cell, constant) => {
                     return Some(TermRef::Constant(lvl, cell, constant))
                 }
-                TermIterState::Var(lvl, cell, var) => return Some(TermRef::Var(lvl, cell, var)),
-                _ => {}
+                TermIterState::Var(lvl, cell, var) => {
+                    return Some(TermRef::Var(lvl, cell, var));
+                }
+                _ => {
+                }
             }
         }
 
index ac672d5a21bedba8d4d46a8ebd1c974ef9e03e71..4d6951fcc6eb114937a08d06132f0f38eb407d6d 100644 (file)
@@ -89,7 +89,7 @@ impl CodeRepo {
             _ => {
                 in_situ_code_dir.insert((name, arity), p);
             }
-        }        
+        }
 
         let mut cg = CodeGenerator::<DebrayAllocator>::new(non_counted_bt);
         let mut decl_code = cg.compile_predicate(&decl.0)?;
index 3eeb48531edff1640982167af99dda5737d950a5..eceb55a35f841e645808927f03312a1bc3651b86 100644 (file)
@@ -179,12 +179,23 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
     }
 
     #[inline]
-    fn pop(&mut self) {
+    pub(crate)
+    fn put_complete_string(&mut self, s: &str) -> Addr {
+        let addr = self.allocate_pstr(s);
+        self.pop();
+
         let h = self.h();
 
-        if h > 0 {
-            self.truncate(h - 1);
+        match &mut self[h - 1] {
+            &mut HeapCellValue::PartialString(_, ref mut has_tail) => {
+                *has_tail = false;
+            }
+            _ => {
+                unreachable!()
+            }
         }
+
+        addr
     }
 
     #[inline]
@@ -219,21 +230,7 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
                 if s.is_empty() {
                     Addr::EmptyList
                 } else {
-                    let addr = self.allocate_pstr(&s);
-                    self.pop();
-
-                    let h = self.h();
-
-                    match &mut self[h - 1] {
-                        &mut HeapCellValue::PartialString(_, ref mut has_tail) => {
-                            *has_tail = false;
-                        }
-                        _ => {
-                            unreachable!()
-                        }
-                    }
-
-                    addr
+                    self.put_complete_string(&s)
                 }
             }
             Constant::Usize(n) => {
@@ -242,6 +239,16 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
         }
     }
 
+    #[inline]
+    pub(crate)
+    fn pop(&mut self) {
+        let h = self.h();
+
+        if h > 0 {
+            self.truncate(h - 1);
+        }
+    }
+
     #[inline]
     pub(crate)
     fn push(&mut self, val: HeapCellValue) -> usize {
index 5718fddd802828f298dbcb511d2dcb0e58ea3af2..a8a985a82afacbd950993195d6d66164abde0ed1 100644 (file)
@@ -274,16 +274,10 @@ impl Addr {
                 let mut heap_pstr_iter =
                     machine_st.heap_pstr_iter(Addr::PStrLocation(h, n));
 
-                let mut buf = String::new();
+                let buf = heap_pstr_iter.to_string();
+                let end_addr = heap_pstr_iter.focus();
 
-                while let Some(Some(c)) = heap_pstr_iter.next() {
-                    buf.push(c);
-                }
-
-                let end_addr =
-                    machine_st.store(machine_st.deref(heap_pstr_iter.focus()));
-
-                if let Addr::EmptyList = end_addr {
+                if end_addr == Addr::EmptyList {
                     Some(Constant::String(Rc::new(buf)))
                 } else {
                     None
index 9ab9002f85b00922ea4110590ed94cccf34a2185..721d7925ebce112b02a0b8a2d7f6d867bfbc3e89 100644 (file)
@@ -21,8 +21,7 @@ use std::io::Write;
 use std::mem;
 use std::ops::{Index, IndexMut};
 
-pub(crate)
-struct HeapPStrIter<'a> {
+pub(crate) struct HeapPStrIter<'a> {
     focus: Addr,
     machine_st: &'a MachineState,
     seen: IndexSet<Addr>,
@@ -41,12 +40,44 @@ impl<'a> HeapPStrIter<'a> {
     #[inline]
     pub(crate)
     fn focus(&'a self) -> Addr {
-        self.focus
+        self.machine_st.store(self.machine_st.deref(self.focus))
     }
+
+    #[inline]
+    pub(crate)
+    fn to_string(&mut self) -> String {
+        let mut buf = String::new();
+
+        while let Some(iteratee) = self.next() {
+            match iteratee {
+                PStrIteratee::Char(c) => {
+                    buf.push(c);
+                }
+                PStrIteratee::PStrSegment(h, n) => {
+                    match &self.machine_st.heap[h] {
+                        HeapCellValue::PartialString(ref pstr, _) => {
+                            buf += pstr.as_str_from(n);
+                        }
+                        _ => {
+                            unreachable!()
+                        }
+                    }
+                }
+            }
+        }
+
+        buf
+    }
+}
+
+#[derive(Clone, Copy)]
+pub(crate) enum PStrIteratee {
+    Char(char),
+    PStrSegment(usize, usize),
 }
 
 impl<'a> Iterator for HeapPStrIter<'a> {
-    type Item = Option<char>;
+    type Item = PStrIteratee;
 
     fn next(&mut self) -> Option<Self::Item> {
         let addr = self.machine_st.store(self.machine_st.deref(self.focus));
@@ -59,13 +90,14 @@ impl<'a> Iterator for HeapPStrIter<'a> {
 
         match addr {
             Addr::PStrLocation(h, n) => {
-                if let &HeapCellValue::PartialString(ref pstr, _) = &self.machine_st.heap[h] {
-                    if let Some(c) = pstr.range_from(n ..).next() {
-                        self.focus = Addr::PStrLocation(h, n + c.len_utf8());
-                        return Some(Some(c));
+                if let &HeapCellValue::PartialString(_, has_tail) = &self.machine_st.heap[h] {
+                    self.focus = if has_tail {
+                        Addr::HeapCell(h + 1)
                     } else {
-                        unreachable!()
-                    }
+                        Addr::EmptyList
+                    };
+
+                    return Some(PStrIteratee::PStrSegment(h, n));
                 } else {
                     unreachable!()
                 }
@@ -73,16 +105,36 @@ impl<'a> Iterator for HeapPStrIter<'a> {
             Addr::Lis(l) => {
                 let addr = self.machine_st.store(self.machine_st.deref(Addr::HeapCell(l)));
 
-                if let Addr::Char(c) = addr {
+                let opt_c = match addr {
+                    Addr::Con(h) if self.machine_st.heap.atom_at(h) => {
+                        if let HeapCellValue::Atom(ref atom, _) = &self.machine_st.heap[h] {
+                            if atom.is_char() {
+                                Some(atom.as_str().chars().next().unwrap())
+                            } else {
+                                None
+                            }
+                        } else {
+                            unreachable!()
+                        }
+                    }
+                    Addr::Char(c) => {
+                        Some(c)
+                    }
+                    _ => {
+                        None
+                    }
+                };
+
+                if let Some(c) = opt_c {
                     self.focus = Addr::HeapCell(l + 1);
-                    return Some(Some(c));
+                    return Some(PStrIteratee::Char(c));
                 } else {
                     return None;
                 }
             }
             Addr::EmptyList => {
                 self.focus = Addr::EmptyList;
-                return Some(None);
+                return None;
             }
             _ => {
                 return None;
@@ -93,24 +145,51 @@ impl<'a> Iterator for HeapPStrIter<'a> {
 
 #[inline]
 pub(super)
-fn compare_pstr<'a>(
-    pstr_iter: HeapPStrIter<'a>,
-    mut c_iter: impl Iterator<Item = char>,
-) -> bool {
-    for opt_c in pstr_iter {
-        match opt_c {
-            Some(_) => {
-                if opt_c != c_iter.next() {
-                    return false;
+fn compare_pstr_to_string<'a>(
+    heap_pstr_iter: &mut HeapPStrIter<'a>,
+    s: &String,
+) -> Option<usize> {
+    let mut s_offset = 0;
+
+    while let Some(iteratee) = heap_pstr_iter.next() {
+        match iteratee {
+            PStrIteratee::Char(c1) => {
+                if let Some(c2) = s[s_offset ..].chars().next() {
+                    if c1 != c2 {
+                        return None;
+                    } else {
+                        s_offset += c1.len_utf8();
+                    }
+                } else {
+                    return None;
                 }
             }
-            None => {
-                return c_iter.next().is_none();
+            PStrIteratee::PStrSegment(h, n) => {
+                match heap_pstr_iter.machine_st.heap[h] {
+                    HeapCellValue::PartialString(ref pstr, _) => {
+                        let t = pstr.as_str_from(n);
+
+                        if s[s_offset ..].starts_with(t) {
+                            s_offset += t.len();
+                        } else if t.starts_with(&s[s_offset ..]) {
+                            heap_pstr_iter.focus =
+                                Addr::PStrLocation(h, n + s[s_offset ..].len());
+
+                            s_offset += s[s_offset ..].len();
+                            return Some(s_offset);
+                        } else {
+                            return None;
+                        }
+                    }
+                    _ => {
+                        unreachable!()
+                    }
+                }
             }
         }
     }
 
-    false
+    Some(s_offset)
 }
 
 pub struct Ball {
index 0768a5eba6c3b8e63a52c828f7d0eb308f181c23..79c84bdf95b77a2a5f946fd8d720c32d6df8f011 100644 (file)
@@ -688,8 +688,8 @@ impl MachineState {
             HeapPtr::HeapCell(ref mut h) => {
                 *h += rhs;
             }
-            &mut HeapPtr::PStrChar(h, ref mut n)
-          | &mut HeapPtr::PStrLocation(h, ref mut n) => {
+            &mut HeapPtr::PStrChar(h, ref mut n) |
+            &mut HeapPtr::PStrLocation(h, ref mut n) => {
                 match &self.heap[h] {
                     HeapCellValue::PartialString(ref pstr, _) => {
                         for c in pstr.range_from(*n ..).take(rhs) {
@@ -768,13 +768,94 @@ impl MachineState {
         self.trail.truncate(self.tr);
     }
 
+    pub(super)
+    fn match_partial_string(&mut self, addr: Addr, string: &String, has_tail: bool) {
+        let mut heap_pstr_iter = self.heap_pstr_iter(addr);
+
+        match compare_pstr_to_string(&mut heap_pstr_iter, string) {
+            Some(prefix_len) if prefix_len == string.len() => {
+                let focus = heap_pstr_iter.focus();
+
+                match focus {
+                    Addr::PStrLocation(h, n) => {
+                        if has_tail {
+                            self.s = HeapPtr::PStrLocation(h, n);
+                            self.mode = MachineMode::Read;
+                        } else {
+                            self.fail = true;
+                        }
+                    }
+                    addr => {
+                        if has_tail {
+                            let h = self.heap.h();
+
+                            self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
+                            self.bind(Ref::HeapCell(h), addr);
+
+                            self.s = HeapPtr::HeapCell(h);
+                            self.mode = MachineMode::Read;
+                        } else {
+                            if let Some(var) = addr.as_var() {
+                                self.bind(var, Addr::EmptyList);
+                            } else {
+                                self.fail = true;
+                            }
+                        }
+                    }
+                }
+            }
+            Some(prefix_len) => {
+                match heap_pstr_iter.focus() {
+                    addr @ Addr::AttrVar(_) |
+                    addr @ Addr::StackCell(..) |
+                    addr @ Addr::HeapCell(_) => {
+                        let h = self.heap.h();
+
+                        let pstr_addr =
+                            if has_tail {
+                                self.s = HeapPtr::HeapCell(h+1);
+                                self.mode = MachineMode::Read;
+
+                                self.heap.allocate_pstr(&string[prefix_len ..])
+                            } else {
+                                self.heap.put_complete_string(&string[prefix_len ..])
+                            };
+
+                        self.bind(addr.as_var().unwrap(), pstr_addr);
+                    }
+                    Addr::Lis(l) if !self.flags.double_quotes.is_atom() => {
+                        let h = self.heap.h();
+
+                        let pstr_addr =
+                            if has_tail {
+                                self.s = HeapPtr::HeapCell(h+1);
+                                self.mode = MachineMode::Read;
+
+                                self.heap.allocate_pstr(&string[prefix_len ..])
+                            } else {
+                                self.heap.put_complete_string(&string[prefix_len ..])
+                            };
+
+                        self.unify(Addr::Lis(l), pstr_addr);
+                    }
+                    _ => {
+                        self.fail = true;
+                    }
+                }
+            }
+            None => {
+                self.fail = true;
+            }
+        }
+    }
+
     pub(super)
     fn write_constant_to_var(&mut self, addr: Addr, c: &Constant) {
         match self.store(self.deref(addr)) {
             Addr::Con(c1) => {
-                self.fail = match &self.heap[c1] {
+                match &self.heap[c1] {
                     HeapCellValue::Atom(ref n1, _) => {
-                        match c {
+                        self.fail = match c {
                             Constant::Atom(ref n2, _) => {
                                 n1 != n2
                             }
@@ -784,10 +865,10 @@ impl MachineState {
                             _ => {
                                 true
                             }
-                        }
+                        };
                     }
                     HeapCellValue::Integer(ref n1) => {
-                        match c {
+                        self.fail = match c {
                             Constant::Fixnum(n2) => {
                                 n1.to_isize() != Some(*n2)
                             }
@@ -800,10 +881,10 @@ impl MachineState {
                             _ => {
                                 true
                             }
-                        }
+                        };
                     }
                     HeapCellValue::Rational(ref r1) => {
-                        if let Constant::Rational(ref r2) = c {
+                        self.fail = if let Constant::Rational(ref r2) = c {
                             r1 != r2
                         } else {
                             true
@@ -811,10 +892,13 @@ impl MachineState {
                     }
                     HeapCellValue::PartialString(..) => {
                         if let Constant::String(ref s2) = c {
-                            let iter = self.heap_pstr_iter(Addr::PStrLocation(c1, 0));
-                            !compare_pstr(iter, s2.chars())
+                            self.match_partial_string(
+                                Addr::PStrLocation(c1, 0),
+                                &s2,
+                                false,
+                            );
                         } else {
-                            true
+                            self.fail = true;
                         }
                     }
                     _ => {
@@ -846,11 +930,14 @@ impl MachineState {
                 self.unify(Addr::Lis(l), addr);
             }
             Addr::PStrLocation(h, n) => {
-                self.fail = if let Constant::String(ref s2) = c {
-                    let iter = self.heap_pstr_iter(Addr::PStrLocation(h, n));
-                    !compare_pstr(iter, s2.chars())
+                if let Constant::String(ref s2) = c {
+                    self.match_partial_string(
+                        Addr::PStrLocation(h, n),
+                        &s2,
+                        false,
+                    )
                 } else {
-                    true
+                    self.fail = true;
                 };
             }
             Addr::Stream(_) => {
@@ -1154,9 +1241,9 @@ impl MachineState {
                         self.s = HeapPtr::PStrChar(h, n);
                         self.mode = MachineMode::Read;
                     }
-                    addr @ Addr::AttrVar(_)
-                  | addr @ Addr::StackCell(..)
-                  | addr @ Addr::HeapCell(_) => {
+                    addr @ Addr::AttrVar(_) |
+                    addr @ Addr::StackCell(..) |
+                    addr @ Addr::HeapCell(_) => {
                         let h = self.heap.h();
 
                         self.heap.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
@@ -1168,9 +1255,15 @@ impl MachineState {
                         self.s = HeapPtr::HeapCell(a);
                         self.mode = MachineMode::Read;
                     }
-                    _ => self.fail = true,
+                    _ => {
+                        self.fail = true;
+                    }
                 };
             }
+            &FactInstruction::GetPartialString(_, ref string, reg, has_tail) => {
+                let addr = self.store(self.deref(self[reg]));
+                self.match_partial_string(addr, string, has_tail);
+            }
             &FactInstruction::GetStructure(ref ct, arity, reg) => {
                 let addr = self.deref(self[reg]);
 
@@ -1191,14 +1284,15 @@ impl MachineState {
                         let h = self.heap.h();
 
                         self.heap.push(HeapCellValue::Addr(Addr::Str(h + 1)));
-                        self.heap
-                            .push(HeapCellValue::NamedStr(arity, ct.name(), ct.spec()));
+                        self.heap.push(HeapCellValue::NamedStr(arity, ct.name(), ct.spec()));
 
                         self.bind(addr.as_var().unwrap(), Addr::HeapCell(h));
 
                         self.mode = MachineMode::Write;
                     }
-                    _ => self.fail = true,
+                    _ => {
+                        self.fail = true;
+                    }
                 };
             }
             &FactInstruction::GetVariable(norm, arg) => {
@@ -1214,7 +1308,9 @@ impl MachineState {
                 match self.mode {
                     MachineMode::Read => {
                         let addr = self.s.read(&self.heap);
+
                         self.write_constant_to_var(addr, c);
+                        self.increment_s_ptr(1);
                     }
                     MachineMode::Write => {
                         let addr = self.heap.put_constant(c.clone());
@@ -1224,12 +1320,13 @@ impl MachineState {
                         }
                     }
                 };
-
-                self.increment_s_ptr(1);
             }
             &FactInstruction::UnifyVariable(reg) => {
                 match self.mode {
-                    MachineMode::Read => self[reg] = self.s.read(&self.heap),
+                    MachineMode::Read => {
+                        self[reg] = self.s.read(&self.heap);
+                        self.increment_s_ptr(1);
+                    }
                     MachineMode::Write => {
                         let h = self.heap.h();
 
@@ -1237,14 +1334,14 @@ impl MachineState {
                         self[reg] = Addr::HeapCell(h);
                     }
                 };
-
-                self.increment_s_ptr(1);
             }
             &FactInstruction::UnifyLocalValue(reg) => {
                 match self.mode {
                     MachineMode::Read => {
                         let reg_addr = self[reg];
+
                         self.unify(reg_addr, self.s.read(&self.heap));
+                        self.increment_s_ptr(1);
                     }
                     MachineMode::Write => {
                         let addr = self.deref(self[reg]);
@@ -1265,26 +1362,26 @@ impl MachineState {
                         self.bind(Ref::HeapCell(h), addr);
                     }
                 };
-
-                self.increment_s_ptr(1);
             }
             &FactInstruction::UnifyValue(reg) => {
                 match self.mode {
                     MachineMode::Read => {
                         let reg_addr = self[reg];
+
                         self.unify(reg_addr, self.s.read(&self.heap));
+                        self.increment_s_ptr(1);
                     }
                     MachineMode::Write => {
                         let heap_val = self.store(self[reg]);
                         self.heap.push(HeapCellValue::Addr(heap_val));
                     }
                 };
-
-                self.increment_s_ptr(1);
             }
             &FactInstruction::UnifyVoid(n) => {
                 match self.mode {
-                    MachineMode::Read => self.increment_s_ptr(n),
+                    MachineMode::Read => {
+                        self.increment_s_ptr(n);
+                    }
                     MachineMode::Write => {
                         let h = self.heap.h();
 
@@ -1394,6 +1491,18 @@ impl MachineState {
             &QueryInstruction::PutList(_, reg) => {
                 self[reg] = Addr::Lis(self.heap.h());
             }
+            &QueryInstruction::PutPartialString(_, ref string, reg, has_tail) => {
+                let pstr_addr =
+                    if has_tail {
+                        let pstr_addr = self.heap.allocate_pstr(&string);
+                        self.heap.pop(); // the tail will be added by the next instruction.
+                        pstr_addr
+                    } else {
+                        self.heap.put_complete_string(&string)
+                    };
+
+                self[reg] = pstr_addr;
+            }
             &QueryInstruction::PutStructure(ref ct, arity, reg) => {
                 let h = self.heap.h();
 
@@ -1466,7 +1575,7 @@ impl MachineState {
             &QueryInstruction::SetVoid(n) => {
                 let h = self.heap.h();
 
-                for i in h..h + n {
+                for i in h .. h + n {
                     self.heap.push(HeapCellValue::Addr(Addr::HeapCell(i)));
                 }
             }
index 4f859c5740151da3b6b3fa27b281817958bf111e..06d80ba1fe8fcd9e768a0bd6d50cf01779f68c37 100644 (file)
@@ -840,27 +840,33 @@ impl MachineState {
         current_output_stream: &mut Stream,
     ) {
         match instr {
-            &Line::Arithmetic(ref arith_instr) => self.execute_arith_instr(arith_instr),
+            &Line::Arithmetic(ref arith_instr) => {
+                self.execute_arith_instr(arith_instr)
+            }
             &Line::Choice(ref choice_instr) => {
                 self.execute_choice_instr(choice_instr, &mut policies.call_policy)
             }
             &Line::Cut(ref cut_instr) => {
                 self.execute_cut_instr(cut_instr, &mut policies.cut_policy)
             }
-            &Line::Control(ref control_instr) => self.execute_ctrl_instr(
-                indices,
-                code_repo,
-                &mut policies.call_policy,
-                &mut policies.cut_policy,
-                current_input_stream,
-                current_output_stream,
-                control_instr,
-            ),
+            &Line::Control(ref control_instr) => {
+                self.execute_ctrl_instr(
+                    indices,
+                    code_repo,
+                    &mut policies.call_policy,
+                    &mut policies.cut_policy,
+                    current_input_stream,
+                    current_output_stream,
+                    control_instr,
+                )
+            }
             &Line::Fact(ref fact_instr) => {
                 self.execute_fact_instr(&fact_instr);
                 self.p += 1;
             }
-            &Line::Indexing(ref indexing_instr) => self.execute_indexing_instr(&indexing_instr),
+            &Line::Indexing(ref indexing_instr) => {
+                self.execute_indexing_instr(&indexing_instr)
+            }
             &Line::IndexedChoice(ref choice_instr) => {
                 self.execute_indexed_choice_instr(choice_instr, &mut policies.call_policy)
             }
index 02e1cf34c395b369f38f27dc0d9398cf139a1c62..700358eb7cd6de1ec73c1351b9757399427af2a8 100644 (file)
@@ -164,7 +164,12 @@ impl PartialString {
 
     pub(super)
     fn clone_from_offset(&self, n: usize) -> Self {
-        let len = if self.len > n { self.len - n } else { 0 };
+        let len =
+            if self.len - '\u{0}'.len_utf8() > n {
+                self.len - n - '\u{0}'.len_utf8()
+            } else {
+                0
+            };
 
         let mut pstr = PartialString {
             buf: ptr::null_mut(),
@@ -216,4 +221,18 @@ impl PartialString {
             ptr::read((self.buf as usize + end_n) as *const u8) == 0u8
         }
     }
+
+    #[inline]
+    pub fn as_str_from(&self, n: usize) -> &str {
+        unsafe {
+            let slice = slice::from_raw_parts(
+                self.buf,
+                self.len - '\u{0}'.len_utf8(),
+            );
+
+            let s = str::from_utf8(slice).unwrap();
+
+            &s[n ..]
+        }
+    }
 }
index 99990896ab7cf80a3472a2f00dccfa510130b0f6..40ccac3f8a3c9d46fa0b585df4ba9f8a8639e6cb 100644 (file)
@@ -1093,8 +1093,9 @@ impl RelationWorker {
                     Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num))
                 }
             }
-            term =>
-                Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num)),
+            term => {
+                Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num))
+            }
         }
     }
 
@@ -1132,8 +1133,7 @@ impl RelationWorker {
 
     fn absorb(&mut self, other: RelationWorker) {
         self.queue.extend(other.queue.into_iter());
-        self.dynamic_clauses
-            .extend(other.dynamic_clauses.into_iter());
+        self.dynamic_clauses.extend(other.dynamic_clauses.into_iter());
     }
 }
 
index 82ba62301f3383878144959196d40f0e298512ba..dda7d4ba8b7e7ec27fb34c60b25717ca2404ff0a 100644 (file)
@@ -121,6 +121,21 @@ macro_rules! functor_term {
     (atom($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
         HeapCellValue::Atom(clause_name!($e), None)
     );
+    (string($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({
+        let len: usize = $aux_lens.iter().sum();
+        let h = len + $arity + 1 + $addendum.h() + $h;
+
+        $addendum.put_complete_string(&$e);
+
+        HeapCellValue::Addr(Addr::PStrLocation(h, 0))
+    });
+    (boolean($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({
+        if $e {
+            functor_term!(atom("true"), $arity, $aux_lens, $addendum)
+        } else {
+            functor_term!(atom("false"), $arity, $aux_lens, $addendum)
+        }
+    });
     ($e:expr, $arity:expr, $aux_lens:expr, $addendum:ident) => (
         $e
     );
@@ -154,7 +169,7 @@ macro_rules! from_constant {
                 let len: usize = $aux_lens.iter().sum();
                 let h = len + $arity + 1 + $addendum.h() + $over_h;
 
-                $addendum.put_constant(Constant::String(s.clone()));
+                $addendum.put_complete_string(&s);
 
                 HeapCellValue::Addr(Addr::PStrLocation(h, 0))
             }
index af70cd0291518a586772f2b04a9d39ffa76bdd83..4162aedefbc7667c9f3f801b0faae655cbb88a1c 100644 (file)
@@ -4,7 +4,6 @@ use prolog_parser::tabled_rc::TabledData;
 
 use crate::prolog::forms::*;
 use crate::prolog::iterators::*;
-use crate::prolog::machine::heap::Heap;
 use crate::prolog::machine::machine_indices::*;
 use crate::prolog::machine::machine_state::MachineState;
 use crate::prolog::machine::streams::Stream;
@@ -13,25 +12,6 @@ use std::collections::VecDeque;
 
 type SubtermDeque = VecDeque<(usize, usize)>;
 
-impl<'a> TermRef<'a> {
-    fn as_addr(&self, heap: &mut Heap, h: usize) -> Addr {
-        match self {
-            &TermRef::AnonVar(_) | &TermRef::Var(..) => {
-                Addr::HeapCell(h)
-            }
-            &TermRef::Cons(..) => {
-                Addr::HeapCell(h)
-            }
-            &TermRef::Constant(_, _, c) => {
-                heap.put_constant(c.clone())
-            }
-            &TermRef::Clause(..) => {
-                Addr::Str(h)
-            }
-        }
-    }
-}
-
 pub type PrologStream = ParsingStream<Stream>;
 
 pub mod readline {
@@ -102,7 +82,6 @@ pub mod readline {
                 result => {
                     result
                 }
-                
             }
         }
     }
@@ -128,24 +107,17 @@ impl MachineState {
     }
 }
 
-fn push_stub_addr(machine_st: &mut MachineState) {
-    let h = machine_st.heap.h();
-    machine_st.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
+#[inline]
+pub(crate)
+fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult {
+    let term_writer = TermWriter::new(machine_st);
+    term_writer.write_term_to_heap(term)
 }
 
-fn modify_head_of_queue(
-    machine_st: &mut MachineState,
-    queue: &mut SubtermDeque,
-    term: TermRef,
-    h: usize,
-) {
-    if let Some((arity, site_h)) = queue.pop_front() {
-        machine_st.heap[site_h] = HeapCellValue::Addr(term.as_addr(&mut machine_st.heap, h));
-
-        if arity > 1 {
-            queue.push_front((arity - 1, site_h + 1));
-        }
-    }
+struct TermWriter<'a> {
+    machine_st: &'a mut MachineState,
+    queue: SubtermDeque,
+    var_dict: HeapVarDict,
 }
 
 pub struct TermWriteResult {
@@ -153,79 +125,168 @@ pub struct TermWriteResult {
     pub(crate) var_dict: HeapVarDict,
 }
 
-pub(crate)
-fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult {
-    let heap_loc = machine_st.heap.h();
+impl<'a> TermWriter<'a> {
+    #[inline]
+    fn new(machine_st: &'a mut MachineState) -> Self {
+        TermWriter {
+            machine_st,
+            queue: SubtermDeque::new(),
+            var_dict: HeapVarDict::new(),
+        }
+    }
 
-    let mut queue = SubtermDeque::new();
-    let mut var_dict = HeapVarDict::new();
+    #[inline]
+    fn modify_head_of_queue(&mut self, term: &TermRef<'a>, h: usize) {
+        if let Some((arity, site_h)) = self.queue.pop_front() {
+            self.machine_st.heap[site_h] =
+                HeapCellValue::Addr(self.term_as_addr(term, h));
 
-    for term in breadth_first_iter(term, true) {
-        let h = machine_st.heap.h();
+            if arity > 1 {
+                self.queue.push_front((arity - 1, site_h + 1));
+            }
+        }
+    }
 
-        match &term {
-            &TermRef::Cons(lvl, ..) => {
-                queue.push_back((2, h + 1));
-                machine_st.heap.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
+    #[inline]
+    fn push_stub_addr(&mut self) {
+        let h = self.machine_st.heap.h();
+        self.machine_st.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
+    }
 
-                push_stub_addr(machine_st);
-                push_stub_addr(machine_st);
+    fn term_as_addr(&mut self, term: &TermRef<'a>, h: usize) -> Addr {
+        match term {
+            &TermRef::AnonVar(_) | &TermRef::Var(..) => {
+                Addr::HeapCell(h)
+            }
+            &TermRef::Cons(..) => {
+                Addr::HeapCell(h)
+            }
+            &TermRef::Constant(_, _, c) => {
+                self.machine_st.heap.put_constant(c.clone())
+            }
+            &TermRef::Clause(..) => {
+                Addr::Str(h)
+            }
+            &TermRef::PartialString(..) => {//_, _, ref pstr, tail) => {
+                Addr::PStrLocation(h, 0)
+                /*
+                match tail {
+                    Term::AnonVar => {
+                        let h = self.machine_st.heap.h();
+                        self.machine_st.heap.allocate_pstr(pstr);
+
+                        Addr::PStrLocation(h, 0)
+                    }
+                    Term::Constant(_, Constant::EmptyList) => {
+                        self.machine_st.heap.put_complete_string(pstr)
+                    }
+                    Term::Var(_, ref var) => {
+                        let h = self.machine_st.heap.h();
 
-                if let Level::Root = lvl {
-                    continue;
+                        self.machine_st.heap.allocate_pstr(pstr);
+                        let tail_h = self.machine_st.heap.h() - 1;
+
+                        if let Some(addr) = self.var_dict.get(var) {
+                            self.machine_st.heap[tail_h] = HeapCellValue::Addr(*addr);
+                        } else {
+                            self.var_dict.insert(var.clone(), Addr::HeapCell(tail_h));
+                        }
+
+                        Addr::PStrLocation(h, 0)
+                    }
+                    _ => {
+                        unreachable!()
+                    }
                 }
+                */
             }
-            &TermRef::Clause(lvl, _, ref ct, subterms) => {
-                queue.push_back((subterms.len(), h + 1));
-                let named = HeapCellValue::NamedStr(subterms.len(), ct.name(), ct.spec());
+        }
+    }
 
-                machine_st.heap.push(named);
+    fn write_term_to_heap(mut self, term: &'a Term) -> TermWriteResult {
+        let heap_loc = self.machine_st.heap.h();
 
-                for _ in 0..subterms.len() {
-                    push_stub_addr(machine_st);
-                }
+        for term in breadth_first_iter(term, true) {
+            let h = self.machine_st.heap.h();
 
-                if let Level::Root = lvl {
-                    continue;
+            match &term {
+                &TermRef::Cons(lvl, ..) => {
+                    self.queue.push_back((2, h + 1));
+                    self.machine_st.heap.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
+
+                    self.push_stub_addr();
+                    self.push_stub_addr();
+
+                    if let Level::Root = lvl {
+                        continue;
+                    }
                 }
-            }
-            &TermRef::AnonVar(Level::Root) | &TermRef::Constant(Level::Root, ..)
-          | &TermRef::Var(Level::Root, ..) => {
-                let addr = term.as_addr(&mut machine_st.heap, h);
+                &TermRef::Clause(lvl, _, ref ct, subterms) => {
+                    self.queue.push_back((subterms.len(), h + 1));
+                    let named = HeapCellValue::NamedStr(subterms.len(), ct.name(), ct.spec());
+
+                    self.machine_st.heap.push(named);
+
+                    for _ in 0..subterms.len() {
+                        self.push_stub_addr();
+                    }
 
-                if !addr.is_heap_bound() {
-                    machine_st.heap.push(HeapCellValue::Addr(addr));
+                    if let Level::Root = lvl {
+                        continue;
+                    }
                 }
-            }
-            &TermRef::AnonVar(_) => {
-                if let Some((arity, site_h)) = queue.pop_front() {
-                    if arity > 1 {
-                        queue.push_front((arity - 1, site_h + 1));
+                &TermRef::AnonVar(Level::Root) | &TermRef::Constant(Level::Root, ..) |
+                &TermRef::Var(Level::Root, ..) => {
+                    let addr = self.term_as_addr(&term, h);
+
+                    if !addr.is_heap_bound() {
+                        self.machine_st.heap.push(HeapCellValue::Addr(addr));
                     }
                 }
+                &TermRef::AnonVar(_) => {
+                    if let Some((arity, site_h)) = self.queue.pop_front() {
+                        if arity > 1 {
+                            self.queue.push_front((arity - 1, site_h + 1));
+                        }
+                    }
 
-                continue;
-            }
-            &TermRef::Var(_, _, ref var) => {
-                if let Some((arity, site_h)) = queue.pop_front() {
-                    if let Some(addr) = var_dict.get(var).cloned() {
-                        machine_st.heap[site_h] = HeapCellValue::Addr(addr);
+                    continue;
+                }
+                &TermRef::PartialString(lvl, _, ref pstr, tail) => {
+                    if tail.is_some() {
+                        self.machine_st.heap.allocate_pstr(&pstr);
                     } else {
-                        var_dict.insert(var.clone(), Addr::HeapCell(site_h));
+                        self.machine_st.heap.put_complete_string(&pstr);
                     }
 
-                    if arity > 1 {
-                        queue.push_front((arity - 1, site_h + 1));
+                    if let Level::Root = lvl {
+                    } else if tail.is_some() {
+                        let h = self.machine_st.heap.h();
+                        self.queue.push_back((1, h - 1));
                     }
                 }
+                &TermRef::Var(_, _, ref var) => {
+                    if let Some((arity, site_h)) = self.queue.pop_front() {
+                        if let Some(addr) = self.var_dict.get(var).cloned() {
+                            self.machine_st.heap[site_h] = HeapCellValue::Addr(addr);
+                        } else {
+                            self.var_dict.insert(var.clone(), Addr::HeapCell(site_h));
+                        }
 
-                continue;
-            }
-            _ => {}
-        };
+                        if arity > 1 {
+                            self.queue.push_front((arity - 1, site_h + 1));
+                        }
+                    }
 
-        modify_head_of_queue(machine_st, &mut queue, term, h);
-    }
+                    continue;
+                }
+                _ => {
+                }
+            };
+
+            self.modify_head_of_queue(&term, h);
+        }
 
-    TermWriteResult { heap_loc, var_dict }
+        TermWriteResult { heap_loc, var_dict: self.var_dict }
+    }
 }
index 285100eb85838a3ce51a03400214bedfbdf6a5f5..7ce9c1564b12629c0a3ee7b4ae7af5162cf9d556 100644 (file)
@@ -17,6 +17,8 @@ pub trait CompilationTarget<'a> {
     fn to_void(_: usize) -> Self;
     fn is_void_instr(&self) -> bool;
 
+    fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self;
+
     fn incr_void_instr(&mut self);
 
     fn constant_subterm(_: Constant) -> Self;
@@ -62,6 +64,10 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
         }
     }
 
+    fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self {
+        FactInstruction::GetPartialString(lvl, string, r, has_tail)
+    }
+
     fn incr_void_instr(&mut self) {
         match self {
             &mut FactInstruction::UnifyVoid(ref mut incr) => *incr += 1,
@@ -117,6 +123,10 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
         QueryInstruction::PutList(lvl, reg)
     }
 
+    fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self {
+        QueryInstruction::PutPartialString(lvl, string, r, has_tail)
+    }
+
     fn to_void(subterms: usize) -> Self {
         QueryInstruction::SetVoid(subterms)
     }
index c44d9232df38bb52e2f10da07d1c80ca041542da..fdb5b90998c879f94c1b1db93492b19067f0da18 100644 (file)
@@ -27,14 +27,14 @@ impl fmt::Display for REPLCodePtr {
         match self {
             REPLCodePtr::CompileBatch =>
                 write!(f, "REPLCodePtr::CompileBatch"),
-           REPLCodePtr::UseModule =>
-               write!(f, "REPLCodePtr::UseModule"),
-           REPLCodePtr::UseQualifiedModule =>
-               write!(f, "REPLCodePtr::UseQualifiedModule"),
-           REPLCodePtr::UseModuleFromFile =>
-               write!(f, "REPLCodePtr::UseModuleFromFile"),
-           REPLCodePtr::UseQualifiedModuleFromFile =>
-               write!(f, "REPLCodePtr::UseQualifiedModuleFromFile")
+               REPLCodePtr::UseModule =>
+                       write!(f, "REPLCodePtr::UseModule"),
+               REPLCodePtr::UseQualifiedModule =>
+                       write!(f, "REPLCodePtr::UseQualifiedModule"),
+               REPLCodePtr::UseModuleFromFile =>
+                       write!(f, "REPLCodePtr::UseModuleFromFile"),
+               REPLCodePtr::UseQualifiedModuleFromFile =>
+                       write!(f, "REPLCodePtr::UseQualifiedModuleFromFile")
         }
     }
 }
@@ -58,7 +58,13 @@ impl fmt::Display for FactInstruction {
             &FactInstruction::GetConstant(lvl, ref constant, ref r) => {
                 write!(f, "get_constant {}, {}{}", constant, lvl, r.reg_num())
             }
-            &FactInstruction::GetList(lvl, ref r) => write!(f, "get_list {}{}", lvl, r.reg_num()),
+            &FactInstruction::GetList(lvl, ref r) => {
+                write!(f, "get_list {}{}", lvl, r.reg_num())
+            }
+            &FactInstruction::GetPartialString(lvl, ref s, r, has_tail) => {
+                write!(f, "get_partial_string({}, {}, {}, {})",
+                       lvl, s, r, has_tail)
+            }
             &FactInstruction::GetStructure(ref ct, ref arity, ref r) => {
                 write!(f, "get_structure {}/{}, {}", ct.name(), arity, r)
             }
@@ -86,7 +92,13 @@ impl fmt::Display for QueryInstruction {
             &QueryInstruction::PutConstant(lvl, ref constant, ref r) => {
                 write!(f, "put_constant {}, {}{}", constant, lvl, r.reg_num())
             }
-            &QueryInstruction::PutList(lvl, ref r) => write!(f, "put_list {}{}", lvl, r.reg_num()),
+            &QueryInstruction::PutList(lvl, ref r) => {
+                write!(f, "put_list {}{}", lvl, r.reg_num())
+            }
+            &QueryInstruction::PutPartialString(lvl, ref s, r, has_tail) => {
+                write!(f, "put_partial_string({}, {}, {}, {})",
+                       lvl, s, r, has_tail)
+            }
             &QueryInstruction::PutStructure(ref ct, ref arity, ref r) => {
                 write!(f, "put_structure {}/{}, {}", ct.name(), arity, r)
             }
@@ -159,9 +171,12 @@ impl fmt::Display for HeapCellValue {
                 write!(f, "{}/{}", name.as_str(), arity)
             }
             &HeapCellValue::PartialString(ref pstr, has_tail) => {
-                write!(f, "pstr ( buf: 0x{:x}, has_tail({}) )",
-                       (pstr as *const _) as usize,
-                       has_tail)
+                write!(
+                    f,
+                    "pstr ( buf: \"{}\", has_tail({}) )",
+                    pstr.as_str_from(0),
+                    has_tail,
+                )
             }
             &HeapCellValue::Stream(ref stream) => {
                 write!(f, "$stream({})", stream.as_ptr() as usize)