add ground/1.
This commit is contained in:
@@ -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),
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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) =>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) =>
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) =>
|
||||
|
||||
@@ -562,3 +562,9 @@ macro_rules! restore_cut_policy {
|
||||
Line::BuiltIn(BuiltInInstruction::RestoreCutPolicy)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! ground_execute {
|
||||
() => (
|
||||
Line::Control(ControlInstruction::GroundExecute)
|
||||
)
|
||||
}
|
||||
|
||||
Submodule src/prolog/parser updated: 7687a36763...5de18ac472
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user