add ground/1.

This commit is contained in:
Mark Thom
2018-02-08 23:51:05 -07:00
parent df3e8b8fce
commit 9c1b48865b
11 changed files with 166 additions and 13 deletions

View File

@@ -94,6 +94,7 @@ The following predicates are built-in to rusty-wam.
* `false/0`
* `float/1`
* `functor/3`
* `ground/1`
* `integer/1`
* `length/2`
* `maplist/1..8`

View File

@@ -399,8 +399,9 @@ pub enum QueryTerm {
Catch(Vec<Box<Term>>),
Cut,
Display(Vec<Box<Term>>),
DuplicateTerm(Vec<Box<Term>>),
DuplicateTerm(Vec<Box<Term>>),
Functor(Vec<Box<Term>>),
Ground(Vec<Box<Term>>),
Inlined(InlinedQueryTerm),
Is(Vec<Box<Term>>),
Jump(JumpStub),
@@ -416,8 +417,9 @@ impl QueryTerm {
&QueryTerm::Catch(_) => 3,
&QueryTerm::Display(_) => 1,
&QueryTerm::Throw(_) => 1,
&QueryTerm::DuplicateTerm(_) => 2,
&QueryTerm::DuplicateTerm(_) => 2,
&QueryTerm::Functor(_) => 3,
&QueryTerm::Ground(_) => 1,
&QueryTerm::Inlined(ref term) => term.arity(),
&QueryTerm::Is(_) => 2,
&QueryTerm::Jump(ref vars) => vars.len(),
@@ -444,6 +446,7 @@ pub enum ClauseType<'a> {
Display,
DuplicateTerm,
Functor,
Ground,
Is,
Root(&'a TabledRc<Atom>),
SetupCallCleanup,
@@ -461,6 +464,7 @@ impl<'a> ClauseType<'a> {
&ClauseType::Deep(_, _, name, _) => name.as_str(),
&ClauseType::DuplicateTerm => "duplicate_term",
&ClauseType::Functor => "functor",
&ClauseType::Ground => "ground",
&ClauseType::Is => "is",
&ClauseType::Root(name) => name.as_str(),
&ClauseType::SetupCallCleanup => "setup_call_cleanup",
@@ -853,7 +857,7 @@ pub enum ControlInstruction {
DisplayExecute,
Deallocate,
DuplicateTermCall,
DuplicateTermExecute,
DuplicateTermExecute,
Execute(TabledRc<Atom>, usize),
ExecuteN(usize),
FunctorCall,
@@ -861,6 +865,8 @@ pub enum ControlInstruction {
GetCleanerCall,
GotoCall(usize, usize), // p, arity.
GotoExecute(usize, usize), // p, arity.
GroundCall,
GroundExecute,
JmpByCall(usize, usize), // arity, global_offset.
JmpByExecute(usize, usize),
IsCall(RegType, ArithmeticTerm),
@@ -883,7 +889,7 @@ impl ControlInstruction {
&ControlInstruction::DuplicateTermCall => true,
&ControlInstruction::DuplicateTermExecute => true,
&ControlInstruction::Execute(_, _) => true,
&ControlInstruction::CallN(_) => true,
&ControlInstruction::CallN(_) => true,
&ControlInstruction::ExecuteN(_) => true,
&ControlInstruction::FunctorCall => true,
&ControlInstruction::FunctorExecute => true,
@@ -892,6 +898,8 @@ impl ControlInstruction {
&ControlInstruction::GetCleanerCall => true,
&ControlInstruction::GotoCall(..) => true,
&ControlInstruction::GotoExecute(..) => true,
&ControlInstruction::GroundCall => true,
&ControlInstruction::GroundExecute => true,
&ControlInstruction::Proceed => true,
&ControlInstruction::IsCall(..) => true,
&ControlInstruction::IsExecute(..) => true,
@@ -964,7 +972,7 @@ pub type Code = Vec<Line>;
pub type CodeDeque = VecDeque<Line>;
#[derive(Clone, PartialEq)]
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Addr {
Con(Constant),
Lis(usize),

View File

@@ -538,7 +538,8 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
is_nonvar!(temp_v!(1)), // nonvar/1, 380.
proceed!(),
restore_cut_policy!(), // restore_cut_policy/0, 382.
proceed!()
proceed!(),
ground_execute!(), // ground/1, 384.
]
}
@@ -588,7 +589,8 @@ pub fn build_code_dir(atom_tbl: TabledData<Atom>) -> (Code, CodeDir, OpDir)
op_dir.insert((tabled_rc!("->", atom_tbl), Fixity::In), (XFY, 1050));
op_dir.insert((tabled_rc!("=..", atom_tbl), Fixity::In), (XFX, 700));
op_dir.insert((tabled_rc!("==", atom_tbl), Fixity::In), (XFX, 700));
// there are 63 registers in the VM, so call/N is defined for all 0 <= N <= 62
// (an extra register is needed for the predicate name)
for arity in 0 .. 63 {
@@ -630,6 +632,8 @@ pub fn build_code_dir(atom_tbl: TabledData<Atom>) -> (Code, CodeDir, OpDir)
code_dir.insert((tabled_rc!("string", atom_tbl), 1), (PredicateKeyType::BuiltIn, 376));
code_dir.insert((tabled_rc!("float", atom_tbl), 1), (PredicateKeyType::BuiltIn, 378));
code_dir.insert((tabled_rc!("nonvar", atom_tbl), 1), (PredicateKeyType::BuiltIn, 380));
code_dir.insert((tabled_rc!("ground", atom_tbl), 1), (PredicateKeyType::BuiltIn, 384));
(builtin_code, code_dir, op_dir)
}

View File

@@ -259,8 +259,10 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
code.push(Line::Control(ControlInstruction::CatchCall)),
&QueryTerm::Display(_) =>
code.push(Line::Control(ControlInstruction::DisplayCall)),
&QueryTerm::DuplicateTerm(_) =>
&QueryTerm::DuplicateTerm(_) =>
code.push(Line::Control(ControlInstruction::DuplicateTermCall)),
&QueryTerm::Ground(_) =>
code.push(Line::Control(ControlInstruction::GroundCall)),
&QueryTerm::Functor(_) =>
code.push(Line::Control(ControlInstruction::FunctorCall)),
&QueryTerm::Inlined(_) =>
@@ -301,6 +303,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
*ctrl = ControlInstruction::DisplayExecute,
ControlInstruction::DuplicateTermCall =>
*ctrl = ControlInstruction::DuplicateTermExecute,
ControlInstruction::GroundCall =>
*ctrl = ControlInstruction::GroundExecute,
ControlInstruction::FunctorCall =>
*ctrl = ControlInstruction::FunctorExecute,
ControlInstruction::JmpByCall(arity, offset) =>

View File

@@ -1,6 +1,7 @@
use prolog::ast::*;
use prolog::machine::machine_state::MachineState;
use std::collections::HashSet;
use std::vec::Vec;
pub struct HeapCellPreOrderIterator<'a> {
@@ -30,7 +31,7 @@ impl<'a> HeapCellPreOrderIterator<'a> {
self.follow(a.clone())
}
}
// called under the assumption that the location at r is about to
// be visited, and so any follow up states need to be added to
// state_stack. returns the dereferenced Addr from Ref.
@@ -121,4 +122,61 @@ impl MachineState {
pub fn post_order_iter<'a>(&'a self, a: Addr) -> HeapCellPostOrderIterator<'a> {
HeapCellPostOrderIterator::new(HeapCellPreOrderIterator::new(self, a))
}
pub fn acyclic_pre_order_iter<'a>(&'a self, a: Addr) -> HeapCellAcyclicIterator<HeapCellPreOrderIterator<'a>>
{
HeapCellAcyclicIterator::new(HeapCellPreOrderIterator::new(self, a))
}
}
pub trait MutStackHeapCellIterator {
fn stack(&mut self) -> &mut Vec<Addr>;
}
impl<'a> MutStackHeapCellIterator for HeapCellPreOrderIterator<'a> {
fn stack(&mut self) -> &mut Vec<Addr> {
&mut self.state_stack
}
}
pub struct HeapCellAcyclicIterator<HeapCellIter> {
iter: HeapCellIter,
seen: HashSet<Addr>
}
impl<HeapCellIter: MutStackHeapCellIterator> HeapCellAcyclicIterator<HeapCellIter>
{
pub fn new(mut iter: HeapCellIter) -> Self {
let mut seen = HashSet::new();
if let Some(addr) = iter.stack().last() {
seen.insert(addr.clone());
}
HeapCellAcyclicIterator { iter, seen }
}
}
impl<HeapCellIter> Iterator for HeapCellAcyclicIterator<HeapCellIter>
where HeapCellIter: Iterator<Item=HeapCellValue>
+ MutStackHeapCellIterator
{
type Item = HeapCellValue;
fn next(&mut self) -> Option<Self::Item> {
while let Some(hcv) = self.iter.next() {
if let Some(addr) = self.iter.stack().pop() {
if self.seen.contains(&addr) {
continue;
} else {
self.iter.stack().push(addr.clone());
self.seen.insert(addr);
}
}
return Some(hcv);
}
None
}
}

View File

@@ -131,6 +131,10 @@ impl fmt::Display for ControlInstruction {
write!(f, "functor_execute"),
&ControlInstruction::Deallocate =>
write!(f, "deallocate"),
&ControlInstruction::GroundCall =>
write!(f, "ground_call"),
&ControlInstruction::GroundExecute =>
write!(f, "ground_execute"),
&ControlInstruction::Execute(ref name, arity) =>
write!(f, "execute {}/{}", name, arity),
&ControlInstruction::GetCleanerCall =>
@@ -212,7 +216,7 @@ impl fmt::Display for BuiltInInstruction {
&BuiltInInstruction::IsString(r) =>
write!(f, "is_string {}", r),
&BuiltInInstruction::IsInteger(r) =>
write!(f, "is_integer {}", r),
write!(f, "is_integer {}", r),
&BuiltInInstruction::DynamicIs =>
write!(f, "call_is"),
&BuiltInInstruction::IsVar(r) =>

View File

@@ -60,6 +60,10 @@ impl<'a> QueryIterator<'a> {
let state = TermIterState::Clause(0, ClauseType::Display, terms);
QueryIterator { state_stack: vec![state] }
},
&QueryTerm::Ground(ref terms) => {
let state = TermIterState::Clause(0, ClauseType::Ground, terms);
QueryIterator { state_stack: vec![state] }
},
&QueryTerm::Inlined(InlinedQueryTerm::CompareNumber(qt, ref terms)) => {
let state = TermIterState::Clause(0, ClauseType::CompareNumber(qt), terms);
QueryIterator { state_stack: vec![state] }
@@ -317,7 +321,7 @@ impl<'a> ChunkedIterator<'a>
arity = child_terms.len();
break;
},
&QueryTerm::Display(_) => {
&QueryTerm::Ground(_) | &QueryTerm::Display(_) => {
result.push(term);
arity = 1;
break;
@@ -341,7 +345,7 @@ impl<'a> ChunkedIterator<'a>
if self.term_loc.chunk_num() > 0 {
self.deep_cut_encountered = true;
}
},
},
};
item = self.iter.next();

View File

@@ -1461,6 +1461,56 @@ SetupCallCleanupCutPolicy.")
self.unify(Addr::HeapCell(old_h), a2);
}
/* TODO: needs careful consideration of cyclic terms.
// returns true on failure.
fn eq_test(&self) -> bool
{
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
let a2 = self.store(self.deref(self[temp_v!(2)].clone()));
let iter1 = self.acyclic_pre_order_iter(a1);
let iter2 = self.acyclic_pre_order_iter(a2);
for (v1, v2) in iter1.zip(iter2) {
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.
fn ground_test(&self) -> bool
{
let a = self.store(self.deref(self[temp_v!(1)].clone()));
for v in self.acyclic_pre_order_iter(a) {
match v {
HeapCellValue::Addr(Addr::HeapCell(..)) =>
return true,
HeapCellValue::Addr(Addr::StackCell(..)) =>
return true,
_ => {}
}
};
false
}
pub(super) fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, cut_policy: &mut Box<CutPolicy>,
instr: &ControlInstruction)
{
@@ -1570,6 +1620,14 @@ SetupCallCleanupCutPolicy.")
self.duplicate_term();
self.p = self.cp;
},
&ControlInstruction::GroundCall => {
self.fail = self.ground_test();
self.p += 1;
},
&ControlInstruction::GroundExecute => {
self.fail = self.ground_test();
self.p = self.cp;
},
&ControlInstruction::Execute(ref name, arity) =>
self.try_execute_predicate(code_dir, name.clone(), arity),
&ControlInstruction::ExecuteN(arity) =>

View File

@@ -562,3 +562,9 @@ macro_rules! restore_cut_policy {
Line::BuiltIn(BuiltInInstruction::RestoreCutPolicy)
)
}
macro_rules! ground_execute {
() => (
Line::Control(ControlInstruction::GroundExecute)
)
}

View File

@@ -1328,6 +1328,12 @@ fn test_queries_on_builtins()
assert_prolog_success!(&mut wam, "?- nonvar(\"sdfsa\").");
assert_prolog_success!(&mut wam, "?- nonvar(atom).");
assert_prolog_success!(&mut wam, "?- nonvar([1,2,3]).");
assert_prolog_success!(&mut wam, "?- A = f(A), ground(f(f(A))), ground(f(A)), ground(A).");
assert_prolog_failure!(&mut wam, "?- B = f(A), ground(B).");
assert_prolog_failure!(&mut wam, "?- B = f(A), ground(A).");
assert_prolog_success!(&mut wam, "?- ground(x), ground(f(x)), X = f(x), ground(g(f(X), [a,b])).");
}
#[test]