add term comparison operators.
This commit is contained in:
@@ -389,6 +389,29 @@ impl CompareNumberQT {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum CompareTermQT {
|
||||||
|
GreaterThan,
|
||||||
|
LessThan,
|
||||||
|
GreaterThanOrEqual,
|
||||||
|
LessThanOrEqual,
|
||||||
|
NotEqual,
|
||||||
|
Equal
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompareTermQT {
|
||||||
|
fn name<'a>(self) -> &'a str {
|
||||||
|
match self {
|
||||||
|
CompareTermQT::GreaterThan => "@>",
|
||||||
|
CompareTermQT::LessThan => "@<",
|
||||||
|
CompareTermQT::GreaterThanOrEqual => "@>=",
|
||||||
|
CompareTermQT::LessThanOrEqual => "@=<",
|
||||||
|
CompareTermQT::NotEqual => "\\=@=",
|
||||||
|
CompareTermQT::Equal => "=@="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// vars of predicate, toplevel offset. Vec<Term> is always a vector
|
// vars of predicate, toplevel offset. Vec<Term> is always a vector
|
||||||
// of vars (we get their adjoining cells this way).
|
// of vars (we get their adjoining cells this way).
|
||||||
pub type JumpStub = Vec<Term>;
|
pub type JumpStub = Vec<Term>;
|
||||||
@@ -397,6 +420,7 @@ pub enum QueryTerm {
|
|||||||
Arg(Vec<Box<Term>>),
|
Arg(Vec<Box<Term>>),
|
||||||
CallN(Vec<Box<Term>>),
|
CallN(Vec<Box<Term>>),
|
||||||
Catch(Vec<Box<Term>>),
|
Catch(Vec<Box<Term>>),
|
||||||
|
CompareTerm(CompareTermQT, Vec<Box<Term>>),
|
||||||
Cut,
|
Cut,
|
||||||
Display(Vec<Box<Term>>),
|
Display(Vec<Box<Term>>),
|
||||||
DuplicateTerm(Vec<Box<Term>>),
|
DuplicateTerm(Vec<Box<Term>>),
|
||||||
@@ -417,6 +441,7 @@ impl QueryTerm {
|
|||||||
match self {
|
match self {
|
||||||
&QueryTerm::Arg(_) => 3,
|
&QueryTerm::Arg(_) => 3,
|
||||||
&QueryTerm::Catch(_) => 3,
|
&QueryTerm::Catch(_) => 3,
|
||||||
|
&QueryTerm::CompareTerm(..) => 2,
|
||||||
&QueryTerm::Display(_) => 1,
|
&QueryTerm::Display(_) => 1,
|
||||||
&QueryTerm::Throw(_) => 1,
|
&QueryTerm::Throw(_) => 1,
|
||||||
&QueryTerm::DuplicateTerm(_) => 2,
|
&QueryTerm::DuplicateTerm(_) => 2,
|
||||||
@@ -446,6 +471,7 @@ pub enum ClauseType<'a> {
|
|||||||
CallN,
|
CallN,
|
||||||
Catch,
|
Catch,
|
||||||
CompareNumber(CompareNumberQT),
|
CompareNumber(CompareNumberQT),
|
||||||
|
CompareTerm(CompareTermQT),
|
||||||
Deep(Level, &'a Cell<RegType>, &'a TabledRc<Atom>, Option<Fixity>),
|
Deep(Level, &'a Cell<RegType>, &'a TabledRc<Atom>, Option<Fixity>),
|
||||||
Display,
|
Display,
|
||||||
DuplicateTerm,
|
DuplicateTerm,
|
||||||
@@ -466,12 +492,13 @@ impl<'a> ClauseType<'a> {
|
|||||||
&ClauseType::CallN => "call",
|
&ClauseType::CallN => "call",
|
||||||
&ClauseType::Catch => "catch",
|
&ClauseType::Catch => "catch",
|
||||||
&ClauseType::CompareNumber(qt) => qt.name(),
|
&ClauseType::CompareNumber(qt) => qt.name(),
|
||||||
|
&ClauseType::CompareTerm(qt) => qt.name(),
|
||||||
&ClauseType::Display => "display",
|
&ClauseType::Display => "display",
|
||||||
&ClauseType::Deep(_, _, name, _) => name.as_str(),
|
&ClauseType::Deep(_, _, name, _) => name.as_str(),
|
||||||
&ClauseType::DuplicateTerm => "duplicate_term",
|
&ClauseType::DuplicateTerm => "duplicate_term",
|
||||||
&ClauseType::Eq => "==",
|
&ClauseType::Eq => "==",
|
||||||
&ClauseType::Functor => "functor",
|
&ClauseType::Functor => "functor",
|
||||||
&ClauseType::Ground => "ground",
|
&ClauseType::Ground => "ground",
|
||||||
&ClauseType::Is => "is",
|
&ClauseType::Is => "is",
|
||||||
&ClauseType::NotEq => "\\==",
|
&ClauseType::NotEq => "\\==",
|
||||||
&ClauseType::Root(name) => name.as_str(),
|
&ClauseType::Root(name) => name.as_str(),
|
||||||
@@ -551,6 +578,32 @@ pub enum Number {
|
|||||||
Rational(Rc<Ratio<BigInt>>)
|
Rational(Rc<Ratio<BigInt>>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for Number {
|
||||||
|
fn partial_cmp(&self, other: &Number) -> Option<Ordering> {
|
||||||
|
match NumberPair::from(self.clone(), other.clone()) {
|
||||||
|
NumberPair::Integer(n1, n2) =>
|
||||||
|
Some(n1.cmp(&n2)),
|
||||||
|
NumberPair::Float(n1, n2) =>
|
||||||
|
Some(n1.cmp(&n2)),
|
||||||
|
NumberPair::Rational(n1, n2) =>
|
||||||
|
Some(n1.cmp(&n2))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for Number {
|
||||||
|
fn cmp(&self, other: &Number) -> Ordering {
|
||||||
|
match NumberPair::from(self.clone(), other.clone()) {
|
||||||
|
NumberPair::Integer(n1, n2) =>
|
||||||
|
n1.cmp(&n2),
|
||||||
|
NumberPair::Float(n1, n2) =>
|
||||||
|
n1.cmp(&n2),
|
||||||
|
NumberPair::Rational(n1, n2) =>
|
||||||
|
n1.cmp(&n2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for Number {
|
impl fmt::Display for Number {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
@@ -820,17 +873,17 @@ pub enum ArithmeticInstruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum BuiltInInstruction {
|
pub enum BuiltInInstruction {
|
||||||
CleanUpBlock,
|
CleanUpBlock,
|
||||||
EraseBall,
|
EraseBall,
|
||||||
Fail,
|
Fail,
|
||||||
GetArgCall,
|
GetArgCall,
|
||||||
GetArgExecute,
|
GetArgExecute,
|
||||||
GetBall,
|
GetBall,
|
||||||
GetCurrentBlock,
|
GetCurrentBlock,
|
||||||
GetCutPoint(RegType),
|
GetCutPoint(RegType),
|
||||||
InstallCleaner,
|
InstallCleaner,
|
||||||
InstallNewBlock,
|
InstallNewBlock,
|
||||||
InternalCallN,
|
InternalCallN,
|
||||||
ResetBlock,
|
ResetBlock,
|
||||||
RestoreCutPolicy,
|
RestoreCutPolicy,
|
||||||
SetBall,
|
SetBall,
|
||||||
@@ -851,6 +904,8 @@ pub enum ControlInstruction {
|
|||||||
CatchExecute,
|
CatchExecute,
|
||||||
CheckCpExecute,
|
CheckCpExecute,
|
||||||
CompareNumber(CompareNumberQT, ArithmeticTerm, ArithmeticTerm),
|
CompareNumber(CompareNumberQT, ArithmeticTerm, ArithmeticTerm),
|
||||||
|
CompareTermCall(CompareTermQT),
|
||||||
|
CompareTermExecute(CompareTermQT),
|
||||||
DisplayCall,
|
DisplayCall,
|
||||||
DisplayExecute,
|
DisplayExecute,
|
||||||
Deallocate,
|
Deallocate,
|
||||||
@@ -868,7 +923,7 @@ pub enum ControlInstruction {
|
|||||||
GotoCall(usize, usize), // p, arity.
|
GotoCall(usize, usize), // p, arity.
|
||||||
GotoExecute(usize, usize), // p, arity.
|
GotoExecute(usize, usize), // p, arity.
|
||||||
GroundCall,
|
GroundCall,
|
||||||
GroundExecute,
|
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),
|
||||||
@@ -896,7 +951,9 @@ impl ControlInstruction {
|
|||||||
&ControlInstruction::Call(_, _, _) => true,
|
&ControlInstruction::Call(_, _, _) => true,
|
||||||
&ControlInstruction::CatchCall => true,
|
&ControlInstruction::CatchCall => true,
|
||||||
&ControlInstruction::CatchExecute => true,
|
&ControlInstruction::CatchExecute => true,
|
||||||
&ControlInstruction::CompareNumber(..) => true,
|
&ControlInstruction::CompareNumber(..) => true,
|
||||||
|
&ControlInstruction::CompareTermCall(..) => true,
|
||||||
|
&ControlInstruction::CompareTermExecute(..) => true,
|
||||||
&ControlInstruction::DisplayCall => true,
|
&ControlInstruction::DisplayCall => true,
|
||||||
&ControlInstruction::DisplayExecute => true,
|
&ControlInstruction::DisplayExecute => true,
|
||||||
&ControlInstruction::DuplicateTermCall => true,
|
&ControlInstruction::DuplicateTermCall => true,
|
||||||
@@ -906,7 +963,7 @@ impl ControlInstruction {
|
|||||||
&ControlInstruction::EqCall => true,
|
&ControlInstruction::EqCall => true,
|
||||||
&ControlInstruction::EqExecute => true,
|
&ControlInstruction::EqExecute => true,
|
||||||
&ControlInstruction::Execute(_, _) => true,
|
&ControlInstruction::Execute(_, _) => true,
|
||||||
&ControlInstruction::CallN(_) => true,
|
&ControlInstruction::CallN(_) => true,
|
||||||
&ControlInstruction::ExecuteN(_) => true,
|
&ControlInstruction::ExecuteN(_) => true,
|
||||||
&ControlInstruction::FunctorCall => true,
|
&ControlInstruction::FunctorCall => true,
|
||||||
&ControlInstruction::FunctorExecute => true,
|
&ControlInstruction::FunctorExecute => true,
|
||||||
@@ -930,7 +987,7 @@ impl ControlInstruction {
|
|||||||
&ControlInstruction::IsCall(..) => true,
|
&ControlInstruction::IsCall(..) => true,
|
||||||
&ControlInstruction::IsExecute(..) => true,
|
&ControlInstruction::IsExecute(..) => true,
|
||||||
&ControlInstruction::JmpByCall(..) => true,
|
&ControlInstruction::JmpByCall(..) => true,
|
||||||
&ControlInstruction::JmpByExecute(..) => true,
|
&ControlInstruction::JmpByExecute(..) => true,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -481,7 +481,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
|
|||||||
retry_me_else!(12),
|
retry_me_else!(12),
|
||||||
allocate!(2),
|
allocate!(2),
|
||||||
query![put_value!(temp_v!(3), 1)],
|
query![put_value!(temp_v!(3), 1)],
|
||||||
reset_block!(),
|
reset_block!(),
|
||||||
query![put_var!(perm_v!(1), 1)],
|
query![put_var!(perm_v!(1), 1)],
|
||||||
get_ball!(),
|
get_ball!(),
|
||||||
get_level!(perm_v!(2)),
|
get_level!(perm_v!(2)),
|
||||||
@@ -489,7 +489,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
|
|||||||
goto_call!(342, 0), // goto run_cleaners_with_handling/0, 342.
|
goto_call!(342, 0), // goto run_cleaners_with_handling/0, 342.
|
||||||
query![put_unsafe_value!(1, 1)],
|
query![put_unsafe_value!(1, 1)],
|
||||||
deallocate!(),
|
deallocate!(),
|
||||||
goto_execute!(59, 1), // goto throw/1, 59.
|
goto_execute!(59, 1), // goto throw/1, 59.
|
||||||
trust_me!(),
|
trust_me!(),
|
||||||
allocate!(0),
|
allocate!(0),
|
||||||
goto_call!(354, 0), // goto run_cleaners_without_handling/0, 354.
|
goto_call!(354, 0), // goto run_cleaners_without_handling/0, 354.
|
||||||
@@ -542,6 +542,10 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
|
|||||||
ground_execute!(), // ground/1, 384.
|
ground_execute!(), // ground/1, 384.
|
||||||
eq_execute!(), // (==)/2, 385.
|
eq_execute!(), // (==)/2, 385.
|
||||||
not_eq_execute!(), // (\==)/2, 386.
|
not_eq_execute!(), // (\==)/2, 386.
|
||||||
|
compare_term_execute!(term_cmp_gte!()), // (@>=)/2, 387.
|
||||||
|
compare_term_execute!(term_cmp_lte!()), // (@=<)/2, 388.
|
||||||
|
compare_term_execute!(term_cmp_gt!()), // (@>)/2, 389.
|
||||||
|
compare_term_execute!(term_cmp_lt!()), // (@<)/2, 390.
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -593,7 +597,11 @@ pub fn build_code_dir(atom_tbl: TabledData<Atom>) -> (Code, CodeDir, OpDir)
|
|||||||
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));
|
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));
|
||||||
|
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));
|
||||||
|
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)
|
||||||
for arity in 0 .. 63 {
|
for arity in 0 .. 63 {
|
||||||
@@ -638,7 +646,11 @@ pub fn build_code_dir(atom_tbl: TabledData<Atom>) -> (Code, CodeDir, OpDir)
|
|||||||
|
|
||||||
code_dir.insert((tabled_rc!("ground", atom_tbl), 1), (PredicateKeyType::BuiltIn, 384));
|
code_dir.insert((tabled_rc!("ground", atom_tbl), 1), (PredicateKeyType::BuiltIn, 384));
|
||||||
code_dir.insert((tabled_rc!("==", atom_tbl), 2), (PredicateKeyType::BuiltIn, 385));
|
code_dir.insert((tabled_rc!("==", atom_tbl), 2), (PredicateKeyType::BuiltIn, 385));
|
||||||
code_dir.insert((tabled_rc!("\\==", atom_tbl), 2), (PredicateKeyType::BuiltIn, 386));
|
code_dir.insert((tabled_rc!("\\==", atom_tbl), 2), (PredicateKeyType::BuiltIn, 386));
|
||||||
|
code_dir.insert((tabled_rc!("@>=", atom_tbl), 2), (PredicateKeyType::BuiltIn, 387));
|
||||||
|
code_dir.insert((tabled_rc!("@=<", atom_tbl), 2), (PredicateKeyType::BuiltIn, 388));
|
||||||
|
code_dir.insert((tabled_rc!("@>", atom_tbl), 2), (PredicateKeyType::BuiltIn, 389));
|
||||||
|
code_dir.insert((tabled_rc!("@<", atom_tbl), 2), (PredicateKeyType::BuiltIn, 390));
|
||||||
|
|
||||||
(builtin_code, code_dir, op_dir)
|
(builtin_code, code_dir, op_dir)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -257,6 +257,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
},
|
},
|
||||||
&QueryTerm::Catch(_) =>
|
&QueryTerm::Catch(_) =>
|
||||||
code.push(Line::Control(ControlInstruction::CatchCall)),
|
code.push(Line::Control(ControlInstruction::CatchCall)),
|
||||||
|
&QueryTerm::CompareTerm(qt, _) =>
|
||||||
|
code.push(Line::Control(ControlInstruction::CompareTermCall(qt))),
|
||||||
&QueryTerm::Display(_) =>
|
&QueryTerm::Display(_) =>
|
||||||
code.push(Line::Control(ControlInstruction::DisplayCall)),
|
code.push(Line::Control(ControlInstruction::DisplayCall)),
|
||||||
&QueryTerm::DuplicateTerm(_) =>
|
&QueryTerm::DuplicateTerm(_) =>
|
||||||
@@ -303,6 +305,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
*ctrl = ControlInstruction::Execute(name, arity),
|
*ctrl = ControlInstruction::Execute(name, arity),
|
||||||
ControlInstruction::CallN(arity) =>
|
ControlInstruction::CallN(arity) =>
|
||||||
*ctrl = ControlInstruction::ExecuteN(arity),
|
*ctrl = ControlInstruction::ExecuteN(arity),
|
||||||
|
ControlInstruction::CompareTermCall(qt) =>
|
||||||
|
*ctrl = ControlInstruction::CompareTermExecute(qt),
|
||||||
ControlInstruction::DisplayCall =>
|
ControlInstruction::DisplayCall =>
|
||||||
*ctrl = ControlInstruction::DisplayExecute,
|
*ctrl = ControlInstruction::DisplayExecute,
|
||||||
ControlInstruction::DuplicateTermCall =>
|
ControlInstruction::DuplicateTermCall =>
|
||||||
|
|||||||
@@ -96,6 +96,20 @@ impl fmt::Display for CompareNumberQT {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for CompareTermQT {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
&CompareTermQT::GreaterThan => write!(f, "@>"),
|
||||||
|
&CompareTermQT::GreaterThanOrEqual => write!(f, "@>="),
|
||||||
|
&CompareTermQT::LessThan => write!(f, "@<"),
|
||||||
|
&CompareTermQT::LessThanOrEqual => write!(f, "@<="),
|
||||||
|
&CompareTermQT::NotEqual => write!(f, "\\=@="),
|
||||||
|
&CompareTermQT::Equal => write!(f, "=@="),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl fmt::Display for ControlInstruction {
|
impl fmt::Display for ControlInstruction {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
@@ -115,6 +129,10 @@ impl fmt::Display for ControlInstruction {
|
|||||||
write!(f, "catch_execute"),
|
write!(f, "catch_execute"),
|
||||||
&ControlInstruction::CheckCpExecute =>
|
&ControlInstruction::CheckCpExecute =>
|
||||||
write!(f, "check_cp_execute"),
|
write!(f, "check_cp_execute"),
|
||||||
|
&ControlInstruction::CompareTermCall(qt) =>
|
||||||
|
write!(f, "compare_term_call {}", qt),
|
||||||
|
&ControlInstruction::CompareTermExecute(qt) =>
|
||||||
|
write!(f, "compare_term_execute {}", qt),
|
||||||
&ControlInstruction::DisplayCall =>
|
&ControlInstruction::DisplayCall =>
|
||||||
write!(f, "display_call"),
|
write!(f, "display_call"),
|
||||||
&ControlInstruction::DisplayExecute =>
|
&ControlInstruction::DisplayExecute =>
|
||||||
|
|||||||
@@ -72,6 +72,10 @@ impl<'a> QueryIterator<'a> {
|
|||||||
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] }
|
||||||
},
|
},
|
||||||
|
&QueryTerm::CompareTerm(qt, ref terms) => {
|
||||||
|
let state = TermIterState::Clause(0, ClauseType::CompareTerm(qt), terms);
|
||||||
|
QueryIterator { state_stack: vec![state] }
|
||||||
|
},
|
||||||
&QueryTerm::Is(ref terms) => {
|
&QueryTerm::Is(ref terms) => {
|
||||||
let state = TermIterState::Clause(0, ClauseType::Is, terms);
|
let state = TermIterState::Clause(0, ClauseType::Is, terms);
|
||||||
QueryIterator { state_stack: vec![state] }
|
QueryIterator { state_stack: vec![state] }
|
||||||
@@ -302,6 +306,11 @@ impl<'a> ChunkedIterator<'a>
|
|||||||
arity = vars.len();
|
arity = vars.len();
|
||||||
break;
|
break;
|
||||||
},
|
},
|
||||||
|
&QueryTerm::CompareTerm(..) => {
|
||||||
|
result.push(term);
|
||||||
|
arity = 2;
|
||||||
|
break;
|
||||||
|
},
|
||||||
&QueryTerm::Term(ref inner_term) =>
|
&QueryTerm::Term(ref inner_term) =>
|
||||||
if let GenContext::Head = self.term_loc {
|
if let GenContext::Head = self.term_loc {
|
||||||
result.push(term);
|
result.push(term);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use prolog::num::rational::Ratio;
|
|||||||
use prolog::or_stack::*;
|
use prolog::or_stack::*;
|
||||||
use prolog::tabled_rc::*;
|
use prolog::tabled_rc::*;
|
||||||
|
|
||||||
use std::cmp::max;
|
use std::cmp::{max, Ordering};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
macro_rules! try_or_fail {
|
macro_rules! try_or_fail {
|
||||||
@@ -1112,6 +1112,147 @@ impl MachineState {
|
|||||||
self.p += 1;
|
self.p += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compare_term(&mut self, qt: CompareTermQT) {
|
||||||
|
let a1 = self[temp_v!(1)].clone();
|
||||||
|
let a2 = self[temp_v!(2)].clone();
|
||||||
|
|
||||||
|
match self.compare_term_test(a1, a2) {
|
||||||
|
Ordering::Greater =>
|
||||||
|
match qt {
|
||||||
|
CompareTermQT::GreaterThan | CompareTermQT::GreaterThanOrEqual => return,
|
||||||
|
_ => self.fail = true
|
||||||
|
},
|
||||||
|
Ordering::Equal =>
|
||||||
|
match qt {
|
||||||
|
CompareTermQT::GreaterThanOrEqual | CompareTermQT::LessThanOrEqual => return,
|
||||||
|
_ => self.fail = true
|
||||||
|
},
|
||||||
|
Ordering::Less =>
|
||||||
|
match qt {
|
||||||
|
CompareTermQT::LessThan | CompareTermQT::LessThanOrEqual => return,
|
||||||
|
_ => self.fail = true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compare_term_test(&self, a1: Addr, a2: Addr) -> Ordering {
|
||||||
|
let iter = self.zipped_acyclic_pre_order_iter(a1, a2);
|
||||||
|
|
||||||
|
for (v1, v2) in iter {
|
||||||
|
match (v1, v2) {
|
||||||
|
(HeapCellValue::Addr(Addr::HeapCell(hc1)),
|
||||||
|
HeapCellValue::Addr(Addr::HeapCell(hc2))) =>
|
||||||
|
if hc1 != hc2 {
|
||||||
|
return hc1.cmp(&hc2);
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
(HeapCellValue::Addr(Addr::HeapCell(_)), _) =>
|
||||||
|
return Ordering::Less,
|
||||||
|
(HeapCellValue::Addr(Addr::StackCell(fr1, sc1)),
|
||||||
|
HeapCellValue::Addr(Addr::StackCell(fr2, sc2))) =>
|
||||||
|
if fr1 > fr2 {
|
||||||
|
return Ordering::Greater;
|
||||||
|
} else if fr1 < fr2 || sc1 < sc2 {
|
||||||
|
return Ordering::Less;
|
||||||
|
} else if sc1 > sc2 {
|
||||||
|
return Ordering::Greater;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
(HeapCellValue::Addr(Addr::StackCell(..)),
|
||||||
|
HeapCellValue::Addr(Addr::HeapCell(_))) =>
|
||||||
|
return Ordering::Greater,
|
||||||
|
(HeapCellValue::Addr(Addr::StackCell(..)), _) =>
|
||||||
|
return Ordering::Less,
|
||||||
|
(HeapCellValue::Addr(Addr::Con(Constant::Number(..))),
|
||||||
|
HeapCellValue::Addr(Addr::HeapCell(_))) =>
|
||||||
|
return Ordering::Greater,
|
||||||
|
(HeapCellValue::Addr(Addr::Con(Constant::Number(..))),
|
||||||
|
HeapCellValue::Addr(Addr::StackCell(..))) =>
|
||||||
|
return Ordering::Greater,
|
||||||
|
(HeapCellValue::Addr(Addr::Con(Constant::Number(n1))),
|
||||||
|
HeapCellValue::Addr(Addr::Con(Constant::Number(n2)))) =>
|
||||||
|
if n1 != n2 {
|
||||||
|
return n1.cmp(&n2);
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
(HeapCellValue::Addr(Addr::Con(Constant::Number(_))), _) =>
|
||||||
|
return Ordering::Less,
|
||||||
|
(HeapCellValue::Addr(Addr::Con(Constant::String(..))),
|
||||||
|
HeapCellValue::Addr(Addr::HeapCell(_))) =>
|
||||||
|
return Ordering::Greater,
|
||||||
|
(HeapCellValue::Addr(Addr::Con(Constant::String(..))),
|
||||||
|
HeapCellValue::Addr(Addr::StackCell(..))) =>
|
||||||
|
return Ordering::Greater,
|
||||||
|
(HeapCellValue::Addr(Addr::Con(Constant::String(_))),
|
||||||
|
HeapCellValue::Addr(Addr::Con(Constant::Number(_)))) =>
|
||||||
|
return Ordering::Greater,
|
||||||
|
(HeapCellValue::Addr(Addr::Con(Constant::String(s1))),
|
||||||
|
HeapCellValue::Addr(Addr::Con(Constant::String(s2)))) =>
|
||||||
|
if s1 != s2 {
|
||||||
|
return s1.cmp(&s2);
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
(HeapCellValue::Addr(Addr::Con(Constant::String(_))), _) =>
|
||||||
|
return Ordering::Less,
|
||||||
|
(HeapCellValue::Addr(Addr::Con(Constant::Atom(..))),
|
||||||
|
HeapCellValue::Addr(Addr::HeapCell(_))) =>
|
||||||
|
return Ordering::Greater,
|
||||||
|
(HeapCellValue::Addr(Addr::Con(Constant::Atom(..))),
|
||||||
|
HeapCellValue::Addr(Addr::StackCell(..))) =>
|
||||||
|
return Ordering::Greater,
|
||||||
|
(HeapCellValue::Addr(Addr::Con(Constant::Atom(_))),
|
||||||
|
HeapCellValue::Addr(Addr::Con(Constant::Number(_)))) =>
|
||||||
|
return Ordering::Greater,
|
||||||
|
(HeapCellValue::Addr(Addr::Con(Constant::Atom(_))),
|
||||||
|
HeapCellValue::Addr(Addr::Con(Constant::String(_)))) =>
|
||||||
|
return Ordering::Greater,
|
||||||
|
(HeapCellValue::Addr(Addr::Con(Constant::Atom(s1))),
|
||||||
|
HeapCellValue::Addr(Addr::Con(Constant::Atom(s2)))) =>
|
||||||
|
if s1 != s2 {
|
||||||
|
return s1.cmp(&s2);
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
(HeapCellValue::Addr(Addr::Con(Constant::Atom(_))), _) =>
|
||||||
|
return Ordering::Less,
|
||||||
|
(HeapCellValue::NamedStr(ar1, n1, _), HeapCellValue::NamedStr(ar2, n2, _)) =>
|
||||||
|
if ar1 < ar2 {
|
||||||
|
return Ordering::Less;
|
||||||
|
} else if ar1 > ar2 {
|
||||||
|
return Ordering::Greater;
|
||||||
|
} else if *n1 != *n2 {
|
||||||
|
return n1.cmp(&n2);
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
(HeapCellValue::Addr(Addr::Lis(_)), HeapCellValue::Addr(Addr::Lis(_))) =>
|
||||||
|
continue,
|
||||||
|
(HeapCellValue::Addr(Addr::Lis(_)), HeapCellValue::NamedStr(ar, n, _))
|
||||||
|
| (HeapCellValue::NamedStr(ar, n, _), HeapCellValue::Addr(Addr::Lis(_))) =>
|
||||||
|
if ar == 2 && *n == "." {
|
||||||
|
continue;
|
||||||
|
} else if ar < 2 {
|
||||||
|
return Ordering::Greater;
|
||||||
|
} else if ar > 2 {
|
||||||
|
return Ordering::Less;
|
||||||
|
} else {
|
||||||
|
return n.cmp(&String::from("."));
|
||||||
|
},
|
||||||
|
(HeapCellValue::NamedStr(..), _) =>
|
||||||
|
return Ordering::Greater,
|
||||||
|
(HeapCellValue::Addr(Addr::Lis(_)), _) =>
|
||||||
|
return Ordering::Greater,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ordering::Equal
|
||||||
|
}
|
||||||
|
|
||||||
fn reset_block(&mut self, addr: Addr) {
|
fn reset_block(&mut self, addr: Addr) {
|
||||||
// let addr = self.deref(self[temp_v!(1)].clone());
|
// let addr = self.deref(self[temp_v!(1)].clone());
|
||||||
|
|
||||||
@@ -1128,7 +1269,7 @@ impl MachineState {
|
|||||||
cut_policy: &mut Box<CutPolicy>,
|
cut_policy: &mut Box<CutPolicy>,
|
||||||
instr: &BuiltInInstruction)
|
instr: &BuiltInInstruction)
|
||||||
{
|
{
|
||||||
match instr {
|
match instr {
|
||||||
&BuiltInInstruction::GetArgCall =>
|
&BuiltInInstruction::GetArgCall =>
|
||||||
try_or_fail!(self, {
|
try_or_fail!(self, {
|
||||||
let val = self.try_get_arg();
|
let val = self.try_get_arg();
|
||||||
@@ -1273,7 +1414,7 @@ SetupCallCleanupCutPolicy.")
|
|||||||
self.or_stack.truncate(self.b);
|
self.or_stack.truncate(self.b);
|
||||||
|
|
||||||
self.fail = true;
|
self.fail = true;
|
||||||
},
|
},
|
||||||
&BuiltInInstruction::InternalCallN =>
|
&BuiltInInstruction::InternalCallN =>
|
||||||
self.handle_internal_call_n(code_dir),
|
self.handle_internal_call_n(code_dir),
|
||||||
&BuiltInInstruction::Fail => {
|
&BuiltInInstruction::Fail => {
|
||||||
@@ -1381,8 +1522,8 @@ SetupCallCleanupCutPolicy.")
|
|||||||
// returns true on failure.
|
// returns true on failure.
|
||||||
fn eq_test(&self) -> bool
|
fn eq_test(&self) -> bool
|
||||||
{
|
{
|
||||||
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
|
let a1 = self[temp_v!(1)].clone();
|
||||||
let a2 = self.store(self.deref(self[temp_v!(2)].clone()));
|
let a2 = self[temp_v!(2)].clone();
|
||||||
|
|
||||||
let iter = self.zipped_acyclic_pre_order_iter(a1, a2);
|
let iter = self.zipped_acyclic_pre_order_iter(a1, a2);
|
||||||
|
|
||||||
@@ -1397,7 +1538,7 @@ SetupCallCleanupCutPolicy.")
|
|||||||
(HeapCellValue::Addr(a1), HeapCellValue::Addr(a2)) =>
|
(HeapCellValue::Addr(a1), HeapCellValue::Addr(a2)) =>
|
||||||
if a1 != a2 {
|
if a1 != a2 {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
_ => return true
|
_ => return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1498,6 +1639,14 @@ SetupCallCleanupCutPolicy.")
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
&ControlInstruction::CompareTermCall(qt) => {
|
||||||
|
self.compare_term(qt);
|
||||||
|
self.p += 1;
|
||||||
|
},
|
||||||
|
&ControlInstruction::CompareTermExecute(qt) => {
|
||||||
|
self.compare_term(qt);
|
||||||
|
self.p = self.cp;
|
||||||
|
},
|
||||||
&ControlInstruction::Deallocate => {
|
&ControlInstruction::Deallocate => {
|
||||||
let e = self.e;
|
let e = self.e;
|
||||||
|
|
||||||
@@ -1717,7 +1866,7 @@ SetupCallCleanupCutPolicy.")
|
|||||||
&ControlInstruction::NotEqExecute => {
|
&ControlInstruction::NotEqExecute => {
|
||||||
self.fail = !self.eq_test();
|
self.fail = !self.eq_test();
|
||||||
self.p = self.cp;
|
self.p = self.cp;
|
||||||
},
|
},
|
||||||
&ControlInstruction::Proceed =>
|
&ControlInstruction::Proceed =>
|
||||||
self.p = self.cp,
|
self.p = self.cp,
|
||||||
&ControlInstruction::ThrowCall => {
|
&ControlInstruction::ThrowCall => {
|
||||||
|
|||||||
@@ -580,3 +580,51 @@ macro_rules! not_eq_execute {
|
|||||||
Line::Control(ControlInstruction::NotEqExecute)
|
Line::Control(ControlInstruction::NotEqExecute)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! compare_term_call {
|
||||||
|
($qt:expr) => (
|
||||||
|
Line::Control(ControlInstruction::CompareTermCall($qt))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! compare_term_execute {
|
||||||
|
($qt:expr) => (
|
||||||
|
Line::Control(ControlInstruction::CompareTermExecute($qt))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! term_cmp_gt {
|
||||||
|
() => (
|
||||||
|
CompareTermQT::GreaterThan
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! term_cmp_lt {
|
||||||
|
() => (
|
||||||
|
CompareTermQT::LessThan
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! term_cmp_gte {
|
||||||
|
() => (
|
||||||
|
CompareTermQT::GreaterThanOrEqual
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! term_cmp_lte {
|
||||||
|
() => (
|
||||||
|
CompareTermQT::LessThanOrEqual
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! term_cmp_ne {
|
||||||
|
() => (
|
||||||
|
CompareTermQT::NotEqual
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! term_cmp_eq {
|
||||||
|
() => (
|
||||||
|
CompareTermQT::Equal
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
Submodule src/prolog/parser updated: b50ed579fd...2e9979b9d2
23
src/tests.rs
23
src/tests.rs
@@ -1351,6 +1351,29 @@ fn test_queries_on_builtins()
|
|||||||
assert_prolog_success!(&mut wam, "?- A \\== B.");
|
assert_prolog_success!(&mut wam, "?- A \\== B.");
|
||||||
assert_prolog_success!(&mut wam, "?- A \\== 12.1.");
|
assert_prolog_success!(&mut wam, "?- A \\== 12.1.");
|
||||||
assert_prolog_failure!(&mut wam, "?- X = x, f(X, x) \\== f(x, X).");
|
assert_prolog_failure!(&mut wam, "?- X = x, f(X, x) \\== f(x, X).");
|
||||||
|
|
||||||
|
assert_prolog_success!(&mut wam, "?- X @=< Y.");
|
||||||
|
assert_prolog_failure!(&mut wam, "?- X @>= Y.");
|
||||||
|
assert_prolog_failure!(&mut wam, "?- X @> Y.");
|
||||||
|
assert_prolog_success!(&mut wam, "?- X @>= X.");
|
||||||
|
assert_prolog_failure!(&mut wam, "?- atom @=< \"string\".");
|
||||||
|
assert_prolog_success!(&mut wam, "?- atom @=< atom.");
|
||||||
|
assert_prolog_failure!(&mut wam, "?- atom @=< aaa.");
|
||||||
|
assert_prolog_success!(&mut wam, "?- atom @>= \"string\".");
|
||||||
|
assert_prolog_success!(&mut wam, "?- X is 3 + 3, X @>= Y.");
|
||||||
|
assert_prolog_success!(&mut wam, "?- f(X) @>= f(X).");
|
||||||
|
assert_prolog_success!(&mut wam, "?- f(X) @>= a.");
|
||||||
|
assert_prolog_failure!(&mut wam, "?- f(X) @=< a.");
|
||||||
|
assert_prolog_success!(&mut wam, "?- [1,2] @=< [1,2].");
|
||||||
|
assert_prolog_failure!(&mut wam, "?- [1,2,3] @=< [1,2].");
|
||||||
|
assert_prolog_success!(&mut wam, "?- [] @=< [1,2].");
|
||||||
|
assert_prolog_failure!(&mut wam, "?- [] @< 1.");
|
||||||
|
assert_prolog_failure!(&mut wam, "?- [] @< \"string\".");
|
||||||
|
assert_prolog_failure!(&mut wam, "?- [] @< atom.");
|
||||||
|
assert_prolog_success!(&mut wam, "?- atom @< [].");
|
||||||
|
assert_prolog_failure!(&mut wam, "?- 1.1 @< 1.");
|
||||||
|
assert_prolog_success!(&mut wam, "?- 1.0 @=< 1.");
|
||||||
|
assert_prolog_success!(&mut wam, "?- 1 @=< 1.0."); //TODO: currently this succeeds. make it fail.
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user