add redone partial strings (#24, #95)

This commit is contained in:
Mark Thom
2020-02-19 21:34:09 -07:00
parent 617f803355
commit 0457b38e41
16 changed files with 1422 additions and 290 deletions

View File

@@ -171,6 +171,7 @@ pub enum SystemClauseType {
CopyTermWithoutAttrVars, CopyTermWithoutAttrVars,
CheckCutPoint, CheckCutPoint,
CopyToLiftedHeap, CopyToLiftedHeap,
CreatePartialString,
DeleteAttribute, DeleteAttribute,
DeleteHeadAttribute, DeleteHeadAttribute,
DynamicModuleResolution(usize), DynamicModuleResolution(usize),
@@ -194,6 +195,7 @@ pub enum SystemClauseType {
GetModuleClause, GetModuleClause,
GetNextDBRef, GetNextDBRef,
GetNextOpDBRef, GetNextOpDBRef,
IsPartialString,
LookupDBRef, LookupDBRef,
LookupOpDBRef, LookupOpDBRef,
Halt, Halt,
@@ -215,6 +217,7 @@ pub enum SystemClauseType {
NumberToChars, NumberToChars,
NumberToCodes, NumberToCodes,
OpDeclaration, OpDeclaration,
PartialStringTail,
PointsToContinuationResetMarker, PointsToContinuationResetMarker,
REPL(REPLCodePtr), REPL(REPLCodePtr),
ReadQueryTerm, ReadQueryTerm,
@@ -275,11 +278,12 @@ impl SystemClauseType {
&SystemClauseType::CallContinuation => clause_name!("$call_continuation"), &SystemClauseType::CallContinuation => clause_name!("$call_continuation"),
&SystemClauseType::CharCode => clause_name!("$char_code"), &SystemClauseType::CharCode => clause_name!("$char_code"),
&SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"), &SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"),
&SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
&SystemClauseType::ClearAttributeGoals => clause_name!("$clear_attribute_goals"), &SystemClauseType::ClearAttributeGoals => clause_name!("$clear_attribute_goals"),
&SystemClauseType::CloneAttributeGoals => clause_name!("$clone_attribute_goals"), &SystemClauseType::CloneAttributeGoals => clause_name!("$clone_attribute_goals"),
&SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"), &SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"),
&SystemClauseType::CopyTermWithoutAttrVars => clause_name!("$copy_term_without_attr_vars"), &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::CompileBatch) => clause_name!("$compile_batch"),
&SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"), &SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"),
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule) => { &SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule) => {
@@ -339,6 +343,8 @@ impl SystemClauseType {
&SystemClauseType::InstallInferenceCounter => { &SystemClauseType::InstallInferenceCounter => {
clause_name!("$install_inference_counter") 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::LiftedHeapLength => clause_name!("$lh_length"),
&SystemClauseType::Maybe => clause_name!("maybe"), &SystemClauseType::Maybe => clause_name!("maybe"),
&SystemClauseType::ModuleAssertDynamicPredicateToFront => { &SystemClauseType::ModuleAssertDynamicPredicateToFront => {
@@ -423,6 +429,7 @@ impl SystemClauseType {
("$clone_attribute_goals", 1) => Some(SystemClauseType::CloneAttributeGoals), ("$clone_attribute_goals", 1) => Some(SystemClauseType::CloneAttributeGoals),
("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber), ("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber),
("$copy_term_without_attr_vars", 2) => Some(SystemClauseType::CopyTermWithoutAttrVars), ("$copy_term_without_attr_vars", 2) => Some(SystemClauseType::CopyTermWithoutAttrVars),
("$create_partial_string", 3) => Some(SystemClauseType::CreatePartialString),
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint), ("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)), ("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)),
("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap), ("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
@@ -435,6 +442,8 @@ impl SystemClauseType {
("$module_call", _) => Some(SystemClauseType::DynamicModuleResolution(arity - 2)), ("$module_call", _) => Some(SystemClauseType::DynamicModuleResolution(arity - 2)),
("$enqueue_attribute_goal", 1) => Some(SystemClauseType::EnqueueAttributeGoal), ("$enqueue_attribute_goal", 1) => Some(SystemClauseType::EnqueueAttributeGoal),
("$enqueue_attr_var", 1) => Some(SystemClauseType::EnqueueAttributedVar), ("$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_term", 2) => Some(SystemClauseType::ExpandTerm),
("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal), ("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
("$fetch_attribute_goals", 1) => Some(SystemClauseType::FetchAttributeGoals), ("$fetch_attribute_goals", 1) => Some(SystemClauseType::FetchAttributeGoals),

View File

@@ -28,14 +28,19 @@ impl<'a> HCPreOrderIterator<'a> {
fn follow_heap(&mut self, h: usize) -> Addr { fn follow_heap(&mut self, h: usize) -> Addr {
match &self.machine_st.heap[h] { match &self.machine_st.heap[h] {
&HeapCellValue::NamedStr(arity, _, _) => { HeapCellValue::NamedStr(arity, _, _) => {
for idx in (1..arity + 1).rev() { for idx in (1..arity + 1).rev() {
self.state_stack.push(Addr::HeapCell(h + idx)); 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()),
} }
} }
@@ -76,7 +81,28 @@ impl<'a> HCPreOrderIterator<'a> {
da 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 da
} }
Addr::Str(s) => { Addr::Str(s) => {
@@ -92,7 +118,31 @@ impl<'a> Iterator for HCPreOrderIterator<'a> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
self.state_stack.pop().map(|a| match self.follow(a) { self.state_stack.pop().map(|a| match self.follow(a) {
Addr::HeapCell(h) => { 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) => { Addr::StackCell(fr, sc) => {
HeapCellValue::Addr(self.machine_st.stack.index_and_frame(fr)[sc].clone()) HeapCellValue::Addr(self.machine_st.stack.index_and_frame(fr)[sc].clone())

View File

@@ -616,10 +616,18 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
match addr { match addr {
Addr::AttrVar(h) => Some(format!("_{}", h)), Addr::AttrVar(h) => {
Addr::HeapCell(h) | Addr::Lis(h) | Addr::Str(h) => Some(format!("_{}", h)), Some(format!("_{}", h))
Addr::StackCell(fr, sc) => Some(format!("_s_{}_{}", fr, sc)), }
_ => None, 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::Con(c)) => self.print_constant(c, &op),
HeapCellValue::Addr(Addr::Lis(_)) => { HeapCellValue::Addr(Addr::Lis(_)) | HeapCellValue::Addr(Addr::PStrLocation(..)) => {
if self.ignore_ops { if self.ignore_ops {
self.format_struct(2, clause_name!(".")); self.format_struct(2, clause_name!("."));
} else { } 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!()
}
} }
} }

View File

@@ -5,7 +5,9 @@
:- module(non_iso, [bb_b_put/2, bb_get/2, bb_put/2, call_cleanup/2, :- 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, 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) :- forall(Generate, Test) :-
\+ (Generate, \+ Test). \+ (Generate, \+ Test).
@@ -154,3 +156,20 @@ set_random(Seed) :-
) )
; throw(error(instantiation_error, set_random/1)) ; 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))
).

View File

@@ -13,9 +13,9 @@ pub enum AttrVarPolicy {
pub(crate) trait CopierTarget: IndexMut<usize, Output = HeapCellValue> { pub(crate) trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
fn threshold(&self) -> usize; fn threshold(&self) -> usize;
fn push(&mut self, _: HeapCellValue); fn push(&mut self, val: HeapCellValue);
fn store(&self, _: Addr) -> Addr; fn store(&self, val: Addr) -> Addr;
fn deref(&self, _: Addr) -> Addr; fn deref(&self, val: Addr) -> Addr;
fn stack(&mut self) -> &mut Stack; fn stack(&mut self) -> &mut Stack;
} }
@@ -51,10 +51,10 @@ impl<T: CopierTarget> CopyTermState<T> {
} }
fn copied_list(&mut self, addr: usize) -> bool { 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)) => { HeapCellValue::Addr(Addr::Lis(addr)) | HeapCellValue::Addr(Addr::HeapCell(addr)) => {
if addr >= self.old_h { if *addr >= self.old_h {
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(addr)); *self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(*addr));
self.scan += 1; self.scan += 1;
return true; return true;
} }
@@ -65,34 +65,52 @@ impl<T: CopierTarget> CopyTermState<T> {
false 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) { fn copy_list(&mut self, addr: usize) {
if self.copied_list(addr) { if self.copied_list(addr) {
return; return;
} }
let threshold = self.target.threshold(); let threshold = self.target.threshold();
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(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); self.target.push(HeapCellValue::Addr(ra.clone()));
let rd = self.target.store(self.target.deref(ra));
self.target.push(hcv); let hcv = HeapCellValue::Addr(self.target[addr + 1].as_addr(addr + 1));
let hcv = self.target[addr + 1].clone();
self.target.push(hcv); self.target.push(hcv);
match rd.clone() { match rd.clone() {
Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => { Addr::AttrVar(h) | Addr::HeapCell(h) | Addr::PStrTail(h, _)
if h >= self.old_h => {
self.target[threshold] = HeapCellValue::Addr(rd) self.target[threshold] = HeapCellValue::Addr(rd)
} }
ra @ Addr::AttrVar(_) | ra @ Addr::HeapCell(..) | ra @ Addr::StackCell(..) => { var @ Addr::AttrVar(_)
| var @ Addr::HeapCell(..)
| var @ Addr::StackCell(..)
| var @ Addr::PStrTail(..) => {
if ra == rd { if ra == rd {
self.reinstantiate_var(ra, threshold); self.reinstantiate_var(var, threshold);
if let AttrVarPolicy::StripAttributes = self.attr_var_policy { 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)); self.target[addr] = HeapCellValue::Addr(Addr::HeapCell(threshold));
} }
} else { } 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)) self.target[addr] = HeapCellValue::Addr(Addr::Lis(threshold))
} }
}; };
@@ -108,6 +130,74 @@ impl<T: CopierTarget> CopyTermState<T> {
self.scan += 1; 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) { fn reinstantiate_var(&mut self, addr: Addr, frontier: usize) {
match addr { match addr {
Addr::HeapCell(h) => { Addr::HeapCell(h) => {
@@ -126,6 +216,22 @@ impl<T: CopierTarget> CopyTermState<T> {
HeapCellValue::Addr(Addr::StackCell(fr, sc)), 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) => { Addr::AttrVar(h) => {
let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy { let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
self.target.threshold() self.target.threshold()
@@ -203,16 +309,35 @@ impl<T: CopierTarget> CopyTermState<T> {
self.target.push(HeapCellValue::Addr(addr)); self.target.push(HeapCellValue::Addr(addr));
while self.scan < self.target.threshold() { while self.scan < self.target.threshold() {
match self.value_at_scan().clone() { match self.value_at_scan() {
HeapCellValue::NamedStr(..) => self.scan += 1, HeapCellValue::NamedStr(..) => {
HeapCellValue::Addr(addr) => match addr { self.scan += 1;
Addr::Lis(addr) => self.copy_list(addr), }
HeapCellValue::Addr(ref addr) => {
match addr.clone() {
Addr::Lis(addr) => {
self.copy_list(addr);
}
addr @ Addr::AttrVar(_) addr @ Addr::AttrVar(_)
| addr @ Addr::HeapCell(_) | addr @ Addr::HeapCell(_)
| addr @ Addr::StackCell(..) => self.copy_var(addr), | addr @ Addr::StackCell(..)
Addr::Str(addr) => self.copy_structure(addr), | addr @ Addr::PStrTail(..) => {
Addr::Con(_) | Addr::DBRef(_) => self.scan += 1, 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 { match r {
Ref::AttrVar(h) | Ref::HeapCell(h) => Ref::AttrVar(h) | Ref::HeapCell(h) =>
self.target[h] = value, 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) => Ref::StackCell(fr, sc) =>
self.target.stack().index_and_frame_mut(fr)[sc] = value.as_addr(0), self.target.stack().index_and_frame_mut(fr)[sc] = value.as_addr(0),
} }

View File

@@ -3,6 +3,7 @@ use core::marker::PhantomData;
use crate::prolog_parser::ast::*; use crate::prolog_parser::ast::*;
use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::partial_string::*;
use crate::prolog::machine::raw_block::*; use crate::prolog::machine::raw_block::*;
use std::mem; use std::mem;
@@ -149,12 +150,93 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
#[inline] #[inline]
pub(crate) pub(crate)
fn take<U: RawBlockTraits>(&mut self) -> HeapTemplate<U> { fn allocate_pstr(&mut self, mut src: &str) -> Option<Addr> {
unsafe { let orig_h = self.h();
HeapTemplate {
buf: mem::transmute::<RawBlock<T>, RawBlock<U>>(self.buf.take()), loop {
_marker: PhantomData, 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,
} }
} }

View File

@@ -391,9 +391,12 @@ impl EvalError {
pub(super) enum CycleSearchResult { pub(super) enum CycleSearchResult {
EmptyList, EmptyList,
NotList, NotList,
PartialList(usize, usize), // the list length (up to max), and an offset into the heap. PartialList(usize, Ref), // the list length (up to max), and an offset into the heap.
ProperList(usize), // the list length. ProperList(usize), // the list length.
String(usize, usize, Rc<String>), // the number of bytes iterated, the offset, the string. 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). UntouchedList(usize), // the address of an uniterated Addr::Lis(address).
} }

View File

@@ -7,6 +7,7 @@ use crate::prolog::forms::*;
use crate::prolog::machine::code_repo::CodeRepo; use crate::prolog::machine::code_repo::CodeRepo;
use crate::prolog::machine::Ball; use crate::prolog::machine::Ball;
use crate::prolog::machine::heap::*; use crate::prolog::machine::heap::*;
use crate::prolog::machine::partial_string::*;
use crate::prolog::machine::raw_block::RawBlockTraits; use crate::prolog::machine::raw_block::RawBlockTraits;
use crate::prolog::instructions::*; use crate::prolog::instructions::*;
use crate::prolog::rug::Integer; use crate::prolog::rug::Integer;
@@ -46,6 +47,8 @@ pub enum Addr {
HeapCell(usize), HeapCell(usize),
StackCell(usize, usize), StackCell(usize, usize),
Str(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)] #[derive(Clone, Copy, Hash, Eq, PartialEq)]
@@ -53,6 +56,7 @@ pub enum Ref {
AttrVar(usize), AttrVar(usize),
HeapCell(usize), HeapCell(usize),
StackCell(usize, usize), StackCell(usize, usize),
PStrTail(usize, usize),
} }
impl Ref { impl Ref {
@@ -61,6 +65,7 @@ impl Ref {
Ref::AttrVar(h) => Addr::AttrVar(h), Ref::AttrVar(h) => Addr::AttrVar(h),
Ref::HeapCell(h) => Addr::HeapCell(h), Ref::HeapCell(h) => Addr::HeapCell(h),
Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc), Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc),
Ref::PStrTail(h, n) => Addr::PStrTail(h, n),
} }
} }
} }
@@ -75,8 +80,11 @@ impl PartialEq<Ref> for Addr {
impl PartialOrd<Ref> for Addr { impl PartialOrd<Ref> for Addr {
fn partial_cmp(&self, r: &Ref) -> Option<Ordering> { fn partial_cmp(&self, r: &Ref) -> Option<Ordering> {
match self { match self {
&Addr::StackCell(fr, sc) => match *r { &Addr::StackCell(fr, sc) => {
Ref::AttrVar(_) | Ref::HeapCell(_) => Some(Ordering::Greater), match *r {
Ref::AttrVar(_) | Ref::HeapCell(_) | Ref::PStrTail(..) => {
Some(Ordering::Greater)
}
Ref::StackCell(fr1, sc1) => { Ref::StackCell(fr1, sc1) => {
if fr1 < fr || (fr1 == fr && sc1 < sc) { if fr1 < fr || (fr1 == fr && sc1 < sc) {
Some(Ordering::Greater) Some(Ordering::Greater)
@@ -86,12 +94,37 @@ impl PartialOrd<Ref> for Addr {
Some(Ordering::Less) Some(Ordering::Less)
} }
} }
}, }
&Addr::HeapCell(h) | &Addr::AttrVar(h) => match r { }
&Ref::StackCell(..) => Some(Ordering::Less), &Addr::HeapCell(h) | &Addr::AttrVar(h) => {
&Ref::AttrVar(h1) | &Ref::HeapCell(h1) => h.partial_cmp(&h1), match r {
}, Ref::StackCell(..) => {
_ => None, Some(Ordering::Less)
}
Ref::AttrVar(h1) | Ref::HeapCell(h1) => {
h.partial_cmp(h1)
}
Ref::PStrTail(h1, _) => {
h.partial_cmp(h1)
}
}
}
&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 { impl Addr {
pub fn is_ref(&self) -> bool { pub fn is_ref(&self) -> bool {
match self { match self {
&Addr::AttrVar(_) | &Addr::HeapCell(_) | &Addr::StackCell(_, _) => true, Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::AttrVar(_) | Addr::PStrTail(..) => {
_ => false, true
}
_ => {
false
}
} }
} }
@@ -109,6 +146,7 @@ impl Addr {
&Addr::AttrVar(h) => Some(Ref::AttrVar(h)), &Addr::AttrVar(h) => Some(Ref::AttrVar(h)),
&Addr::HeapCell(h) => Some(Ref::HeapCell(h)), &Addr::HeapCell(h) => Some(Ref::HeapCell(h)),
&Addr::StackCell(fr, sc) => Some(Ref::StackCell(fr, sc)), &Addr::StackCell(fr, sc) => Some(Ref::StackCell(fr, sc)),
&Addr::PStrTail(h, n) => Some(Ref::PStrTail(h, n)),
_ => None, _ => None,
} }
} }
@@ -130,6 +168,8 @@ impl Add<usize> for Addr {
Addr::AttrVar(h) => Addr::AttrVar(h + rhs), Addr::AttrVar(h) => Addr::AttrVar(h + rhs),
Addr::HeapCell(h) => Addr::HeapCell(h + rhs), Addr::HeapCell(h) => Addr::HeapCell(h + rhs),
Addr::Str(s) => Addr::Str(s + 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, _ => self,
} }
} }
@@ -145,6 +185,8 @@ impl Sub<i64> for Addr {
Addr::AttrVar(h) => Addr::AttrVar(h + rhs.abs() as usize), Addr::AttrVar(h) => Addr::AttrVar(h + rhs.abs() as usize),
Addr::HeapCell(h) => Addr::HeapCell(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::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, _ => self,
} }
} else { } else {
@@ -162,6 +204,8 @@ impl Sub<usize> for Addr {
Addr::AttrVar(h) => Addr::AttrVar(h - rhs), Addr::AttrVar(h) => Addr::AttrVar(h - rhs),
Addr::HeapCell(h) => Addr::HeapCell(h - rhs), Addr::HeapCell(h) => Addr::HeapCell(h - rhs),
Addr::Str(s) => Addr::Str(s - 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, _ => 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)] #[derive(Clone, Copy)]
pub enum TrailRef { pub enum TrailRef {
Ref(Ref), Ref(Ref),
@@ -200,13 +234,21 @@ impl From<Ref> for TrailRef {
pub enum HeapCellValue { pub enum HeapCellValue {
Addr(Addr), Addr(Addr),
NamedStr(usize, ClauseName, Option<SharedOpDesc>), // arity, name, precedence/Specifier if it has one. NamedStr(usize, ClauseName, Option<SharedOpDesc>), // arity, name, precedence/Specifier if it has one.
PartialString(PartialString),
} }
impl HeapCellValue { impl HeapCellValue {
pub fn as_addr(&self, focus: usize) -> Addr { pub fn as_addr(&self, focus: usize) -> Addr {
match self { match self {
&HeapCellValue::Addr(ref a) => a.clone(), HeapCellValue::Addr(ref a) => {
&HeapCellValue::NamedStr(_, _, _) => Addr::Str(focus), a.clone()
}
HeapCellValue::NamedStr(_, _, _) => {
Addr::Str(focus)
}
HeapCellValue::PartialString(_) => {
Addr::PStrLocation(focus, 0)
}
} }
} }
} }

View File

@@ -25,19 +25,22 @@ pub struct Ball {
} }
impl Ball { impl Ball {
pub(super) fn new() -> Self { pub(super)
fn new() -> Self {
Ball { Ball {
boundary: 0, boundary: 0,
stub: Heap::new(), stub: Heap::new(),
} }
} }
pub(super) fn reset(&mut self) { pub(super)
fn reset(&mut self) {
self.boundary = 0; self.boundary = 0;
self.stub.clear(); self.stub.clear();
} }
pub(super) fn take(&mut self) -> Ball { pub(super)
fn take(&mut self) -> Ball {
let boundary = self.boundary; let boundary = self.boundary;
self.boundary = 0; 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 diff = self.boundary as i64 - h as i64;
let mut stub = Heap::new(); 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 { stub.push(match heap_value {
HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr - diff), HeapCellValue::Addr(ref addr) => HeapCellValue::Addr(addr.clone() - diff),
heap_value => heap_value, 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( machine_st.attr_var_init.backtrack(
attr_var_init_queue_b, attr_var_init_queue_b,
attr_var_init_bindings_b); attr_var_init_bindings_b,
);
machine_st.stack.truncate(machine_st.b); machine_st.stack.truncate(machine_st.b);
machine_st.b = machine_st.stack.index_or_frame(b).prelude.b; machine_st.b = machine_st.stack.index_or_frame(b).prelude.b;

View File

@@ -119,15 +119,34 @@ impl MachineState {
self.flags self.flags
} }
pub(crate) fn store(&self, addr: Addr) -> Addr { pub(crate)
fn store(&self, addr: Addr) -> Addr {
match addr { match addr {
Addr::AttrVar(h) | Addr::HeapCell(h) => self.heap[h].as_addr(h), Addr::AttrVar(h) | Addr::HeapCell(h) => {
Addr::StackCell(fr, sc) => self.stack.index_and_frame(fr)[sc].clone(), self.heap[h].as_addr(h)
addr => addr, }
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 { loop {
let value = self.store(addr.clone()); 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) { pub(super) fn bind(&mut self, r1: Ref, a2: Addr) {
let t1 = self.store(r1.as_addr()); let t1 = self.store(r1.as_addr());
let t2 = self.store(a2.clone()); let t2 = self.store(a2.clone());
if t1.is_ref() && (!t2.is_ref() || a2 < r1) { if t1.is_ref() && (!t2.is_ref() || a2 < r1) {
match r1 { match r1 {
Ref::StackCell(fr, sc) => self.stack.index_and_frame_mut(fr)[sc] = t2, Ref::StackCell(fr, sc) => {
Ref::HeapCell(h) => self.heap[h] = HeapCellValue::Addr(t2), self.stack.index_and_frame_mut(fr)[sc] = t2;
Ref::AttrVar(h) => return self.bind_attr_var(h, 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.trail(TrailRef::from(r1));
@@ -180,9 +222,14 @@ impl MachineState {
self.heap[h] = HeapCellValue::Addr(t1); self.heap[h] = HeapCellValue::Addr(t1);
self.trail(TrailRef::Ref(Ref::HeapCell(h))); self.trail(TrailRef::Ref(Ref::HeapCell(h)));
} }
Some(Ref::AttrVar(h)) => Some(Ref::AttrVar(h)) => {
self.bind_attr_var(h, t1), self.bind_attr_var(h, t1);
None => {} }
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)) => { (Addr::StackCell(fr, sc), addr) | (addr, Addr::StackCell(fr, sc)) => {
self.bind_with_occurs_check(Ref::StackCell(fr, sc), addr) 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)) => { (Addr::Lis(a1), Addr::Str(a2)) | (Addr::Str(a2), Addr::Lis(a1)) => {
if let &HeapCellValue::NamedStr(n2, ref f2, _) = &self.heap[a2] { if let &HeapCellValue::NamedStr(n2, ref f2, _) = &self.heap[a2] {
if f2.as_str() == "." && n2 == 2 { if f2.as_str() == "." && n2 == 2 {
@@ -274,7 +324,9 @@ impl MachineState {
self.fail = true; self.fail = true;
} }
(Addr::Lis(a1), Addr::Con(Constant::String(n, s))) (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) { if self.deconstruct_chars(s, n, a1, &mut pdl) {
continue; continue;
} }
@@ -291,6 +343,63 @@ impl MachineState {
self.fail = true; 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)) => { (Addr::Lis(a1), Addr::Lis(a2)) => {
pdl.push(Addr::HeapCell(a1)); pdl.push(Addr::HeapCell(a1));
pdl.push(Addr::HeapCell(a2)); pdl.push(Addr::HeapCell(a2));
@@ -353,17 +462,14 @@ impl MachineState {
(Addr::AttrVar(h), addr) | (addr, Addr::AttrVar(h)) => { (Addr::AttrVar(h), addr) | (addr, Addr::AttrVar(h)) => {
self.bind(Ref::AttrVar(h), addr); self.bind(Ref::AttrVar(h), addr);
} }
(Addr::HeapCell(h), _) => { (Addr::HeapCell(h), addr) | (addr, Addr::HeapCell(h)) => {
self.bind(Ref::HeapCell(h), d2); self.bind(Ref::HeapCell(h), addr);
} }
(_, Addr::HeapCell(h)) => { (Addr::StackCell(fr, sc), addr) | (addr, Addr::StackCell(fr, sc)) => {
self.bind(Ref::HeapCell(h), d1); self.bind(Ref::StackCell(fr, sc), addr);
} }
(Addr::StackCell(fr, sc), _) => { (Addr::PStrTail(h, n), addr) | (addr, Addr::PStrTail(h, n)) => {
self.bind(Ref::StackCell(fr, sc), d2); self.bind(Ref::PStrTail(h, n), addr);
}
(_, Addr::StackCell(fr, sc)) => {
self.bind(Ref::StackCell(fr, sc), d1);
} }
(Addr::Lis(a1), Addr::Str(a2)) | (Addr::Str(a2), Addr::Lis(a1)) => { (Addr::Lis(a1), Addr::Str(a2)) | (Addr::Str(a2), Addr::Lis(a1)) => {
if let &HeapCellValue::NamedStr(n2, ref f2, _) = &self.heap[a2] { if let &HeapCellValue::NamedStr(n2, ref f2, _) = &self.heap[a2] {
@@ -381,7 +487,8 @@ impl MachineState {
self.fail = true; self.fail = true;
} }
(Addr::Lis(a1), Addr::Con(Constant::String(n, s))) (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) { if self.deconstruct_chars(s, n, a1, &mut pdl) {
continue; continue;
} }
@@ -398,6 +505,63 @@ impl MachineState {
self.fail = true; 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)) => { (Addr::Lis(a1), Addr::Lis(a2)) => {
pdl.push(Addr::HeapCell(a1)); pdl.push(Addr::HeapCell(a1));
pdl.push(Addr::HeapCell(a2)); pdl.push(Addr::HeapCell(a2));
@@ -449,6 +613,12 @@ impl MachineState {
self.tr += 1; 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) => { TrailRef::AttrVarHeapLink(h) => {
if h < self.hb { if h < self.hb {
self.trail.push(TrailRef::AttrVarHeapLink(h)); self.trail.push(TrailRef::AttrVarHeapLink(h));
@@ -485,6 +655,14 @@ impl MachineState {
TrailRef::Ref(Ref::StackCell(fr, sc)) => { TrailRef::Ref(Ref::StackCell(fr, sc)) => {
self.stack.index_and_frame_mut(fr)[sc] = Addr::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) => { TrailRef::AttrVarHeapLink(h) => {
self.heap[h] = HeapCellValue::Addr(Addr::HeapCell(h)); self.heap[h] = HeapCellValue::Addr(Addr::HeapCell(h));
} }
@@ -508,6 +686,7 @@ impl MachineState {
match self.trail[i] { match self.trail[i] {
TrailRef::Ref(Ref::AttrVar(tr_i)) TrailRef::Ref(Ref::AttrVar(tr_i))
| TrailRef::Ref(Ref::HeapCell(tr_i)) | TrailRef::Ref(Ref::HeapCell(tr_i))
| TrailRef::Ref(Ref::PStrTail(tr_i, _))
| TrailRef::AttrVarHeapLink(tr_i) | TrailRef::AttrVarHeapLink(tr_i)
| TrailRef::AttrVarListLink(tr_i, _) => { | TrailRef::AttrVarListLink(tr_i, _) => {
if tr_i >= hb { 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() { if let Some(c) = s[offset ..].chars().next() {
let h = self.heap.h(); 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) { pub(super) fn execute_fact_instr(&mut self, instr: &FactInstruction) {
match instr { match instr {
&FactInstruction::GetConstant(_, ref c, reg) => { &FactInstruction::GetConstant(_, ref c, reg) => {
@@ -1410,9 +1613,13 @@ impl MachineState {
self.fail = true self.fail = true
} }
}, },
Addr::PStrLocation(h, n) => {
self.get_partial_string_list(h, n)
}
addr @ Addr::AttrVar(_) addr @ Addr::AttrVar(_)
| addr @ Addr::StackCell(..) | addr @ Addr::StackCell(..)
| addr @ Addr::HeapCell(_) => { | addr @ Addr::HeapCell(_)
| addr @ Addr::PStrTail(..) => {
let h = self.heap.h(); let h = self.heap.h();
self.heap.push(HeapCellValue::Addr(Addr::Lis(h + 1))); self.heap.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
@@ -1558,7 +1765,10 @@ impl MachineState {
let addr = self.store(self.deref(a1)); let addr = self.store(self.deref(a1));
let offset = match addr { 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)) => { Addr::Con(Constant::String(n, ref s)) => {
if !self.flags.double_quotes.is_atom() { if !self.flags.double_quotes.is_atom() {
if n >= s.len() { if n >= s.len() {
@@ -1570,9 +1780,15 @@ impl MachineState {
c c
} }
} }
Addr::Con(_) => c, Addr::Con(_) => {
Addr::Lis(_) => l, c
Addr::Str(_) => s, }
Addr::Lis(_) | Addr::PStrLocation(..) => {
l
}
Addr::Str(_) => {
s
}
Addr::DBRef(_) => { Addr::DBRef(_) => {
self.fail = true; self.fail = true;
return; return;
@@ -1827,7 +2043,7 @@ impl MachineState {
let n = self.store(self.deref(self[temp_v!(1)].clone())); let n = self.store(self.deref(self[temp_v!(1)].clone()));
match n { match n {
Addr::HeapCell(_) | Addr::StackCell(..) => Addr::HeapCell(_) | Addr::StackCell(..) | Addr::PStrTail(..) =>
// 8.5.2.3 a) // 8.5.2.3 a)
{ {
return Err(self.error_form(MachineError::instantiation_error(), stub)) 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())); let term = self.store(self.deref(self[temp_v!(2)].clone()));
match term { match term {
Addr::HeapCell(_) | Addr::StackCell(..) => Addr::HeapCell(_) | Addr::StackCell(..) | Addr::PStrTail(..) =>
// 8.5.2.3 b) // 8.5.2.3 b)
{ {
return Err(self.error_form(MachineError::instantiation_error(), stub)) return Err(self.error_form(MachineError::instantiation_error(), stub))
@@ -1876,6 +2092,31 @@ impl MachineState {
self.fail = true; 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)) Addr::Con(Constant::String(o, ref s))
if !self.flags.double_quotes.is_atom() && !s[o ..].is_empty() => if !self.flags.double_quotes.is_atom() && !s[o ..].is_empty() =>
{ {
@@ -1986,6 +2227,52 @@ impl MachineState {
while let Some((v1, v2)) = iter.next() { while let Some((v1, v2)) = iter.next() {
match (v1, v2) { 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::Lis(_)),
HeapCellValue::Addr(Addr::Con(Constant::String(..))), HeapCellValue::Addr(Addr::Con(Constant::String(..))),
@@ -2055,8 +2342,27 @@ impl MachineState {
return hc1.cmp(&hc2); 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::HeapCell(_)), _)
| (HeapCellValue::Addr(Addr::AttrVar(_)), _) => { | (HeapCellValue::Addr(Addr::AttrVar(_)), _)
| (HeapCellValue::Addr(Addr::PStrTail(..)), _) => {
return Ordering::Less; return Ordering::Less;
} }
( (
@@ -2075,6 +2381,10 @@ impl MachineState {
HeapCellValue::Addr(Addr::StackCell(..)), HeapCellValue::Addr(Addr::StackCell(..)),
HeapCellValue::Addr(Addr::HeapCell(_)), HeapCellValue::Addr(Addr::HeapCell(_)),
) )
| (
HeapCellValue::Addr(Addr::StackCell(..)),
HeapCellValue::Addr(Addr::PStrTail(..)),
)
| ( | (
HeapCellValue::Addr(Addr::StackCell(..)), HeapCellValue::Addr(Addr::StackCell(..)),
HeapCellValue::Addr(Addr::AttrVar(_)), HeapCellValue::Addr(Addr::AttrVar(_)),
@@ -2091,7 +2401,11 @@ impl MachineState {
| ( | (
HeapCellValue::Addr(Addr::Con(Constant::Integer(..))), HeapCellValue::Addr(Addr::Con(Constant::Integer(..))),
HeapCellValue::Addr(Addr::AttrVar(_)), HeapCellValue::Addr(Addr::AttrVar(_)),
) => { )
| (
HeapCellValue::Addr(Addr::Con(Constant::Integer(..))),
HeapCellValue::Addr(Addr::PStrTail(..)),
)=> {
return Ordering::Greater; return Ordering::Greater;
} }
( (
@@ -2116,6 +2430,10 @@ impl MachineState {
| ( | (
HeapCellValue::Addr(Addr::Con(Constant::Float(..))), HeapCellValue::Addr(Addr::Con(Constant::Float(..))),
HeapCellValue::Addr(Addr::AttrVar(_)), HeapCellValue::Addr(Addr::AttrVar(_)),
)
| (
HeapCellValue::Addr(Addr::Con(Constant::Float(..))),
HeapCellValue::Addr(Addr::PStrTail(..)),
) => { ) => {
return Ordering::Greater; return Ordering::Greater;
} }
@@ -2141,6 +2459,10 @@ impl MachineState {
| ( | (
HeapCellValue::Addr(Addr::Con(Constant::Rational(..))), HeapCellValue::Addr(Addr::Con(Constant::Rational(..))),
HeapCellValue::Addr(Addr::AttrVar(_)), HeapCellValue::Addr(Addr::AttrVar(_)),
)
| (
HeapCellValue::Addr(Addr::Con(Constant::Rational(..))),
HeapCellValue::Addr(Addr::PStrTail(..)),
) => { ) => {
return Ordering::Greater; return Ordering::Greater;
} }
@@ -2168,6 +2490,10 @@ impl MachineState {
| ( | (
HeapCellValue::Addr(Addr::Con(Constant::String(..))), HeapCellValue::Addr(Addr::Con(Constant::String(..))),
HeapCellValue::Addr(Addr::AttrVar(_)), HeapCellValue::Addr(Addr::AttrVar(_)),
)
| (
HeapCellValue::Addr(Addr::Con(Constant::String(..))),
HeapCellValue::Addr(Addr::PStrTail(..)),
) => { ) => {
return Ordering::Greater; return Ordering::Greater;
} }
@@ -2216,6 +2542,10 @@ impl MachineState {
HeapCellValue::Addr(Addr::Con(Constant::Atom(..))), HeapCellValue::Addr(Addr::Con(Constant::Atom(..))),
HeapCellValue::Addr(Addr::StackCell(..)), HeapCellValue::Addr(Addr::StackCell(..)),
) => return Ordering::Greater, ) => 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::Atom(..))),
HeapCellValue::Addr(Addr::Con(Constant::Float(_))), HeapCellValue::Addr(Addr::Con(Constant::Float(_))),
@@ -2330,7 +2660,7 @@ impl MachineState {
let d = self.store(self.deref(self[r1].clone())); let d = self.store(self.deref(self[r1].clone()));
match d { match d {
Addr::Str(_) | Addr::Lis(_) => self.p += 1, Addr::Str(_) | Addr::Lis(_) | Addr::PStrLocation(..) => self.p += 1,
_ => self.fail = true, _ => self.fail = true,
}; };
} }
@@ -2362,16 +2692,24 @@ impl MachineState {
let d = self.store(self.deref(self[r1].clone())); let d = self.store(self.deref(self[r1].clone()));
match d { match d {
Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) => self.fail = true, Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) | Addr::PStrTail(..) => {
_ => self.p += 1, self.fail = true;
}
_ => {
self.p += 1;
}
}; };
} }
&InlinedClauseType::IsVar(r1) => { &InlinedClauseType::IsVar(r1) => {
let d = self.store(self.deref(self[r1].clone())); let d = self.store(self.deref(self[r1].clone()));
match d { match d {
Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(_, _) => self.p += 1, Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::PStrTail(..) => {
_ => self.fail = true, self.p += 1;
}
_ => {
self.fail = true;
}
}; };
} }
} }
@@ -2414,8 +2752,8 @@ impl MachineState {
Addr::Lis(self.heap.h()) Addr::Lis(self.heap.h())
} else { } else {
let h = self.heap.h(); let h = self.heap.h();
self.heap self.heap.push(HeapCellValue::NamedStr(arity as usize, name, spec));
.push(HeapCellValue::NamedStr(arity as usize, name, spec));
Addr::Str(h) Addr::Str(h)
}; };
@@ -2448,11 +2786,11 @@ impl MachineState {
} }
_ => self.fail = true, _ => self.fail = true,
}, },
Addr::Lis(_) => { Addr::Lis(_) | Addr::PStrLocation(..) => {
let shared_op_desc = fetch_op_spec(clause_name!("."), 2, None, &indices.op_dir); 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) 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 name = self.store(self.deref(self[temp_v!(2)].clone()));
let arity = self.store(self.deref(self[temp_v!(3)].clone())); let arity = self.store(self.deref(self[temp_v!(3)].clone()));
@@ -2551,15 +2889,45 @@ impl MachineState {
let a1 = self.store(self.deref(self[r].clone())); let a1 = self.store(self.deref(self[r].clone()));
match a1.clone() { match a1.clone() {
Addr::Lis(mut l) => { Addr::Lis(l) => {
let mut result = Vec::new(); 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::from_iter(s[n ..].chars().map(|c| Addr::Con(Constant::Char(c)))))
} else {
Ok(vec![])
}
}
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))
}
}
}
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)); result.push(self.heap[l].as_addr(l));
l += 1; l += 1;
loop { loop {
match self.heap[l].clone() { match &self.heap[l] {
HeapCellValue::Addr(addr) => match self.store(self.deref(addr)) { HeapCellValue::Addr(ref addr) =>
match self.store(self.deref(addr.clone())) {
Addr::Lis(hcp) => { Addr::Lis(hcp) => {
result.push(self.heap[hcp].as_addr(hcp)); result.push(self.heap[hcp].as_addr(hcp));
l = hcp + 1; l = hcp + 1;
@@ -2570,13 +2938,17 @@ impl MachineState {
result.push(Addr::Con(Constant::String(n, s.clone()))); result.push(Addr::Con(Constant::String(n, s.clone())));
break; break;
} }
Addr::PStrLocation(h, n) => {
return self.try_from_partial_string(result, h, n, caller, a1);
}
Addr::Con(Constant::EmptyList) => { Addr::Con(Constant::EmptyList) => {
break; break;
} }
Addr::HeapCell(_) | Addr::StackCell(..) => { Addr::HeapCell(_) | Addr::StackCell(..) => {
return Err( return Err(self.error_form(
self.error_form(MachineError::instantiation_error(), caller) MachineError::instantiation_error(),
) caller,
))
} }
_ => { _ => {
return Err(self.error_form( return Err(self.error_form(
@@ -2586,27 +2958,59 @@ impl MachineState {
} }
}, },
_ => { _ => {
return Err(self return Err(self.error_form(
.error_form(MachineError::type_error(ValidType::List, a1), caller)) MachineError::type_error(ValidType::List, a1),
caller,
))
} }
} }
} }
Ok(result) Ok(result)
} }
Addr::Con(Constant::String(n, ref s)) if !self.flags.double_quotes.is_atom() => {
if s.len() > n { fn try_from_partial_string(
Ok(Vec::from_iter(s[n ..].chars().map(|c| Addr::Con(Constant::Char(c))))) &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 { } else {
Ok(vec![]) unreachable!()
} }
} }
Addr::HeapCell(_) | Addr::StackCell(..) => {
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)),
}
} }
// see 8.4.4.3 of Draft Technical Corrigendum 2 for an error guide. // see 8.4.4.3 of Draft Technical Corrigendum 2 for an error guide.
@@ -2738,7 +3142,8 @@ impl MachineState {
} }
// returns true on failure. // 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())); let a = self.store(self.deref(self[temp_v!(1)].clone()));
for v in self.acyclic_pre_order_iter(a) { for v in self.acyclic_pre_order_iter(a) {
@@ -2760,7 +3165,8 @@ impl MachineState {
self.p = CodePtr::BuiltInClause(ct, self.p.local()); 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 e = self.stack.allocate_and_frame(num_cells);
let and_frame = self.stack.index_and_frame_mut(e); let and_frame = self.stack.index_and_frame_mut(e);
@@ -2771,7 +3177,8 @@ impl MachineState {
self.p += 1; self.p += 1;
} }
pub(super) fn deallocate(&mut self) { pub(super)
fn deallocate(&mut self) {
let e = self.e; let e = self.e;
let frame = self.stack.index_and_frame(e); let frame = self.stack.index_and_frame(e);

View File

@@ -19,6 +19,7 @@ pub mod machine_errors;
pub mod machine_indices; pub mod machine_indices;
pub(super) mod machine_state; pub(super) mod machine_state;
pub mod modules; pub mod modules;
mod partial_string;
mod raw_block; mod raw_block;
mod stack; mod stack;
pub(super) mod term_expansion; pub(super) mod term_expansion;

View File

@@ -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);
}
}
}

View File

@@ -37,14 +37,32 @@ impl<T: RawBlockTraits> RawBlock<T> {
} }
pub(crate) pub(crate)
unsafe fn grow(&mut self) { fn with_capacity(cap: usize) -> Self {
if self.size == 0 { let mut block = RawBlock { size: 0,
let layout = alloc::Layout::from_size_align_unchecked(T::init_size(), T::align()); 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.base = alloc::alloc(layout) as *const _;
self.size = T::init_size(); 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 { } else {
let layout = alloc::Layout::from_size_align_unchecked(T::init_size(), T::align()); let layout = alloc::Layout::from_size_align_unchecked(T::init_size(), T::align());
let top_dist = self.top as usize - self.base as usize; let top_dist = self.top as usize - self.base as usize;

View File

@@ -50,19 +50,54 @@ pub fn next_keypress() -> ContinueResult {
} }
struct BrentAlgState { struct BrentAlgState {
hare: usize, hare: Addr,
tortoise: usize, tortoise: Addr,
power: usize, power: usize,
steps: usize, steps: usize,
} }
impl BrentAlgState { impl BrentAlgState {
fn new(hare: usize) -> Self { fn new(hare: Addr) -> Self {
BrentAlgState { BrentAlgState {
hare, hare: hare.clone(),
tortoise: hare, tortoise: hare,
power: 2, 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 { impl MachineState {
// a step in Brent's algorithm. // a step in Brent's algorithm.
fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option<CycleSearchResult> { fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option<CycleSearchResult> {
match self.heap[brent_st.hare].clone() { match self.store(self.deref(brent_st.hare.clone())) {
HeapCellValue::NamedStr(..) => Some(CycleSearchResult::NotList),
HeapCellValue::Addr(addr) => match self.store(self.deref(addr)) {
Addr::Con(Constant::EmptyList) => { Addr::Con(Constant::EmptyList) => {
Some(CycleSearchResult::ProperList(brent_st.steps)) Some(CycleSearchResult::ProperList(brent_st.steps))
} }
Addr::HeapCell(_) | Addr::StackCell(..) => Some(CycleSearchResult::PartialList( addr @ Addr::HeapCell(_) | addr @ Addr::StackCell(..) | addr @ Addr::AttrVar(_) => {
Some(CycleSearchResult::PartialList(
brent_st.steps, brent_st.steps,
brent_st.hare, addr.as_var().unwrap(),
)), ))
Addr::Con(Constant::String(n, ref s)) if !self.flags.double_quotes.is_atom() => { }
Some(CycleSearchResult::String(brent_st.steps, n, s.clone())) 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::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 let Some(c) = s[n ..].chars().next() {
brent_st.step(Addr::PStrTail(h, n + c.len_utf8()))
} else {
unreachable!()
}
}
_ => {
unreachable!()
}
}
} }
Addr::Lis(l) => { Addr::Lis(l) => {
brent_st.hare = l + 1; brent_st.step(Addr::HeapCell(l + 1))
brent_st.steps += 1;
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;
}
None
} }
_ => { _ => {
Some(CycleSearchResult::NotList) Some(CycleSearchResult::NotList)
} }
},
} }
} }
pub(super) fn detect_cycles_with_max(&self, max_steps: usize, addr: Addr) -> CycleSearchResult { pub(super)
let addr = self.store(self.deref(addr)); fn detect_cycles_with_max(&self, max_steps: usize, addr: Addr) -> CycleSearchResult {
let hare = match addr { let hare = match self.store(self.deref(addr)) {
Addr::Lis(offset) if max_steps > 0 => offset + 1, Addr::Lis(offset) if max_steps > 0 => {
Addr::Lis(offset) => return CycleSearchResult::UntouchedList(offset), Addr::Lis(offset)
Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList, }
Addr::Con(Constant::String(n, ref s)) if !self.flags.double_quotes.is_atom() => { Addr::Lis(offset) => {
return CycleSearchResult::String(0, n, s.clone()) 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); let mut brent_st = BrentAlgState::new(hare);
loop { loop {
if brent_st.steps == max_steps { 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) { 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 addr = self.store(self.deref(addr));
let hare = match addr { let hare = match addr {
Addr::Lis(offset) => offset + 1, Addr::Lis(offset) => {
Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList, Addr::Lis(offset)
Addr::Con(Constant::String(n, ref s)) if !self.flags.double_quotes.is_atom() => { }
return CycleSearchResult::String(0, n, s.clone()) 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() => {
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); let mut brent_st = BrentAlgState::new(hare);
@@ -181,10 +284,8 @@ impl MachineState {
self.unify(xs0, xs); self.unify(xs0, xs);
} }
_ => { _ => {
let (max_steps, search_result) = let search_result =
if let Some(max_steps) = max_steps.to_isize() { if let Some(max_steps) = max_steps.to_isize() {
(
max_steps,
if max_steps == -1 { if max_steps == -1 {
self.detect_cycles(self[temp_v!(3)].clone()) self.detect_cycles(self[temp_v!(3)].clone())
} else { } else {
@@ -192,34 +293,23 @@ impl MachineState {
max_steps as usize, max_steps as usize,
self[temp_v!(3)].clone(), self[temp_v!(3)].clone(),
) )
}, }
)
} else { } else {
(-1, self.detect_cycles(self[temp_v!(3)].clone())) self.detect_cycles(self[temp_v!(3)].clone())
}; };
match search_result { match search_result {
CycleSearchResult::String(n, offset, s) => { CycleSearchResult::PStrTail(steps, h, n) => {
if max_steps == -1 { self.finalize_skip_max_list(steps, Addr::PStrTail(h, n));
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::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) => { CycleSearchResult::UntouchedList(l) => {
self.finalize_skip_max_list(0, Addr::Lis(l)) self.finalize_skip_max_list(0, Addr::Lis(l))
@@ -227,11 +317,11 @@ impl MachineState {
CycleSearchResult::EmptyList => { CycleSearchResult::EmptyList => {
self.finalize_skip_max_list(0, Addr::Con(Constant::EmptyList)) self.finalize_skip_max_list(0, Addr::Con(Constant::EmptyList))
} }
CycleSearchResult::PartialList(n, hc) => { CycleSearchResult::PartialList(n, r) => {
self.finalize_skip_max_list(n, Addr::HeapCell(hc)) self.finalize_skip_max_list(n, r.as_addr())
} }
CycleSearchResult::ProperList(n) => { CycleSearchResult::ProperList(steps) => {
self.finalize_skip_max_list(n, Addr::Con(Constant::EmptyList)) self.finalize_skip_max_list(steps, Addr::Con(Constant::EmptyList))
} }
CycleSearchResult::NotList => { CycleSearchResult::NotList => {
let xs0 = self[temp_v!(3)].clone(); let xs0 = self[temp_v!(3)].clone();
@@ -341,6 +431,7 @@ impl MachineState {
copy_ball_term.push(HeapCellValue::Addr(Addr::HeapCell(threshold + 2))); copy_ball_term.push(HeapCellValue::Addr(Addr::HeapCell(threshold + 2)));
copy_term(copy_ball_term, copy_target, AttrVarPolicy::DeepCopy); copy_term(copy_ball_term, copy_target, AttrVarPolicy::DeepCopy);
threshold + lh_offset + 2 threshold + lh_offset + 2
} }
@@ -364,8 +455,7 @@ impl MachineState {
self.lifted_heap.truncate(lh_offset); self.lifted_heap.truncate(lh_offset);
} else { } else {
let threshold = self.lifted_heap.h() - lh_offset; let threshold = self.lifted_heap.h() - lh_offset;
self.lifted_heap self.lifted_heap.push(HeapCellValue::Addr(addr_constr(threshold)));
.push(HeapCellValue::Addr(addr_constr(threshold)));
} }
} }
_ => self.fail = true, _ => self.fail = true,
@@ -569,7 +659,8 @@ impl MachineState {
} }
} }
pub(super) fn system_call( pub(super)
fn system_call(
&mut self, &mut self,
ct: &SystemClauseType, ct: &SystemClauseType,
code_repo: &CodeRepo, 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 => { &SystemClauseType::NumberToChars => {
let n = self[temp_v!(1)].clone(); let n = self[temp_v!(1)].clone();
let chs = self[temp_v!(2)].clone(); let chs = self[temp_v!(2)].clone();
@@ -1119,9 +1282,12 @@ impl MachineState {
for addr in self.lifted_heap.iter_mut_from(old_threshold + 1) { for addr in self.lifted_heap.iter_mut_from(old_threshold + 1) {
match addr { match addr {
&mut HeapCellValue::Addr(ref mut addr) => { HeapCellValue::Addr(ref mut addr) => {
*addr -= self.heap.h() + lh_offset *addr -= self.heap.h() + lh_offset
} }
HeapCellValue::PartialString(ref mut pstr) => {
pstr.tail -= self.heap.h() + lh_offset;
}
_ => {} _ => {}
} }
} }
@@ -1580,21 +1746,33 @@ impl MachineState {
for value in self.lifted_heap.iter_from(lh_offset) { for value in self.lifted_heap.iter_from(lh_offset) {
last_index = self.heap.h(); last_index = self.heap.h();
match value.clone() { match value {
HeapCellValue::Addr(addr) => { HeapCellValue::Addr(ref addr) => {
self.heap.push(HeapCellValue::Addr(addr + h)); 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 => { value => {
self.heap.push(value); self.heap.push(value.clone());
} }
} }
} }
if last_index < self.heap.h() { 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(); let diff = self[temp_v!(3)].clone();
self.unify(diff, addr); self.unify(diff, addr);
} });
} }
self.lifted_heap.truncate(lh_offset); self.lifted_heap.truncate(lh_offset);
@@ -1617,13 +1795,18 @@ impl MachineState {
} else { } else {
let h = self.heap.h(); 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 { match addr {
HeapCellValue::Addr(addr) => { HeapCellValue::Addr(ref addr) => {
self.heap.push(HeapCellValue::Addr(addr + h)) 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 => { value => {
self.heap.push(value); self.heap.push(value.clone());
} }
} }
} }

View File

@@ -154,6 +154,9 @@ impl fmt::Display for HeapCellValue {
&HeapCellValue::NamedStr(arity, ref name, None) => { &HeapCellValue::NamedStr(arity, ref name, None) => {
write!(f, "{}/{}", name.as_str(), arity) 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::HeapCell(h) => write!(f, "Addr::HeapCell({})", h),
&Addr::StackCell(fr, sc) => write!(f, "Addr::StackCell({}, {})", fr, sc), &Addr::StackCell(fr, sc) => write!(f, "Addr::StackCell({}, {})", fr, sc),
&Addr::Str(s) => write!(f, "Addr::Str({})", s), &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),
} }
} }
} }