add ground/1.
This commit is contained in:
@@ -94,6 +94,7 @@ The following predicates are built-in to rusty-wam.
|
|||||||
* `false/0`
|
* `false/0`
|
||||||
* `float/1`
|
* `float/1`
|
||||||
* `functor/3`
|
* `functor/3`
|
||||||
|
* `ground/1`
|
||||||
* `integer/1`
|
* `integer/1`
|
||||||
* `length/2`
|
* `length/2`
|
||||||
* `maplist/1..8`
|
* `maplist/1..8`
|
||||||
|
|||||||
@@ -401,6 +401,7 @@ pub enum QueryTerm {
|
|||||||
Display(Vec<Box<Term>>),
|
Display(Vec<Box<Term>>),
|
||||||
DuplicateTerm(Vec<Box<Term>>),
|
DuplicateTerm(Vec<Box<Term>>),
|
||||||
Functor(Vec<Box<Term>>),
|
Functor(Vec<Box<Term>>),
|
||||||
|
Ground(Vec<Box<Term>>),
|
||||||
Inlined(InlinedQueryTerm),
|
Inlined(InlinedQueryTerm),
|
||||||
Is(Vec<Box<Term>>),
|
Is(Vec<Box<Term>>),
|
||||||
Jump(JumpStub),
|
Jump(JumpStub),
|
||||||
@@ -418,6 +419,7 @@ impl QueryTerm {
|
|||||||
&QueryTerm::Throw(_) => 1,
|
&QueryTerm::Throw(_) => 1,
|
||||||
&QueryTerm::DuplicateTerm(_) => 2,
|
&QueryTerm::DuplicateTerm(_) => 2,
|
||||||
&QueryTerm::Functor(_) => 3,
|
&QueryTerm::Functor(_) => 3,
|
||||||
|
&QueryTerm::Ground(_) => 1,
|
||||||
&QueryTerm::Inlined(ref term) => term.arity(),
|
&QueryTerm::Inlined(ref term) => term.arity(),
|
||||||
&QueryTerm::Is(_) => 2,
|
&QueryTerm::Is(_) => 2,
|
||||||
&QueryTerm::Jump(ref vars) => vars.len(),
|
&QueryTerm::Jump(ref vars) => vars.len(),
|
||||||
@@ -444,6 +446,7 @@ pub enum ClauseType<'a> {
|
|||||||
Display,
|
Display,
|
||||||
DuplicateTerm,
|
DuplicateTerm,
|
||||||
Functor,
|
Functor,
|
||||||
|
Ground,
|
||||||
Is,
|
Is,
|
||||||
Root(&'a TabledRc<Atom>),
|
Root(&'a TabledRc<Atom>),
|
||||||
SetupCallCleanup,
|
SetupCallCleanup,
|
||||||
@@ -461,6 +464,7 @@ impl<'a> ClauseType<'a> {
|
|||||||
&ClauseType::Deep(_, _, name, _) => name.as_str(),
|
&ClauseType::Deep(_, _, name, _) => name.as_str(),
|
||||||
&ClauseType::DuplicateTerm => "duplicate_term",
|
&ClauseType::DuplicateTerm => "duplicate_term",
|
||||||
&ClauseType::Functor => "functor",
|
&ClauseType::Functor => "functor",
|
||||||
|
&ClauseType::Ground => "ground",
|
||||||
&ClauseType::Is => "is",
|
&ClauseType::Is => "is",
|
||||||
&ClauseType::Root(name) => name.as_str(),
|
&ClauseType::Root(name) => name.as_str(),
|
||||||
&ClauseType::SetupCallCleanup => "setup_call_cleanup",
|
&ClauseType::SetupCallCleanup => "setup_call_cleanup",
|
||||||
@@ -861,6 +865,8 @@ pub enum ControlInstruction {
|
|||||||
GetCleanerCall,
|
GetCleanerCall,
|
||||||
GotoCall(usize, usize), // p, arity.
|
GotoCall(usize, usize), // p, arity.
|
||||||
GotoExecute(usize, usize), // p, arity.
|
GotoExecute(usize, usize), // p, arity.
|
||||||
|
GroundCall,
|
||||||
|
GroundExecute,
|
||||||
JmpByCall(usize, usize), // arity, global_offset.
|
JmpByCall(usize, usize), // arity, global_offset.
|
||||||
JmpByExecute(usize, usize),
|
JmpByExecute(usize, usize),
|
||||||
IsCall(RegType, ArithmeticTerm),
|
IsCall(RegType, ArithmeticTerm),
|
||||||
@@ -892,6 +898,8 @@ impl ControlInstruction {
|
|||||||
&ControlInstruction::GetCleanerCall => true,
|
&ControlInstruction::GetCleanerCall => true,
|
||||||
&ControlInstruction::GotoCall(..) => true,
|
&ControlInstruction::GotoCall(..) => true,
|
||||||
&ControlInstruction::GotoExecute(..) => true,
|
&ControlInstruction::GotoExecute(..) => true,
|
||||||
|
&ControlInstruction::GroundCall => true,
|
||||||
|
&ControlInstruction::GroundExecute => true,
|
||||||
&ControlInstruction::Proceed => true,
|
&ControlInstruction::Proceed => true,
|
||||||
&ControlInstruction::IsCall(..) => true,
|
&ControlInstruction::IsCall(..) => true,
|
||||||
&ControlInstruction::IsExecute(..) => true,
|
&ControlInstruction::IsExecute(..) => true,
|
||||||
@@ -964,7 +972,7 @@ pub type Code = Vec<Line>;
|
|||||||
|
|
||||||
pub type CodeDeque = VecDeque<Line>;
|
pub type CodeDeque = VecDeque<Line>;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum Addr {
|
pub enum Addr {
|
||||||
Con(Constant),
|
Con(Constant),
|
||||||
Lis(usize),
|
Lis(usize),
|
||||||
|
|||||||
@@ -538,7 +538,8 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
|
|||||||
is_nonvar!(temp_v!(1)), // nonvar/1, 380.
|
is_nonvar!(temp_v!(1)), // nonvar/1, 380.
|
||||||
proceed!(),
|
proceed!(),
|
||||||
restore_cut_policy!(), // restore_cut_policy/0, 382.
|
restore_cut_policy!(), // restore_cut_policy/0, 382.
|
||||||
proceed!()
|
proceed!(),
|
||||||
|
ground_execute!(), // ground/1, 384.
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -588,6 +589,7 @@ 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), (XFY, 1050));
|
||||||
|
|
||||||
op_dir.insert((tabled_rc!("=..", atom_tbl), Fixity::In), (XFX, 700));
|
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
|
// 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)
|
// (an extra register is needed for the predicate name)
|
||||||
@@ -631,5 +633,7 @@ pub fn build_code_dir(atom_tbl: TabledData<Atom>) -> (Code, CodeDir, OpDir)
|
|||||||
code_dir.insert((tabled_rc!("float", atom_tbl), 1), (PredicateKeyType::BuiltIn, 378));
|
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!("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)
|
(builtin_code, code_dir, op_dir)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -261,6 +261,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
code.push(Line::Control(ControlInstruction::DisplayCall)),
|
code.push(Line::Control(ControlInstruction::DisplayCall)),
|
||||||
&QueryTerm::DuplicateTerm(_) =>
|
&QueryTerm::DuplicateTerm(_) =>
|
||||||
code.push(Line::Control(ControlInstruction::DuplicateTermCall)),
|
code.push(Line::Control(ControlInstruction::DuplicateTermCall)),
|
||||||
|
&QueryTerm::Ground(_) =>
|
||||||
|
code.push(Line::Control(ControlInstruction::GroundCall)),
|
||||||
&QueryTerm::Functor(_) =>
|
&QueryTerm::Functor(_) =>
|
||||||
code.push(Line::Control(ControlInstruction::FunctorCall)),
|
code.push(Line::Control(ControlInstruction::FunctorCall)),
|
||||||
&QueryTerm::Inlined(_) =>
|
&QueryTerm::Inlined(_) =>
|
||||||
@@ -301,6 +303,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
*ctrl = ControlInstruction::DisplayExecute,
|
*ctrl = ControlInstruction::DisplayExecute,
|
||||||
ControlInstruction::DuplicateTermCall =>
|
ControlInstruction::DuplicateTermCall =>
|
||||||
*ctrl = ControlInstruction::DuplicateTermExecute,
|
*ctrl = ControlInstruction::DuplicateTermExecute,
|
||||||
|
ControlInstruction::GroundCall =>
|
||||||
|
*ctrl = ControlInstruction::GroundExecute,
|
||||||
ControlInstruction::FunctorCall =>
|
ControlInstruction::FunctorCall =>
|
||||||
*ctrl = ControlInstruction::FunctorExecute,
|
*ctrl = ControlInstruction::FunctorExecute,
|
||||||
ControlInstruction::JmpByCall(arity, offset) =>
|
ControlInstruction::JmpByCall(arity, offset) =>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use prolog::ast::*;
|
use prolog::ast::*;
|
||||||
use prolog::machine::machine_state::MachineState;
|
use prolog::machine::machine_state::MachineState;
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
pub struct HeapCellPreOrderIterator<'a> {
|
pub struct HeapCellPreOrderIterator<'a> {
|
||||||
@@ -121,4 +122,61 @@ impl MachineState {
|
|||||||
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))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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"),
|
write!(f, "functor_execute"),
|
||||||
&ControlInstruction::Deallocate =>
|
&ControlInstruction::Deallocate =>
|
||||||
write!(f, "deallocate"),
|
write!(f, "deallocate"),
|
||||||
|
&ControlInstruction::GroundCall =>
|
||||||
|
write!(f, "ground_call"),
|
||||||
|
&ControlInstruction::GroundExecute =>
|
||||||
|
write!(f, "ground_execute"),
|
||||||
&ControlInstruction::Execute(ref name, arity) =>
|
&ControlInstruction::Execute(ref name, arity) =>
|
||||||
write!(f, "execute {}/{}", name, arity),
|
write!(f, "execute {}/{}", name, arity),
|
||||||
&ControlInstruction::GetCleanerCall =>
|
&ControlInstruction::GetCleanerCall =>
|
||||||
|
|||||||
@@ -60,6 +60,10 @@ impl<'a> QueryIterator<'a> {
|
|||||||
let state = TermIterState::Clause(0, ClauseType::Display, terms);
|
let state = TermIterState::Clause(0, ClauseType::Display, terms);
|
||||||
QueryIterator { state_stack: vec![state] }
|
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)) => {
|
&QueryTerm::Inlined(InlinedQueryTerm::CompareNumber(qt, ref terms)) => {
|
||||||
let state = TermIterState::Clause(0, ClauseType::CompareNumber(qt), terms);
|
let state = TermIterState::Clause(0, ClauseType::CompareNumber(qt), terms);
|
||||||
QueryIterator { state_stack: vec![state] }
|
QueryIterator { state_stack: vec![state] }
|
||||||
@@ -317,7 +321,7 @@ impl<'a> ChunkedIterator<'a>
|
|||||||
arity = child_terms.len();
|
arity = child_terms.len();
|
||||||
break;
|
break;
|
||||||
},
|
},
|
||||||
&QueryTerm::Display(_) => {
|
&QueryTerm::Ground(_) | &QueryTerm::Display(_) => {
|
||||||
result.push(term);
|
result.push(term);
|
||||||
arity = 1;
|
arity = 1;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1461,6 +1461,56 @@ SetupCallCleanupCutPolicy.")
|
|||||||
self.unify(Addr::HeapCell(old_h), a2);
|
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>,
|
pub(super) fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, cut_policy: &mut Box<CutPolicy>,
|
||||||
instr: &ControlInstruction)
|
instr: &ControlInstruction)
|
||||||
{
|
{
|
||||||
@@ -1570,6 +1620,14 @@ SetupCallCleanupCutPolicy.")
|
|||||||
self.duplicate_term();
|
self.duplicate_term();
|
||||||
self.p = self.cp;
|
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) =>
|
&ControlInstruction::Execute(ref name, arity) =>
|
||||||
self.try_execute_predicate(code_dir, name.clone(), arity),
|
self.try_execute_predicate(code_dir, name.clone(), arity),
|
||||||
&ControlInstruction::ExecuteN(arity) =>
|
&ControlInstruction::ExecuteN(arity) =>
|
||||||
|
|||||||
@@ -562,3 +562,9 @@ macro_rules! restore_cut_policy {
|
|||||||
Line::BuiltIn(BuiltInInstruction::RestoreCutPolicy)
|
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(\"sdfsa\").");
|
||||||
assert_prolog_success!(&mut wam, "?- nonvar(atom).");
|
assert_prolog_success!(&mut wam, "?- nonvar(atom).");
|
||||||
assert_prolog_success!(&mut wam, "?- nonvar([1,2,3]).");
|
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]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user