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