add support for printing cyclic terms.
This commit is contained in:
@@ -1362,6 +1362,32 @@ impl Addr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Add<usize> for Addr {
|
||||||
|
type Output = Addr;
|
||||||
|
|
||||||
|
fn add(self, rhs: usize) -> Self::Output {
|
||||||
|
match self {
|
||||||
|
Addr::Lis(a) => Addr::Lis(a + rhs),
|
||||||
|
Addr::HeapCell(hc) => Addr::HeapCell(hc + rhs),
|
||||||
|
Addr::Str(s) => Addr::Str(s + rhs),
|
||||||
|
_ => self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub<usize> for Addr {
|
||||||
|
type Output = Addr;
|
||||||
|
|
||||||
|
fn sub(self, rhs: usize) -> Self::Output {
|
||||||
|
match self {
|
||||||
|
Addr::Lis(a) => Addr::Lis(a - rhs),
|
||||||
|
Addr::HeapCell(hc) => Addr::HeapCell(hc - rhs),
|
||||||
|
Addr::Str(s) => Addr::Str(s - rhs),
|
||||||
|
_ => self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Ref> for Addr {
|
impl From<Ref> for Addr {
|
||||||
fn from(r: Ref) -> Self {
|
fn from(r: Ref) -> Self {
|
||||||
match r {
|
match r {
|
||||||
@@ -1371,7 +1397,7 @@ impl From<Ref> for Addr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
|
||||||
pub enum Ref {
|
pub enum Ref {
|
||||||
HeapCell(usize),
|
HeapCell(usize),
|
||||||
StackCell(usize, usize)
|
StackCell(usize, usize)
|
||||||
|
|||||||
@@ -4,6 +4,19 @@ use prolog::ast::*;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ops::IndexMut;
|
use std::ops::IndexMut;
|
||||||
|
|
||||||
|
// allows us to reconstruct a HeapVarDict by relating variables
|
||||||
|
// in an existing HeapVarDict to the ones created in fn duplicate_term.
|
||||||
|
// It is used to create meaningful error reports at the toplevel.
|
||||||
|
pub struct CellRedirect(pub HashMap<Addr, Addr>);
|
||||||
|
|
||||||
|
impl CellRedirect {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
CellRedirect(HashMap::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Trail = Vec<(Ref, HeapCellValue)>;
|
||||||
|
|
||||||
pub trait CopierTarget
|
pub trait CopierTarget
|
||||||
{
|
{
|
||||||
fn source(&self) -> usize;
|
fn source(&self) -> usize;
|
||||||
@@ -13,21 +26,50 @@ pub trait CopierTarget
|
|||||||
fn deref(&self, Addr) -> Addr;
|
fn deref(&self, Addr) -> Addr;
|
||||||
fn stack(&mut self) -> &mut AndStack;
|
fn stack(&mut self) -> &mut AndStack;
|
||||||
|
|
||||||
|
fn compile_redirect(&mut self, trail: Trail, list_redirect: HashMap<usize, usize>, old_h: usize)
|
||||||
|
-> CellRedirect
|
||||||
|
where Self: IndexMut<usize, Output=HeapCellValue>
|
||||||
|
{
|
||||||
|
let mut cell_redirect: HashMap<Addr, Addr> = HashMap::new();
|
||||||
|
|
||||||
|
for (r, hcv) in trail {
|
||||||
|
let addr = Addr::from(r);
|
||||||
|
|
||||||
|
match r {
|
||||||
|
Ref::HeapCell(hc) => {
|
||||||
|
cell_redirect.insert(addr, self[hc].as_addr(hc) - old_h);
|
||||||
|
self[hc] = hcv;
|
||||||
|
},
|
||||||
|
Ref::StackCell(fr, sc) => {
|
||||||
|
cell_redirect.insert(addr, self.stack()[fr][sc].clone() - old_h);
|
||||||
|
self.stack()[fr][sc] = hcv.as_addr(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (l, h) in list_redirect {
|
||||||
|
cell_redirect.insert(Addr::Lis(l), Addr::Lis(h - old_h));
|
||||||
|
}
|
||||||
|
|
||||||
|
CellRedirect(cell_redirect)
|
||||||
|
}
|
||||||
|
|
||||||
// duplicate_term(L1, L2) uses Cheney's algorithm to copy the term
|
// duplicate_term(L1, L2) uses Cheney's algorithm to copy the term
|
||||||
// at L1 to L2. trail is kept to restore the innards of L1 after
|
// at L1 to L2. trail is kept to restore the innards of L1 after
|
||||||
// it's been copied to L2.
|
// it's been copied to L2.
|
||||||
fn duplicate_term(&mut self, a: Addr) where Self: IndexMut<usize, Output=HeapCellValue>
|
fn duplicate_term(&mut self, addr: Addr) -> CellRedirect
|
||||||
|
where Self: IndexMut<usize, Output=HeapCellValue>
|
||||||
{
|
{
|
||||||
let mut trail: Vec<(Ref, HeapCellValue)>= Vec::new();
|
let mut trail = Trail::new();
|
||||||
let mut scan = self.source();
|
let mut scan = self.source();
|
||||||
let old_h = self.threshold();
|
let old_h = self.threshold();
|
||||||
|
|
||||||
// Lists have a flattened representation as structures,
|
// Lists have a compressed representation as structures,
|
||||||
// removing the need for a NamedStr variant, so we use a
|
// removing the need for NamedStr, so we use a redirection
|
||||||
// redirection table for reconstructing lists.
|
// table for copying lists.
|
||||||
let mut list_redirect = HashMap::new();
|
let mut list_redirect = HashMap::new();
|
||||||
|
|
||||||
self.push(HeapCellValue::Addr(a));
|
self.push(HeapCellValue::Addr(addr));
|
||||||
|
|
||||||
while scan < self.threshold() {
|
while scan < self.threshold() {
|
||||||
match self[scan].clone() {
|
match self[scan].clone() {
|
||||||
@@ -110,11 +152,6 @@ pub trait CopierTarget
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (r, hcv) in trail {
|
self.compile_redirect(trail, list_redirect, old_h)
|
||||||
match r {
|
|
||||||
Ref::HeapCell(hc) => self[hc] = hcv,
|
|
||||||
Ref::StackCell(fr, sc) => self.stack()[fr][sc] = hcv.as_addr(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -179,45 +179,6 @@ where HCIter: Iterator<Item=HeapCellValue> + MutStackHCIterator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct HCDerefAcyclicIterator<HCIter> {
|
|
||||||
iter: HCIter,
|
|
||||||
seen: HashSet<Addr>
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type HCDerefAcyclicPreOrderIterator<'a> = HCDerefAcyclicIterator<HCPreOrderIterator<'a>>;
|
|
||||||
|
|
||||||
impl<'a> HCPreOrderIterator<'a> {
|
|
||||||
pub fn deref_acyclic_iter(self) -> HCDerefAcyclicPreOrderIterator<'a> {
|
|
||||||
HCDerefAcyclicIterator::new(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<HCIter: MutStackHCIterator> HCDerefAcyclicIterator<HCIter>
|
|
||||||
{
|
|
||||||
pub fn new(iter: HCIter) -> Self {
|
|
||||||
HCDerefAcyclicIterator { iter, seen: HashSet::new() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<HCIter> Iterator for HCDerefAcyclicIterator<HCIter>
|
|
||||||
where HCIter: Iterator<Item=HeapCellValue> + MutStackHCIterator
|
|
||||||
{
|
|
||||||
type Item = HeapCellValue;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
loop {
|
|
||||||
match self.iter.next() {
|
|
||||||
Some(HeapCellValue::Addr(addr)) =>
|
|
||||||
if !self.seen.contains(&addr) {
|
|
||||||
self.seen.insert(addr.clone());
|
|
||||||
return Some(HeapCellValue::Addr(addr));
|
|
||||||
},
|
|
||||||
item => return item
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct HCZippedAcyclicIterator<HCIter> {
|
pub struct HCZippedAcyclicIterator<HCIter> {
|
||||||
i1: HCIter,
|
i1: HCIter,
|
||||||
i2: HCIter,
|
i2: HCIter,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use prolog::machine::machine_state::MachineState;
|
|||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -58,7 +59,7 @@ pub struct PrinterOutputter {
|
|||||||
contents: String
|
contents: String
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HCValueOutputter for PrinterOutputter {
|
impl HCValueOutputter for PrinterOutputter {
|
||||||
type Output = String;
|
type Output = String;
|
||||||
|
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
@@ -102,7 +103,7 @@ impl HCValueFormatter for DisplayFormatter {
|
|||||||
let mut new_name = String::from("'");
|
let mut new_name = String::from("'");
|
||||||
new_name += ct.name().as_str();
|
new_name += ct.name().as_str();
|
||||||
new_name += "'";
|
new_name += "'";
|
||||||
|
|
||||||
self.format_struct(arity, ct.name(), state_stack);
|
self.format_struct(arity, ct.name(), state_stack);
|
||||||
} else {
|
} else {
|
||||||
self.format_struct(arity, ct.name(), state_stack);
|
self.format_struct(arity, ct.name(), state_stack);
|
||||||
@@ -142,41 +143,90 @@ impl HCValueFormatter for TermFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct HCPrinter<'a, Formatter, Outputter> {
|
pub struct HCPrinter<'a, Formatter, Outputter> {
|
||||||
formatter: Formatter,
|
formatter: Formatter,
|
||||||
outputter: Outputter,
|
outputter: Outputter,
|
||||||
iter: HCDerefAcyclicPreOrderIterator<'a>,
|
machine_st: &'a MachineState,
|
||||||
state_stack: Vec<TokenOrRedirect>,
|
state_stack: Vec<TokenOrRedirect>,
|
||||||
heap_locs: Cow<'a, HeapVarDict>
|
heap_locs: Cow<'a, HeapVarDict>,
|
||||||
|
printed_vars: HashSet<Addr>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
|
impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
|
||||||
HCPrinter<'a, Formatter, Outputter>
|
HCPrinter<'a, Formatter, Outputter>
|
||||||
{
|
{
|
||||||
pub fn new(machine_st: &'a MachineState, addr: Addr, fmt: Formatter, output: Outputter) -> Self
|
pub fn new(machine_st: &'a MachineState, fmt: Formatter, output: Outputter) -> Self
|
||||||
{
|
{
|
||||||
let iter = HCPreOrderIterator::new(&machine_st, addr);
|
|
||||||
|
|
||||||
HCPrinter { formatter: fmt,
|
HCPrinter { formatter: fmt,
|
||||||
outputter: output,
|
outputter: output,
|
||||||
iter: iter.deref_acyclic_iter(),
|
machine_st,
|
||||||
state_stack: vec![],
|
state_stack: vec![],
|
||||||
heap_locs: Cow::default() }
|
heap_locs: Cow::default(),
|
||||||
|
printed_vars: HashSet::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_heap_locs(machine_st: &'a MachineState, addr: Addr, fmt: Formatter,
|
pub fn from_heap_locs(machine_st: &'a MachineState, fmt: Formatter,
|
||||||
output: Outputter, heap_locs: &'a HeapVarDict)
|
output: Outputter, heap_locs: &'a HeapVarDict)
|
||||||
-> Self
|
-> Self
|
||||||
{
|
{
|
||||||
let iter = HCPreOrderIterator::new(&machine_st, addr);
|
let mut printer = Self::new(machine_st, fmt, output);
|
||||||
|
|
||||||
HCPrinter { formatter: fmt,
|
printer.heap_locs = Cow::Borrowed(heap_locs);
|
||||||
outputter: output,
|
printer
|
||||||
iter: iter.deref_acyclic_iter(),
|
}
|
||||||
state_stack: vec![],
|
|
||||||
heap_locs: Cow::Borrowed(heap_locs) }
|
pub fn from_heap_locs_as_seen(machine_st: &'a MachineState, fmt: Formatter,
|
||||||
|
output: Outputter, heap_locs: &'a HeapVarDict)
|
||||||
|
-> Self
|
||||||
|
{
|
||||||
|
let mut printer = Self::from_heap_locs(machine_st, fmt, output, heap_locs);
|
||||||
|
|
||||||
|
for (_, addr) in heap_locs.iter() {
|
||||||
|
let addr = machine_st.store(machine_st.deref(addr.clone()));
|
||||||
|
printer.printed_vars.insert(addr.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
printer
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_heap_term(&mut self, heap_val: HeapCellValue) {
|
// returns a HeapCellValue iff the next element to come hasn't been seen previously.
|
||||||
|
fn check_for_seen(&mut self, iter: &mut HCPreOrderIterator) -> Option<HeapCellValue> {
|
||||||
|
iter.stack().last().cloned().and_then(|addr| {
|
||||||
|
let addr = self.machine_st.store(self.machine_st.deref(addr));
|
||||||
|
|
||||||
|
for (var, var_addr) in self.heap_locs.iter() {
|
||||||
|
if &addr == &self.machine_st.store(self.machine_st.deref(var_addr.clone())) {
|
||||||
|
if !self.printed_vars.contains(&addr) {
|
||||||
|
self.printed_vars.insert(addr);
|
||||||
|
return iter.next();
|
||||||
|
} else {
|
||||||
|
iter.stack().pop();
|
||||||
|
self.outputter.append(var.as_str());
|
||||||
|
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// addr is not the address of a named variable. If it is a variable,
|
||||||
|
// it must be anonymous.
|
||||||
|
if addr.is_ref() {
|
||||||
|
self.outputter.append("_");
|
||||||
|
iter.stack().pop();
|
||||||
|
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
iter.next()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_heap_term(&mut self, iter: &mut HCPreOrderIterator)
|
||||||
|
{
|
||||||
|
let heap_val = match self.check_for_seen(iter) {
|
||||||
|
Some(heap_val) => heap_val,
|
||||||
|
_ => return
|
||||||
|
};
|
||||||
|
|
||||||
match heap_val {
|
match heap_val {
|
||||||
HeapCellValue::NamedStr(arity, name, fixity) => {
|
HeapCellValue::NamedStr(arity, name, fixity) => {
|
||||||
let ct = ClauseType::from(name, arity, fixity);
|
let ct = ClauseType::from(name, arity, fixity);
|
||||||
@@ -220,7 +270,11 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print(mut self) -> Outputter {
|
//TODO: idea: hand a mutable ref to iter to handle_heap_term,
|
||||||
|
// and have it query the stack before getting the next thing.
|
||||||
|
pub fn print(mut self, addr: Addr) -> Outputter {
|
||||||
|
let mut iter = HCPreOrderIterator::new(&self.machine_st, addr);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if let Some(loc_data) = self.state_stack.pop() {
|
if let Some(loc_data) = self.state_stack.pop() {
|
||||||
match loc_data {
|
match loc_data {
|
||||||
@@ -228,10 +282,8 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
|
|||||||
self.outputter.append(" "),
|
self.outputter.append(" "),
|
||||||
TokenOrRedirect::Atom(atom) =>
|
TokenOrRedirect::Atom(atom) =>
|
||||||
self.outputter.append(atom.as_str()),
|
self.outputter.append(atom.as_str()),
|
||||||
TokenOrRedirect::Redirect => {
|
TokenOrRedirect::Redirect =>
|
||||||
let heap_val = self.iter.next().unwrap();
|
self.handle_heap_term(&mut iter),
|
||||||
self.handle_heap_term(heap_val);
|
|
||||||
},
|
|
||||||
TokenOrRedirect::Close =>
|
TokenOrRedirect::Close =>
|
||||||
self.outputter.append(")"),
|
self.outputter.append(")"),
|
||||||
TokenOrRedirect::Open =>
|
TokenOrRedirect::Open =>
|
||||||
@@ -251,8 +303,8 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
|
|||||||
TokenOrRedirect::Comma =>
|
TokenOrRedirect::Comma =>
|
||||||
self.outputter.append(", ")
|
self.outputter.append(", ")
|
||||||
}
|
}
|
||||||
} else if let Some(heap_val) = self.iter.next() {
|
} else if !iter.stack().is_empty() {
|
||||||
self.handle_heap_term(heap_val);
|
self.handle_heap_term(&mut iter);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,8 +135,8 @@ impl MachineState {
|
|||||||
pub(super) fn throw_exception(&mut self, err: MachineError) {
|
pub(super) fn throw_exception(&mut self, err: MachineError) {
|
||||||
let h = self.heap.h;
|
let h = self.heap.h;
|
||||||
|
|
||||||
self.ball.0 = 0;
|
self.ball.boundary = 0;
|
||||||
self.ball.1.truncate(0);
|
self.ball.stub.truncate(0);
|
||||||
|
|
||||||
self.heap.append(err);
|
self.heap.append(err);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use prolog::and_stack::*;
|
use prolog::and_stack::*;
|
||||||
use prolog::ast::*;
|
use prolog::ast::*;
|
||||||
use prolog::copier::*;
|
use prolog::copier::*;
|
||||||
|
use prolog::machine::machine_errors::MachineStub;
|
||||||
use prolog::num::{BigInt, BigUint, Zero, One};
|
use prolog::num::{BigInt, BigUint, Zero, One};
|
||||||
use prolog::or_stack::*;
|
use prolog::or_stack::*;
|
||||||
use prolog::heap_print::*;
|
use prolog::heap_print::*;
|
||||||
@@ -14,6 +15,22 @@ use std::mem::swap;
|
|||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub(super) struct Ball {
|
||||||
|
pub(super) boundary: usize, // ball.0
|
||||||
|
pub(super) stub: MachineStub, // ball.1
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ball {
|
||||||
|
pub(super) fn new() -> Self {
|
||||||
|
Ball { boundary: 0, stub: MachineStub::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn reset(&mut self) {
|
||||||
|
self.boundary = 0;
|
||||||
|
self.stub.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) struct CodeDirs<'a> {
|
pub(crate) struct CodeDirs<'a> {
|
||||||
code_dir: &'a CodeDir,
|
code_dir: &'a CodeDir,
|
||||||
modules: &'a HashMap<ClauseName, Module>
|
modules: &'a HashMap<ClauseName, Module>
|
||||||
@@ -109,7 +126,7 @@ impl<'a> Index<usize> for DuplicateBallTerm<'a> {
|
|||||||
&self.state.heap[index]
|
&self.state.heap[index]
|
||||||
} else {
|
} else {
|
||||||
let index = index - self.heap_boundary;
|
let index = index - self.heap_boundary;
|
||||||
&self.state.ball.1[index]
|
&self.state.ball.stub[index]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,7 +137,7 @@ impl<'a> IndexMut<usize> for DuplicateBallTerm<'a> {
|
|||||||
&mut self.state.heap[index]
|
&mut self.state.heap[index]
|
||||||
} else {
|
} else {
|
||||||
let index = index - self.heap_boundary;
|
let index = index - self.heap_boundary;
|
||||||
&mut self.state.ball.1[index]
|
&mut self.state.ball.stub[index]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,11 +149,11 @@ impl<'a> CopierTarget for DuplicateBallTerm<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn threshold(&self) -> usize {
|
fn threshold(&self) -> usize {
|
||||||
self.heap_boundary + self.state.ball.1.len()
|
self.heap_boundary + self.state.ball.stub.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push(&mut self, hcv: HeapCellValue) {
|
fn push(&mut self, hcv: HeapCellValue) {
|
||||||
self.state.ball.1.push(hcv);
|
self.state.ball.stub.push(hcv);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn store(&self, a: Addr) -> Addr {
|
fn store(&self, a: Addr) -> Addr {
|
||||||
@@ -203,7 +220,8 @@ pub struct MachineState {
|
|||||||
pub(super) tr: usize,
|
pub(super) tr: usize,
|
||||||
pub(super) hb: usize,
|
pub(super) hb: usize,
|
||||||
pub(super) block: usize, // an offset into the OR stack.
|
pub(super) block: usize, // an offset into the OR stack.
|
||||||
pub(super) ball: (usize, Vec<HeapCellValue>), // heap boundary, and a term copy
|
pub(super) ball: Ball,
|
||||||
|
pub(super) redirect: CellRedirect,
|
||||||
pub(super) interms: Vec<Number>, // intermediate numbers.
|
pub(super) interms: Vec<Number>, // intermediate numbers.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ impl MachineState {
|
|||||||
tr: 0,
|
tr: 0,
|
||||||
hb: 0,
|
hb: 0,
|
||||||
block: 0,
|
block: 0,
|
||||||
ball: (0, Vec::new()),
|
ball: Ball::new(),
|
||||||
|
redirect: CellRedirect::new(),
|
||||||
interms: vec![Number::default(); 256]
|
interms: vec![Number::default(); 256]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,7 +98,7 @@ impl MachineState {
|
|||||||
fn print_var_eq<Fmt, Outputter>(&self, var: Rc<Var>, addr: Addr, var_dir: &HeapVarDict,
|
fn print_var_eq<Fmt, Outputter>(&self, var: Rc<Var>, addr: Addr, var_dir: &HeapVarDict,
|
||||||
fmt: Fmt, mut output: Outputter)
|
fmt: Fmt, mut output: Outputter)
|
||||||
-> Outputter
|
-> Outputter
|
||||||
where Fmt: HCValueFormatter, Outputter: HCValueOutputter
|
where Fmt: HCValueFormatter, Outputter: HCValueOutputter
|
||||||
{
|
{
|
||||||
let orig_len = output.len();
|
let orig_len = output.len();
|
||||||
|
|
||||||
@@ -106,8 +107,8 @@ impl MachineState {
|
|||||||
output.append(var.as_str());
|
output.append(var.as_str());
|
||||||
output.append(" = ");
|
output.append(" = ");
|
||||||
|
|
||||||
let printer = HCPrinter::from_heap_locs(&self, addr, fmt, output, var_dir);
|
let printer = HCPrinter::from_heap_locs(&self, fmt, output, var_dir);
|
||||||
let mut output = printer.print();
|
let mut output = printer.print(addr);
|
||||||
|
|
||||||
if output.ends_with(var.as_str()) {
|
if output.ends_with(var.as_str()) {
|
||||||
output.truncate(orig_len);
|
output.truncate(orig_len);
|
||||||
@@ -115,13 +116,23 @@ impl MachineState {
|
|||||||
|
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super)
|
||||||
|
fn print_exception<Fmt, Outputter>(&self, addr: Addr, var_dir: &HeapVarDict,
|
||||||
|
fmt: Fmt, output: Outputter)
|
||||||
|
-> Outputter
|
||||||
|
where Fmt: HCValueFormatter, Outputter: HCValueOutputter
|
||||||
|
{
|
||||||
|
let printer = HCPrinter::from_heap_locs_as_seen(&self, fmt, output, var_dir);
|
||||||
|
printer.print(addr)
|
||||||
|
}
|
||||||
|
|
||||||
pub(super)
|
pub(super)
|
||||||
fn print_term<Fmt, Outputter>(&self, addr: Addr, fmt: Fmt, output: Outputter) -> Outputter
|
fn print_term<Fmt, Outputter>(&self, addr: Addr, fmt: Fmt, output: Outputter) -> Outputter
|
||||||
where Fmt: HCValueFormatter, Outputter: HCValueOutputter
|
where Fmt: HCValueFormatter, Outputter: HCValueOutputter
|
||||||
{
|
{
|
||||||
let printer = HCPrinter::new(&self, addr, fmt, output);
|
let printer = HCPrinter::new(&self, fmt, output);
|
||||||
printer.print()
|
printer.print(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn unify(&mut self, a1: Addr, a2: Addr) {
|
pub(super) fn unify(&mut self, a1: Addr, a2: Addr) {
|
||||||
@@ -1089,26 +1100,25 @@ impl MachineState {
|
|||||||
Some((name, arity + narity - 1))
|
Some((name, arity + narity - 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn copy_and_align_ball_to_heap(&mut self) {
|
fn heap_ball_boundary_diff(&self) -> usize {
|
||||||
let diff = if self.ball.0 > self.heap.h {
|
if self.ball.boundary > self.heap.h {
|
||||||
self.ball.0 - self.heap.h
|
self.ball.boundary - self.heap.h
|
||||||
} else {
|
} else {
|
||||||
self.heap.h - self.ball.0
|
self.heap.h - self.ball.boundary
|
||||||
};
|
}
|
||||||
|
}
|
||||||
for heap_value in self.ball.1.iter().cloned() {
|
|
||||||
|
pub(super) fn copy_and_align_ball_to_heap(&mut self) -> usize {
|
||||||
|
let diff = self.heap_ball_boundary_diff();
|
||||||
|
|
||||||
|
for heap_value in self.ball.stub.iter().cloned() {
|
||||||
self.heap.push(match heap_value {
|
self.heap.push(match heap_value {
|
||||||
HeapCellValue::Addr(Addr::Con(c)) =>
|
HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr - diff),
|
||||||
HeapCellValue::Addr(Addr::Con(c)),
|
|
||||||
HeapCellValue::Addr(Addr::Lis(a)) =>
|
|
||||||
HeapCellValue::Addr(Addr::Lis(a - diff)),
|
|
||||||
HeapCellValue::Addr(Addr::HeapCell(hc)) =>
|
|
||||||
HeapCellValue::Addr(Addr::HeapCell(hc - diff)),
|
|
||||||
HeapCellValue::Addr(Addr::Str(s)) =>
|
|
||||||
HeapCellValue::Addr(Addr::Str(s - diff)),
|
|
||||||
_ => heap_value
|
_ => heap_value
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
diff
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn is_cyclic_term(&self, addr: Addr) -> bool {
|
pub(super) fn is_cyclic_term(&self, addr: Addr) -> bool {
|
||||||
@@ -1179,6 +1189,25 @@ impl MachineState {
|
|||||||
self.p += 1;
|
self.p += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// everything in self.redirect is potentially offset on the heap by 'offset',
|
||||||
|
// so correct for that when building the HeapVarDict.
|
||||||
|
pub(super) fn reconstruct_dict(&self, heap_locs: &HeapVarDict, offset: usize) -> HeapVarDict
|
||||||
|
{
|
||||||
|
let mut dest_heap_locs = HeapVarDict::new();
|
||||||
|
|
||||||
|
'outer:
|
||||||
|
for (orig_addr, addr) in self.redirect.0.iter() {
|
||||||
|
for (var, var_addr) in heap_locs.iter() {
|
||||||
|
if orig_addr == &self.store(self.deref(var_addr.clone())) {
|
||||||
|
dest_heap_locs.insert(var.clone(), addr.clone() + offset);
|
||||||
|
continue 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dest_heap_locs
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn compare_term(&mut self, qt: CompareTermQT) {
|
pub(super) fn compare_term(&mut self, qt: CompareTermQT) {
|
||||||
let a1 = self[temp_v!(1)].clone();
|
let a1 = self[temp_v!(1)].clone();
|
||||||
let a2 = self[temp_v!(2)].clone();
|
let a2 = self[temp_v!(2)].clone();
|
||||||
@@ -1433,8 +1462,7 @@ impl MachineState {
|
|||||||
try_or_fail!(self, call_policy.trust_me(self));
|
try_or_fail!(self, call_policy.trust_me(self));
|
||||||
},
|
},
|
||||||
&BuiltInInstruction::EraseBall => {
|
&BuiltInInstruction::EraseBall => {
|
||||||
self.ball.0 = 0;
|
self.ball.reset();
|
||||||
self.ball.1.truncate(0);
|
|
||||||
self.p += 1;
|
self.p += 1;
|
||||||
},
|
},
|
||||||
&BuiltInInstruction::GetArg(lco) =>
|
&BuiltInInstruction::GetArg(lco) =>
|
||||||
@@ -1460,7 +1488,7 @@ impl MachineState {
|
|||||||
let addr = self.store(self.deref(self[temp_v!(1)].clone()));
|
let addr = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||||
let h = self.heap.h;
|
let h = self.heap.h;
|
||||||
|
|
||||||
if self.ball.1.len() > 0 {
|
if self.ball.stub.len() > 0 {
|
||||||
self.copy_and_align_ball_to_heap();
|
self.copy_and_align_ball_to_heap();
|
||||||
} else {
|
} else {
|
||||||
self.fail = true;
|
self.fail = true;
|
||||||
@@ -1608,13 +1636,14 @@ impl MachineState {
|
|||||||
},
|
},
|
||||||
&BuiltInInstruction::SetBall => {
|
&BuiltInInstruction::SetBall => {
|
||||||
let addr = self[temp_v!(1)].clone();
|
let addr = self[temp_v!(1)].clone();
|
||||||
self.ball.0 = self.heap.h;
|
self.ball.boundary = self.heap.h;
|
||||||
|
|
||||||
{
|
let cell_redirect = {
|
||||||
let mut duplicator = DuplicateBallTerm::new(self);
|
let mut duplicator = DuplicateBallTerm::new(self);
|
||||||
duplicator.duplicate_term(addr);
|
duplicator.duplicate_term(addr)
|
||||||
}
|
};
|
||||||
|
|
||||||
|
self.redirect.0.extend(cell_redirect.0.into_iter());
|
||||||
self.p += 1;
|
self.p += 1;
|
||||||
},
|
},
|
||||||
&BuiltInInstruction::SetCutPoint(r) =>
|
&BuiltInInstruction::SetCutPoint(r) =>
|
||||||
@@ -2323,6 +2352,8 @@ impl MachineState {
|
|||||||
self.or_stack.clear();
|
self.or_stack.clear();
|
||||||
self.registers = vec![Addr::HeapCell(0); 64];
|
self.registers = vec![Addr::HeapCell(0); 64];
|
||||||
self.block = 0;
|
self.block = 0;
|
||||||
self.ball = (0, Vec::new());
|
|
||||||
|
self.ball.reset();
|
||||||
|
self.redirect.0.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,11 +57,11 @@ impl<'a> SubModuleUser for MachineCodeIndex<'a> {
|
|||||||
fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: ModuleCodeIndex) {
|
fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: ModuleCodeIndex) {
|
||||||
if let Some(ref mut code_idx) = self.code_dir.get_mut(&(name.clone(), arity)) {
|
if let Some(ref mut code_idx) = self.code_dir.get_mut(&(name.clone(), arity)) {
|
||||||
println!("warning: overwriting {}/{}", &name, arity);
|
println!("warning: overwriting {}/{}", &name, arity);
|
||||||
set_code_index!(code_idx, idx.0, idx.1);
|
set_code_index!(code_idx, idx.0, idx.1);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.code_dir.insert((name, arity), CodeIndex::from(idx));
|
self.code_dir.insert((name, arity), CodeIndex::from(idx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,7 +99,7 @@ impl Machine {
|
|||||||
if &code_idx.borrow().1 != &module_name {
|
if &code_idx.borrow().1 != &module_name {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.code_dir.remove(&(name.clone(), arity));
|
self.code_dir.remove(&(name.clone(), arity));
|
||||||
|
|
||||||
// remove or respecify ops.
|
// remove or respecify ops.
|
||||||
@@ -194,7 +194,7 @@ impl Machine {
|
|||||||
Some(&CodeIndex (ref idx)) if idx.borrow().1 != clause_name!("user") =>
|
Some(&CodeIndex (ref idx)) if idx.borrow().1 != clause_name!("user") =>
|
||||||
return EvalSession::from(SessionError::ImpermissibleEntry(format!("{}/{}",
|
return EvalSession::from(SessionError::ImpermissibleEntry(format!("{}/{}",
|
||||||
name,
|
name,
|
||||||
arity))),
|
arity))),
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -370,18 +370,20 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fail(&mut self) -> EvalSession
|
fn fail(&mut self, heap_locs: &HeapVarDict) -> EvalSession
|
||||||
{
|
{
|
||||||
if self.ms.ball.1.len() > 0 {
|
if self.ms.ball.stub.len() > 0 {
|
||||||
let h = self.ms.heap.h;
|
let h = self.ms.heap.h;
|
||||||
self.ms.copy_and_align_ball_to_heap();
|
self.ms.copy_and_align_ball_to_heap();
|
||||||
|
|
||||||
let msg = self.ms.print_term(Addr::HeapCell(h),
|
let heap_locs = self.ms.reconstruct_dict(heap_locs, h);
|
||||||
TermFormatter {},
|
let error_str = self.ms.print_exception(Addr::HeapCell(h),
|
||||||
PrinterOutputter::new())
|
&heap_locs,
|
||||||
.result();
|
TermFormatter {},
|
||||||
|
PrinterOutputter::new())
|
||||||
|
.result();
|
||||||
|
|
||||||
EvalSession::from(SessionError::QueryFailureWithException(msg))
|
EvalSession::from(SessionError::QueryFailureWithException(error_str))
|
||||||
} else {
|
} else {
|
||||||
EvalSession::from(SessionError::QueryFailure)
|
EvalSession::from(SessionError::QueryFailure)
|
||||||
}
|
}
|
||||||
@@ -395,7 +397,7 @@ impl Machine {
|
|||||||
self.run_query(&alloc_locs, &mut heap_locs);
|
self.run_query(&alloc_locs, &mut heap_locs);
|
||||||
|
|
||||||
if self.failed() {
|
if self.failed() {
|
||||||
self.fail()
|
self.fail(&heap_locs)
|
||||||
} else {
|
} else {
|
||||||
EvalSession::InitialQuerySuccess(alloc_locs, heap_locs)
|
EvalSession::InitialQuerySuccess(alloc_locs, heap_locs)
|
||||||
}
|
}
|
||||||
@@ -414,7 +416,7 @@ impl Machine {
|
|||||||
self.run_query(alloc_l, heap_l);
|
self.run_query(alloc_l, heap_l);
|
||||||
|
|
||||||
if self.failed() {
|
if self.failed() {
|
||||||
self.fail()
|
self.fail(&heap_l)
|
||||||
} else {
|
} else {
|
||||||
EvalSession::SubsequentQuerySuccess
|
EvalSession::SubsequentQuerySuccess
|
||||||
}
|
}
|
||||||
|
|||||||
41
src/tests.rs
41
src/tests.rs
@@ -271,7 +271,7 @@ fn test_queries_on_rules() {
|
|||||||
assert_prolog_success!(&mut wam, "?- p(f(X, g(Y), Z), g(Z), h).",
|
assert_prolog_success!(&mut wam, "?- p(f(X, g(Y), Z), g(Z), h).",
|
||||||
[["Z = b", "Y = b", "X = f(a)"]]);
|
[["Z = b", "Y = b", "X = f(a)"]]);
|
||||||
assert_prolog_success!(&mut wam, "?- p(Z, Y, X).",
|
assert_prolog_success!(&mut wam, "?- p(Z, Y, X).",
|
||||||
[["X = h", "Y = g(b)", "Z = f(f(a), g(b), _7)"]]);
|
[["X = h", "Y = g(b)", "Z = f(f(a), g(b), _)"]]);
|
||||||
assert_prolog_success!(&mut wam, "?- p(f(X, Y, Z), Y, h).",
|
assert_prolog_success!(&mut wam, "?- p(f(X, Y, Z), Y, h).",
|
||||||
[["Y = g(b)", "Z = _3", "X = f(a)"]]);
|
[["Y = g(b)", "Z = _3", "X = f(a)"]]);
|
||||||
|
|
||||||
@@ -539,7 +539,7 @@ fn test_queries_on_lists()
|
|||||||
|
|
||||||
assert_prolog_success!(&mut wam, "?- p([Z, Z]).", [["Z = _0"]]);
|
assert_prolog_success!(&mut wam, "?- p([Z, Z]).", [["Z = _0"]]);
|
||||||
assert_prolog_failure!(&mut wam, "?- p([Z, W, Y]).");
|
assert_prolog_failure!(&mut wam, "?- p([Z, W, Y]).");
|
||||||
assert_prolog_success!(&mut wam, "?- p([Z | W]).", [["Z = _0", "W = [_3]"]]);
|
assert_prolog_success!(&mut wam, "?- p([Z | W]).", [["Z = _0", "W = [_]"]]);
|
||||||
assert_prolog_success!(&mut wam, "?- p([Z | [Z]]).", [["Z = _0"]]);
|
assert_prolog_success!(&mut wam, "?- p([Z | [Z]]).", [["Z = _0"]]);
|
||||||
assert_prolog_success!(&mut wam, "?- p([Z | [W]]).", [["Z = _2", "W = _0"]]);
|
assert_prolog_success!(&mut wam, "?- p([Z | [W]]).", [["Z = _2", "W = _0"]]);
|
||||||
assert_prolog_failure!(&mut wam, "?- p([Z | []]).");
|
assert_prolog_failure!(&mut wam, "?- p([Z | []]).");
|
||||||
@@ -600,7 +600,7 @@ fn test_queries_on_conjuctive_queries() {
|
|||||||
submit(&mut wam, "p(a, [f(g(X))]).");
|
submit(&mut wam, "p(a, [f(g(X))]).");
|
||||||
submit(&mut wam, "q(Y, c).");
|
submit(&mut wam, "q(Y, c).");
|
||||||
|
|
||||||
assert_prolog_success!(&mut wam, "?- p(X, Y), q(Y, Z).", [["Y = [f(g(_9))]", "X = a", "Z = c"]]);
|
assert_prolog_success!(&mut wam, "?- p(X, Y), q(Y, Z).", [["Y = [f(g(_))]", "X = a", "Z = c"]]);
|
||||||
assert_prolog_failure!(&mut wam, "?- p(X, Y), q(Y, X).");
|
assert_prolog_failure!(&mut wam, "?- p(X, Y), q(Y, X).");
|
||||||
|
|
||||||
submit(&mut wam, "member(X, [X|_]).
|
submit(&mut wam, "member(X, [X|_]).
|
||||||
@@ -632,10 +632,10 @@ fn test_queries_on_conjuctive_queries() {
|
|||||||
submit(&mut wam, "q(Y, c).");
|
submit(&mut wam, "q(Y, c).");
|
||||||
|
|
||||||
assert_prolog_success!(&mut wam, "?- p(X, Y), q(Y, Z).",
|
assert_prolog_success!(&mut wam, "?- p(X, Y), q(Y, Z).",
|
||||||
[["X = a", "Z = c", "Y = [f(g(_9))]"],
|
[["X = a", "Z = c", "Y = [f(g(_))]"],
|
||||||
["X = _0", "Z = c", "Y = c"]]);
|
["X = _0", "Z = c", "Y = c"]]);
|
||||||
assert_prolog_success!(&mut wam, "?- p(X, Y), !, q(Y, Z).",
|
assert_prolog_success!(&mut wam, "?- p(X, Y), !, q(Y, Z).",
|
||||||
[["Z = c", "Y = [f(g(_9))]", "X = a"]]);
|
[["Z = c", "Y = [f(g(_))]", "X = a"]]);
|
||||||
|
|
||||||
submit(&mut wam, "q([f(g(x))], Z). q([f(g(y))], Y). q([f(g(z))], a).");
|
submit(&mut wam, "q([f(g(x))], Z). q([f(g(y))], Y). q([f(g(z))], a).");
|
||||||
|
|
||||||
@@ -1260,8 +1260,8 @@ fn test_queries_on_builtins()
|
|||||||
|
|
||||||
assert_prolog_success!(&mut wam, "?- functor(F, f, 0).", [["F = f"]]);
|
assert_prolog_success!(&mut wam, "?- functor(F, f, 0).", [["F = f"]]);
|
||||||
|
|
||||||
assert_prolog_success!(&mut wam, "?- functor(Func, f, 3).", [["Func = f(_2, _3, _4)"]]);
|
assert_prolog_success!(&mut wam, "?- functor(Func, f, 3).", [["Func = f(_, _, _)"]]);
|
||||||
assert_prolog_success!(&mut wam, "?- functor(Func, f, 4).", [["Func = f(_2, _3, _4, _5)"]]);
|
assert_prolog_success!(&mut wam, "?- functor(Func, f, 4).", [["Func = f(_, _, _, _)"]]);
|
||||||
|
|
||||||
assert_prolog_success!(&mut wam, "?- catch(functor(F, \"sdf\", 3), error(E, _), true).",
|
assert_prolog_success!(&mut wam, "?- catch(functor(F, \"sdf\", 3), error(E, _), true).",
|
||||||
[["E = instantiation_error", "F = _1"]]);
|
[["E = instantiation_error", "F = _1"]]);
|
||||||
@@ -1289,14 +1289,14 @@ fn test_queries_on_builtins()
|
|||||||
|
|
||||||
assert_prolog_success_with_limit!(&mut wam, "?- length(Xs, N).",
|
assert_prolog_success_with_limit!(&mut wam, "?- length(Xs, N).",
|
||||||
[["N = 0", "Xs = []"],
|
[["N = 0", "Xs = []"],
|
||||||
["N = 1", "Xs = [_3]"],
|
["N = 1", "Xs = [_]"],
|
||||||
["N = 2", "Xs = [_3, _6]"],
|
["N = 2", "Xs = [_, _]"],
|
||||||
["N = 3", "Xs = [_3, _6, _9]"],
|
["N = 3", "Xs = [_, _, _]"],
|
||||||
["N = 4", "Xs = [_3, _6, _9, _12]"],
|
["N = 4", "Xs = [_, _, _, _]"],
|
||||||
["N = 5", "Xs = [_3, _6, _9, _12, _15]"]],
|
["N = 5", "Xs = [_, _, _, _, _]"]],
|
||||||
6);
|
6);
|
||||||
|
|
||||||
assert_prolog_success!(&mut wam, "?- length(Xs, 3).", [["Xs = [_2, _5, _8]"]]);
|
assert_prolog_success!(&mut wam, "?- length(Xs, 3).", [["Xs = [_, _, _]"]]);
|
||||||
assert_prolog_success!(&mut wam, "?- length([a,b,c], N).", [["N = 3"]]);
|
assert_prolog_success!(&mut wam, "?- length([a,b,c], N).", [["N = 3"]]);
|
||||||
assert_prolog_success!(&mut wam, "?- length([], N).", [["N = 0"]]);
|
assert_prolog_success!(&mut wam, "?- length([], N).", [["N = 0"]]);
|
||||||
assert_prolog_success!(&mut wam, "?- length(Xs, 0).", [["Xs = []"]]);
|
assert_prolog_success!(&mut wam, "?- length(Xs, 0).", [["Xs = []"]]);
|
||||||
@@ -1413,11 +1413,14 @@ fn test_queries_on_builtins()
|
|||||||
assert_prolog_success!(&mut wam, "?- keysort([1-1, 1-1], Sorted).",
|
assert_prolog_success!(&mut wam, "?- keysort([1-1, 1-1], Sorted).",
|
||||||
[["Sorted = [1 - 1, 1 - 1]"]]);
|
[["Sorted = [1 - 1, 1 - 1]"]]);
|
||||||
assert_prolog_success!(&mut wam, "?- keysort([2-99, 1-a, 3-f(_), 1-z, 1-a, 2-44], Sorted).",
|
assert_prolog_success!(&mut wam, "?- keysort([2-99, 1-a, 3-f(_), 1-z, 1-a, 2-44], Sorted).",
|
||||||
[["Sorted = [1 - a, 1 - z, 1 - a, 2 - 99, 2 - 44, 3 - f(_7)]"]]);
|
[["Sorted = [1 - a, 1 - z, 1 - a, 2 - 99, 2 - 44, 3 - f(_)]"]]);
|
||||||
assert_prolog_success!(&mut wam, "?- keysort([X-1,1-1],[2-1,1-1]).",
|
assert_prolog_success!(&mut wam, "?- keysort([X-1,1-1],[2-1,1-1]).",
|
||||||
[["X = 2"]]);
|
[["X = 2"]]);
|
||||||
//TODO: enable the printer to print cyclic terms. Then run this test.
|
|
||||||
//assert_prolog_failure!(&mut wam, "?- Pairs = [a-a|Pairs], keysort(Pairs, _).");
|
assert_prolog_failure!(&mut wam, "?- Pairs = [a-a|Pairs], keysort(Pairs, _).");
|
||||||
|
// assert_prolog_success!(&mut wam, "?- Pairs = [a-a|Pairs], catch(keysort(Pairs, _), error(E, _), true).",
|
||||||
|
// [["E = type_error(list, Pairs)", "Pairs = [a - a | Pairs]"]]);
|
||||||
|
|
||||||
assert_prolog_success!(&mut wam, "?- keysort([], L).",
|
assert_prolog_success!(&mut wam, "?- keysort([], L).",
|
||||||
[["L = []"]]);
|
[["L = []"]]);
|
||||||
assert_prolog_success!(&mut wam, "?- catch(keysort([a|_], _), error(E, _), true).",
|
assert_prolog_success!(&mut wam, "?- catch(keysort([a|_], _), error(E, _), true).",
|
||||||
@@ -1425,9 +1428,9 @@ fn test_queries_on_builtins()
|
|||||||
assert_prolog_success!(&mut wam, "?- catch(keysort([],[a|a]),error(Pat, _),true).",
|
assert_prolog_success!(&mut wam, "?- catch(keysort([],[a|a]),error(Pat, _),true).",
|
||||||
[["Pat = type_error(list, [a | a])"]]);
|
[["Pat = type_error(list, [a | a])"]]);
|
||||||
assert_prolog_success!(&mut wam, "?- catch(keysort(_, _), error(E, _), true).",
|
assert_prolog_success!(&mut wam, "?- catch(keysort(_, _), error(E, _), true).",
|
||||||
[["E = type_error(list, _12)"]]);
|
[["E = type_error(list, _)"]]);
|
||||||
assert_prolog_success!(&mut wam, "?- catch(keysort([a-1], [_|b]), error(E, _), true).",
|
assert_prolog_success!(&mut wam, "?- catch(keysort([a-1], [_|b]), error(E, _), true).",
|
||||||
[["E = type_error(list, [_23 | b])"]]);
|
[["E = type_error(list, [_ | b])"]]);
|
||||||
assert_prolog_success!(&mut wam, "?- catch(keysort([a-1], [a-b,c-d,a]), error(E, _), true).",
|
assert_prolog_success!(&mut wam, "?- catch(keysort([a-1], [a-b,c-d,a]), error(E, _), true).",
|
||||||
[["E = type_error(pair, a)"]]);
|
[["E = type_error(pair, a)"]]);
|
||||||
assert_prolog_success!(&mut wam, "?- catch(keysort([a], [a-b]), error(E, _), true).",
|
assert_prolog_success!(&mut wam, "?- catch(keysort([a], [a-b]), error(E, _), true).",
|
||||||
@@ -1440,7 +1443,7 @@ fn test_queries_on_builtins()
|
|||||||
assert_prolog_success!(&mut wam, "?- sort([], L).",
|
assert_prolog_success!(&mut wam, "?- sort([], L).",
|
||||||
[["L = []"]]);
|
[["L = []"]]);
|
||||||
assert_prolog_success!(&mut wam, "?- catch(sort(_, []), error(E, _), true).",
|
assert_prolog_success!(&mut wam, "?- catch(sort(_, []), error(E, _), true).",
|
||||||
[["E = type_error(list, _12)"]]);
|
[["E = type_error(list, _)"]]);
|
||||||
assert_prolog_success!(&mut wam, "?- catch(sort([a,b,c], not_a_list), error(E, _), true).",
|
assert_prolog_success!(&mut wam, "?- catch(sort([a,b,c], not_a_list), error(E, _), true).",
|
||||||
[["E = type_error(list, not_a_list)"]]);
|
[["E = type_error(list, not_a_list)"]]);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user