CopyTermWithoutAttrVars,
CheckCutPoint,
CopyToLiftedHeap,
+ CreatePartialString,
DeleteAttribute,
DeleteHeadAttribute,
DynamicModuleResolution(usize),
GetModuleClause,
GetNextDBRef,
GetNextOpDBRef,
+ IsPartialString,
LookupDBRef,
LookupOpDBRef,
Halt,
NumberToChars,
NumberToCodes,
OpDeclaration,
+ PartialStringTail,
PointsToContinuationResetMarker,
REPL(REPLCodePtr),
ReadQueryTerm,
&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) => {
&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 => {
("$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),
("$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),
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()),
}
}
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() {
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) => {
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())
}
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
+ }
}
}
}
}
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 {
})
}
}
+ _ => {
+ // This is the partial string case. We never clone a partial string
+ // for printing purposes, so.. this.
+ unreachable!()
+ }
}
}
:- 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
)
:- 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).
)
; 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))
+ ).
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;
}
}
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;
}
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 {
}
}
_ => {
- 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))
}
};
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) => {
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()
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;
+ }
}
}
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),
}
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;
#[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,
}
}
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 {
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;
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)]
AttrVar(usize),
HeapCell(usize),
StackCell(usize, usize),
+ PStrTail(usize, usize),
}
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),
}
}
}
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
+ }
}
}
}
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
+ }
}
}
&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,
}
}
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,
}
}
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 {
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,
}
}
}
}
-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),
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)
+ }
}
}
}
}
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;
}
}
- 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(),
});
}
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;
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());
}
}
+ 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));
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 => {
+ }
}
}
}
(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 {
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;
}
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));
(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] {
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() =>
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));
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));
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));
}
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 {
};
}
- 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();
}
}
+ 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) => {
_ => {
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)));
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() {
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;
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))
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))
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() =>
{
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(..))),
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;
}
(
HeapCellValue::Addr(Addr::StackCell(..)),
HeapCellValue::Addr(Addr::HeapCell(_)),
)
+ | (
+ HeapCellValue::Addr(Addr::StackCell(..)),
+ HeapCellValue::Addr(Addr::PStrTail(..)),
+ )
| (
HeapCellValue::Addr(Addr::StackCell(..)),
HeapCellValue::Addr(Addr::AttrVar(_)),
| (
HeapCellValue::Addr(Addr::Con(Constant::Integer(..))),
HeapCellValue::Addr(Addr::AttrVar(_)),
- ) => {
+ )
+ | (
+ HeapCellValue::Addr(Addr::Con(Constant::Integer(..))),
+ HeapCellValue::Addr(Addr::PStrTail(..)),
+ )=> {
return Ordering::Greater;
}
(
| (
HeapCellValue::Addr(Addr::Con(Constant::Float(..))),
HeapCellValue::Addr(Addr::AttrVar(_)),
+ )
+ | (
+ HeapCellValue::Addr(Addr::Con(Constant::Float(..))),
+ HeapCellValue::Addr(Addr::PStrTail(..)),
) => {
return Ordering::Greater;
}
| (
HeapCellValue::Addr(Addr::Con(Constant::Rational(..))),
HeapCellValue::Addr(Addr::AttrVar(_)),
+ )
+ | (
+ HeapCellValue::Addr(Addr::Con(Constant::Rational(..))),
+ HeapCellValue::Addr(Addr::PStrTail(..)),
) => {
return Ordering::Greater;
}
| (
HeapCellValue::Addr(Addr::Con(Constant::String(..))),
HeapCellValue::Addr(Addr::AttrVar(_)),
+ )
+ | (
+ HeapCellValue::Addr(Addr::Con(Constant::String(..))),
+ HeapCellValue::Addr(Addr::PStrTail(..)),
) => {
return Ordering::Greater;
}
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(_))),
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,
};
}
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;
+ }
};
}
}
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)
};
}
_ => 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()));
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 {
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!()
+ }
}
}
}
// 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) {
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);
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);
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;
--- /dev/null
+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);
+ }
+ }
+}
}
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;
}
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
+ }
}
}
}
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) {
}
}
- 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);
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))
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();
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,
copy_ball_term.push(HeapCellValue::Addr(Addr::HeapCell(threshold + 2)));
copy_term(copy_ball_term, copy_target, AttrVarPolicy::DeepCopy);
+
threshold + lh_offset + 2
}
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,
}
}
- pub(super) fn system_call(
+ pub(super)
+ fn system_call(
&mut self,
ct: &SystemClauseType,
code_repo: &CodeRepo,
},
}
}
+ &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();
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,
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;
+ }
_ => {}
}
}
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);
} 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());
}
}
}
&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())
+ }
}
}
}
&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),
}
}
}