fix printer

This commit is contained in:
Mark Thom
2019-01-22 22:57:23 -07:00
parent e92996126b
commit 34414b6895
3 changed files with 129 additions and 118 deletions

View File

@@ -10,7 +10,7 @@ license = "BSD-3-Clause"
downcast = "0.9.1" downcast = "0.9.1"
num = "0.2" num = "0.2"
ordered-float = "0.5.0" ordered-float = "0.5.0"
prolog_parser = { version = "0.7.22", path = "../prolog_parser" } prolog_parser = "0.7.22"
[dependencies.termion] [dependencies.termion]
version = "1.4.0" version = "1.4.0"

View File

@@ -9,6 +9,7 @@ use prolog::ordered_float::OrderedFloat;
use std::cell::Cell; use std::cell::Cell;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::iter::once; use std::iter::once;
use std::ops::{Range, RangeFrom};
use std::rc::Rc; use std::rc::Rc;
/* contains the location, name, precision and Specifier of the parent op. */ /* contains the location, name, precision and Specifier of the parent op. */
@@ -54,7 +55,6 @@ pub enum TokenOrRedirect {
OpenList(Rc<Cell<bool>>), OpenList(Rc<Cell<bool>>),
CloseList(Rc<Cell<bool>>), CloseList(Rc<Cell<bool>>),
HeadTailSeparator, HeadTailSeparator,
Space
} }
pub trait HCValueOutputter { pub trait HCValueOutputter {
@@ -64,11 +64,13 @@ pub trait HCValueOutputter {
fn push_char(&mut self, char); fn push_char(&mut self, char);
fn append(&mut self, &str); fn append(&mut self, &str);
fn begin_new_var(&mut self); fn begin_new_var(&mut self);
fn insert_from_end(&mut self, usize, char); fn insert(&mut self, usize, char);
fn result(self) -> Self::Output; fn result(self) -> Self::Output;
fn ends_with(&self, &str) -> bool; fn ends_with(&self, &str) -> bool;
fn len(&self) -> usize; fn len(&self) -> usize;
fn truncate(&mut self, usize); fn truncate(&mut self, usize);
fn range(&self, Range<usize>) -> &str;
fn range_from(&self, RangeFrom<usize>) -> &str;
} }
pub struct PrinterOutputter { pub struct PrinterOutputter {
@@ -96,9 +98,8 @@ impl HCValueOutputter for PrinterOutputter {
} }
} }
fn insert_from_end(&mut self, idx: usize, c: char) { fn insert(&mut self, idx: usize, c: char) {
let len = self.contents.len(); self.contents.insert(idx, c);
self.contents.insert(len - idx, c);
} }
fn result(self) -> Self::Output { fn result(self) -> Self::Output {
@@ -116,6 +117,14 @@ impl HCValueOutputter for PrinterOutputter {
fn truncate(&mut self, len: usize) { fn truncate(&mut self, len: usize) {
self.contents.truncate(len); self.contents.truncate(len);
} }
fn range(&self, index: Range<usize>) -> &str {
&self.contents.as_str()[index]
}
fn range_from(&self, index: RangeFrom<usize>) -> &str {
&self.contents.as_str()[index]
}
} }
#[inline] #[inline]
@@ -158,34 +167,29 @@ pub struct HCPrinter<'a, Outputter> {
state_stack: Vec<TokenOrRedirect>, state_stack: Vec<TokenOrRedirect>,
heap_locs: ReverseHeapVarDict, heap_locs: ReverseHeapVarDict,
printed_vars: HashSet<Addr>, printed_vars: HashSet<Addr>,
last_item_idx: usize,
pub(crate) numbervars: bool, pub(crate) numbervars: bool,
pub(crate) quoted: bool, pub(crate) quoted: bool,
pub(crate) ignore_ops: bool pub(crate) ignore_ops: bool
} }
macro_rules! push_space_if_amb { macro_rules! push_space_if_amb {
($self:expr, $atom:expr, $op:expr, $action:block) => ( ($self:expr, $atom:expr, $action:block) => (
match $self.ambiguity_check($atom, $op) { if $self.ambiguity_check($atom) {
Some(DirectedOp::Left(lop, (_, spec))) => if !$self.outputter.range(0 .. $self.last_item_idx).ends_with(" ") {
if is_infix!(spec) { $self.outputter.insert($self.last_item_idx, ' ');
$self.outputter.insert_from_end(lop.as_str().len(), ' '); }
$self.outputter.push_char(' ');
$action; $self.outputter.push_char(' ');
} else { $action;
$self.outputter.push_char(' '); } else {
$action; $action;
}, }
Some(DirectedOp::Right(..)) => {
$action;
$self.outputter.push_char(' ');
},
None => $action
};
) )
} }
fn continues_with_append(atom: &str, op: &str) -> bool { fn continues_with_append(atom: &str, op: &str) -> bool {
match atom.chars().next() { match atom.chars().last() {
Some(ac) => op.chars().next().map(|oc| { Some(ac) => op.chars().next().map(|oc| {
if alpha_char!(ac) { if alpha_char!(ac) {
alpha_numeric_char!(oc) alpha_numeric_char!(oc)
@@ -269,6 +273,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
state_stack: vec![], state_stack: vec![],
heap_locs: ReverseHeapVarDict::new(), heap_locs: ReverseHeapVarDict::new(),
printed_vars: HashSet::new(), printed_vars: HashSet::new(),
last_item_idx: 0,
numbervars: false, numbervars: false,
quoted: false, quoted: false,
ignore_ops: false } ignore_ops: false }
@@ -291,28 +296,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
} }
} }
// return op itself if there is an ambiguity to indicate the direction the op #[inline]
// lies, None otherwise. fn ambiguity_check(&self, atom: &str) -> bool
fn ambiguity_check(&self, atom: &str, op: &Option<DirectedOp>) -> Option<DirectedOp>
{ {
match op { let tail = self.outputter.range_from(self.last_item_idx ..);
&Some(DirectedOp::Left(ref lop, (priority, spec))) if is_infix!(spec) => continues_with_append(tail, atom)
if self.outputter.ends_with(&format!(" {}", lop.as_str())) {
Some(DirectedOp::Left(lop.clone(), (priority, spec)))
} else if continues_with_append(lop.as_str(), atom) {
Some(DirectedOp::Left(lop.clone(), (priority, spec)))
} else {
None
},
&Some(DirectedOp::Left(ref lop, spec))
if continues_with_append(lop.as_str(), atom) =>
Some(DirectedOp::Left(lop.clone(), spec)),
&Some(DirectedOp::Right(ref rop, spec))
if continues_with_append(atom, rop.as_str()) =>
Some(DirectedOp::Right(rop.clone(), spec)),
_ =>
None
}
} }
fn enqueue_op(&mut self, ct: ClauseType, spec: (usize, Specifier)) { fn enqueue_op(&mut self, ct: ClauseType, spec: (usize, Specifier)) {
@@ -371,6 +359,18 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
self.format_struct(arity, ct.name()); self.format_struct(arity, ct.name());
} }
#[inline]
fn push_char(&mut self, c: char) {
self.outputter.push_char(c);
self.last_item_idx = self.outputter.len();
}
#[inline]
fn append_str(&mut self, s: &str) {
self.last_item_idx = self.outputter.len();
self.outputter.append(s);
}
fn offset_as_string(&self, addr: Addr) -> Option<String> { fn offset_as_string(&self, addr: Addr) -> Option<String> {
match addr { match addr {
Addr::HeapCell(h) | Addr::Lis(h) | Addr::Str(h) => Addr::HeapCell(h) | Addr::Lis(h) | Addr::Str(h) =>
@@ -381,8 +381,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
} }
} }
fn check_for_seen(&mut self, iter: &mut HCPreOrderIterator, op: &Option<DirectedOp>) fn check_for_seen(&mut self, iter: &mut HCPreOrderIterator) -> Option<HeapCellValue>
-> Option<HeapCellValue>
{ {
iter.stack().last().cloned().and_then(|addr| { iter.stack().last().cloned().and_then(|addr| {
let addr = self.machine_st.store(self.machine_st.deref(addr)); let addr = self.machine_st.store(self.machine_st.deref(addr));
@@ -393,8 +392,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
return iter.next(); return iter.next();
} else { } else {
iter.stack().pop(); iter.stack().pop();
push_space_if_amb!(self, &var, op, { push_space_if_amb!(self, &var, {
self.outputter.append(&var); self.append_str(&var);
}); });
return None; return None;
@@ -404,8 +403,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
iter.stack().pop(); iter.stack().pop();
if let Some(offset_str) = self.offset_as_string(addr) { if let Some(offset_str) = self.offset_as_string(addr) {
push_space_if_amb!(self, &offset_str, op, { push_space_if_amb!(self, &offset_str, {
self.outputter.append(offset_str.as_str()); self.append_str(offset_str.as_str());
}); });
} }
@@ -428,13 +427,13 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
fn print_atom(&mut self, atom: &ClauseName, spec: Option<(usize, Specifier)>) { fn print_atom(&mut self, atom: &ClauseName, spec: Option<(usize, Specifier)>) {
match atom.as_str() { match atom.as_str() {
"" => self.outputter.append("''"), "" => self.append_str("''"),
";" | "!" => self.outputter.append(atom.as_str()), ";" | "!" => self.append_str(atom.as_str()),
s => if spec.is_some() || !self.quoted || non_quoted_token(s.chars()) { s => if spec.is_some() || !self.quoted || non_quoted_token(s.chars()) {
self.outputter.append(atom.as_str()) self.append_str(atom.as_str())
} else { } else {
if self.quoted { if self.quoted {
self.outputter.push_char('\''); self.push_char('\'');
} }
for c in atom.as_str().chars() { for c in atom.as_str().chars() {
@@ -442,7 +441,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
} }
if self.quoted { if self.quoted {
self.outputter.push_char('\''); self.push_char('\'');
} }
} }
} }
@@ -450,15 +449,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
fn print_char(&mut self, c: char) { fn print_char(&mut self, c: char) {
match c { match c {
'\n' => self.outputter.append("\\n"), '\n' => self.append_str("\\n"),
'\r' => self.outputter.append("\\r"), '\r' => self.append_str("\\r"),
'\t' => self.outputter.append("\\t"), '\t' => self.append_str("\\t"),
'\u{0b}' => self.outputter.append("\\v"), // UTF-8 vertical tab '\u{0b}' => self.append_str("\\v"), // UTF-8 vertical tab
'\u{0c}' => self.outputter.append("\\f"), // UTF-8 form feed '\u{0c}' => self.append_str("\\f"), // UTF-8 form feed
'\u{08}' => self.outputter.append("\\b"), // UTF-8 backspace '\u{08}' => self.append_str("\\b"), // UTF-8 backspace
'\u{07}' => self.outputter.append("\\a"), // UTF-8 alert '\u{07}' => self.append_str("\\a"), // UTF-8 alert
'\x20' ... '\x7e' => self.outputter.push_char(c), '\x20' ... '\x7e' => self.push_char(c),
_ => self.outputter.append(&format!("\\x{:x}", c as u32)) _ => self.append_str(&format!("\\x{:x}", c as u32))
}; };
} }
@@ -467,51 +466,51 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
Constant::Atom(ref atom, Some(spec)) => { Constant::Atom(ref atom, Some(spec)) => {
if let Some(ref op) = op { if let Some(ref op) = op {
if self.outputter.ends_with(&format!(" {}", op.as_str())) { if self.outputter.ends_with(&format!(" {}", op.as_str())) {
self.outputter.push_char(' '); self.push_char(' ');
} }
self.outputter.push_char('('); self.push_char('(');
} }
self.print_atom(atom, Some(spec)); self.print_atom(atom, Some(spec));
if op.is_some() { if op.is_some() {
self.outputter.push_char(')'); self.push_char(')');
} }
}, },
Constant::Atom(ref atom, None) => Constant::Atom(ref atom, None) =>
push_space_if_amb!(self, atom.as_str(), &op, { push_space_if_amb!(self, atom.as_str(), {
self.print_atom(atom, None); self.print_atom(atom, None);
}), }),
Constant::Char(c) if non_quoted_token(once(c)) => Constant::Char(c) if non_quoted_token(once(c)) =>
self.print_char(c), self.print_char(c),
Constant::Char(c) => Constant::Char(c) =>
if self.quoted { if self.quoted {
self.outputter.push_char('\''); self.push_char('\'');
self.print_char(c); self.print_char(c);
self.outputter.push_char('\''); self.push_char('\'');
} else { } else {
self.print_char(c); self.print_char(c);
}, },
Constant::EmptyList => Constant::EmptyList =>
self.outputter.append("[]"), self.append_str("[]"),
Constant::Number(Number::Float(fl)) => Constant::Number(Number::Float(fl)) =>
if &fl == &OrderedFloat(0f64) { if &fl == &OrderedFloat(0f64) {
push_space_if_amb!(self, "0", &op, { push_space_if_amb!(self, "0", {
self.outputter.append("0"); self.append_str("0");
}); });
} else { } else {
let output_str = format!("{}", fl); let output_str = format!("{}", fl);
push_space_if_amb!(self, &output_str, &op, { push_space_if_amb!(self, &output_str, {
self.outputter.append(&output_str); self.append_str(&output_str);
}); });
}, },
Constant::Number(n) => { Constant::Number(n) => {
let output_str = format!("{}", n); let output_str = format!("{}", n);
push_space_if_amb!(self, &output_str, &op, { push_space_if_amb!(self, &output_str, {
self.outputter.append(&output_str); self.append_str(&output_str);
}); });
}, },
Constant::String(s) => Constant::String(s) =>
@@ -524,20 +523,20 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
} }
} else if s.is_expandable() { } else if s.is_expandable() {
if !self.at_cdr(" | _") { if !self.at_cdr(" | _") {
self.outputter.push_char('_'); self.push_char('_');
} }
} else if !self.at_cdr("") { } else if !self.at_cdr("") {
self.outputter.append("[]"); self.append_str("[]");
} }
} else { // for now, == DoubleQuotes::Atom } else { // for now, == DoubleQuotes::Atom
let borrowed_str = s.borrow(); let borrowed_str = s.borrow();
self.outputter.append("\""); self.push_char('"');
self.outputter.append(&borrowed_str[s.cursor() ..]); self.append_str(&borrowed_str[s.cursor() ..]);
self.outputter.append("\""); self.push_char('"');
}, },
Constant::Usize(i) => Constant::Usize(i) =>
self.outputter.append(&format!("u{}", i)) self.append_str(&format!("u{}", i))
} }
} }
@@ -556,13 +555,13 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
fn handle_heap_term(&mut self, iter: &mut HCPreOrderIterator, op: Option<DirectedOp>, fn handle_heap_term(&mut self, iter: &mut HCPreOrderIterator, op: Option<DirectedOp>,
is_functor_redirect: bool) is_functor_redirect: bool)
{ {
let heap_val = match self.check_for_seen(iter, &op) { let heap_val = match self.check_for_seen(iter) {
Some(heap_val) => heap_val, Some(heap_val) => heap_val,
None => return None => return
}; };
match heap_val { match heap_val {
HeapCellValue::NamedStr(arity, ref name, Some(spec)) => { HeapCellValue::NamedStr(arity, ref name, Some(spec)) => {
let add_brackets = if !self.ignore_ops { let add_brackets = if !self.ignore_ops {
if let Some(ref op) = &op { if let Some(ref op) = &op {
needs_bracketing(spec, op) needs_bracketing(spec, op)
@@ -572,7 +571,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
} else { } else {
false false
}; };
if add_brackets { if add_brackets {
self.state_stack.push(TokenOrRedirect::Close); self.state_stack.push(TokenOrRedirect::Close);
} }
@@ -583,15 +582,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
if add_brackets { if add_brackets {
self.state_stack.push(TokenOrRedirect::Open); self.state_stack.push(TokenOrRedirect::Open);
} }
if let Some(op) = op {
if !add_brackets && self.outputter.ends_with(&format!(" {}", op.as_str())) {
self.state_stack.push(TokenOrRedirect::Space);
}
}
}, },
HeapCellValue::NamedStr(0, name, fixity) => HeapCellValue::NamedStr(0, name, fixity) =>
push_space_if_amb!(self, name.as_str(), &op, { push_space_if_amb!(self, name.as_str(), {
let ct = ClauseType::from(name, 0, fixity); let ct = ClauseType::from(name, 0, fixity);
self.format_clause(iter, 0, ct); self.format_clause(iter, 0, ct);
}), }),
@@ -601,7 +594,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
}, },
HeapCellValue::Addr(Addr::Con(Constant::EmptyList)) => HeapCellValue::Addr(Addr::Con(Constant::EmptyList)) =>
if !self.at_cdr("") { if !self.at_cdr("") {
self.outputter.append("[]"); self.append_str("[]");
}, },
HeapCellValue::Addr(Addr::Con(c)) => HeapCellValue::Addr(Addr::Con(c)) =>
self.print_constant(c, &op), self.print_constant(c, &op),
@@ -613,8 +606,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
}, },
HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr) =>
if let Some(offset_str) = self.offset_as_string(addr) { if let Some(offset_str) = self.offset_as_string(addr) {
push_space_if_amb!(self, &offset_str, &op, { push_space_if_amb!(self, &offset_str, {
self.outputter.append(offset_str.as_str()); self.append_str(offset_str.as_str());
}) })
} }
} }
@@ -624,8 +617,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
let len = self.outputter.len(); let len = self.outputter.len();
if self.outputter.ends_with(" | ") { if self.outputter.ends_with(" | ") {
self.outputter.truncate(len - 3); self.outputter.truncate(len - " | ".len());
self.outputter.append(tr); self.append_str(tr);
true true
} else { } else {
@@ -644,31 +637,29 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
TokenOrRedirect::Op(atom, spec) => TokenOrRedirect::Op(atom, spec) =>
self.print_atom(&atom, Some(spec)), self.print_atom(&atom, Some(spec)),
TokenOrRedirect::NumberedVar(num_var) => TokenOrRedirect::NumberedVar(num_var) =>
self.outputter.append(num_var.as_str()), self.append_str(num_var.as_str()),
TokenOrRedirect::CompositeRedirect(op) => TokenOrRedirect::CompositeRedirect(op) =>
self.handle_heap_term(&mut iter, Some(op), false), self.handle_heap_term(&mut iter, Some(op), false),
TokenOrRedirect::FunctorRedirect => TokenOrRedirect::FunctorRedirect =>
self.handle_heap_term(&mut iter, None, true), self.handle_heap_term(&mut iter, None, true),
TokenOrRedirect::Space =>
self.outputter.push_char(' '),
TokenOrRedirect::Close => TokenOrRedirect::Close =>
self.outputter.push_char(')'), self.push_char(')'),
TokenOrRedirect::Open => TokenOrRedirect::Open =>
self.outputter.push_char('('), self.push_char('('),
TokenOrRedirect::OpenList(delimit) => TokenOrRedirect::OpenList(delimit) =>
if !self.at_cdr(", ") { if !self.at_cdr(", ") {
self.outputter.push_char('['); self.push_char('[');
} else { } else {
delimit.set(false); delimit.set(false);
}, },
TokenOrRedirect::CloseList(delimit) => TokenOrRedirect::CloseList(delimit) =>
if delimit.get() { if delimit.get() {
self.outputter.push_char(']'); self.push_char(']');
}, },
TokenOrRedirect::HeadTailSeparator => TokenOrRedirect::HeadTailSeparator =>
self.outputter.append(" | "), self.append_str(" | "),
TokenOrRedirect::Comma => TokenOrRedirect::Comma =>
self.outputter.append(", ") self.append_str(", ")
} }
} else if !iter.stack().is_empty() { } else if !iter.stack().is_empty() {
self.handle_heap_term(&mut iter, None, false); self.handle_heap_term(&mut iter, None, false);

View File

@@ -6,6 +6,7 @@ use prolog::toplevel::*;
use std::collections::HashSet; use std::collections::HashSet;
use std::mem::swap; use std::mem::swap;
use std::ops::{Range, RangeFrom};
pub struct TestOutputter { pub struct TestOutputter {
results: Vec<HashSet<String>>, results: Vec<HashSet<String>>,
@@ -50,11 +51,10 @@ impl HCValueOutputter for TestOutputter {
} }
} }
fn insert_from_end(&mut self, idx: usize, c: char) { fn insert(&mut self, idx: usize, c: char) {
let len = self.focus.len(); self.focus.insert(idx, c);
self.focus.insert(len - idx, c);
} }
fn result(self) -> Self::Output { fn result(self) -> Self::Output {
self.results self.results
} }
@@ -70,6 +70,14 @@ impl HCValueOutputter for TestOutputter {
fn truncate(&mut self, len: usize) { fn truncate(&mut self, len: usize) {
self.focus.truncate(len); self.focus.truncate(len);
} }
fn range(&self, index: Range<usize>) -> &str {
&self.focus.as_str()[index]
}
fn range_from(&self, index: RangeFrom<usize>) -> &str {
&self.focus.as_str()[index]
}
} }
pub fn collect_test_output(wam: &mut Machine, alloc_locs: AllocVarDict, mut heap_locs: HeapVarDict) pub fn collect_test_output(wam: &mut Machine, alloc_locs: AllocVarDict, mut heap_locs: HeapVarDict)
@@ -1387,7 +1395,7 @@ reverse(Xs, Ys) :- lists:reverse(Xs, Ys).
assert_prolog_success!(&mut wam, "?- reverse(_, _)."); assert_prolog_success!(&mut wam, "?- reverse(_, _).");
submit(&mut wam, ":- use_module(library(lists), [])."); submit(&mut wam, ":- use_module(library(lists), []).");
assert_prolog_success!(&mut wam, "?- catch(reverse(_, _), error(existence_error(procedure, P), _), true).", assert_prolog_success!(&mut wam, "?- catch(reverse(_, _), error(existence_error(procedure, P), _), true).",
[["P = reverse/2"]]); [["P = reverse/2"]]);
} }
@@ -1689,6 +1697,18 @@ fn test_queries_on_builtins()
[["X = (:-):-(:-)"]]); [["X = (:-):-(:-)"]]);
assert_prolog_success!(&mut wam, "?- X = (a:-b,c).", assert_prolog_success!(&mut wam, "?- X = (a:-b,c).",
[["X = a:-b,c"]]); [["X = a:-b,c"]]);
assert_prolog_success!(&mut wam, "?- X = f((f:-a,b,c)).",
[["X = f((f:-a,b,c))"]]);
assert_prolog_success!(&mut wam, "?- X = f((f:-a,(b,c))).",
[["X = f((f:-a,b,c))"]]);
assert_prolog_success!(&mut wam, "?- X = f((a,b,c)).",
[["X = f((a,b,c))"]]);
assert_prolog_success!(&mut wam, "?- X = f((a,(b,c))).",
[["X = f((a,b,c))"]]);
assert_prolog_success!(&mut wam, "?- X = f(((a,b),c)).",
[["X = f(((a,b),c))"]]);
assert_prolog_success!(&mut wam, "?- X = f(((a,b),(c, d))).",
[["X = f(((a,b),c,d))"]]);
} }
#[test] #[test]
@@ -1877,7 +1897,7 @@ fn test_queries_on_dcgs()
let mut wam = Machine::new(); let mut wam = Machine::new();
submit(&mut wam, ":- use_module(library(dcgs))."); submit(&mut wam, ":- use_module(library(dcgs)).");
// test case by YeGoblynQueene from hacker news. // test case by YeGoblynQueene from hacker news.
compile_user_module(&mut wam, compile_user_module(&mut wam,
" ability(destroy, X) --> destroy(X). " ability(destroy, X) --> destroy(X).
@@ -1888,7 +1908,7 @@ fn test_queries_on_dcgs()
permanent(X) --> [land], land(X). permanent(X) --> [land], land(X).
spell(X) --> [sorcery], sorcery(X). spell(X) --> [sorcery], sorcery(X).
spell(X) --> [instant], instant(X). spell(X) --> [instant], instant(X).
creature('Llanowar Elves') --> []. creature('Llanowar Elves') --> [].
artifact('Ankh of Mishra') --> []. artifact('Ankh of Mishra') --> [].
land('Mountain') --> []. land('Mountain') --> [].
@@ -1992,7 +2012,7 @@ fn test_queries_on_string_lists()
assert_prolog_success!(&mut wam, "?- partial_string(\"abc\", X), matcher(X, Y), partial_string(\"def\", Y).", assert_prolog_success!(&mut wam, "?- partial_string(\"abc\", X), matcher(X, Y), partial_string(\"def\", Y).",
[["X = [a, b, c, d, e, f | _]", [["X = [a, b, c, d, e, f | _]",
"Y = [d, e, f | _]"]]); "Y = [d, e, f | _]"]]);
assert_prolog_success!(&mut wam, "?- partial_string(\"abc\", X), matcher(X, Y), partial_string(\"def\", Y), assert_prolog_success!(&mut wam, "?- partial_string(\"abc\", X), matcher(X, Y), partial_string(\"def\", Y),
Y = \"defghijkl\".", Y = \"defghijkl\".",
[["X = [a, b, c, d, e, f, g, h, i, j, k, l]", [["X = [a, b, c, d, e, f, g, h, i, j, k, l]",
@@ -2001,7 +2021,7 @@ fn test_queries_on_string_lists()
\"defghijkl\" = Y.", \"defghijkl\" = Y.",
[["X = [a, b, c, d, e, f, g, h, i, j, k, l]", [["X = [a, b, c, d, e, f, g, h, i, j, k, l]",
"Y = [d, e, f, g, h, i, j, k, l]"]]); "Y = [d, e, f, g, h, i, j, k, l]"]]);
assert_prolog_success!(&mut wam, "?- partial_string(\"abc\", X), matcher(X, Y), Y = [d, e, f | G].", assert_prolog_success!(&mut wam, "?- partial_string(\"abc\", X), matcher(X, Y), Y = [d, e, f | G].",
[["X = [a, b, c, d, e, f | _]", "Y = [d, e, f | _]", "G = _"]]); [["X = [a, b, c, d, e, f | _]", "Y = [d, e, f | _]", "G = _"]]);
assert_prolog_success!(&mut wam, "?- partial_string(\"abc\", X), matcher(X, Y), [d, e, f | G] = Y.", assert_prolog_success!(&mut wam, "?- partial_string(\"abc\", X), matcher(X, Y), [d, e, f | G] = Y.",
@@ -2096,7 +2116,7 @@ fn test_queries_on_string_lists()
["X = [b, d | _]", "Y = [d | _]"]]); ["X = [b, d | _]", "Y = [d | _]"]]);
assert_prolog_success!(&mut wam, "?- partial_string(\"bc\", X), matcher(X, Y).", assert_prolog_success!(&mut wam, "?- partial_string(\"bc\", X), matcher(X, Y).",
[["X = [b, c | _]", "Y = [c | _]"]]); [["X = [b, c | _]", "Y = [c | _]"]]);
submit(&mut wam, "f(\"appendy jones\"). submit(&mut wam, "f(\"appendy jones\").
f(\"appendy smithers jones\"). f(\"appendy smithers jones\").
f(\"appendy o'toole\")."); f(\"appendy o'toole\").");