* `false/0`
* `float/1`
* `functor/3`
+* `ground/1`
* `integer/1`
* `length/2`
* `maplist/1..8`
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),
&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(),
Display,
DuplicateTerm,
Functor,
+ Ground,
Is,
Root(&'a TabledRc<Atom>),
SetupCallCleanup,
&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",
DisplayExecute,
Deallocate,
DuplicateTermCall,
- DuplicateTermExecute,
+ DuplicateTermExecute,
Execute(TabledRc<Atom>, usize),
ExecuteN(usize),
FunctorCall,
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),
&ControlInstruction::DuplicateTermCall => true,
&ControlInstruction::DuplicateTermExecute => true,
&ControlInstruction::Execute(_, _) => true,
- &ControlInstruction::CallN(_) => true,
+ &ControlInstruction::CallN(_) => true,
&ControlInstruction::ExecuteN(_) => true,
&ControlInstruction::FunctorCall => true,
&ControlInstruction::FunctorExecute => true,
&ControlInstruction::GetCleanerCall => true,
&ControlInstruction::GotoCall(..) => true,
&ControlInstruction::GotoExecute(..) => true,
+ &ControlInstruction::GroundCall => true,
+ &ControlInstruction::GroundExecute => true,
&ControlInstruction::Proceed => true,
&ControlInstruction::IsCall(..) => true,
&ControlInstruction::IsExecute(..) => true,
pub type CodeDeque = VecDeque<Line>;
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Addr {
Con(Constant),
Lis(usize),
is_nonvar!(temp_v!(1)), // nonvar/1, 380.
proceed!(),
restore_cut_policy!(), // restore_cut_policy/0, 382.
- proceed!()
+ proceed!(),
+ ground_execute!(), // ground/1, 384.
]
}
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 {
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)
}
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(_) =>
*ctrl = ControlInstruction::DisplayExecute,
ControlInstruction::DuplicateTermCall =>
*ctrl = ControlInstruction::DuplicateTermExecute,
+ ControlInstruction::GroundCall =>
+ *ctrl = ControlInstruction::GroundExecute,
ControlInstruction::FunctorCall =>
*ctrl = ControlInstruction::FunctorExecute,
ControlInstruction::JmpByCall(arity, offset) =>
use prolog::ast::*;
use prolog::machine::machine_state::MachineState;
+use std::collections::HashSet;
use std::vec::Vec;
pub struct 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.
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
+ }
}
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 =>
&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) =>
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] }
arity = child_terms.len();
break;
},
- &QueryTerm::Display(_) => {
+ &QueryTerm::Ground(_) | &QueryTerm::Display(_) => {
result.push(term);
arity = 1;
break;
if self.term_loc.chunk_num() > 0 {
self.deep_cut_encountered = true;
}
- },
+ },
};
item = self.iter.next();
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)
{
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) =>
Line::BuiltIn(BuiltInInstruction::RestoreCutPolicy)
)
}
+
+macro_rules! ground_execute {
+ () => (
+ Line::Control(ControlInstruction::GroundExecute)
+ )
+}
-Subproject commit 7687a367636a79972788b2633de8fbba7778eb10
+Subproject commit 5de18ac4728701492cc19fd08d32b40f4d5918a3
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]