support strings as char lists in term comparisons

This commit is contained in:
Mark Thom
2018-08-23 01:24:26 -06:00
parent ddf5593e44
commit 7884a20042
5 changed files with 114 additions and 77 deletions

View File

@@ -39,17 +39,28 @@ impl<'a> HCPreOrderIterator<'a> {
{ {
let da = self.machine_st.store(self.machine_st.deref(addr)); let da = self.machine_st.store(self.machine_st.deref(addr));
match &da { match da {
&Addr::Con(_) => da, Addr::Con(Constant::String(ref s))
&Addr::Lis(a) => { 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 + 1));
self.state_stack.push(Addr::HeapCell(a)); self.state_stack.push(Addr::HeapCell(a));
da da
}, },
&Addr::HeapCell(_) | &Addr::StackCell(_, _) => Addr::HeapCell(_) | Addr::StackCell(_, _) =>
da, da,
&Addr::Str(s) => Addr::Str(s) =>
self.follow_heap(s) // record terms of structure. self.follow_heap(s) // record terms of structure.
} }
} }

View File

@@ -1,9 +1,8 @@
use prolog::ast::*; use prolog::ast::*;
use prolog::num::*; use prolog::num::*;
use prolog::heap_iter::*; use prolog::heap_iter::*;
use prolog::machine::machine_state::{DoubleQuotes, MachineState}; use prolog::machine::machine_state::MachineState;
use prolog::ordered_float::OrderedFloat; use prolog::ordered_float::OrderedFloat;
use prolog::string_list::*;
use std::cell::Cell; use std::cell::Cell;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
@@ -12,7 +11,6 @@ use std::rc::Rc;
#[derive(Clone)] #[derive(Clone)]
pub enum TokenOrRedirect { pub enum TokenOrRedirect {
Atom(ClauseName), Atom(ClauseName),
Char(char),
NumberedVar(String), NumberedVar(String),
Redirect, Redirect,
Open, 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) { fn print_char(&mut self, c: char) {
if non_quoted_token(c) { if non_quoted_token(c) {
self.outputter.push_char(c); self.outputter.push_char(c);
@@ -351,8 +331,13 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
Constant::Number(n) => Constant::Number(n) =>
self.outputter.append(&format!("{}", n)), self.outputter.append(&format!("{}", n)),
Constant::String(s) => Constant::String(s) =>
if let DoubleQuotes::Chars = self.machine_st.machine_flags().double_quotes { if self.machine_st.machine_flags().double_quotes.is_chars() {
self.expand_char_list(s); 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 } else { // for now, == DoubleQuotes::Atom
self.outputter.append("\""); self.outputter.append("\"");
self.outputter.append(s.borrow().as_str()); self.outputter.append(s.borrow().as_str());
@@ -362,6 +347,18 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
self.outputter.append(&format!("u{}", i)) 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) fn handle_heap_term(&mut self, iter: &mut HCPreOrderIterator)
{ {
@@ -381,17 +378,8 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
}, },
HeapCellValue::Addr(Addr::Con(c)) => HeapCellValue::Addr(Addr::Con(c)) =>
self.print_constant(c), self.print_constant(c),
HeapCellValue::Addr(Addr::Lis(_)) => { HeapCellValue::Addr(Addr::Lis(_)) =>
let cell = Rc::new(Cell::new(true)); self.push_list(),
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) => self.print_offset(addr) HeapCellValue::Addr(addr) => self.print_offset(addr)
} }
} }
@@ -417,8 +405,6 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
match loc_data { match loc_data {
TokenOrRedirect::Atom(atom) => TokenOrRedirect::Atom(atom) =>
self.outputter.append(atom.as_str()), self.outputter.append(atom.as_str()),
TokenOrRedirect::Char(c) =>
self.print_char(c),
TokenOrRedirect::NumberedVar(num_var) => TokenOrRedirect::NumberedVar(num_var) =>
self.outputter.append(num_var.as_str()), self.outputter.append(num_var.as_str()),
TokenOrRedirect::Redirect => TokenOrRedirect::Redirect =>

View File

@@ -622,7 +622,15 @@ pub(crate) trait CallPolicy: Any {
return_from_clause!(machine_st.last_call, machine_st) return_from_clause!(machine_st.last_call, machine_st)
}, },
&BuiltInClauseType::Eq => { &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) return_from_clause!(machine_st.last_call, machine_st)
}, },
&BuiltInClauseType::Ground => { &BuiltInClauseType::Ground => {
@@ -634,7 +642,15 @@ pub(crate) trait CallPolicy: Any {
return_from_clause!(machine_st.last_call, machine_st) return_from_clause!(machine_st.last_call, machine_st)
}, },
&BuiltInClauseType::NotEq => { &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) return_from_clause!(machine_st.last_call, machine_st)
}, },
&BuiltInClauseType::Sort => { &BuiltInClauseType::Sort => {

View File

@@ -1324,6 +1324,37 @@ impl MachineState {
for (v1, v2) in iter { for (v1, v2) in iter {
match (v1, v2) { 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(hc1)),
HeapCellValue::Addr(Addr::HeapCell(hc2))) => HeapCellValue::Addr(Addr::HeapCell(hc2))) =>
if hc1 != hc2 { if hc1 != hc2 {
@@ -1413,7 +1444,7 @@ impl MachineState {
return Ordering::Less; return Ordering::Less;
} else { } else {
return n.as_str().cmp("."); return n.as_str().cmp(".");
}, },
(HeapCellValue::NamedStr(..), _) => (HeapCellValue::NamedStr(..), _) =>
return Ordering::Greater, return Ordering::Greater,
(HeapCellValue::Addr(Addr::Lis(_)), _) => (HeapCellValue::Addr(Addr::Lis(_)), _) =>
@@ -1723,33 +1754,6 @@ impl MachineState {
self.unify(Addr::HeapCell(old_h), a2); self.unify(Addr::HeapCell(old_h), a2);
} }
// returns true on failure.
pub(super) fn eq_test(&self) -> bool
{
let a1 = self[temp_v!(1)].clone();
let a2 = self[temp_v!(2)].clone();
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 {
return true;
},
(HeapCellValue::Addr(Addr::Lis(_)), HeapCellValue::Addr(Addr::Lis(_))) =>
continue,
(HeapCellValue::Addr(a1), HeapCellValue::Addr(a2)) =>
if a1 != a2 {
return true;
},
_ => return true
}
}
false
}
// returns true on failure. // returns true on failure.
pub(super) fn structural_eq_test(&self) -> bool pub(super) fn structural_eq_test(&self) -> bool
{ {
@@ -1762,6 +1766,30 @@ impl MachineState {
for (v1, v2) in iter { for (v1, v2) in iter {
match (v1, v2) { match (v1, v2) {
(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::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;
},
(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, _)) => (HeapCellValue::NamedStr(ar1, n1, _), HeapCellValue::NamedStr(ar2, n2, _)) =>
if ar1 != ar2 || n1 != n2 { if ar1 != ar2 || n1 != n2 {
return true; return true;

View File

@@ -24,7 +24,8 @@ pub struct StringList {
impl Hash for StringList { impl Hash for StringList {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&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] #[inline]
pub fn head(&self) -> Option<char> { pub fn head(&self) -> Option<char> {
self.borrow()[self.cursor ..].chars().next() self.borrow()[self.cursor ..].chars().next()