]> Repositorios git - scryer-prolog.git/commitdiff
add redone partial strings (#24, #95)
authorMark Thom <[email protected]>
Thu, 20 Feb 2020 04:34:09 +0000 (21:34 -0700)
committerMark Thom <[email protected]>
Thu, 20 Feb 2020 04:34:09 +0000 (21:34 -0700)
16 files changed:
src/prolog/clause_types.rs
src/prolog/heap_iter.rs
src/prolog/heap_print.rs
src/prolog/lib/builtins.pl
src/prolog/lib/non_iso.pl
src/prolog/machine/copier.rs
src/prolog/machine/heap.rs
src/prolog/machine/machine_errors.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 [new file with mode: 0644]
src/prolog/machine/raw_block.rs
src/prolog/machine/system_calls.rs
src/prolog/write.rs

index 7d61cab7bfbbade245926f906e3a7b48cef0faa2..6f7a9187aaf5b7e061fcf0422e4e3e291c6b3b52 100644 (file)
@@ -171,6 +171,7 @@ pub enum SystemClauseType {
     CopyTermWithoutAttrVars,
     CheckCutPoint,
     CopyToLiftedHeap,
+    CreatePartialString,
     DeleteAttribute,
     DeleteHeadAttribute,
     DynamicModuleResolution(usize),
@@ -194,6 +195,7 @@ pub enum SystemClauseType {
     GetModuleClause,
     GetNextDBRef,
     GetNextOpDBRef,
+    IsPartialString,
     LookupDBRef,
     LookupOpDBRef,
     Halt,
@@ -215,6 +217,7 @@ pub enum SystemClauseType {
     NumberToChars,
     NumberToCodes,
     OpDeclaration,
+    PartialStringTail,
     PointsToContinuationResetMarker,
     REPL(REPLCodePtr),
     ReadQueryTerm,
@@ -275,11 +278,12 @@ impl SystemClauseType {
             &SystemClauseType::CallContinuation => clause_name!("$call_continuation"),
             &SystemClauseType::CharCode => clause_name!("$char_code"),
             &SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"),
+            &SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
             &SystemClauseType::ClearAttributeGoals => clause_name!("$clear_attribute_goals"),
             &SystemClauseType::CloneAttributeGoals => clause_name!("$clone_attribute_goals"),
             &SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"),
             &SystemClauseType::CopyTermWithoutAttrVars => clause_name!("$copy_term_without_attr_vars"),
-            &SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
+            &SystemClauseType::CreatePartialString => clause_name!("$create_partial_string"),
             &SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"),
            &SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"),
            &SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule) => {
@@ -339,6 +343,8 @@ impl SystemClauseType {
             &SystemClauseType::InstallInferenceCounter => {
                 clause_name!("$install_inference_counter")
             }
+            &SystemClauseType::IsPartialString => clause_name!("$is_partial_string"),
+            &SystemClauseType::PartialStringTail => clause_name!("$partial_string_tail"),
             &SystemClauseType::LiftedHeapLength => clause_name!("$lh_length"),
             &SystemClauseType::Maybe => clause_name!("maybe"),
             &SystemClauseType::ModuleAssertDynamicPredicateToFront => {
@@ -423,6 +429,7 @@ impl SystemClauseType {
             ("$clone_attribute_goals", 1) => Some(SystemClauseType::CloneAttributeGoals),
             ("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber),
             ("$copy_term_without_attr_vars", 2) => Some(SystemClauseType::CopyTermWithoutAttrVars),
+            ("$create_partial_string", 3) => Some(SystemClauseType::CreatePartialString),
             ("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
             ("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)),
             ("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
@@ -435,6 +442,8 @@ impl SystemClauseType {
             ("$module_call", _) => Some(SystemClauseType::DynamicModuleResolution(arity - 2)),
             ("$enqueue_attribute_goal", 1) => Some(SystemClauseType::EnqueueAttributeGoal),
             ("$enqueue_attr_var", 1) => Some(SystemClauseType::EnqueueAttributedVar),
+            ("$partial_string_tail", 2) => Some(SystemClauseType::PartialStringTail),
+            ("$is_partial_string", 1) => Some(SystemClauseType::IsPartialString),
             ("$expand_term", 2) => Some(SystemClauseType::ExpandTerm),
             ("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
             ("$fetch_attribute_goals", 1) => Some(SystemClauseType::FetchAttributeGoals),
index 13f2b3557e7b9557162f2af9ac7e257387dba1fe..ca0c25a19a91504c239bed77445fc709b5df99c2 100644 (file)
@@ -28,14 +28,19 @@ impl<'a> HCPreOrderIterator<'a> {
 
     fn follow_heap(&mut self, h: usize) -> Addr {
         match &self.machine_st.heap[h] {
-            &HeapCellValue::NamedStr(arity, _, _) => {
+            HeapCellValue::NamedStr(arity, _, _) => {
                 for idx in (1..arity + 1).rev() {
                     self.state_stack.push(Addr::HeapCell(h + idx));
                 }
 
-                Addr::HeapCell(h)
+                Addr::Str(h)
+            }
+            HeapCellValue::Addr(ref a) => {
+                self.follow(a.clone())
+            }
+            HeapCellValue::PartialString(_) => {
+                self.follow(Addr::PStrLocation(h, 0))
             }
-            &HeapCellValue::Addr(ref a) => self.follow(a.clone()),
         }
     }
 
@@ -51,7 +56,7 @@ impl<'a> HCPreOrderIterator<'a> {
                     if s.len() > n {
                         if let Some(c) = s[n ..].chars().next() {
                             let o = c.len_utf8();
-                        
+
                             self.state_stack.push(Addr::Con(Constant::String(n+o, s.clone())));
 
                             if self.machine_st.machine_flags().double_quotes.is_codes() {
@@ -76,7 +81,28 @@ impl<'a> HCPreOrderIterator<'a> {
 
                 da
             }
-            Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(_, _) => {
+            Addr::PStrLocation(h, n) => {
+                if let HeapCellValue::PartialString(ref pstr) = &self.machine_st.heap[h] {
+                    let s = pstr.block_as_str();
+
+                    if let Some(c) = s[n ..].chars().next() {
+                        if pstr.len() > n + c.len_utf8() {                        
+                            self.state_stack.push(Addr::PStrLocation(h, n + c.len_utf8()));
+                        } else {
+                            self.state_stack.push(Addr::PStrTail(h, n + c.len_utf8()));
+                        }
+
+                        self.state_stack.push(Addr::Con(Constant::Char(c)));
+                    } else {
+                        unreachable!()
+                    }
+                } else {
+                    unreachable!()
+                }
+
+                Addr::PStrLocation(h, n)
+            }
+            Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::PStrTail(..) => {
                 da
             }
             Addr::Str(s) => {
@@ -92,7 +118,31 @@ impl<'a> Iterator for HCPreOrderIterator<'a> {
     fn next(&mut self) -> Option<Self::Item> {
         self.state_stack.pop().map(|a| match self.follow(a) {
             Addr::HeapCell(h) => {
-                self.machine_st.heap[h].clone()
+                HeapCellValue::Addr(self.machine_st.heap[h].as_addr(h))
+            }
+            Addr::Str(s) => {
+                match &self.machine_st.heap[s] {
+                    val @ HeapCellValue::NamedStr(..) => {
+                        val.clone()
+                    }
+                    _ => {
+                        unreachable!()
+                    }
+                }
+            }
+            Addr::PStrTail(h, n) => {
+                match &self.machine_st.heap[h] {
+                    HeapCellValue::PartialString(ref pstr) => {
+                        if pstr.len() > n {
+                            HeapCellValue::Addr(Addr::PStrLocation(h, n))
+                        } else {
+                            HeapCellValue::Addr(pstr.tail_addr().clone())
+                        }
+                    }
+                    _ => {
+                        unreachable!()
+                    }
+                }
             }
             Addr::StackCell(fr, sc) => {
                 HeapCellValue::Addr(self.machine_st.stack.index_and_frame(fr)[sc].clone())
index a89bbd4a4c37a3a9641589ebe47d4311465d9966..407f57a38b1edb3eaeff7578f98482889ae4dabd 100644 (file)
@@ -616,10 +616,18 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
         }
 
         match addr {
-            Addr::AttrVar(h) => Some(format!("_{}", h)),
-            Addr::HeapCell(h) | Addr::Lis(h) | Addr::Str(h) => Some(format!("_{}", h)),
-            Addr::StackCell(fr, sc) => Some(format!("_s_{}_{}", fr, sc)),
-            _ => None,
+            Addr::AttrVar(h) => {
+                Some(format!("_{}", h))
+            }
+            Addr::HeapCell(h) | Addr::Lis(h) | Addr::Str(h) | Addr::PStrTail(h, _) => {
+                Some(format!("_{}", h))
+            }
+            Addr::StackCell(fr, sc) => {
+                Some(format!("_s_{}_{}", fr, sc))
+            }
+            _ => {
+                None
+            }
         }
     }
 
@@ -944,7 +952,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
                 }
             }
             HeapCellValue::Addr(Addr::Con(c)) => self.print_constant(c, &op),
-            HeapCellValue::Addr(Addr::Lis(_)) => {
+            HeapCellValue::Addr(Addr::Lis(_)) | HeapCellValue::Addr(Addr::PStrLocation(..)) => {
                 if self.ignore_ops {
                     self.format_struct(2, clause_name!("."));
                 } else {
@@ -958,6 +966,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
                     })
                 }
             }
+            _ => {
+                // This is the partial string case. We never clone a partial string
+                // for printing purposes, so.. this.
+                unreachable!()
+            }
         }
     }
 
index 5092d4c5603d1787e79e66566e33fae729eb943f..5ff87d0733eb2c2c69d4b514fca3a14b57e8a615 100644 (file)
@@ -236,7 +236,7 @@ G1 -> G2 :- '$get_b_value'(B), '$call_with_default_policy'(->(G1, G2, B)).
 :- non_counted_backtracking univ_errors/3.
 univ_errors(Term, List, N) :-
     '$skip_max_list'(N, -1, List, R),
-    ( var(R)       ->
+    ( var(R)        ->
        (  var(Term), throw(error(instantiation_error, (=..)/2))      % 8.5.3.3 a)
        ;  true
        )
index 136e1e3a5659fd7d0ab2e9747869b6759926035e..6c35f7793766b11aea03cf1d39bfebc0f9b387c3 100644 (file)
@@ -5,7 +5,9 @@
 
 :- module(non_iso, [bb_b_put/2, bb_get/2, bb_put/2, call_cleanup/2,
                    call_with_inference_limit/3, forall/2, maybe/0,
-                   set_random/1, setup_call_cleanup/3, variant/2]).
+                   partial_string/1, partial_string/3,
+                   partial_string_tail/2, set_random/1,
+                   setup_call_cleanup/3, variant/2]).
 
 forall(Generate, Test) :-
     \+ (Generate, \+ Test).
@@ -154,3 +156,20 @@ set_random(Seed) :-
        )
     ;  throw(error(instantiation_error, set_random/1))
     ).
+
+partial_string(String, L, L0) :-
+    (  String == [] -> throw(error(type_error(list, []), partial_string/3))
+    ;  catch(atom_chars(Atom, String),
+            error(E, _),
+            throw(error(E, partial_string/3)))
+    ),
+    '$create_partial_string'(Atom, L, L0).
+
+partial_string(String) :-
+    '$is_partial_string'(String).
+
+partial_string_tail(String, Tail) :-
+    (  partial_string(String) ->
+       '$partial_string_tail'(String, Tail)
+    ;  throw(error(type_error(partial_string, String), partial_string_tail/2))
+    ).
index 8fe112662ac4a3e1cd9a1fe90a70e0e2bfd74da5..c95208480dd9f1301a78d64dbbe504a188156fd4 100644 (file)
@@ -13,9 +13,9 @@ pub enum AttrVarPolicy {
 
 pub(crate) trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
     fn threshold(&self) -> usize;
-    fn push(&mut self, _: HeapCellValue);
-    fn store(&self, _: Addr) -> Addr;
-    fn deref(&self, _: Addr) -> Addr;
+    fn push(&mut self, val: HeapCellValue);
+    fn store(&self, val: Addr) -> Addr;
+    fn deref(&self, val: Addr) -> Addr;
     fn stack(&mut self) -> &mut Stack;
 }
 
@@ -51,10 +51,10 @@ impl<T: CopierTarget> CopyTermState<T> {
     }
 
     fn copied_list(&mut self, addr: usize) -> bool {
-        match self.target[addr].clone() {
+        match &self.target[addr] {
             HeapCellValue::Addr(Addr::Lis(addr)) | HeapCellValue::Addr(Addr::HeapCell(addr)) => {
-                if addr >= self.old_h {
-                    *self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(addr));
+                if *addr >= self.old_h {
+                    *self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(*addr));
                     self.scan += 1;
                     return true;
                 }
@@ -65,34 +65,52 @@ impl<T: CopierTarget> CopyTermState<T> {
         false
     }
 
+    fn copied_partial_string(&mut self, addr: usize) -> bool {
+        if let HeapCellValue::PartialString(ref pstr) = &self.target[addr] {
+            if let Addr::PStrLocation(h, n) = pstr.tail_addr() {
+                if *h >= self.old_h {
+                    *self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(*h, *n));
+                    self.scan += 1;
+                    return true;
+                }
+            }
+        }
+
+        false
+    }
+
     fn copy_list(&mut self, addr: usize) {
         if self.copied_list(addr) {
             return;
         }
 
         let threshold = self.target.threshold();
+
         *self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(threshold));
 
-        let hcv = self.target[addr].clone();
+        let ra = self.target[addr].as_addr(threshold);
+        let rd = self.target.store(self.target.deref(ra.clone()));
 
-        let ra = hcv.as_addr(threshold);
-        let rd = self.target.store(self.target.deref(ra));
+        self.target.push(HeapCellValue::Addr(ra.clone()));
+
+        let hcv = HeapCellValue::Addr(self.target[addr + 1].as_addr(addr + 1));
 
-        self.target.push(hcv);
-        
-        let hcv = self.target[addr + 1].clone();
         self.target.push(hcv);
 
         match rd.clone() {
-            Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => {
-                self.target[threshold] = HeapCellValue::Addr(rd)
-            }
-            ra @ Addr::AttrVar(_) | ra @ Addr::HeapCell(..) | ra @ Addr::StackCell(..) => {
+            Addr::AttrVar(h) | Addr::HeapCell(h) | Addr::PStrTail(h, _)
+                if h >= self.old_h => {
+                    self.target[threshold] = HeapCellValue::Addr(rd)
+                }
+            var @ Addr::AttrVar(_)
+          | var @ Addr::HeapCell(..)
+          | var @ Addr::StackCell(..)
+          | var @ Addr::PStrTail(..) => {
                 if ra == rd {
-                    self.reinstantiate_var(ra, threshold);
+                    self.reinstantiate_var(var, threshold);
 
                     if let AttrVarPolicy::StripAttributes = self.attr_var_policy {
-                        self.trail.push((Ref::HeapCell(addr), self.target[addr].clone()));
+                        self.trail.push((Ref::HeapCell(addr), HeapCellValue::Addr(ra)));
                         self.target[addr] = HeapCellValue::Addr(Addr::HeapCell(threshold));
                     }
                 } else {
@@ -100,7 +118,11 @@ impl<T: CopierTarget> CopyTermState<T> {
                 }
             }
             _ => {
-                self.trail.push((Ref::HeapCell(addr), self.target[addr].clone()));
+                self.trail.push((
+                    Ref::HeapCell(addr),
+                    HeapCellValue::Addr(self.target[addr].as_addr(addr)),
+                ));
+
                 self.target[addr] = HeapCellValue::Addr(Addr::Lis(threshold))
             }
         };
@@ -108,6 +130,74 @@ impl<T: CopierTarget> CopyTermState<T> {
         self.scan += 1;
     }
 
+
+    fn copy_partial_string(&mut self, addr: usize, n: usize) {
+        let threshold = self.target.threshold();
+
+        let tail_addr =
+            match &self.target[addr] {
+                HeapCellValue::PartialString(ref pstr) => {
+                    self.trail.push((
+                        Ref::PStrTail(addr, 0),
+                        HeapCellValue::Addr(pstr.tail.clone()),
+                    ));
+
+                    self.target.store(self.target.deref(pstr.tail.clone()))
+                }
+                _ => {
+                    unreachable!()
+                }
+            };
+
+        let pstr =
+            match &mut self.target[addr] {
+                HeapCellValue::PartialString(ref mut pstr) => {
+                    let mut new_pstr = pstr.clone_from_offset(n);
+
+                    if let Addr::PStrTail(h, n) = &tail_addr {
+                        new_pstr.tail = if *h == addr {
+                            Addr::PStrTail(threshold, *n)
+                        } else {
+                            Addr::HeapCell(threshold + 1)
+                        };
+                    } else {
+                        new_pstr.tail = Addr::HeapCell(threshold + 1);
+                    }
+
+                    pstr.tail = Addr::PStrLocation(threshold, 0);
+                    new_pstr
+                }
+                _ => {
+                    unreachable!()
+                }
+            };
+
+        match tail_addr {
+            Addr::PStrTail(h, _) if h == addr => {
+                self.target.push(HeapCellValue::PartialString(pstr));
+            }
+            addr => {
+                self.target.push(HeapCellValue::PartialString(pstr));
+                self.target.push(HeapCellValue::Addr(addr));
+            }
+        }
+    }
+
+    fn copy_partial_string_from(&mut self, addr: usize, n: usize) {
+        if self.copied_partial_string(addr) {
+            return;
+        }
+
+        let threshold = self.target.threshold();
+
+        self.target[self.scan] =
+            HeapCellValue::Addr(Addr::PStrLocation(threshold, n));
+
+        self.scan += 1;
+
+        self.copy_partial_string(addr, n);
+    }
+
     fn reinstantiate_var(&mut self, addr: Addr, frontier: usize) {
         match addr {
             Addr::HeapCell(h) => {
@@ -126,6 +216,22 @@ impl<T: CopierTarget> CopyTermState<T> {
                     HeapCellValue::Addr(Addr::StackCell(fr, sc)),
                 ));
             }
+            Addr::PStrTail(h, n) => {
+                match &mut self.target[h] {
+                    HeapCellValue::PartialString(ref mut pstr) => {
+                        pstr.tail = Addr::PStrTail(frontier, n);
+                    }
+                    _ => {
+                        unreachable!()
+                    }
+                }
+
+                self.target[frontier] = HeapCellValue::Addr(Addr::PStrTail(frontier, n));
+                self.trail.push((
+                    Ref::PStrTail(h, n),
+                    HeapCellValue::Addr(Addr::PStrTail(h, n))
+                ));
+            }
             Addr::AttrVar(h) => {
                 let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
                     self.target.threshold()
@@ -203,16 +309,35 @@ impl<T: CopierTarget> CopyTermState<T> {
         self.target.push(HeapCellValue::Addr(addr));
 
         while self.scan < self.target.threshold() {
-            match self.value_at_scan().clone() {
-                HeapCellValue::NamedStr(..) => self.scan += 1,
-                HeapCellValue::Addr(addr) => match addr {
-                    Addr::Lis(addr) => self.copy_list(addr),
-                    addr @ Addr::AttrVar(_)
-                  | addr @ Addr::HeapCell(_)
-                  | addr @ Addr::StackCell(..) => self.copy_var(addr),
-                    Addr::Str(addr) => self.copy_structure(addr),
-                    Addr::Con(_) | Addr::DBRef(_) => self.scan += 1,
-                },
+            match self.value_at_scan() {
+                HeapCellValue::NamedStr(..) => {
+                    self.scan += 1;
+                }
+                HeapCellValue::Addr(ref addr) => {
+                    match addr.clone() {
+                        Addr::Lis(addr) => {
+                            self.copy_list(addr);
+                        }
+                        addr @ Addr::AttrVar(_)
+                      | addr @ Addr::HeapCell(_)
+                      | addr @ Addr::StackCell(..)
+                      | addr @ Addr::PStrTail(..) => {
+                            self.copy_var(addr);
+                        }
+                        Addr::Str(addr) => {
+                            self.copy_structure(addr);
+                        }
+                        Addr::PStrLocation(addr, n) => {
+                            self.copy_partial_string_from(addr, n);
+                        }
+                        Addr::Con(_) | Addr::DBRef(_) => {
+                            self.scan += 1;
+                        }
+                    }
+                }
+                HeapCellValue::PartialString(_) => {
+                    self.scan += 1;
+                }
             }
         }
 
@@ -224,6 +349,10 @@ impl<T: CopierTarget> CopyTermState<T> {
             match r {
                 Ref::AttrVar(h) | Ref::HeapCell(h) =>
                     self.target[h] = value,
+                Ref::PStrTail(h, _) =>
+                    if let HeapCellValue::PartialString(ref mut pstr) = &mut self.target[h] {
+                        pstr.tail = value.as_addr(0);
+                    },
                 Ref::StackCell(fr, sc) =>
                     self.target.stack().index_and_frame_mut(fr)[sc] = value.as_addr(0),
             }
index b3d406e3e636c34d99820c96cc5a3ff7d5ea3ce3..6fe60b851db56299cba7d7f00f7d5260a4424cba 100644 (file)
@@ -3,6 +3,7 @@ use core::marker::PhantomData;
 use crate::prolog_parser::ast::*;
 
 use crate::prolog::machine::machine_indices::*;
+use crate::prolog::machine::partial_string::*;
 use crate::prolog::machine::raw_block::*;
 
 use std::mem;
@@ -149,12 +150,93 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
 
     #[inline]
     pub(crate)
-    fn take<U: RawBlockTraits>(&mut self) -> HeapTemplate<U> {
-        unsafe {
-            HeapTemplate {
-                buf: mem::transmute::<RawBlock<T>, RawBlock<U>>(self.buf.take()),
-                _marker: PhantomData,
+    fn allocate_pstr(&mut self, mut src: &str) -> Option<Addr> {
+        let orig_h = self.h();
+        
+        loop {
+            if src == "" {
+                return if orig_h == self.h() {
+                    None
+                } else {
+                    let prev_h = self.h() - 1;
+
+                    match &mut self[prev_h] {
+                        HeapCellValue::PartialString(ref mut pstr) => {
+                            let s = pstr.block_as_str();
+                            pstr.tail = Addr::PStrTail(prev_h, s.len());
+                        }
+                        _ => {
+                            unreachable!()
+                        }
+                    }
+
+                    Some(Addr::PStrLocation(orig_h, 0))
+                };
             }
+            
+            let h = self.h();
+
+            let (mut pstr, rest_src) =
+                match PartialString::new(src, h) {
+                    Some(tuple) => {
+                        tuple
+                    }
+                    None => {
+                        if src.len() > '\u{0}'.len_utf8() {
+                            src = &src['\u{0}'.len_utf8() ..];
+                            continue;
+                        } else if orig_h == h {
+                            return None;
+                        } else {
+                            let prev_h = h - 1;
+
+                            match &mut self[prev_h] {
+                                HeapCellValue::PartialString(ref mut pstr) => {
+                                    let s = pstr.block_as_str();
+                                    pstr.tail = Addr::PStrTail(prev_h, s.len());
+                                }
+                                _ => {
+                                    unreachable!()
+                                }
+                            }
+
+                            return Some(Addr::PStrLocation(orig_h, 0));
+                        }
+                    }
+                };
+
+            let new_top = unsafe {
+                self.buf.new_block(mem::size_of::<HeapCellValue>())
+            };
+
+            if rest_src != "" {
+                pstr.tail = Addr::PStrLocation(h+1, 0);
+                src = rest_src;
+            } else {
+                pstr.tail = Addr::PStrTail(h, src.len());
+            }
+
+            unsafe{
+                ptr::write(
+                    self.buf.top as *mut _,
+                    HeapCellValue::PartialString(pstr),
+                );
+            }
+            
+            self.buf.top = new_top;
+            
+            if rest_src == "" {                
+                return Some(Addr::PStrLocation(orig_h, 0));
+            }            
+        }
+    }
+
+    #[inline]
+    pub(crate)
+    fn take(&mut self) -> Self {
+        HeapTemplate {
+            buf: self.buf.take(),
+            _marker: PhantomData,
         }
     }
 
index c084c6459a19340330293efb4b557b4b1a01e8e0..7986261971f0ba03b132a8e58bc04d011d367854 100644 (file)
@@ -391,10 +391,13 @@ impl EvalError {
 pub(super) enum CycleSearchResult {
     EmptyList,
     NotList,
-    PartialList(usize, usize), // the list length (up to max), and an offset into the heap.
-    ProperList(usize),         // the list length.
-    String(usize, usize, Rc<String>), // the number of bytes iterated, the offset, the string.
-    UntouchedList(usize),      // the address of an uniterated Addr::Lis(address).
+    PartialList(usize, Ref),  // the list length (up to max), and an offset into the heap.
+    ProperList(usize),          // the list length.
+    CompleteString(usize, Rc<String>), // the string length (in bytes), the string.
+    UntouchedString(usize, Rc<String>),    // the cut off, past which is the untouched string.
+    PStrLocation(usize, usize, usize), // the list length (up to max), the heap offset, byte offset into the string.
+    PStrTail(usize, usize, usize),     // the list length (up to max), the heap offset, byte offset into the string.
+    UntouchedList(usize),       // the address of an uniterated Addr::Lis(address).
 }
 
 impl MachineState {
index 44e086b12c7de4a177da6269fde50412fda2cf28..9805699a1987caae8f2ab6b2f2c528f3430ab2c4 100644 (file)
@@ -7,6 +7,7 @@ use crate::prolog::forms::*;
 use crate::prolog::machine::code_repo::CodeRepo;
 use crate::prolog::machine::Ball;
 use crate::prolog::machine::heap::*;
+use crate::prolog::machine::partial_string::*;
 use crate::prolog::machine::raw_block::RawBlockTraits;
 use crate::prolog::instructions::*;
 use crate::prolog::rug::Integer;
@@ -46,6 +47,8 @@ pub enum Addr {
     HeapCell(usize),
     StackCell(usize, usize),
     Str(usize),
+    PStrLocation(usize, usize), // location of pstr in heap, offset into string in bytes.
+    PStrTail(usize, usize), // location of pstr in heap, offset into string in bytes.
 }
 
 #[derive(Clone, Copy, Hash, Eq, PartialEq)]
@@ -53,6 +56,7 @@ pub enum Ref {
     AttrVar(usize),
     HeapCell(usize),
     StackCell(usize, usize),
+    PStrTail(usize, usize),
 }
 
 impl Ref {
@@ -61,6 +65,7 @@ impl Ref {
             Ref::AttrVar(h) => Addr::AttrVar(h),
             Ref::HeapCell(h) => Addr::HeapCell(h),
             Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc),
+            Ref::PStrTail(h, n) => Addr::PStrTail(h, n),
         }
     }
 }
@@ -75,23 +80,51 @@ impl PartialEq<Ref> for Addr {
 impl PartialOrd<Ref> for Addr {
     fn partial_cmp(&self, r: &Ref) -> Option<Ordering> {
         match self {
-            &Addr::StackCell(fr, sc) => match *r {
-                Ref::AttrVar(_) | Ref::HeapCell(_) => Some(Ordering::Greater),
-                Ref::StackCell(fr1, sc1) => {
-                    if fr1 < fr || (fr1 == fr && sc1 < sc) {
+            &Addr::StackCell(fr, sc) => {
+                match *r {
+                    Ref::AttrVar(_) | Ref::HeapCell(_) | Ref::PStrTail(..) => {
                         Some(Ordering::Greater)
-                    } else if fr1 == fr && sc1 == sc {
-                        Some(Ordering::Equal)
-                    } else {
+                    }
+                    Ref::StackCell(fr1, sc1) => {
+                        if fr1 < fr || (fr1 == fr && sc1 < sc) {
+                            Some(Ordering::Greater)
+                        } else if fr1 == fr && sc1 == sc {
+                            Some(Ordering::Equal)
+                        } else {
+                            Some(Ordering::Less)
+                        }
+                    }
+                }
+            }
+            &Addr::HeapCell(h) | &Addr::AttrVar(h) => {
+                match r {
+                    Ref::StackCell(..) => {
                         Some(Ordering::Less)
                     }
+                    Ref::AttrVar(h1) | Ref::HeapCell(h1) => {
+                        h.partial_cmp(h1)
+                    }
+                    Ref::PStrTail(h1, _) => {
+                        h.partial_cmp(h1)
+                    }
                 }
-            },
-            &Addr::HeapCell(h) | &Addr::AttrVar(h) => match r {
-                &Ref::StackCell(..) => Some(Ordering::Less),
-                &Ref::AttrVar(h1) | &Ref::HeapCell(h1) => h.partial_cmp(&h1),
-            },
-            _ => None,
+            }
+            &Addr::PStrTail(h, n) => {
+                match r {
+                    Ref::StackCell(..) => {
+                        Some(Ordering::Less)
+                    }
+                    Ref::AttrVar(h1) | Ref::HeapCell(h1) => {
+                        h.partial_cmp(h1)
+                    }
+                    Ref::PStrTail(h1, n1) => {
+                        Some(h.cmp(h1).then_with(|| n.cmp(n1)))
+                    }
+                }
+            }
+            _ => {
+                None
+            }
         }
     }
 }
@@ -99,8 +132,12 @@ impl PartialOrd<Ref> for Addr {
 impl Addr {
     pub fn is_ref(&self) -> bool {
         match self {
-            &Addr::AttrVar(_) | &Addr::HeapCell(_) | &Addr::StackCell(_, _) => true,
-            _ => false,
+            Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::AttrVar(_) | Addr::PStrTail(..) => {
+                true
+            }
+            _ => {
+                false
+            }
         }
     }
 
@@ -109,6 +146,7 @@ impl Addr {
             &Addr::AttrVar(h) => Some(Ref::AttrVar(h)),
             &Addr::HeapCell(h) => Some(Ref::HeapCell(h)),
             &Addr::StackCell(fr, sc) => Some(Ref::StackCell(fr, sc)),
+            &Addr::PStrTail(h, n) => Some(Ref::PStrTail(h, n)),
             _ => None,
         }
     }
@@ -130,6 +168,8 @@ impl Add<usize> for Addr {
             Addr::AttrVar(h) => Addr::AttrVar(h + rhs),
             Addr::HeapCell(h) => Addr::HeapCell(h + rhs),
             Addr::Str(s) => Addr::Str(s + rhs),
+            Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs, n),
+            Addr::PStrTail(h, n) => Addr::PStrTail(h + rhs, n),
             _ => self,
         }
     }
@@ -145,6 +185,8 @@ impl Sub<i64> for Addr {
                 Addr::AttrVar(h) => Addr::AttrVar(h + rhs.abs() as usize),
                 Addr::HeapCell(h) => Addr::HeapCell(h + rhs.abs() as usize),
                 Addr::Str(s) => Addr::Str(s + rhs.abs() as usize),
+                Addr::PStrTail(h, n) => Addr::PStrTail(h + rhs.abs() as usize, n),
+                Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs.abs() as usize, n),
                 _ => self,
             }
         } else {
@@ -162,6 +204,8 @@ impl Sub<usize> for Addr {
             Addr::AttrVar(h) => Addr::AttrVar(h - rhs),
             Addr::HeapCell(h) => Addr::HeapCell(h - rhs),
             Addr::Str(s) => Addr::Str(s - rhs),
+            Addr::PStrTail(h, n) => Addr::PStrTail(h - rhs, n),
+            Addr::PStrLocation(h, n) => Addr::PStrLocation(h - rhs, n),
             _ => self,
         }
     }
@@ -173,16 +217,6 @@ impl SubAssign<usize> for Addr {
     }
 }
 
-impl From<Ref> for Addr {
-    fn from(r: Ref) -> Self {
-        match r {
-            Ref::AttrVar(h) => Addr::AttrVar(h),
-            Ref::HeapCell(h) => Addr::HeapCell(h),
-            Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc),
-        }
-    }
-}
-
 #[derive(Clone, Copy)]
 pub enum TrailRef {
     Ref(Ref),
@@ -200,13 +234,21 @@ impl From<Ref> for TrailRef {
 pub enum HeapCellValue {
     Addr(Addr),
     NamedStr(usize, ClauseName, Option<SharedOpDesc>), // arity, name, precedence/Specifier if it has one.
+    PartialString(PartialString),
 }
 
 impl HeapCellValue {
     pub fn as_addr(&self, focus: usize) -> Addr {
         match self {
-            &HeapCellValue::Addr(ref a) => a.clone(),
-            &HeapCellValue::NamedStr(_, _, _) => Addr::Str(focus),
+            HeapCellValue::Addr(ref a) => {
+                a.clone()
+            }
+            HeapCellValue::NamedStr(_, _, _) => {
+                Addr::Str(focus)
+            }
+            HeapCellValue::PartialString(_) => {
+                Addr::PStrLocation(focus, 0)
+            }
         }
     }
 }
index 5eb4dccc41061a482dc30489cc55b737c541eaba..4c626b0d22b8ec917aa1814644bc06fb42abfaac 100644 (file)
@@ -25,19 +25,22 @@ pub struct Ball {
 }
 
 impl Ball {
-    pub(super) fn new() -> Self {
+    pub(super)
+    fn new() -> Self {
         Ball {
             boundary: 0,
             stub: Heap::new(),
         }
     }
 
-    pub(super) fn reset(&mut self) {
+    pub(super)
+    fn reset(&mut self) {
         self.boundary = 0;
         self.stub.clear();
     }
 
-    pub(super) fn take(&mut self) -> Ball {
+    pub(super)
+    fn take(&mut self) -> Ball {
         let boundary = self.boundary;
         self.boundary = 0;
 
@@ -47,14 +50,20 @@ impl Ball {
         }
     }
 
-    pub(super) fn copy_and_align(&self, h: usize) -> Heap {
+    pub(super)
+    fn copy_and_align(&self, h: usize) -> Heap {
         let diff = self.boundary as i64 - h as i64;
         let mut stub = Heap::new();
 
-        for heap_value in self.stub.iter_from(0).cloned() {
+        for heap_value in self.stub.iter_from(0) {
             stub.push(match heap_value {
-                HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr - diff),
-                heap_value => heap_value,
+                HeapCellValue::Addr(ref addr) => HeapCellValue::Addr(addr.clone() - diff),
+                HeapCellValue::PartialString(ref pstr) => {
+                    let mut new_pstr = pstr.clone();
+                    new_pstr.tail = pstr.tail.clone() - diff;
+                    HeapCellValue::PartialString(new_pstr)
+                }
+                heap_value => heap_value.clone(),
             });
         }
 
@@ -524,7 +533,8 @@ pub(crate) trait CallPolicy: Any {
 
         machine_st.attr_var_init.backtrack(
             attr_var_init_queue_b,
-            attr_var_init_bindings_b);
+            attr_var_init_bindings_b,
+        );
 
         machine_st.stack.truncate(machine_st.b);
         machine_st.b = machine_st.stack.index_or_frame(b).prelude.b;
index e18cee940a48808f5b878ffca3e8ca35d489feed..d93144a12727db60d536a306521c5290f3767cb6 100644 (file)
@@ -119,15 +119,34 @@ impl MachineState {
         self.flags
     }
 
-    pub(crate) fn store(&self, addr: Addr) -> Addr {
+    pub(crate)
+    fn store(&self, addr: Addr) -> Addr {
         match addr {
-            Addr::AttrVar(h) | Addr::HeapCell(h) => self.heap[h].as_addr(h),
-            Addr::StackCell(fr, sc) => self.stack.index_and_frame(fr)[sc].clone(),
-            addr => addr,
+            Addr::AttrVar(h) | Addr::HeapCell(h) => {
+                self.heap[h].as_addr(h)
+            }
+            Addr::StackCell(fr, sc) => {
+                self.stack.index_and_frame(fr)[sc].clone()
+            }
+            Addr::PStrTail(h, n) => {
+                if let HeapCellValue::PartialString(ref pstr) = &self.heap[h] {
+                    if pstr.len() > n {
+                        Addr::PStrLocation(h, n)
+                    } else {
+                        pstr.tail.clone()
+                    }
+                } else {
+                    unreachable!()
+                }
+            }
+            addr => {
+                addr
+            }
         }
     }
 
-    pub(crate) fn deref(&self, mut addr: Addr) -> Addr {
+    pub(crate)
+    fn deref(&self, mut addr: Addr) -> Addr {
         loop {
             let value = self.store(addr.clone());
 
@@ -158,15 +177,38 @@ impl MachineState {
         }
     }
 
+    fn bind_pstr_tail(&mut self, h: usize, t2: Addr) {
+        let pstr_len = match &mut self.heap[h] {
+            HeapCellValue::PartialString(ref mut pstr) => {
+                pstr.tail = t2;
+                pstr.len()
+            }
+            _ => {
+                unreachable!()
+            }
+        };
+
+        self.trail(TrailRef::from(Ref::PStrTail(h, pstr_len)));
+    }
+
     pub(super) fn bind(&mut self, r1: Ref, a2: Addr) {
         let t1 = self.store(r1.as_addr());
         let t2 = self.store(a2.clone());
 
         if t1.is_ref() && (!t2.is_ref() || a2 < r1) {
             match r1 {
-                Ref::StackCell(fr, sc) => self.stack.index_and_frame_mut(fr)[sc] = t2,
-                Ref::HeapCell(h) => self.heap[h] = HeapCellValue::Addr(t2),
-                Ref::AttrVar(h) => return self.bind_attr_var(h, t2),
+                Ref::StackCell(fr, sc) => {
+                    self.stack.index_and_frame_mut(fr)[sc] = t2;
+                }
+                Ref::HeapCell(h) => {
+                    self.heap[h] = HeapCellValue::Addr(t2);
+                }
+                Ref::AttrVar(h) => {
+                    return self.bind_attr_var(h, t2);
+                }
+                Ref::PStrTail(h, _) => {
+                    return self.bind_pstr_tail(h, t2);
+                }
             };
 
             self.trail(TrailRef::from(r1));
@@ -180,9 +222,14 @@ impl MachineState {
                     self.heap[h] = HeapCellValue::Addr(t1);
                     self.trail(TrailRef::Ref(Ref::HeapCell(h)));
                 }
-                Some(Ref::AttrVar(h)) =>
-                    self.bind_attr_var(h, t1),
-                None => {}
+                Some(Ref::AttrVar(h)) => {
+                    self.bind_attr_var(h, t1);
+                }
+                Some(Ref::PStrTail(h, _)) => {
+                    self.bind_pstr_tail(h, t1);
+                }
+                None => {
+                }
             }
         }
     }
@@ -258,6 +305,9 @@ impl MachineState {
                     (Addr::StackCell(fr, sc), addr) | (addr, Addr::StackCell(fr, sc)) => {
                         self.bind_with_occurs_check(Ref::StackCell(fr, sc), addr)
                     }
+                    (Addr::PStrTail(h, n), addr) | (addr, Addr::PStrTail(h, n)) => {
+                        self.bind_with_occurs_check(Ref::PStrTail(h, n), addr);
+                    }
                     (Addr::Lis(a1), Addr::Str(a2)) | (Addr::Str(a2), Addr::Lis(a1)) => {
                         if let &HeapCellValue::NamedStr(n2, ref f2, _) = &self.heap[a2] {
                             if f2.as_str() == "." && n2 == 2 {
@@ -274,7 +324,9 @@ impl MachineState {
                         self.fail = true;
                     }
                     (Addr::Lis(a1), Addr::Con(Constant::String(n, s)))
-                  | (Addr::Con(Constant::String(n, s)), Addr::Lis(a1)) => {
+                  | (Addr::Con(Constant::String(n, s)), Addr::Lis(a1))
+                        if !self.flags.double_quotes.is_atom() =>
+                    {
                         if self.deconstruct_chars(s, n, a1, &mut pdl) {
                             continue;
                         }
@@ -291,6 +343,63 @@ impl MachineState {
 
                         self.fail = true;
                     }
+                    (Addr::PStrLocation(h, n), Addr::Lis(l))
+                  | (Addr::Lis(l), Addr::PStrLocation(h, n)) => {
+                        if let HeapCellValue::PartialString(ref pstr) = &self.heap[h] {
+                            let s = pstr.block_as_str();
+
+                            if let Some(c) = s[n ..].chars().next() {
+                                pdl.push(Addr::PStrTail(h, n + c.len_utf8()));
+                                pdl.push(Addr::HeapCell(l + 1));
+
+                                pdl.push(Addr::Con(Constant::Char(c)));
+                                pdl.push(Addr::HeapCell(l));
+                            }
+                        }
+                    }
+                    (Addr::PStrLocation(h, n), Addr::Con(Constant::String(n1, s)))
+                  | (Addr::Con(Constant::String(n1, s)), Addr::PStrLocation(h, n))
+                        if self.flags.double_quotes.is_chars() => {
+                            if let HeapCellValue::PartialString(ref pstr) = &self.heap[h] {
+                                let pstr_s = pstr.block_as_str();
+
+                                if let Some(c) = pstr_s[n ..].chars().next() {
+                                    if let Some(c1) = s[n1 ..].chars().next() {
+                                        if c == c1 {
+                                            pdl.push(Addr::Con(Constant::String(n1 + c.len_utf8(), s)));
+                                            pdl.push(Addr::PStrTail(h, n + c.len_utf8()));
+
+                                            continue;
+                                        }
+                                    }
+                                }
+
+                                self.fail = true;
+                                break;
+                            }
+                        }
+                    (Addr::PStrLocation(h1, n1), Addr::PStrLocation(h2, n2)) => {
+                        if let HeapCellValue::PartialString(ref pstr1) = &self.heap[h1] {
+                            if let HeapCellValue::PartialString(ref pstr2) = &self.heap[h2] {
+                                let pstr_s1 = pstr1.block_as_str();
+                                let pstr_s2 = pstr2.block_as_str();
+
+                                if let Some(c1) = pstr_s1[n1 ..].chars().next() {
+                                    if let Some(c2) = pstr_s2[n2 ..].chars().next() {
+                                        if c1 == c2 {
+                                            pdl.push(Addr::PStrTail(h1, n1 + c1.len_utf8()));
+                                            pdl.push(Addr::PStrTail(h2, n2 + c2.len_utf8()));
+
+                                            continue;
+                                        }
+                                    }
+                                }
+
+                                self.fail = true;
+                                break;
+                            }
+                        }
+                    }
                     (Addr::Lis(a1), Addr::Lis(a2)) => {
                         pdl.push(Addr::HeapCell(a1));
                         pdl.push(Addr::HeapCell(a2));
@@ -353,17 +462,14 @@ impl MachineState {
                     (Addr::AttrVar(h), addr) | (addr, Addr::AttrVar(h)) => {
                         self.bind(Ref::AttrVar(h), addr);
                     }
-                    (Addr::HeapCell(h), _) => {
-                        self.bind(Ref::HeapCell(h), d2);
-                    }
-                    (_, Addr::HeapCell(h)) => {
-                        self.bind(Ref::HeapCell(h), d1);
+                    (Addr::HeapCell(h), addr) | (addr, Addr::HeapCell(h)) => {
+                        self.bind(Ref::HeapCell(h), addr);
                     }
-                    (Addr::StackCell(fr, sc), _) => {
-                        self.bind(Ref::StackCell(fr, sc), d2);
+                    (Addr::StackCell(fr, sc), addr) | (addr, Addr::StackCell(fr, sc)) => {
+                        self.bind(Ref::StackCell(fr, sc), addr);
                     }
-                    (_, Addr::StackCell(fr, sc)) => {
-                        self.bind(Ref::StackCell(fr, sc), d1);
+                    (Addr::PStrTail(h, n), addr) | (addr, Addr::PStrTail(h, n)) => {
+                        self.bind(Ref::PStrTail(h, n), addr);
                     }
                     (Addr::Lis(a1), Addr::Str(a2)) | (Addr::Str(a2), Addr::Lis(a1)) => {
                         if let &HeapCellValue::NamedStr(n2, ref f2, _) = &self.heap[a2] {
@@ -381,13 +487,14 @@ impl MachineState {
                         self.fail = true;
                     }
                     (Addr::Lis(a1), Addr::Con(Constant::String(n, s)))
-                  | (Addr::Con(Constant::String(n, s)), Addr::Lis(a1)) => {
-                        if self.deconstruct_chars(s, n, a1, &mut pdl) {
-                            continue;
-                        }
+                  | (Addr::Con(Constant::String(n, s)), Addr::Lis(a1))
+                        if !self.flags.double_quotes.is_atom() => {
+                            if self.deconstruct_chars(s, n, a1, &mut pdl) {
+                                continue;
+                            }
 
-                        self.fail = true;
-                    }
+                            self.fail = true;
+                        }
                     (Addr::Con(Constant::EmptyList), Addr::Con(Constant::String(n, ref s)))
                   | (Addr::Con(Constant::String(n, ref s)), Addr::Con(Constant::EmptyList))
                         if !self.flags.double_quotes.is_atom() =>
@@ -398,6 +505,63 @@ impl MachineState {
 
                         self.fail = true;
                     }
+                    (Addr::PStrLocation(h, n), Addr::Lis(l))
+                  | (Addr::Lis(l), Addr::PStrLocation(h, n)) => {
+                        if let HeapCellValue::PartialString(ref pstr) = &self.heap[h] {
+                            let s = pstr.block_as_str();
+
+                            if let Some(c) = s[n ..].chars().next() {
+                                pdl.push(Addr::PStrTail(h, n + c.len_utf8()));
+                                pdl.push(Addr::HeapCell(l + 1));
+
+                                pdl.push(Addr::Con(Constant::Char(c)));
+                                pdl.push(Addr::HeapCell(l));
+                            }
+                        }
+                    }
+                    (Addr::PStrLocation(h, n), Addr::Con(Constant::String(n1, s)))
+                  | (Addr::Con(Constant::String(n1, s)), Addr::PStrLocation(h, n))
+                        if self.flags.double_quotes.is_chars() => {
+                            if let HeapCellValue::PartialString(ref pstr) = &self.heap[h] {
+                                let pstr_s = pstr.block_as_str();
+
+                                if let Some(c) = pstr_s[n ..].chars().next() {
+                                    if let Some(c1) = s[n1 ..].chars().next() {
+                                        if c == c1 {
+                                            pdl.push(Addr::Con(Constant::String(n1 + c.len_utf8(), s)));
+                                            pdl.push(Addr::PStrTail(h, n + c.len_utf8()));
+
+                                            continue;
+                                        }
+                                    }
+                                }
+
+                                self.fail = true;
+                                break;
+                            }
+                        }
+                    (Addr::PStrLocation(h1, n1), Addr::PStrLocation(h2, n2)) => {
+                        if let HeapCellValue::PartialString(ref pstr1) = &self.heap[h1] {
+                            if let HeapCellValue::PartialString(ref pstr2) = &self.heap[h2] {
+                                let pstr_s1 = pstr1.block_as_str();
+                                let pstr_s2 = pstr2.block_as_str();
+
+                                if let Some(c1) = pstr_s1[n1 ..].chars().next() {
+                                    if let Some(c2) = pstr_s2[n2 ..].chars().next() {
+                                        if c1 == c2 {
+                                            pdl.push(Addr::PStrTail(h1, n1 + c1.len_utf8()));
+                                            pdl.push(Addr::PStrTail(h2, n2 + c2.len_utf8()));
+
+                                            continue;
+                                        }
+                                    }
+                                }
+
+                                self.fail = true;
+                                break;
+                            }
+                        }
+                    }
                     (Addr::Lis(a1), Addr::Lis(a2)) => {
                         pdl.push(Addr::HeapCell(a1));
                         pdl.push(Addr::HeapCell(a2));
@@ -449,6 +613,12 @@ impl MachineState {
                     self.tr += 1;
                 }
             }
+            TrailRef::Ref(Ref::PStrTail(h, n)) => {
+                if h < self.hb {
+                    self.trail.push(TrailRef::Ref(Ref::PStrTail(h, n)));
+                    self.tr += 1;
+                }
+            }
             TrailRef::AttrVarHeapLink(h) => {
                 if h < self.hb {
                     self.trail.push(TrailRef::AttrVarHeapLink(h));
@@ -485,6 +655,14 @@ impl MachineState {
                 TrailRef::Ref(Ref::StackCell(fr, sc)) => {
                     self.stack.index_and_frame_mut(fr)[sc] = Addr::StackCell(fr, sc)
                 }
+                TrailRef::Ref(Ref::PStrTail(h, n)) => {
+                    if let HeapCellValue::PartialString(ref mut pstr) = &mut self.heap[h] {
+                        pstr.truncate(n);
+                        pstr.tail = Addr::PStrTail(h, n);
+
+                        self.tr += 1;
+                    }
+                }
                 TrailRef::AttrVarHeapLink(h) => {
                     self.heap[h] = HeapCellValue::Addr(Addr::HeapCell(h));
                 }
@@ -508,6 +686,7 @@ impl MachineState {
             match self.trail[i] {
                 TrailRef::Ref(Ref::AttrVar(tr_i))
               | TrailRef::Ref(Ref::HeapCell(tr_i))
+              | TrailRef::Ref(Ref::PStrTail(tr_i, _))
               | TrailRef::AttrVarHeapLink(tr_i)
               | TrailRef::AttrVarListLink(tr_i, _) => {
                     if tr_i >= hb {
@@ -1375,7 +1554,8 @@ impl MachineState {
         };
     }
 
-    fn get_char_list(&mut self, offset: usize, s: Rc<String>) {
+    fn get_char_list(&mut self, offset: usize, s: Rc<String>)
+    {
         if let Some(c) = s[offset ..].chars().next() {
             let h = self.heap.h();
 
@@ -1390,6 +1570,29 @@ impl MachineState {
         }
     }
 
+    fn get_partial_string_list(&mut self, pstr_h: usize, offset: usize)
+    {
+        let (c, pstr_tail) =
+            if let HeapCellValue::PartialString(ref pstr) = &self.heap[pstr_h] {
+                let s = pstr.block_as_str();
+
+                if let Some(c) = s[offset ..].chars().next() {
+                    (c, Addr::PStrTail(pstr_h, offset + c.len_utf8()))
+                } else {
+                    unreachable!()
+                }
+            } else {
+                unreachable!()
+            };
+
+        self.s = self.heap.h();
+
+        self.heap.push(HeapCellValue::Addr(Addr::Con(Constant::Char(c))));
+        self.heap.push(HeapCellValue::Addr(pstr_tail));
+
+        self.mode = MachineMode::Read;
+    }
+
     pub(super) fn execute_fact_instr(&mut self, instr: &FactInstruction) {
         match instr {
             &FactInstruction::GetConstant(_, ref c, reg) => {
@@ -1409,10 +1612,14 @@ impl MachineState {
                             _ => {
                                 self.fail = true
                             }
-                    },
+                        },
+                    Addr::PStrLocation(h, n) => {
+                        self.get_partial_string_list(h, n)
+                    }
                     addr @ Addr::AttrVar(_)
                   | addr @ Addr::StackCell(..)
-                  | addr @ Addr::HeapCell(_) => {
+                  | addr @ Addr::HeapCell(_)
+                  | addr @ Addr::PStrTail(..) => {
                         let h = self.heap.h();
 
                         self.heap.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
@@ -1558,7 +1765,10 @@ impl MachineState {
                 let addr = self.store(self.deref(a1));
 
                 let offset = match addr {
-                    Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(..) => v,
+                    Addr::HeapCell(_) | Addr::StackCell(..)
+                  | Addr::AttrVar(..) | Addr::PStrTail(..) => {
+                        v
+                    }
                     Addr::Con(Constant::String(n, ref s)) => {
                         if !self.flags.double_quotes.is_atom() {
                             if n >= s.len() {
@@ -1570,9 +1780,15 @@ impl MachineState {
                             c
                         }
                     }
-                    Addr::Con(_) => c,
-                    Addr::Lis(_) => l,
-                    Addr::Str(_) => s,
+                    Addr::Con(_) => {
+                        c
+                    }
+                    Addr::Lis(_) | Addr::PStrLocation(..) => {
+                        l
+                    }
+                    Addr::Str(_) => {
+                        s
+                    }
                     Addr::DBRef(_) => {
                         self.fail = true;
                         return;
@@ -1827,7 +2043,7 @@ impl MachineState {
         let n = self.store(self.deref(self[temp_v!(1)].clone()));
 
         match n {
-            Addr::HeapCell(_) | Addr::StackCell(..) =>
+            Addr::HeapCell(_) | Addr::StackCell(..) | Addr::PStrTail(..) =>
             // 8.5.2.3 a)
             {
                 return Err(self.error_form(MachineError::instantiation_error(), stub))
@@ -1852,7 +2068,7 @@ impl MachineState {
                 let term = self.store(self.deref(self[temp_v!(2)].clone()));
 
                 match term {
-                    Addr::HeapCell(_) | Addr::StackCell(..) =>
+                    Addr::HeapCell(_) | Addr::StackCell(..) | Addr::PStrTail(..) =>
                     // 8.5.2.3 b)
                     {
                         return Err(self.error_form(MachineError::instantiation_error(), stub))
@@ -1876,6 +2092,31 @@ impl MachineState {
                             self.fail = true;
                         }
                     }
+                    Addr::PStrLocation(h, offset) => {
+                        if n == 1 || n == 2 {
+                            let a3 = self[temp_v!(3)].clone();
+                            let h_a =
+                                if let HeapCellValue::PartialString(ref pstr) = &self.heap[h] {
+                                    let s = pstr.block_as_str();
+
+                                    if let Some(c) = s[offset ..].chars().next() {
+                                        if n == 1 {
+                                            Addr::Con(Constant::Char(c))
+                                        } else {
+                                            Addr::PStrTail(h, offset + c.len_utf8())
+                                        }
+                                    } else {
+                                        unreachable!()
+                                    }
+                                } else {
+                                    unreachable!()
+                                };
+
+                            self.unify(a3, h_a);
+                        } else {
+                            self.fail = true;
+                        }
+                    }
                     Addr::Con(Constant::String(o, ref s))
                         if !self.flags.double_quotes.is_atom() && !s[o ..].is_empty() =>
                     {
@@ -1986,6 +2227,52 @@ impl MachineState {
 
         while let Some((v1, v2)) = iter.next() {
             match (v1, v2) {
+                (
+                    HeapCellValue::Addr(Addr::Lis(_)),
+                    HeapCellValue::Addr(Addr::PStrLocation(..)),
+                )
+                | (
+                    HeapCellValue::Addr(Addr::PStrLocation(..)),
+                    HeapCellValue::Addr(Addr::Lis(_)),
+                )
+                | (
+                    HeapCellValue::Addr(Addr::PStrLocation(..)),
+                    HeapCellValue::Addr(Addr::PStrLocation(..)),
+                )
+                | (
+                    HeapCellValue::Addr(Addr::PStrTail(..)),
+                    HeapCellValue::Addr(Addr::PStrTail(..)),
+                ) => {
+                }
+                (
+                    HeapCellValue::Addr(Addr::PStrLocation(h1, _)),
+                    HeapCellValue::Addr(Addr::PStrTail(h2, _)),
+                ) => {
+                    return if h1 == h2 {
+                        Ordering::Less
+                    } else {
+                        h1.cmp(&h2)
+                    };
+                }
+                (
+                    HeapCellValue::Addr(Addr::PStrTail(h2, _)),
+                    HeapCellValue::Addr(Addr::PStrLocation(h1, _)),
+                ) => {
+                    return if h1 == h2 {
+                        Ordering::Greater
+                    } else {
+                        h2.cmp(&h1)
+                    };
+                }
+                (
+                    HeapCellValue::Addr(Addr::PStrLocation(..)),
+                    HeapCellValue::Addr(Addr::Con(Constant::String(..))),
+                )
+                | (
+                    HeapCellValue::Addr(Addr::Con(Constant::String(..))),
+                    HeapCellValue::Addr(Addr::PStrLocation(..)),
+                ) if self.flags.double_quotes.is_chars() => {
+                }
                 (
                     HeapCellValue::Addr(Addr::Lis(_)),
                     HeapCellValue::Addr(Addr::Con(Constant::String(..))),
@@ -2055,8 +2342,27 @@ impl MachineState {
                         return hc1.cmp(&hc2);
                     }
                 }
+                (
+                    HeapCellValue::Addr(Addr::PStrTail(hc1, _)),
+                    HeapCellValue::Addr(Addr::HeapCell(hc2)),
+                )
+                | (
+                    HeapCellValue::Addr(Addr::HeapCell(hc1)),
+                    HeapCellValue::Addr(Addr::PStrTail(hc2, _)),
+                )
+                | (
+                    HeapCellValue::Addr(Addr::PStrTail(hc1, _)),
+                    HeapCellValue::Addr(Addr::AttrVar(hc2)),
+                )
+                | (
+                    HeapCellValue::Addr(Addr::AttrVar(hc1)),
+                    HeapCellValue::Addr(Addr::PStrTail(hc2, _)),
+                ) => {
+                    return hc1.cmp(&hc2);
+                }
                 (HeapCellValue::Addr(Addr::HeapCell(_)), _)
-              | (HeapCellValue::Addr(Addr::AttrVar(_)), _) => {
+              | (HeapCellValue::Addr(Addr::AttrVar(_)), _)
+              | (HeapCellValue::Addr(Addr::PStrTail(..)), _) => {
                     return Ordering::Less;
                 }
                 (
@@ -2075,6 +2381,10 @@ impl MachineState {
                     HeapCellValue::Addr(Addr::StackCell(..)),
                     HeapCellValue::Addr(Addr::HeapCell(_)),
                 )
+                | (
+                    HeapCellValue::Addr(Addr::StackCell(..)),
+                    HeapCellValue::Addr(Addr::PStrTail(..)),
+                )
                 | (
                     HeapCellValue::Addr(Addr::StackCell(..)),
                     HeapCellValue::Addr(Addr::AttrVar(_)),
@@ -2091,7 +2401,11 @@ impl MachineState {
                 | (
                     HeapCellValue::Addr(Addr::Con(Constant::Integer(..))),
                     HeapCellValue::Addr(Addr::AttrVar(_)),
-                ) => {
+                )
+                | (
+                    HeapCellValue::Addr(Addr::Con(Constant::Integer(..))),
+                    HeapCellValue::Addr(Addr::PStrTail(..)),
+                )=> {
                     return Ordering::Greater;
                 }
                 (
@@ -2116,6 +2430,10 @@ impl MachineState {
                 | (
                     HeapCellValue::Addr(Addr::Con(Constant::Float(..))),
                     HeapCellValue::Addr(Addr::AttrVar(_)),
+                )
+                | (
+                    HeapCellValue::Addr(Addr::Con(Constant::Float(..))),
+                    HeapCellValue::Addr(Addr::PStrTail(..)),
                 ) => {
                     return Ordering::Greater;
                 }
@@ -2141,6 +2459,10 @@ impl MachineState {
                 | (
                     HeapCellValue::Addr(Addr::Con(Constant::Rational(..))),
                     HeapCellValue::Addr(Addr::AttrVar(_)),
+                )
+                | (
+                    HeapCellValue::Addr(Addr::Con(Constant::Rational(..))),
+                    HeapCellValue::Addr(Addr::PStrTail(..)),
                 ) => {
                     return Ordering::Greater;
                 }
@@ -2168,6 +2490,10 @@ impl MachineState {
                 | (
                     HeapCellValue::Addr(Addr::Con(Constant::String(..))),
                     HeapCellValue::Addr(Addr::AttrVar(_)),
+                )
+                | (
+                    HeapCellValue::Addr(Addr::Con(Constant::String(..))),
+                    HeapCellValue::Addr(Addr::PStrTail(..)),
                 ) => {
                     return Ordering::Greater;
                 }
@@ -2216,6 +2542,10 @@ impl MachineState {
                     HeapCellValue::Addr(Addr::Con(Constant::Atom(..))),
                     HeapCellValue::Addr(Addr::StackCell(..)),
                 ) => return Ordering::Greater,
+                (
+                    HeapCellValue::Addr(Addr::Con(Constant::Atom(..))),
+                    HeapCellValue::Addr(Addr::PStrTail(..)),
+                ) => return Ordering::Greater,
                 (
                     HeapCellValue::Addr(Addr::Con(Constant::Atom(..))),
                     HeapCellValue::Addr(Addr::Con(Constant::Float(_))),
@@ -2330,7 +2660,7 @@ impl MachineState {
                 let d = self.store(self.deref(self[r1].clone()));
 
                 match d {
-                    Addr::Str(_) | Addr::Lis(_) => self.p += 1,
+                    Addr::Str(_) | Addr::Lis(_) | Addr::PStrLocation(..) => self.p += 1,
                     _ => self.fail = true,
                 };
             }
@@ -2362,16 +2692,24 @@ impl MachineState {
                 let d = self.store(self.deref(self[r1].clone()));
 
                 match d {
-                    Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) => self.fail = true,
-                    _ => self.p += 1,
+                    Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) | Addr::PStrTail(..) => {
+                        self.fail = true;
+                    }
+                    _ => {
+                        self.p += 1;
+                    }
                 };
             }
             &InlinedClauseType::IsVar(r1) => {
                 let d = self.store(self.deref(self[r1].clone()));
 
                 match d {
-                    Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(_, _) => self.p += 1,
-                    _ => self.fail = true,
+                    Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::PStrTail(..) => {
+                        self.p += 1;
+                    }
+                    _ => {
+                        self.fail = true;
+                    }
                 };
             }
         }
@@ -2414,8 +2752,8 @@ impl MachineState {
             Addr::Lis(self.heap.h())
         } else {
             let h = self.heap.h();
-            self.heap
-                .push(HeapCellValue::NamedStr(arity as usize, name, spec));
+            self.heap.push(HeapCellValue::NamedStr(arity as usize, name, spec));
+
             Addr::Str(h)
         };
 
@@ -2448,11 +2786,11 @@ impl MachineState {
                 }
                 _ => self.fail = true,
             },
-            Addr::Lis(_) => {
+            Addr::Lis(_) | Addr::PStrLocation(..) => {
                 let shared_op_desc = fetch_op_spec(clause_name!("."), 2, None, &indices.op_dir);
                 self.try_functor_compound_case(clause_name!("."), 2, shared_op_desc)
             }
-            Addr::AttrVar(..) | Addr::HeapCell(_) | Addr::StackCell(..) => {
+            Addr::AttrVar(..) | Addr::HeapCell(_) | Addr::StackCell(..) | Addr::PStrTail(..) => {
                 let name = self.store(self.deref(self[temp_v!(2)].clone()));
                 let arity = self.store(self.deref(self[temp_v!(3)].clone()));
 
@@ -2551,48 +2889,8 @@ impl MachineState {
         let a1 = self.store(self.deref(self[r].clone()));
 
         match a1.clone() {
-            Addr::Lis(mut l) => {
-                let mut result = Vec::new();
-
-                result.push(self.heap[l].as_addr(l));
-                l += 1;
-
-                loop {
-                    match self.heap[l].clone() {
-                        HeapCellValue::Addr(addr) => match self.store(self.deref(addr)) {
-                            Addr::Lis(hcp) => {
-                                result.push(self.heap[hcp].as_addr(hcp));
-                                l = hcp + 1;
-                            }
-                            Addr::Con(Constant::String(n, ref s))
-                                if !self.flags.double_quotes.is_atom() =>
-                            {
-                                result.push(Addr::Con(Constant::String(n, s.clone())));
-                                break;
-                            }
-                            Addr::Con(Constant::EmptyList) => {
-                                break;
-                            }
-                            Addr::HeapCell(_) | Addr::StackCell(..) => {
-                                return Err(
-                                    self.error_form(MachineError::instantiation_error(), caller)
-                                )
-                            }
-                            _ => {
-                                return Err(self.error_form(
-                                    MachineError::type_error(ValidType::List, a1),
-                                    caller,
-                                ))
-                            }
-                        },
-                        _ => {
-                            return Err(self
-                                .error_form(MachineError::type_error(ValidType::List, a1), caller))
-                        }
-                    }
-                }
-
-                Ok(result)
+            Addr::Lis(l) => {
+                self.try_from_inner_list(vec![], l, caller, a1)
             }
             Addr::Con(Constant::String(n, ref s)) if !self.flags.double_quotes.is_atom() => {
                 if s.len() > n {
@@ -2601,11 +2899,117 @@ impl MachineState {
                     Ok(vec![])
                 }
             }
-            Addr::HeapCell(_) | Addr::StackCell(..) => {
+            Addr::PStrLocation(h, n) => {
+                self.try_from_partial_string(vec![], h, n, caller, a1)
+            }
+            Addr::HeapCell(_) | Addr::StackCell(..) | Addr::PStrTail(..) => {
                 Err(self.error_form(MachineError::instantiation_error(), caller))
             }
-            Addr::Con(Constant::EmptyList) => Ok(vec![]),
-            _ => Err(self.error_form(MachineError::type_error(ValidType::List, a1), caller)),
+            Addr::Con(Constant::EmptyList) => {
+                Ok(vec![])
+            }
+            _ => {
+                Err(self.error_form(MachineError::type_error(ValidType::List, a1), caller))
+            }
+        }
+    }
+
+    fn try_from_inner_list(
+        &self,
+        mut result: Vec<Addr>,
+        mut l: usize,
+        caller: MachineStub,
+        a1: Addr,
+    ) -> Result<Vec<Addr>, MachineStub> {
+        result.push(self.heap[l].as_addr(l));
+        l += 1;
+
+        loop {
+            match &self.heap[l] {
+                HeapCellValue::Addr(ref addr) =>
+                    match self.store(self.deref(addr.clone())) {
+                        Addr::Lis(hcp) => {
+                            result.push(self.heap[hcp].as_addr(hcp));
+                            l = hcp + 1;
+                        }
+                        Addr::Con(Constant::String(n, ref s))
+                            if !self.flags.double_quotes.is_atom() =>
+                        {
+                            result.push(Addr::Con(Constant::String(n, s.clone())));
+                            break;
+                        }
+                        Addr::PStrLocation(h, n) => {
+                            return self.try_from_partial_string(result, h, n, caller, a1);
+                        }
+                        Addr::Con(Constant::EmptyList) => {
+                            break;
+                        }
+                        Addr::HeapCell(_) | Addr::StackCell(..) => {
+                            return Err(self.error_form(
+                                MachineError::instantiation_error(),
+                                caller,
+                            ))
+                        }
+                        _ => {
+                            return Err(self.error_form(
+                                MachineError::type_error(ValidType::List, a1),
+                                caller,
+                            ))
+                        }
+                    },
+                _ => {
+                    return Err(self.error_form(
+                        MachineError::type_error(ValidType::List, a1),
+                        caller,
+                    ))
+                }
+            }
+        }
+
+        Ok(result)
+    }
+
+    fn try_from_partial_string(
+        &self,
+        mut chars: Vec<Addr>,
+        mut h: usize,
+        mut n: usize,
+        caller: MachineStub,
+        a1: Addr,
+    ) -> Result<Vec<Addr>, MachineStub> {
+        loop {
+            if let HeapCellValue::PartialString(ref pstr) = &self.heap[h] {
+                let s = pstr.block_as_str();
+
+                chars.extend(s[n ..].chars().map(|c| Addr::Con(Constant::Char(c))));
+
+                match self.store(self.deref(pstr.tail.clone())) {
+                    Addr::Con(Constant::EmptyList) => {
+                        return Ok(chars);
+                    }
+                    Addr::Con(Constant::String(n, ref s))
+                        if !self.flags.double_quotes.is_atom() =>
+                    {
+                        chars.push(Addr::Con(Constant::String(n, s.clone())));
+                        return Ok(chars);
+                    }
+                    Addr::Lis(l) => {
+                        return self.try_from_inner_list(chars, l, caller, a1);
+                    }
+                    Addr::PStrLocation(h1, n1) => {
+                        h = h1;
+                        n = n1;
+                    }
+                    _ => {
+                        return Err(self.error_form(
+                            MachineError::type_error(ValidType::List, a1),
+                            caller,
+                        ))
+                    }
+                }
+            } else {
+                unreachable!()
+            }
         }
     }
 
@@ -2738,7 +3142,8 @@ impl MachineState {
     }
 
     // returns true on failure.
-    pub(super) fn ground_test(&self) -> bool {
+    pub(super)
+    fn ground_test(&self) -> bool {
         let a = self.store(self.deref(self[temp_v!(1)].clone()));
 
         for v in self.acyclic_pre_order_iter(a) {
@@ -2760,7 +3165,8 @@ impl MachineState {
         self.p = CodePtr::BuiltInClause(ct, self.p.local());
     }
 
-    pub(super) fn allocate(&mut self, num_cells: usize) {
+    pub(super)
+    fn allocate(&mut self, num_cells: usize) {
         let e = self.stack.allocate_and_frame(num_cells);
         let and_frame = self.stack.index_and_frame_mut(e);
 
@@ -2771,7 +3177,8 @@ impl MachineState {
         self.p += 1;
     }
 
-    pub(super) fn deallocate(&mut self) {
+    pub(super)
+    fn deallocate(&mut self) {
         let e = self.e;
         let frame = self.stack.index_and_frame(e);
 
index e1f0265b003281f369304d272da8fee85175f86b..6415dd4e1610735e691e9f39871fe8da994f17f5 100644 (file)
@@ -19,6 +19,7 @@ pub mod machine_errors;
 pub mod machine_indices;
 pub(super) mod machine_state;
 pub mod modules;
+mod partial_string;
 mod raw_block;
 mod stack;
 pub(super) mod term_expansion;
diff --git a/src/prolog/machine/partial_string.rs b/src/prolog/machine/partial_string.rs
new file mode 100644 (file)
index 0000000..189a8ba
--- /dev/null
@@ -0,0 +1,161 @@
+use crate::prolog::machine::machine_indices::*;
+use crate::prolog::machine::raw_block::*;
+
+use std::mem;
+use std::ptr;
+use std::slice;
+use std::str;
+
+pub(crate) struct PartialStringTraits {}
+
+impl RawBlockTraits for PartialStringTraits {
+    #[inline]
+    fn init_size() -> usize {
+        0
+    }
+
+    #[inline]
+    fn align() -> usize {
+        mem::align_of::<char>()
+    }
+}
+
+pub struct PartialString {
+    pub(super) buf: RawBlock<PartialStringTraits>,
+    pub(super) tail: Addr,
+}
+
+impl Clone for PartialString {
+    #[inline]
+    fn clone(&self) -> Self {
+        self.clone_from_offset(0)
+    }
+}
+
+impl PartialEq for PartialString {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        self as *const _ == other as *const _
+    }
+}
+
+fn scan_for_terminator(src: &str) -> usize {
+    let mut terminator_idx = 0;
+
+    for c in src.chars() {
+        if c == '\u{0}' {
+            break;
+        }
+
+        terminator_idx += c.len_utf8();
+    }
+
+    terminator_idx
+}
+
+impl PartialString {
+    pub(super)
+    fn new(src: &str, h: usize) -> Option<(Self, &str)> {
+        let pstr = PartialString {
+            buf: RawBlock::with_capacity(src.len() + '\u{0}'.len_utf8()),
+            tail: Addr::PStrTail(h, 0),
+        };
+
+        unsafe {
+            pstr.append_chars(src)
+        }
+    }
+
+    unsafe fn append_chars(mut self, src: &str) -> Option<(Self, &str)> {
+        let terminator_idx = scan_for_terminator(src);
+        
+        if terminator_idx == 0 {
+            return None;
+        }
+        
+        let new_top = self.buf.new_block(terminator_idx + '\u{0}'.len_utf8());
+
+        ptr::copy(
+            src.as_ptr(),
+            self.buf.top as *mut _,
+            terminator_idx,
+        );
+
+        self.buf.top = (new_top as usize - '\u{0}'.len_utf8()) as *const _;
+        self.write_terminator_at(terminator_idx);
+
+        Some(if terminator_idx != src.len() {
+            (self, &src[terminator_idx + '\u{0}'.len_utf8() ..])
+        } else {
+            (self, "")
+        })
+    }
+
+    /* Ordinarily cloning of heap cell values is done in copy_term,
+     * so we rely on it to set the tail correctly. here it's set to PStrTail(0, 0),
+     * because we don't know its heap location. */
+    pub(super)
+    fn clone_from_offset(&self, n: usize) -> Self {
+        let mut pstr = PartialString {
+            buf: RawBlock::with_capacity(self.len() + '\u{0}'.len_utf8()),
+            tail: Addr::PStrTail(0, 0),
+        };
+
+        unsafe {
+            let len = if self.len() > n { self.len() - n } else { 0 };            
+            let new_top = pstr.buf.new_block(len + '\u{0}'.len_utf8());
+
+            if len > 0 {
+                ptr::copy(
+                    (self.buf.base as usize + n) as *mut u8,
+                    pstr.buf.base as *mut _,
+                    len,
+                );                
+            }
+
+            pstr.write_terminator_at(len);
+            pstr.buf.top = (new_top as usize - '\u{0}'.len_utf8()) as *const _;
+        }
+
+        pstr
+    }
+
+    #[inline]
+    pub(super)
+    fn write_terminator_at(&mut self, index: usize) {
+        unsafe {
+            ptr::write(
+                (self.buf.base as usize + index) as *mut u8,
+                0u8,
+            );
+        }
+    }
+
+    #[inline]
+    pub(crate)
+    fn block_as_str(&self) -> &str {
+        unsafe {
+            let slice = slice::from_raw_parts(self.buf.base, self.len());
+            str::from_utf8(slice).unwrap()
+        }
+    }
+
+    #[inline]
+    pub(crate)
+    fn tail_addr(&self) -> &Addr {
+        &self.tail
+    }
+
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.buf.top as usize - self.buf.base as usize
+    }
+
+    #[inline]
+    pub fn truncate(&mut self, len: usize) {
+        if (len + self.buf.base as usize) < self.buf.top as usize {
+            self.buf.top = (len + self.buf.base as usize) as *const _;
+            self.write_terminator_at(len);
+        }
+    }
+}
index b9e7f7edb65939ca3e4152405ef59abb341484fd..3ae383d5762b5ae703c984a36f75f3b0bd382e82 100644 (file)
@@ -37,14 +37,32 @@ impl<T: RawBlockTraits> RawBlock<T> {
     }
 
     pub(crate)
-    unsafe fn grow(&mut self) {
-        if self.size == 0 {
-            let layout = alloc::Layout::from_size_align_unchecked(T::init_size(), T::align());
+    fn with_capacity(cap: usize) -> Self {
+        let mut block = RawBlock { size: 0,
+                                   base: ptr::null(),
+                                   top: ptr::null(),
+                                   _marker: PhantomData };
+
+        unsafe {
+            block.init_at_size(cap);
+        }
+
+        block
+    }
+
+    unsafe fn init_at_size(&mut self, cap: usize) {
+        let layout = alloc::Layout::from_size_align_unchecked(cap, T::align());
 
-            self.base = alloc::alloc(layout) as *const _;
-            self.size = T::init_size();
+        self.base = alloc::alloc(layout) as *const _;
+        self.size = cap;
 
-            self.top = T::base_offset(self.base);
+        self.top = T::base_offset(self.base);
+    }
+
+    pub(super)
+    unsafe fn grow(&mut self) {
+        if self.size == 0 {
+            self.init_at_size(T::init_size());
         } else {
             let layout = alloc::Layout::from_size_align_unchecked(T::init_size(), T::align());
             let top_dist = self.top as usize - self.base as usize;
index 1eb3f912f8de4b157b6386796eb1482a97fa37a3..6915a8638eea4bbacf085dfbbfca74dca9ad5c07 100644 (file)
@@ -50,19 +50,54 @@ pub fn next_keypress() -> ContinueResult {
 }
 
 struct BrentAlgState {
-    hare: usize,
-    tortoise: usize,
+    hare: Addr,
+    tortoise: Addr,
     power: usize,
     steps: usize,
 }
 
 impl BrentAlgState {
-    fn new(hare: usize) -> Self {
+    fn new(hare: Addr) -> Self {
         BrentAlgState {
-            hare,
+            hare: hare.clone(),
             tortoise: hare,
             power: 2,
-            steps: 1,
+            steps: 0,
+        }
+    }
+
+    fn step(&mut self, hare: Addr) -> Option<CycleSearchResult> {
+        self.hare = hare;
+        self.steps += 1;
+
+        if self.tortoise == self.hare {
+            return Some(CycleSearchResult::NotList);
+        } else if self.steps == self.power {
+            self.tortoise = self.hare.clone();
+            self.power <<= 1;
+        }
+
+
+        None
+    }
+
+    fn to_result(self) -> CycleSearchResult {
+        match self.hare {
+            addr @ Addr::HeapCell(_) | addr @ Addr::StackCell(..) | addr @ Addr::AttrVar(_) => {
+                CycleSearchResult::PartialList(self.steps, addr.as_var().unwrap())
+            }
+            Addr::PStrLocation(h, n) => {
+                CycleSearchResult::PStrLocation(self.steps, h, n)
+            }
+            Addr::PStrTail(h, n) => {
+                CycleSearchResult::PStrTail(self.steps, h, n)
+            }
+            Addr::Con(Constant::EmptyList) => {
+                CycleSearchResult::ProperList(self.steps)
+            }
+            _ => {
+                CycleSearchResult::NotList
+            }
         }
     }
 }
@@ -77,56 +112,107 @@ fn is_builtin_predicate(name: &ClauseName) -> bool {
 impl MachineState {
     // a step in Brent's algorithm.
     fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option<CycleSearchResult> {
-        match self.heap[brent_st.hare].clone() {
-            HeapCellValue::NamedStr(..) => Some(CycleSearchResult::NotList),
-            HeapCellValue::Addr(addr) => match self.store(self.deref(addr)) {
-                Addr::Con(Constant::EmptyList) => {
-                    Some(CycleSearchResult::ProperList(brent_st.steps))
-                }
-                Addr::HeapCell(_) | Addr::StackCell(..) => Some(CycleSearchResult::PartialList(
+        match self.store(self.deref(brent_st.hare.clone())) {
+            Addr::Con(Constant::EmptyList) => {
+                Some(CycleSearchResult::ProperList(brent_st.steps))
+            }
+            addr @ Addr::HeapCell(_) | addr @ Addr::StackCell(..) | addr @ Addr::AttrVar(_) => {
+                Some(CycleSearchResult::PartialList(
                     brent_st.steps,
-                    brent_st.hare,
-                )),
-                Addr::Con(Constant::String(n, ref s)) if !self.flags.double_quotes.is_atom() => {
-                    Some(CycleSearchResult::String(brent_st.steps, n, s.clone()))
+                    addr.as_var().unwrap(),
+                ))
+            }
+            Addr::Con(Constant::String(n, s)) if !self.flags.double_quotes.is_atom() => {
+                if let Some(c) = s.chars().next() {
+                    brent_st.step(Addr::Con(Constant::String(n + c.len_utf8(), s)))
+                } else {
+                    Some(CycleSearchResult::CompleteString(s.len(), s))
                 }
-                Addr::Lis(l) => {
-                    brent_st.hare = l + 1;
-                    brent_st.steps += 1;
+            }
+            Addr::PStrTail(h, n) => {
+                Some(CycleSearchResult::PStrTail(brent_st.steps, h, n))
+            }
+            Addr::PStrLocation(h, n) => {
+                match &self.heap[h] {
+                    HeapCellValue::PartialString(ref pstr) => {
+                        let s = pstr.block_as_str();
 
-                    if brent_st.tortoise == brent_st.hare {
-                        return Some(CycleSearchResult::NotList);
-                    } else if brent_st.steps == brent_st.power {
-                        brent_st.tortoise = brent_st.hare;
-                        brent_st.power <<= 1;
+                        if let Some(c) = s[n ..].chars().next() {
+                            brent_st.step(Addr::PStrTail(h, n + c.len_utf8()))
+                        } else {
+                            unreachable!()
+                        }
+                    }
+                    _ => {
+                        unreachable!()
                     }
-
-                    None
-                }
-                _ => {
-                    Some(CycleSearchResult::NotList)
                 }
-            },
+            }
+            Addr::Lis(l) => {
+                brent_st.step(Addr::HeapCell(l + 1))
+            }
+            _ => {
+                Some(CycleSearchResult::NotList)
+            }
         }
     }
 
-    pub(super) fn detect_cycles_with_max(&self, max_steps: usize, addr: Addr) -> CycleSearchResult {
-        let addr = self.store(self.deref(addr));
-        let hare = match addr {
-            Addr::Lis(offset) if max_steps > 0 => offset + 1,
-            Addr::Lis(offset) => return CycleSearchResult::UntouchedList(offset),
-            Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList,
-            Addr::Con(Constant::String(n, ref s)) if !self.flags.double_quotes.is_atom() => {
-                return CycleSearchResult::String(0, n, s.clone())
+    pub(super)
+    fn detect_cycles_with_max(&self, max_steps: usize, addr: Addr) -> CycleSearchResult {
+        let hare = match self.store(self.deref(addr)) {
+            Addr::Lis(offset) if max_steps > 0 => {
+                Addr::Lis(offset)
+            }
+            Addr::Lis(offset) => {
+                return CycleSearchResult::UntouchedList(offset);
+            }
+            Addr::PStrLocation(h, n) if max_steps > 0 => {
+                Addr::PStrLocation(h, n)
+            }
+            Addr::PStrLocation(h, _) => {
+                return CycleSearchResult::UntouchedList(h);
+            }
+            Addr::PStrTail(h, n) => {
+                return CycleSearchResult::PStrTail(0, h, n);
+            }
+            Addr::Con(Constant::EmptyList) => {
+                return CycleSearchResult::EmptyList;
+            }
+            Addr::Con(Constant::String(0, ref s))
+                if max_steps > 0 && !self.flags.double_quotes.is_atom() => {
+                    if max_steps >= s.len() {
+                        return CycleSearchResult::CompleteString(s.len(), s.clone());
+                    } else {
+                        return CycleSearchResult::UntouchedString(max_steps, s.clone());
+                    }
+                }
+            Addr::Con(Constant::String(0, ref s))
+                if !self.flags.double_quotes.is_atom() => {
+                    return CycleSearchResult::UntouchedString(0, s.clone());
+                }
+            Addr::Con(Constant::String(n, ref s))
+                if max_steps > 0 && !self.flags.double_quotes.is_atom() => {
+                    if max_steps >= s.len() - n {
+                        let s = Rc::new(String::from(&s[n ..]));
+                        return CycleSearchResult::CompleteString(s.len(), s);
+                    } else {
+                        return CycleSearchResult::UntouchedString(max_steps, s.clone());
+                    }
+                }
+            Addr::Con(Constant::String(n, ref s))
+                if !self.flags.double_quotes.is_atom() => {
+                    return CycleSearchResult::UntouchedString(n, s.clone());
+                }
+            _ => {
+                return CycleSearchResult::NotList;
             }
-            _ => return CycleSearchResult::NotList,
         };
 
         let mut brent_st = BrentAlgState::new(hare);
 
         loop {
             if brent_st.steps == max_steps {
-                return CycleSearchResult::PartialList(brent_st.steps, brent_st.hare);
+                return brent_st.to_result();
             }
 
             if let Some(result) = self.brents_alg_step(&mut brent_st) {
@@ -135,15 +221,32 @@ impl MachineState {
         }
     }
 
-    pub(super) fn detect_cycles(&self, addr: Addr) -> CycleSearchResult {
+    pub(super)
+    fn detect_cycles(&self, addr: Addr) -> CycleSearchResult {
         let addr = self.store(self.deref(addr));
         let hare = match addr {
-            Addr::Lis(offset) => offset + 1,
-            Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList,
+            Addr::Lis(offset) => {
+                Addr::Lis(offset)
+            }
+            Addr::Con(Constant::EmptyList) => {
+                return CycleSearchResult::EmptyList;
+            }
+            Addr::PStrLocation(h, n) => {
+                Addr::PStrLocation(h, n)
+            }
+            Addr::PStrTail(h, n) => {
+                return CycleSearchResult::PStrTail(0, h, n);
+            }
+            Addr::Con(Constant::String(0, ref s)) if !self.flags.double_quotes.is_atom() => {
+                return CycleSearchResult::CompleteString(s.len(), s.clone());
+            }
             Addr::Con(Constant::String(n, ref s)) if !self.flags.double_quotes.is_atom() => {
-                return CycleSearchResult::String(0, n, s.clone())
+                let s = Rc::new(String::from(&s[n ..]));
+                return CycleSearchResult::CompleteString(s.len(), s);
+            }
+            _ => {
+                return CycleSearchResult::NotList;
             }
-            _ => return CycleSearchResult::NotList,
         };
 
         let mut brent_st = BrentAlgState::new(hare);
@@ -181,45 +284,32 @@ impl MachineState {
                             self.unify(xs0, xs);
                         }
                         _ => {
-                            let (max_steps, search_result) =
+                            let search_result =
                                 if let Some(max_steps) = max_steps.to_isize() {
-                                    (
-                                        max_steps,
-                                        if max_steps == -1 {
-                                            self.detect_cycles(self[temp_v!(3)].clone())
-                                        } else {
-                                            self.detect_cycles_with_max(
-                                                max_steps as usize,
-                                                self[temp_v!(3)].clone(),
-                                            )
-                                        },
-                                    )
+                                    if max_steps == -1 {
+                                        self.detect_cycles(self[temp_v!(3)].clone())
+                                    } else {
+                                        self.detect_cycles_with_max(
+                                            max_steps as usize,
+                                            self[temp_v!(3)].clone(),
+                                        )
+                                    }
                                 } else {
-                                    (-1, self.detect_cycles(self[temp_v!(3)].clone()))
+                                    self.detect_cycles(self[temp_v!(3)].clone())
                                 };
 
                             match search_result {
-                                CycleSearchResult::String(n, offset, s) => {
-                                    if max_steps == -1 {
-                                        self.finalize_skip_max_list(
-                                            s[offset ..].len(),
-                                            Addr::Con(Constant::EmptyList),
-                                        )
-                                    } else {
-                                        let i = (max_steps as usize) - n;
-
-                                        if s.len() < i {
-                                            self.finalize_skip_max_list(
-                                                s[n + offset + i..].len(),
-                                                Addr::Con(Constant::EmptyList),
-                                            )
-                                        } else {
-                                            self.finalize_skip_max_list(
-                                                i + n + offset,
-                                                Addr::Con(Constant::String(n + i + offset, s)),
-                                            )
-                                        }
-                                    }
+                                CycleSearchResult::PStrTail(steps, h, n) => {
+                                    self.finalize_skip_max_list(steps, Addr::PStrTail(h, n));
+                                }
+                                CycleSearchResult::PStrLocation(steps, h, n) => {
+                                    self.finalize_skip_max_list(steps, Addr::PStrLocation(h, n));
+                                }
+                                CycleSearchResult::CompleteString(n, _) => {
+                                    self.finalize_skip_max_list(n, Addr::Con(Constant::EmptyList));
+                                }
+                                CycleSearchResult::UntouchedString(n, s) => {
+                                    self.finalize_skip_max_list(0, Addr::Con(Constant::String(n, s)));
                                 }
                                 CycleSearchResult::UntouchedList(l) => {
                                     self.finalize_skip_max_list(0, Addr::Lis(l))
@@ -227,11 +317,11 @@ impl MachineState {
                                 CycleSearchResult::EmptyList => {
                                     self.finalize_skip_max_list(0, Addr::Con(Constant::EmptyList))
                                 }
-                                CycleSearchResult::PartialList(n, hc) => {
-                                    self.finalize_skip_max_list(n, Addr::HeapCell(hc))
+                                CycleSearchResult::PartialList(n, r) => {
+                                    self.finalize_skip_max_list(n, r.as_addr())
                                 }
-                                CycleSearchResult::ProperList(n) => {
-                                    self.finalize_skip_max_list(n, Addr::Con(Constant::EmptyList))
+                                CycleSearchResult::ProperList(steps) => {
+                                    self.finalize_skip_max_list(steps, Addr::Con(Constant::EmptyList))
                                 }
                                 CycleSearchResult::NotList => {
                                     let xs0 = self[temp_v!(3)].clone();
@@ -329,7 +419,7 @@ impl MachineState {
 
     fn copy_findall_solution(&mut self, lh_offset: usize, copy_target: Addr) -> usize {
         let threshold = self.lifted_heap.h() - lh_offset;
-        
+
         let mut copy_ball_term = CopyBallTerm::new(
             &mut self.stack,
             &mut self.heap,
@@ -341,6 +431,7 @@ impl MachineState {
         copy_ball_term.push(HeapCellValue::Addr(Addr::HeapCell(threshold + 2)));
 
         copy_term(copy_ball_term, copy_target, AttrVarPolicy::DeepCopy);
+
         threshold + lh_offset + 2
     }
 
@@ -364,8 +455,7 @@ impl MachineState {
                     self.lifted_heap.truncate(lh_offset);
                 } else {
                     let threshold = self.lifted_heap.h() - lh_offset;
-                    self.lifted_heap
-                        .push(HeapCellValue::Addr(addr_constr(threshold)));
+                    self.lifted_heap.push(HeapCellValue::Addr(addr_constr(threshold)));
                 }
             }
             _ => self.fail = true,
@@ -569,7 +659,8 @@ impl MachineState {
         }
     }
 
-    pub(super) fn system_call(
+    pub(super)
+    fn system_call(
         &mut self,
         ct: &SystemClauseType,
         code_repo: &CodeRepo,
@@ -835,6 +926,78 @@ impl MachineState {
                     },
                 }
             }
+            &SystemClauseType::CreatePartialString => {
+                let atom = match self.store(self.deref(self[temp_v!(1)].clone())) {
+                    Addr::Con(Constant::Atom(atom, _)) => {
+                        atom
+                    }
+                    _ => {
+                        unreachable!()
+                    }
+                };
+
+                let h = self.heap.h();
+                let pstr =
+                    match self.heap.allocate_pstr(atom.as_str()) {
+                        Some(pstr_addr) => {
+                            pstr_addr
+                        }
+                        None => {
+                            let stub = MachineError::functor_stub(clause_name!("partial_string"), 3);
+                            let err = MachineError::type_error(
+                                ValidType::Character,
+                                Addr::Con(Constant::Char('\u{0}')),
+                            );
+
+                            return Err(self.error_form(err, stub));
+                        }
+                    };
+
+                let pstr_tail = match &self.heap[h] {
+                    HeapCellValue::PartialString(ref pstr) => {
+                        pstr.tail_addr().clone()
+                    }
+                    _ => {
+                        unreachable!()
+                    }
+                };
+
+                self.unify(self[temp_v!(2)].clone(), pstr);
+
+                if !self.fail {
+                    self.unify(self[temp_v!(3)].clone(), pstr_tail);
+                }
+            }
+            &SystemClauseType::IsPartialString => {
+                let pstr = self.store(self.deref(self[temp_v!(1)].clone()));
+
+                match pstr {
+                    Addr::PStrLocation(..) => {
+                    }
+                    _ => {
+                        self.fail = true;
+                    }
+                }
+            }
+            &SystemClauseType::PartialStringTail => {
+                let pstr = self.store(self.deref(self[temp_v!(1)].clone()));
+
+                match pstr {
+                    Addr::PStrLocation(h, _) => {
+                        let tail = if let HeapCellValue::PartialString(ref pstr) = &self.heap[h] {
+                            pstr.tail.clone()
+                        } else {
+                            unreachable!()
+                        };
+
+                        let target = self[temp_v!(2)].clone();
+                        self.unify(tail, target);
+                    }
+                    _ => {
+                        unreachable!()
+                    }
+                }
+            }
             &SystemClauseType::NumberToChars => {
                 let n = self[temp_v!(1)].clone();
                 let chs = self[temp_v!(2)].clone();
@@ -925,7 +1088,7 @@ impl MachineState {
                             Addr::Con(Constant::Integer(n)) => {
                                 let c = self.int_to_char_code(&n, "char_code", 2)?;
                                 let c = std::char::from_u32(c).unwrap();
-                                
+
                                 self.unify(Addr::Con(Constant::Char(c)), addr.clone());
                             }
                             _ => self.fail = true,
@@ -1119,9 +1282,12 @@ impl MachineState {
 
                         for addr in self.lifted_heap.iter_mut_from(old_threshold + 1) {
                             match addr {
-                                &mut HeapCellValue::Addr(ref mut addr) => {
+                                HeapCellValue::Addr(ref mut addr) => {
                                     *addr -= self.heap.h() + lh_offset
                                 }
+                                HeapCellValue::PartialString(ref mut pstr) => {
+                                    pstr.tail -= self.heap.h() + lh_offset;
+                                }
                                 _ => {}
                             }
                         }
@@ -1579,22 +1745,34 @@ impl MachineState {
 
                             for value in self.lifted_heap.iter_from(lh_offset) {
                                 last_index = self.heap.h();
-                                
-                                match value.clone() {
-                                    HeapCellValue::Addr(addr) => {
-                                        self.heap.push(HeapCellValue::Addr(addr + h));
+
+                                match value {
+                                    HeapCellValue::Addr(ref addr) => {
+                                        self.heap.push(HeapCellValue::Addr(addr.clone() + h));
+                                    }
+                                    HeapCellValue::PartialString(ref pstr) => {
+                                        let mut new_pstr = pstr.clone();
+                                        new_pstr.tail = pstr.tail.clone() + h;
+                                        self.heap.push(HeapCellValue::PartialString(new_pstr));
                                     }
                                     value => {
-                                        self.heap.push(value);
+                                        self.heap.push(value.clone());
                                     }
                                 }
                             }
 
                             if last_index < self.heap.h() {
-                                if let HeapCellValue::Addr(addr) = self.heap[last_index].clone() {
+                                let addr_opt =
+                                    if let HeapCellValue::Addr(ref addr) = &self.heap[last_index] {
+                                        Some(addr.clone())
+                                    } else {
+                                        None
+                                    };
+
+                                addr_opt.map(|addr| {
                                     let diff = self[temp_v!(3)].clone();
                                     self.unify(diff, addr);
-                                }
+                                });
                             }
 
                             self.lifted_heap.truncate(lh_offset);
@@ -1617,13 +1795,18 @@ impl MachineState {
                         } else {
                             let h = self.heap.h();
 
-                            for addr in self.lifted_heap.iter_from(lh_offset).cloned() {
+                            for addr in self.lifted_heap.iter_from(lh_offset) {
                                 match addr {
-                                    HeapCellValue::Addr(addr) => {
-                                        self.heap.push(HeapCellValue::Addr(addr + h))
+                                    HeapCellValue::Addr(ref addr) => {
+                                        self.heap.push(HeapCellValue::Addr(addr.clone() + h))
+                                    }
+                                    HeapCellValue::PartialString(ref pstr) => {
+                                        let mut new_pstr = pstr.clone();
+                                        new_pstr.tail = pstr.tail.clone() + h;
+                                        self.heap.push(HeapCellValue::PartialString(new_pstr));
                                     }
                                     value => {
-                                        self.heap.push(value);
+                                        self.heap.push(value.clone());
                                     }
                                 }
                             }
index f76694fc2c80d22b2b5dbc2066d5bac6ec97f615..96a52919646406bb79bdd353c73da15b437b9639 100644 (file)
@@ -154,6 +154,9 @@ impl fmt::Display for HeapCellValue {
             &HeapCellValue::NamedStr(arity, ref name, None) => {
                 write!(f, "{}/{}", name.as_str(), arity)
             }
+            &HeapCellValue::PartialString(ref pstr) => {
+                write!(f, "pstr ( buf: {}, tail: {} )", pstr.block_as_str(), pstr.tail_addr())
+            }
         }
     }
 }
@@ -179,6 +182,8 @@ impl fmt::Display for Addr {
             &Addr::HeapCell(h) => write!(f, "Addr::HeapCell({})", h),
             &Addr::StackCell(fr, sc) => write!(f, "Addr::StackCell({}, {})", fr, sc),
             &Addr::Str(s) => write!(f, "Addr::Str({})", s),
+            &Addr::PStrLocation(h, n) => write!(f, "Addr::PStrLocation({}, {})", h, n),
+            &Addr::PStrTail(h, n) => write!(f, "Addr::PStrTail({}, {})", h, n),
         }
     }
 }