support strings as char lists in term comparisons
This commit is contained in:
@@ -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.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 =>
|
||||||
|
|||||||
@@ -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 => {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user