add cyclic_term
This commit is contained in:
@@ -134,6 +134,7 @@ The following predicates are built-in to rusty-wam.
|
|||||||
* `catch/3`
|
* `catch/3`
|
||||||
* `compare/3`
|
* `compare/3`
|
||||||
* `compound/1`
|
* `compound/1`
|
||||||
|
* `cyclic_term/1`
|
||||||
* `display/1`
|
* `display/1`
|
||||||
* `duplicate_term/2`
|
* `duplicate_term/2`
|
||||||
* `false/0`
|
* `false/0`
|
||||||
|
|||||||
@@ -132,11 +132,14 @@ impl PredicateClause {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub type OpDirKey = (ClauseName, Fixity);
|
pub type OpDirKey = (ClauseName, Fixity);
|
||||||
|
|
||||||
// name and fixity -> operator type and precedence.
|
// name and fixity -> operator type and precedence.
|
||||||
pub type OpDir = HashMap<OpDirKey, (Specifier, usize, ClauseName)>;
|
pub type OpDir = HashMap<OpDirKey, (Specifier, usize, ClauseName)>;
|
||||||
|
|
||||||
pub type CodeDir = HashMap<PredicateKey, (usize, ClauseName)>;
|
pub type CodeDir = HashMap<PredicateKey, (usize, ClauseName)>;
|
||||||
|
|
||||||
|
pub type TermDir = HashMap<PredicateKey, Predicate>;
|
||||||
|
|
||||||
pub type PredicateKey = (ClauseName, usize); // name, arity.
|
pub type PredicateKey = (ClauseName, usize); // name, arity.
|
||||||
|
|
||||||
pub struct ModuleDecl {
|
pub struct ModuleDecl {
|
||||||
@@ -249,11 +252,7 @@ impl TopLevel {
|
|||||||
&TopLevel::Declaration(_) => None,
|
&TopLevel::Declaration(_) => None,
|
||||||
&TopLevel::Fact(ref term) => term.name(),
|
&TopLevel::Fact(ref term) => term.name(),
|
||||||
&TopLevel::Predicate(ref clauses) =>
|
&TopLevel::Predicate(ref clauses) =>
|
||||||
if let Some(ref term) = clauses.first() {
|
clauses.first().and_then(|ref term| term.name()),
|
||||||
term.name()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
},
|
|
||||||
&TopLevel::Query(_) => None,
|
&TopLevel::Query(_) => None,
|
||||||
&TopLevel::Rule(Rule { ref head, .. }) =>
|
&TopLevel::Rule(Rule { ref head, .. }) =>
|
||||||
Some(head.0.clone())
|
Some(head.0.clone())
|
||||||
@@ -270,6 +269,15 @@ impl TopLevel {
|
|||||||
&TopLevel::Rule(Rule { ref head, .. }) => head.1.len()
|
&TopLevel::Rule(Rule { ref head, .. }) => head.1.len()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_predicate(self) -> Option<Predicate> {
|
||||||
|
match self {
|
||||||
|
TopLevel::Fact(term) => Some(vec![PredicateClause::Fact(term)]),
|
||||||
|
TopLevel::Rule(rule) => Some(vec![PredicateClause::Rule(rule)]),
|
||||||
|
TopLevel::Predicate(pred) => Some(pred),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
@@ -680,6 +688,7 @@ pub enum ClauseType {
|
|||||||
Catch,
|
Catch,
|
||||||
Compare,
|
Compare,
|
||||||
CompareTerm(CompareTermQT),
|
CompareTerm(CompareTermQT),
|
||||||
|
CyclicTerm,
|
||||||
Display,
|
Display,
|
||||||
DuplicateTerm,
|
DuplicateTerm,
|
||||||
Eq,
|
Eq,
|
||||||
@@ -775,12 +784,13 @@ impl ClauseType {
|
|||||||
pub fn name(&self) -> ClauseName {
|
pub fn name(&self) -> ClauseName {
|
||||||
match self {
|
match self {
|
||||||
&ClauseType::AcyclicTerm => clause_name!("acyclic_term"),
|
&ClauseType::AcyclicTerm => clause_name!("acyclic_term"),
|
||||||
&ClauseType::Arg => clause_name!("arg"),
|
&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"),
|
||||||
&ClauseType::Compare => clause_name!("compare"),
|
&ClauseType::Compare => clause_name!("compare"),
|
||||||
&ClauseType::CompareTerm(qt) => clause_name!(qt.name()),
|
&ClauseType::CompareTerm(qt) => clause_name!(qt.name()),
|
||||||
|
&ClauseType::CyclicTerm => clause_name!("cyclic_term"),
|
||||||
&ClauseType::Display => clause_name!("display"),
|
&ClauseType::Display => clause_name!("display"),
|
||||||
&ClauseType::DuplicateTerm => clause_name!("duplicate_term"),
|
&ClauseType::DuplicateTerm => clause_name!("duplicate_term"),
|
||||||
&ClauseType::Eq => clause_name!("=="),
|
&ClauseType::Eq => clause_name!("=="),
|
||||||
@@ -806,6 +816,7 @@ impl ClauseType {
|
|||||||
("call_with_inference_limit", 3) => ClauseType::CallWithInferenceLimit,
|
("call_with_inference_limit", 3) => ClauseType::CallWithInferenceLimit,
|
||||||
("catch", 3) => ClauseType::Catch,
|
("catch", 3) => ClauseType::Catch,
|
||||||
("compare", 3) => ClauseType::Compare,
|
("compare", 3) => ClauseType::Compare,
|
||||||
|
("cyclic_term", 1) => ClauseType::CyclicTerm,
|
||||||
("@>", 2) => ClauseType::CompareTerm(CompareTermQT::GreaterThan),
|
("@>", 2) => ClauseType::CompareTerm(CompareTermQT::GreaterThan),
|
||||||
("@<", 2) => ClauseType::CompareTerm(CompareTermQT::LessThan),
|
("@<", 2) => ClauseType::CompareTerm(CompareTermQT::LessThan),
|
||||||
("@>=", 2) => ClauseType::CompareTerm(CompareTermQT::GreaterThanOrEqual),
|
("@>=", 2) => ClauseType::CompareTerm(CompareTermQT::GreaterThanOrEqual),
|
||||||
@@ -1200,7 +1211,7 @@ pub enum BuiltInInstruction {
|
|||||||
CompareNumber(CompareNumberQT, ArithmeticTerm, ArithmeticTerm),
|
CompareNumber(CompareNumberQT, ArithmeticTerm, ArithmeticTerm),
|
||||||
DefaultRetryMeElse(usize),
|
DefaultRetryMeElse(usize),
|
||||||
DefaultSetCutPoint(RegType),
|
DefaultSetCutPoint(RegType),
|
||||||
DefaultTrustMe,
|
DefaultTrustMe,
|
||||||
EraseBall,
|
EraseBall,
|
||||||
Fail,
|
Fail,
|
||||||
GetArg(bool), // last call.
|
GetArg(bool), // last call.
|
||||||
@@ -1211,7 +1222,7 @@ pub enum BuiltInInstruction {
|
|||||||
InstallCleaner,
|
InstallCleaner,
|
||||||
InstallInferenceCounter(RegType, RegType, RegType),
|
InstallInferenceCounter(RegType, RegType, RegType),
|
||||||
InstallNewBlock,
|
InstallNewBlock,
|
||||||
InternalCallN,
|
InternalCallN,
|
||||||
RemoveCallPolicyCheck,
|
RemoveCallPolicyCheck,
|
||||||
RemoveInferenceCounter(RegType, RegType),
|
RemoveInferenceCounter(RegType, RegType),
|
||||||
ResetBlock,
|
ResetBlock,
|
||||||
|
|||||||
@@ -626,6 +626,7 @@ fn get_builtins() -> Code {
|
|||||||
sort_execute!(), // sort/2, 467.
|
sort_execute!(), // sort/2, 467.
|
||||||
keysort_execute!(), // keysort/2, 468.
|
keysort_execute!(), // keysort/2, 468.
|
||||||
acyclic_term_execute!(), // acyclic_term/1, 469.
|
acyclic_term_execute!(), // acyclic_term/1, 469.
|
||||||
|
cyclic_term_execute!(), // cyclic_term/1, 470.
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -742,6 +743,7 @@ pub fn build_code_and_op_dirs() -> (CodeDir, OpDir)
|
|||||||
code_dir.insert((clause_name!("sort"), 2), (467, builtin.clone()));
|
code_dir.insert((clause_name!("sort"), 2), (467, builtin.clone()));
|
||||||
code_dir.insert((clause_name!("keysort"), 2), (468, builtin.clone()));
|
code_dir.insert((clause_name!("keysort"), 2), (468, builtin.clone()));
|
||||||
code_dir.insert((clause_name!("acyclic_term"), 1), (469, builtin.clone()));
|
code_dir.insert((clause_name!("acyclic_term"), 1), (469, builtin.clone()));
|
||||||
|
code_dir.insert((clause_name!("cyclic_term"), 1), (470, builtin.clone()));
|
||||||
|
|
||||||
(code_dir, op_dir)
|
(code_dir, op_dir)
|
||||||
}
|
}
|
||||||
@@ -804,7 +806,8 @@ pub fn builtin_module() -> Module
|
|||||||
(clause_name!("atom"), 1),
|
(clause_name!("atom"), 1),
|
||||||
(clause_name!("sort"), 2),
|
(clause_name!("sort"), 2),
|
||||||
(clause_name!("keysort"), 2),
|
(clause_name!("keysort"), 2),
|
||||||
(clause_name!("acyclic_term"), 1)]);
|
(clause_name!("acyclic_term"), 1),
|
||||||
|
(clause_name!("cyclic_term"), 1)]);
|
||||||
|
|
||||||
for arity in 0 .. 63 {
|
for arity in 0 .. 63 {
|
||||||
module_decl.exports.push((clause_name!("call"), arity));
|
module_decl.exports.push((clause_name!("call"), arity));
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use prolog::iterators::*;
|
|||||||
use prolog::targets::*;
|
use prolog::targets::*;
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::collections::HashMap;
|
use std::collections::{HashMap};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
|||||||
@@ -496,7 +496,7 @@ fn compile_decl(wam: &mut Machine, tl: TopLevel, queue: Vec<TopLevel>) -> EvalSe
|
|||||||
|
|
||||||
if !code.is_empty() {
|
if !code.is_empty() {
|
||||||
if let Some(name) = tl.name() {
|
if let Some(name) = tl.name() {
|
||||||
wam.add_user_code(name, tl.arity(), code)
|
wam.add_user_code(name, tl.arity(), code, tl.as_predicate().unwrap())
|
||||||
} else {
|
} else {
|
||||||
EvalSession::from(EvalError::NamelessEntry)
|
EvalSession::from(EvalError::NamelessEntry)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
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::*;
|
||||||
@@ -10,7 +9,7 @@ use prolog::tabled_rc::*;
|
|||||||
use downcast::Any;
|
use downcast::Any;
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::HashMap;
|
||||||
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;
|
||||||
@@ -397,30 +396,8 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
{
|
{
|
||||||
match ct {
|
match ct {
|
||||||
&ClauseType::AcyclicTerm => {
|
&ClauseType::AcyclicTerm => {
|
||||||
let addr = machine_st[temp_v!(1)].clone();
|
let addr = machine_st[temp_v!(1)].clone();
|
||||||
let mut seen = HashSet::new();
|
machine_st.fail = machine_st.is_cyclic_term(addr);
|
||||||
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)
|
return_from_clause!(lco, machine_st)
|
||||||
},
|
},
|
||||||
&ClauseType::Arg => {
|
&ClauseType::Arg => {
|
||||||
@@ -476,6 +453,11 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
|
|
||||||
return_from_clause!(lco, machine_st)
|
return_from_clause!(lco, machine_st)
|
||||||
},
|
},
|
||||||
|
&ClauseType::CyclicTerm => {
|
||||||
|
let addr = machine_st[temp_v!(1)].clone();
|
||||||
|
machine_st.fail = !machine_st.is_cyclic_term(addr);
|
||||||
|
return_from_clause!(lco, machine_st)
|
||||||
|
},
|
||||||
&ClauseType::Display => {
|
&ClauseType::Display => {
|
||||||
let output = machine_st.print_term(machine_st[temp_v!(1)].clone(),
|
let output = machine_st.print_term(machine_st[temp_v!(1)].clone(),
|
||||||
DisplayFormatter {},
|
DisplayFormatter {},
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use prolog::or_stack::*;
|
|||||||
use prolog::tabled_rc::*;
|
use prolog::tabled_rc::*;
|
||||||
|
|
||||||
use std::cmp::{max, Ordering};
|
use std::cmp::{max, Ordering};
|
||||||
use std::collections::HashMap;
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
macro_rules! try_or_fail {
|
macro_rules! try_or_fail {
|
||||||
@@ -1001,6 +1001,30 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn is_cyclic_term(&self, addr: Addr) -> bool {
|
||||||
|
let mut seen = HashSet::new();
|
||||||
|
let mut fail = false;
|
||||||
|
|
||||||
|
let mut iter = self.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fail
|
||||||
|
}
|
||||||
|
|
||||||
fn try_get_arg(&mut self) -> Result<(), Vec<HeapCellValue>>
|
fn try_get_arg(&mut self) -> Result<(), Vec<HeapCellValue>>
|
||||||
{
|
{
|
||||||
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
|
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||||
|
|||||||
@@ -25,8 +25,9 @@ pub struct Machine {
|
|||||||
call_policy: Box<CallPolicy>,
|
call_policy: Box<CallPolicy>,
|
||||||
cut_policy: Box<CutPolicy>,
|
cut_policy: Box<CutPolicy>,
|
||||||
code: Code,
|
code: Code,
|
||||||
code_dir: CodeDir,
|
code_dir: CodeDir,
|
||||||
pub op_dir: OpDir,
|
pub op_dir: OpDir,
|
||||||
|
term_dir: TermDir,
|
||||||
modules: HashMap<ClauseName, Module>,
|
modules: HashMap<ClauseName, Module>,
|
||||||
cached_query: Option<Code>
|
cached_query: Option<Code>
|
||||||
}
|
}
|
||||||
@@ -68,6 +69,7 @@ impl Machine {
|
|||||||
cut_policy: Box::new(DefaultCutPolicy {}),
|
cut_policy: Box::new(DefaultCutPolicy {}),
|
||||||
code,
|
code,
|
||||||
code_dir,
|
code_dir,
|
||||||
|
term_dir: TermDir::new(),
|
||||||
op_dir,
|
op_dir,
|
||||||
modules: HashMap::new(),
|
modules: HashMap::new(),
|
||||||
cached_query: None
|
cached_query: None
|
||||||
@@ -173,7 +175,8 @@ impl Machine {
|
|||||||
self.code.extend(code.into_iter());
|
self.code.extend(code.into_iter());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_user_code(&mut self, name: ClauseName, arity: usize, code: Code) -> EvalSession
|
pub fn add_user_code(&mut self, name: ClauseName, arity: usize, code: Code, pred: Predicate)
|
||||||
|
-> EvalSession
|
||||||
{
|
{
|
||||||
match self.code_dir.get(&(name.clone(), arity)) {
|
match self.code_dir.get(&(name.clone(), arity)) {
|
||||||
Some(&(_, ref mod_name)) if mod_name == &clause_name!("builtin") =>
|
Some(&(_, ref mod_name)) if mod_name == &clause_name!("builtin") =>
|
||||||
@@ -184,8 +187,9 @@ impl Machine {
|
|||||||
let offset = self.code.len();
|
let offset = self.code.len();
|
||||||
|
|
||||||
self.code.extend(code.into_iter());
|
self.code.extend(code.into_iter());
|
||||||
|
self.term_dir.insert((name.clone(), arity), pred);
|
||||||
self.code_dir.insert((name, arity), (offset, clause_name!("user")));
|
self.code_dir.insert((name, arity), (offset, clause_name!("user")));
|
||||||
|
|
||||||
EvalSession::EntrySuccess
|
EvalSession::EntrySuccess
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -734,6 +734,12 @@ macro_rules! acyclic_term_execute {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! cyclic_term_execute {
|
||||||
|
() => (
|
||||||
|
Line::Control(ControlInstruction::CallClause(ClauseType::CyclicTerm, 1, 0, true))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! return_from_clause {
|
macro_rules! return_from_clause {
|
||||||
($lco:expr, $machine_st:expr) => {{
|
($lco:expr, $machine_st:expr) => {{
|
||||||
if $lco {
|
if $lco {
|
||||||
|
|||||||
Reference in New Issue
Block a user