add acyclic term

This commit is contained in:
Mark Thom
2018-03-28 21:17:46 -06:00
parent eb694cbba7
commit 80b59bae83
4 changed files with 46 additions and 12 deletions

View File

@@ -122,6 +122,7 @@ The following predicates are built-in to rusty-wam.
* `(=..)/2` * `(=..)/2`
* `(->)/2` * `(->)/2`
* `(;)/2` * `(;)/2`
* `acyclic_term/2`
* `append/3` * `append/3`
* `arg/3` * `arg/3`
* `atom/1` * `atom/1`

View File

@@ -673,6 +673,7 @@ pub struct Rule {
#[derive(Clone)] #[derive(Clone)]
pub enum ClauseType { pub enum ClauseType {
AcyclicTerm,
Arg, Arg,
CallN, CallN,
CallWithInferenceLimit, CallWithInferenceLimit,
@@ -773,7 +774,8 @@ impl ClauseType {
pub fn name(&self) -> ClauseName { pub fn name(&self) -> ClauseName {
match self { match self {
&ClauseType::Arg => clause_name!("arg"), &ClauseType::AcyclicTerm => clause_name!("acyclic_term"),
&ClauseType::Arg => clause_name!("arg"),
&ClauseType::CallN => clause_name!("call"), &ClauseType::CallN => clause_name!("call"),
&ClauseType::CallWithInferenceLimit => clause_name!("call_with_inference_limit"), &ClauseType::CallWithInferenceLimit => clause_name!("call_with_inference_limit"),
&ClauseType::Catch => clause_name!("catch"), &ClauseType::Catch => clause_name!("catch"),
@@ -798,6 +800,7 @@ impl ClauseType {
pub fn from(name: ClauseName, arity: usize, fixity: Option<Fixity>) -> Self { pub fn from(name: ClauseName, arity: usize, fixity: Option<Fixity>) -> Self {
match (name.as_str(), arity) { match (name.as_str(), arity) {
("acyclic_term", 1) => ClauseType::AcyclicTerm,
("arg", 3) => ClauseType::Arg, ("arg", 3) => ClauseType::Arg,
("call", _) => ClauseType::CallN, ("call", _) => ClauseType::CallN,
("call_with_inference_limit", 3) => ClauseType::CallWithInferenceLimit, ("call_with_inference_limit", 3) => ClauseType::CallWithInferenceLimit,

View File

@@ -59,18 +59,16 @@ impl<'a> Iterator for HeapCellPreOrderIterator<'a> {
type Item = HeapCellValue; type Item = HeapCellValue;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if let Some(a) = self.state_stack.pop() { self.state_stack.pop().map(|a| {
match self.follow(a) { match self.follow(a) {
Addr::HeapCell(h) => Some(self.machine_st.heap[h].clone()), Addr::HeapCell(h) =>
Addr::StackCell(fr, sc) => { self.machine_st.heap[h].clone(),
let heap_val = HeapCellValue::Addr(self.machine_st.and_stack[fr][sc].clone()); Addr::StackCell(fr, sc) =>
Some(heap_val) HeapCellValue::Addr(self.machine_st.and_stack[fr][sc].clone()),
}, da =>
da => Some(HeapCellValue::Addr(da)) HeapCellValue::Addr(da)
} }
} else { })
None
}
} }
} }
@@ -119,6 +117,10 @@ impl<'a> Iterator for HeapCellPostOrderIterator<'a> {
} }
impl MachineState { impl MachineState {
pub fn pre_order_iter<'a>(&'a self, a: Addr) -> HeapCellPreOrderIterator<'a> {
HeapCellPreOrderIterator::new(self, a)
}
pub fn post_order_iter<'a>(&'a self, a: Addr) -> HeapCellPostOrderIterator<'a> { pub fn post_order_iter<'a>(&'a self, a: Addr) -> HeapCellPostOrderIterator<'a> {
HeapCellPostOrderIterator::new(HeapCellPreOrderIterator::new(self, a)) HeapCellPostOrderIterator::new(HeapCellPreOrderIterator::new(self, a))
} }

View File

@@ -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::heap_iter::*;
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::*;
@@ -9,7 +10,7 @@ use prolog::tabled_rc::*;
use downcast::Any; use downcast::Any;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::HashMap; use std::collections::{HashMap, HashSet};
use std::mem::swap; use std::mem::swap;
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
use std::rc::Rc; use std::rc::Rc;
@@ -395,6 +396,33 @@ pub(crate) trait CallPolicy: Any {
-> CallResult -> CallResult
{ {
match ct { match ct {
&ClauseType::AcyclicTerm => {
let addr = machine_st[temp_v!(1)].clone();
let mut seen = HashSet::new();
let mut fail = false;
{
let mut iter = machine_st.pre_order_iter(addr);
loop {
if let Some(addr) = iter.stack().last() {
if !seen.contains(addr) {
seen.insert(addr.clone());
} else {
fail = true;
break;
}
}
if iter.next().is_none() {
break;
}
}
}
machine_st.fail = fail;
return_from_clause!(lco, machine_st)
},
&ClauseType::Arg => { &ClauseType::Arg => {
if !lco { if !lco {
machine_st.cp = machine_st.p.clone() + 1; machine_st.cp = machine_st.p.clone() + 1;