From 7884a2004286dd1430611fbcc2f1a7d5cb8ada86 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 23 Aug 2018 01:24:26 -0600 Subject: [PATCH] support strings as char lists in term comparisons --- src/prolog/heap_iter.rs | 21 ++++-- src/prolog/heap_print.rs | 58 +++++++---------- src/prolog/machine/machine_state.rs | 20 +++++- src/prolog/machine/machine_state_impl.rs | 82 ++++++++++++++++-------- src/prolog/string_list.rs | 8 +-- 5 files changed, 113 insertions(+), 76 deletions(-) diff --git a/src/prolog/heap_iter.rs b/src/prolog/heap_iter.rs index 4b9544e1..e5f045ba 100644 --- a/src/prolog/heap_iter.rs +++ b/src/prolog/heap_iter.rs @@ -39,17 +39,28 @@ impl<'a> HCPreOrderIterator<'a> { { let da = self.machine_st.store(self.machine_st.deref(addr)); - match &da { - &Addr::Con(_) => da, - &Addr::Lis(a) => { + match da { + Addr::Con(Constant::String(ref s)) + if self.machine_st.machine_flags().double_quotes.is_chars() => { + if let Some(c) = s.head() { + let tail = s.tail(); + + self.state_stack.push(Addr::Con(Constant::String(tail))); + self.state_stack.push(Addr::Con(Constant::Char(c))); + } + + Addr::Con(Constant::String(s.clone())) + }, + Addr::Con(_) => da, + Addr::Lis(a) => { self.state_stack.push(Addr::HeapCell(a + 1)); self.state_stack.push(Addr::HeapCell(a)); da }, - &Addr::HeapCell(_) | &Addr::StackCell(_, _) => + Addr::HeapCell(_) | Addr::StackCell(_, _) => da, - &Addr::Str(s) => + Addr::Str(s) => self.follow_heap(s) // record terms of structure. } } diff --git a/src/prolog/heap_print.rs b/src/prolog/heap_print.rs index 2ae1f57c..a7ae573b 100644 --- a/src/prolog/heap_print.rs +++ b/src/prolog/heap_print.rs @@ -1,9 +1,8 @@ use prolog::ast::*; use prolog::num::*; use prolog::heap_iter::*; -use prolog::machine::machine_state::{DoubleQuotes, MachineState}; +use prolog::machine::machine_state::MachineState; use prolog::ordered_float::OrderedFloat; -use prolog::string_list::*; use std::cell::Cell; use std::collections::{HashMap, HashSet}; @@ -12,7 +11,6 @@ use std::rc::Rc; #[derive(Clone)] pub enum TokenOrRedirect { Atom(ClauseName), - Char(char), NumberedVar(String), Redirect, Open, @@ -292,24 +290,6 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter> } } - fn expand_char_list(&mut self, s: StringList) { - let cell = Rc::new(Cell::new(true)); - let cursor = s.cursor(); - - self.state_stack.push(TokenOrRedirect::CloseList(cell.clone())); - - if !s.is_empty() { - for c in s.borrow()[cursor ..].chars().rev() { - self.state_stack.push(TokenOrRedirect::Char(c)); - self.state_stack.push(TokenOrRedirect::Comma); - } - - self.state_stack.pop(); - } - - self.state_stack.push(TokenOrRedirect::OpenList(cell)); - } - fn print_char(&mut self, c: char) { if non_quoted_token(c) { self.outputter.push_char(c); @@ -351,8 +331,13 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter> Constant::Number(n) => self.outputter.append(&format!("{}", n)), Constant::String(s) => - if let DoubleQuotes::Chars = self.machine_st.machine_flags().double_quotes { - self.expand_char_list(s); + if self.machine_st.machine_flags().double_quotes.is_chars() { + if !s.is_empty() { + self.push_list(); + } else if !self.at_cdr("") { + self.outputter.append("[]"); + } + // self.expand_char_list(s); } else { // for now, == DoubleQuotes::Atom self.outputter.append("\""); self.outputter.append(s.borrow().as_str()); @@ -362,6 +347,18 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter> self.outputter.append(&format!("u{}", i)) } } + + fn push_list(&mut self) { + let cell = Rc::new(Cell::new(true)); + + self.state_stack.push(TokenOrRedirect::CloseList(cell.clone())); + + self.state_stack.push(TokenOrRedirect::Redirect); + self.state_stack.push(TokenOrRedirect::HeadTailSeparator); // bar + self.state_stack.push(TokenOrRedirect::Redirect); + + self.state_stack.push(TokenOrRedirect::OpenList(cell)); + } fn handle_heap_term(&mut self, iter: &mut HCPreOrderIterator) { @@ -381,17 +378,8 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter> }, HeapCellValue::Addr(Addr::Con(c)) => self.print_constant(c), - HeapCellValue::Addr(Addr::Lis(_)) => { - let cell = Rc::new(Cell::new(true)); - - self.state_stack.push(TokenOrRedirect::CloseList(cell.clone())); - - self.state_stack.push(TokenOrRedirect::Redirect); - self.state_stack.push(TokenOrRedirect::HeadTailSeparator); // bar - self.state_stack.push(TokenOrRedirect::Redirect); - - self.state_stack.push(TokenOrRedirect::OpenList(cell)); - }, + HeapCellValue::Addr(Addr::Lis(_)) => + self.push_list(), HeapCellValue::Addr(addr) => self.print_offset(addr) } } @@ -417,8 +405,6 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter> match loc_data { TokenOrRedirect::Atom(atom) => self.outputter.append(atom.as_str()), - TokenOrRedirect::Char(c) => - self.print_char(c), TokenOrRedirect::NumberedVar(num_var) => self.outputter.append(num_var.as_str()), TokenOrRedirect::Redirect => diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index 950ae36b..6ff632cd 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -622,7 +622,15 @@ pub(crate) trait CallPolicy: Any { return_from_clause!(machine_st.last_call, machine_st) }, &BuiltInClauseType::Eq => { - machine_st.fail = machine_st.eq_test(); + let a1 = machine_st[temp_v!(1)].clone(); + let a2 = machine_st[temp_v!(2)].clone(); + + machine_st.fail = if let Ordering::Equal = machine_st.compare_term_test(&a1, &a2) { + false + } else { + true + }; + return_from_clause!(machine_st.last_call, machine_st) }, &BuiltInClauseType::Ground => { @@ -634,7 +642,15 @@ pub(crate) trait CallPolicy: Any { return_from_clause!(machine_st.last_call, machine_st) }, &BuiltInClauseType::NotEq => { - machine_st.fail = !machine_st.eq_test(); + let a1 = machine_st[temp_v!(1)].clone(); + let a2 = machine_st[temp_v!(2)].clone(); + + machine_st.fail = if let Ordering::Equal = machine_st.compare_term_test(&a1, &a2) { + true + } else { + false + }; + return_from_clause!(machine_st.last_call, machine_st) }, &BuiltInClauseType::Sort => { diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index f6100893..12db9d2a 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -1324,6 +1324,37 @@ impl MachineState { for (v1, v2) in iter { match (v1, v2) { + (HeapCellValue::Addr(Addr::Lis(_)), HeapCellValue::Addr(Addr::Con(Constant::String(_)))) + | (HeapCellValue::Addr(Addr::Con(Constant::String(_))), HeapCellValue::Addr(Addr::Lis(_))) + if self.flags.double_quotes.is_chars() => {}, + (HeapCellValue::Addr(Addr::Con(Constant::EmptyList)), + HeapCellValue::Addr(Addr::Con(Constant::String(ref s)))) + if self.flags.double_quotes.is_chars() => if s.is_empty() { + return Ordering::Equal; + } else { + return Ordering::Greater; + }, + (HeapCellValue::Addr(Addr::Con(Constant::Atom(atom))), + HeapCellValue::Addr(Addr::Con(Constant::Char(c)))) => + return if atom.as_str().chars().count() == 1 { + atom.as_str().chars().next().cmp(&Some(c)) + } else { + Ordering::Greater + }, + (HeapCellValue::Addr(Addr::Con(Constant::Char(c))), + HeapCellValue::Addr(Addr::Con(Constant::Atom(atom)))) => + return if atom.as_str().chars().count() == 1 { + Some(c).cmp(&atom.as_str().chars().next()) + } else { + Ordering::Less + }, + (HeapCellValue::Addr(Addr::Con(Constant::String(ref s))), + HeapCellValue::Addr(Addr::Con(Constant::EmptyList))) + if self.flags.double_quotes.is_chars() => if s.is_empty() { + return Ordering::Equal; + } else { + return Ordering::Less; + }, (HeapCellValue::Addr(Addr::HeapCell(hc1)), HeapCellValue::Addr(Addr::HeapCell(hc2))) => if hc1 != hc2 { @@ -1413,7 +1444,7 @@ impl MachineState { return Ordering::Less; } else { return n.as_str().cmp("."); - }, + }, (HeapCellValue::NamedStr(..), _) => return Ordering::Greater, (HeapCellValue::Addr(Addr::Lis(_)), _) => @@ -1724,44 +1755,41 @@ impl MachineState { } // returns true on failure. - pub(super) fn eq_test(&self) -> bool + pub(super) fn structural_eq_test(&self) -> bool { let a1 = self[temp_v!(1)].clone(); let a2 = self[temp_v!(2)].clone(); + let mut var_pairs = HashMap::new(); + let iter = self.zipped_acyclic_pre_order_iter(a1, a2); for (v1, v2) in iter { match (v1, v2) { - (HeapCellValue::NamedStr(ar1, n1, _), HeapCellValue::NamedStr(ar2, n2, _)) => - if ar1 != ar2 || n1 != n2 { + (HeapCellValue::Addr(Addr::Lis(_)), HeapCellValue::Addr(Addr::Con(Constant::String(ref s)))) + | (HeapCellValue::Addr(Addr::Con(Constant::String(ref s))), HeapCellValue::Addr(Addr::Lis(_))) + if self.flags.double_quotes.is_chars() => if s.is_empty() { return true; }, - (HeapCellValue::Addr(Addr::Lis(_)), HeapCellValue::Addr(Addr::Lis(_))) => - continue, - (HeapCellValue::Addr(a1), HeapCellValue::Addr(a2)) => - if a1 != a2 { + (HeapCellValue::Addr(Addr::Con(Constant::String(ref s))), + HeapCellValue::Addr(Addr::Con(Constant::EmptyList))) + | (HeapCellValue::Addr(Addr::Con(Constant::EmptyList)), + HeapCellValue::Addr(Addr::Con(Constant::String(ref s)))) + if self.flags.double_quotes.is_chars() => if !s.is_empty() { return true; }, - _ => return true - } - } - - false - } - - // returns true on failure. - pub(super) fn structural_eq_test(&self) -> bool - { - let a1 = self[temp_v!(1)].clone(); - let a2 = self[temp_v!(2)].clone(); - - let mut var_pairs = HashMap::new(); - - let iter = self.zipped_acyclic_pre_order_iter(a1, a2); - - for (v1, v2) in iter { - match (v1, v2) { + (HeapCellValue::Addr(Addr::Con(Constant::Atom(atom))), + HeapCellValue::Addr(Addr::Con(Constant::Char(c)))) + | (HeapCellValue::Addr(Addr::Con(Constant::Char(c))), + HeapCellValue::Addr(Addr::Con(Constant::Atom(atom)))) => { + if atom.as_str().chars().count() == 1 { + if Some(c) == atom.as_str().chars().next() { + continue; + } + } + + return true; + }, (HeapCellValue::NamedStr(ar1, n1, _), HeapCellValue::NamedStr(ar2, n2, _)) => if ar1 != ar2 || n1 != n2 { return true; diff --git a/src/prolog/string_list.rs b/src/prolog/string_list.rs index d2acb5c7..d4f8e35e 100644 --- a/src/prolog/string_list.rs +++ b/src/prolog/string_list.rs @@ -24,7 +24,8 @@ pub struct StringList { impl Hash for StringList { fn hash(&self, state: &mut H) { - self.borrow().hash(state) + let h = self.borrow().hash(state); + (h, self.cursor, self.expandable).hash(state); } } @@ -63,11 +64,6 @@ impl StringList { } } - #[inline] - pub fn cursor(&self) -> usize { - self.cursor - } - #[inline] pub fn head(&self) -> Option { self.borrow()[self.cursor ..].chars().next() -- 2.54.0