Merge pull request #3211 from mthom/setof_correction_and_opt
Correct and optimize setof/3 and bagof/3
This commit is contained in:
@@ -643,11 +643,6 @@ enum SystemClauseType {
|
|||||||
UnattributedVar,
|
UnattributedVar,
|
||||||
#[strum_discriminants(strum(props(Arity = "4", Name = "$get_db_refs")))]
|
#[strum_discriminants(strum(props(Arity = "4", Name = "$get_db_refs")))]
|
||||||
GetDBRefs,
|
GetDBRefs,
|
||||||
#[strum_discriminants(strum(props(
|
|
||||||
Arity = "2",
|
|
||||||
Name = "$keysort_with_constant_var_ordering"
|
|
||||||
)))]
|
|
||||||
KeySortWithConstantVarOrdering,
|
|
||||||
#[strum_discriminants(strum(props(Arity = "0", Name = "$inference_limit_exceeded")))]
|
#[strum_discriminants(strum(props(Arity = "0", Name = "$inference_limit_exceeded")))]
|
||||||
InferenceLimitExceeded,
|
InferenceLimitExceeded,
|
||||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$argv")))]
|
#[strum_discriminants(strum(props(Arity = "1", Name = "$argv")))]
|
||||||
|
|||||||
@@ -639,7 +639,10 @@ impl CodeGenerator {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
InlinedClauseType::IsRational(..) => match terms[0] {
|
InlinedClauseType::IsRational(..) => match terms[0] {
|
||||||
Term::Literal(_, Literal::Rational(_)) => {
|
Term::Literal(
|
||||||
|
_,
|
||||||
|
Literal::Rational(_) | Literal::Fixnum(_) | Literal::Integer(_),
|
||||||
|
) => {
|
||||||
instr!("$succeed")
|
instr!("$succeed")
|
||||||
}
|
}
|
||||||
Term::Var(ref vr, ref name) => {
|
Term::Var(ref vr, ref name) => {
|
||||||
@@ -679,10 +682,13 @@ impl CodeGenerator {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
InlinedClauseType::IsNumber(..) => match terms[0] {
|
InlinedClauseType::IsNumber(..) => match terms[0] {
|
||||||
Term::Literal(_, Literal::F64(..))
|
Term::Literal(
|
||||||
| Term::Literal(_, Literal::Rational(_))
|
_,
|
||||||
| Term::Literal(_, Literal::Integer(_))
|
Literal::F64(..)
|
||||||
| Term::Literal(_, Literal::Fixnum(_)) => {
|
| Literal::Rational(_)
|
||||||
|
| Literal::Integer(_)
|
||||||
|
| Literal::Fixnum(_),
|
||||||
|
) => {
|
||||||
instr!("$succeed")
|
instr!("$succeed")
|
||||||
}
|
}
|
||||||
Term::Var(ref vr, ref name) => {
|
Term::Var(ref vr, ref name) => {
|
||||||
@@ -988,20 +994,27 @@ impl CodeGenerator {
|
|||||||
self.marker.in_tail_position = false;
|
self.marker.in_tail_position = false;
|
||||||
self.marker.reset_contents();
|
self.marker.reset_contents();
|
||||||
}
|
}
|
||||||
ClauseItem::FirstBranch(num_branches) => {
|
ClauseItem::FirstBranch {
|
||||||
|
branch_num,
|
||||||
|
num_branches,
|
||||||
|
} => {
|
||||||
branch_code_stack.add_new_branch_stack();
|
branch_code_stack.add_new_branch_stack();
|
||||||
branch_code_stack.add_new_branch();
|
branch_code_stack.add_new_branch();
|
||||||
|
|
||||||
self.marker.branch_stack.add_branch_stack(num_branches);
|
self.marker
|
||||||
|
.branch_stack
|
||||||
|
.add_branch_stack(branch_num.clone(), num_branches);
|
||||||
self.marker.add_branch();
|
self.marker.add_branch();
|
||||||
}
|
}
|
||||||
ClauseItem::NextBranch => {
|
ClauseItem::NextBranch { branch_num } => {
|
||||||
branch_code_stack.add_new_branch();
|
branch_code_stack.add_new_branch();
|
||||||
|
|
||||||
self.marker.add_branch();
|
self.marker.add_branch();
|
||||||
self.marker.branch_stack.incr_current_branch();
|
self.marker
|
||||||
|
.branch_stack
|
||||||
|
.incr_current_branch(branch_num.clone());
|
||||||
}
|
}
|
||||||
ClauseItem::BranchEnd(depth) => {
|
ClauseItem::BranchEnd { depth } => {
|
||||||
if !clause_iter.in_tail_position() {
|
if !clause_iter.in_tail_position() {
|
||||||
let subsumed_hits =
|
let subsumed_hits =
|
||||||
branch_code_stack.push_missing_vars(depth, &mut self.marker);
|
branch_code_stack.push_missing_vars(depth, &mut self.marker);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::allocator::*;
|
use crate::allocator::*;
|
||||||
use crate::codegen::SubsumedBranchHits;
|
use crate::codegen::SubsumedBranchHits;
|
||||||
use crate::forms::{GenContext, Level};
|
use crate::forms::{BranchNumber, GenContext, Level};
|
||||||
use crate::instructions::*;
|
use crate::instructions::*;
|
||||||
use crate::machine::disjuncts::VarData;
|
use crate::machine::disjuncts::VarData;
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
@@ -24,24 +24,26 @@ pub struct BranchOccurrences {
|
|||||||
pub shallow_safety: BitSet<usize>, // unset means safe, set means unsafe (after the branch merge)
|
pub shallow_safety: BitSet<usize>, // unset means safe, set means unsafe (after the branch merge)
|
||||||
pub deep_safety: BitSet<usize>,
|
pub deep_safety: BitSet<usize>,
|
||||||
pub num_branches: usize,
|
pub num_branches: usize,
|
||||||
pub current_branch: usize,
|
pub current_branch_idx: usize,
|
||||||
|
pub current_branch_num: BranchNumber,
|
||||||
pub subsumed_hits: SubsumedBranchHits,
|
pub subsumed_hits: SubsumedBranchHits,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BranchOccurrences {
|
impl BranchOccurrences {
|
||||||
fn new(num_branches: usize) -> Self {
|
fn new(current_branch_num: BranchNumber, num_branches: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
hits: BranchHits::with_hasher(FxBuildHasher::default()),
|
hits: BranchHits::with_hasher(FxBuildHasher::default()),
|
||||||
shallow_safety: BitSet::default(),
|
shallow_safety: BitSet::default(),
|
||||||
deep_safety: BitSet::default(),
|
deep_safety: BitSet::default(),
|
||||||
num_branches,
|
num_branches,
|
||||||
current_branch: 0,
|
current_branch_idx: 0,
|
||||||
|
current_branch_num,
|
||||||
subsumed_hits: SubsumedBranchHits::with_hasher(FxBuildHasher::default()),
|
subsumed_hits: SubsumedBranchHits::with_hasher(FxBuildHasher::default()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add_branch_occurrence(&mut self, var_num: usize) {
|
pub(crate) fn add_branch_occurrence(&mut self, var_num: usize) {
|
||||||
debug_assert!(self.current_branch < self.num_branches);
|
debug_assert!(self.current_branch_idx < self.num_branches);
|
||||||
let num_branches = self.num_branches;
|
let num_branches = self.num_branches;
|
||||||
|
|
||||||
let entry = self
|
let entry = self
|
||||||
@@ -49,7 +51,7 @@ impl BranchOccurrences {
|
|||||||
.entry(var_num)
|
.entry(var_num)
|
||||||
.or_insert_with(|| BitVec::repeat(false, num_branches));
|
.or_insert_with(|| BitVec::repeat(false, num_branches));
|
||||||
|
|
||||||
entry.set(self.current_branch, true);
|
entry.set(self.current_branch_idx, true);
|
||||||
self.subsumed_hits.insert(var_num);
|
self.subsumed_hits.insert(var_num);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,19 +78,6 @@ impl DerefMut for BranchStack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BranchStack {
|
impl BranchStack {
|
||||||
fn branch_subsumes(&self, branch: &BranchDesignator, sub_branch: &BranchDesignator) -> bool {
|
|
||||||
if branch.branch_stack_num < sub_branch.branch_stack_num {
|
|
||||||
if branch.branch_stack_num == 0 {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
let idx = branch.branch_stack_num - 1;
|
|
||||||
self[idx].current_branch == branch.branch_num
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
branch == sub_branch
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn safety_unneeded_in_branch(
|
fn safety_unneeded_in_branch(
|
||||||
&self,
|
&self,
|
||||||
safety: &VarSafetyStatus,
|
safety: &VarSafetyStatus,
|
||||||
@@ -96,9 +85,9 @@ impl BranchStack {
|
|||||||
) -> bool {
|
) -> bool {
|
||||||
match safety {
|
match safety {
|
||||||
VarSafetyStatus::Needed => false,
|
VarSafetyStatus::Needed => false,
|
||||||
VarSafetyStatus::LocallyUnneeded(planter_branch) => {
|
VarSafetyStatus::LocallyUnneeded(planter_branch) => planter_branch
|
||||||
self.branch_subsumes(planter_branch, branch)
|
.branch_num
|
||||||
}
|
.has_as_subbranch(&branch.branch_num),
|
||||||
VarSafetyStatus::GloballyUnneeded => true,
|
VarSafetyStatus::GloballyUnneeded => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,27 +98,24 @@ impl BranchStack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add_branch_stack(&mut self, num_branches: usize) {
|
pub(crate) fn add_branch_stack(&mut self, branch_num: BranchNumber, num_branches: usize) {
|
||||||
self.push(BranchOccurrences::new(num_branches));
|
self.push(BranchOccurrences::new(branch_num, num_branches));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn current_branch_designator(&self) -> BranchDesignator {
|
pub(crate) fn current_branch_designator(&self) -> BranchDesignator {
|
||||||
let branch_stack_num = self.len();
|
|
||||||
let branch_num = self
|
let branch_num = self
|
||||||
.last()
|
.last()
|
||||||
.map(|occurrences| occurrences.current_branch)
|
.map(|occurrences| occurrences.current_branch_num.clone())
|
||||||
.unwrap_or(0);
|
.unwrap_or_else(|| BranchNumber::default());
|
||||||
|
|
||||||
BranchDesignator {
|
BranchDesignator { branch_num }
|
||||||
branch_stack_num,
|
|
||||||
branch_num,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn incr_current_branch(&mut self) {
|
pub(crate) fn incr_current_branch(&mut self, branch_num: BranchNumber) {
|
||||||
let branch_occurrences = self.last_mut().unwrap();
|
let branch_occurrences = self.last_mut().unwrap();
|
||||||
branch_occurrences.current_branch += 1;
|
branch_occurrences.current_branch_idx += 1;
|
||||||
|
branch_occurrences.current_branch_num = branch_num;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -235,12 +221,12 @@ impl DebrayAllocator {
|
|||||||
VarAlloc::Perm(_, allocation) => {
|
VarAlloc::Perm(_, allocation) => {
|
||||||
let shallow_safety = VarSafetyStatus::needed_if(
|
let shallow_safety = VarSafetyStatus::needed_if(
|
||||||
shallow_safety.contains(var_num),
|
shallow_safety.contains(var_num),
|
||||||
branch_designator,
|
&branch_designator,
|
||||||
);
|
);
|
||||||
|
|
||||||
let deep_safety = VarSafetyStatus::needed_if(
|
let deep_safety = VarSafetyStatus::needed_if(
|
||||||
deep_safety.contains(var_num),
|
deep_safety.contains(var_num),
|
||||||
branch_designator,
|
&branch_designator,
|
||||||
);
|
);
|
||||||
|
|
||||||
if running_count < num_occurrences {
|
if running_count < num_occurrences {
|
||||||
@@ -531,11 +517,11 @@ impl DebrayAllocator {
|
|||||||
..
|
..
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
*deep_safety = VarSafetyStatus::unneeded(branch_designator);
|
*deep_safety = VarSafetyStatus::unneeded(&branch_designator);
|
||||||
*shallow_safety = VarSafetyStatus::unneeded(branch_designator);
|
*shallow_safety = VarSafetyStatus::unneeded(&branch_designator);
|
||||||
}
|
}
|
||||||
VarAlloc::Temp { safety, .. } => {
|
VarAlloc::Temp { safety, .. } => {
|
||||||
*safety = VarSafetyStatus::unneeded(branch_designator);
|
*safety = VarSafetyStatus::unneeded(&branch_designator);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
@@ -557,8 +543,8 @@ impl DebrayAllocator {
|
|||||||
) => {
|
) => {
|
||||||
// GetVariable in head chunk is considered safe.
|
// GetVariable in head chunk is considered safe.
|
||||||
if lvl == Level::Deep {
|
if lvl == Level::Deep {
|
||||||
*deep_safety = VarSafetyStatus::unneeded(branch_designator);
|
*deep_safety = VarSafetyStatus::unneeded(&branch_designator);
|
||||||
*shallow_safety = VarSafetyStatus::unneeded(branch_designator);
|
*shallow_safety = VarSafetyStatus::unneeded(&branch_designator);
|
||||||
} else if term_loc == GenContext::Head {
|
} else if term_loc == GenContext::Head {
|
||||||
*shallow_safety = VarSafetyStatus::GloballyUnneeded;
|
*shallow_safety = VarSafetyStatus::GloballyUnneeded;
|
||||||
} else if let Some(&temp_var_num) = self.shallow_temp_mappings.get(&self.arg_c) {
|
} else if let Some(&temp_var_num) = self.shallow_temp_mappings.get(&self.arg_c) {
|
||||||
@@ -605,7 +591,7 @@ impl DebrayAllocator {
|
|||||||
{
|
{
|
||||||
Target::argument_to_value(r, arg_c)
|
Target::argument_to_value(r, arg_c)
|
||||||
} else {
|
} else {
|
||||||
*shallow_safety = VarSafetyStatus::unneeded(branch_designator);
|
*shallow_safety = VarSafetyStatus::unneeded(&branch_designator);
|
||||||
Target::unsafe_argument_to_value(r, arg_c)
|
Target::unsafe_argument_to_value(r, arg_c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -640,7 +626,7 @@ impl DebrayAllocator {
|
|||||||
{
|
{
|
||||||
Target::subterm_to_value(r)
|
Target::subterm_to_value(r)
|
||||||
} else {
|
} else {
|
||||||
*deep_safety = VarSafetyStatus::unneeded(branch_designator);
|
*deep_safety = VarSafetyStatus::unneeded(&branch_designator);
|
||||||
Target::unsafe_subterm_to_value(r)
|
Target::unsafe_subterm_to_value(r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -651,7 +637,7 @@ impl DebrayAllocator {
|
|||||||
{
|
{
|
||||||
Target::subterm_to_value(r)
|
Target::subterm_to_value(r)
|
||||||
} else {
|
} else {
|
||||||
*safety = VarSafetyStatus::unneeded(branch_designator);
|
*safety = VarSafetyStatus::unneeded(&branch_designator);
|
||||||
Target::unsafe_subterm_to_value(r)
|
Target::unsafe_subterm_to_value(r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
97
src/forms.rs
97
src/forms.rs
@@ -18,9 +18,11 @@ use indexmap::{IndexMap, IndexSet};
|
|||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
use std::cmp::Ordering;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
use std::ops::{AddAssign, Deref, DerefMut};
|
use std::ops::{AddAssign, Deref, DerefMut};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
@@ -42,12 +44,6 @@ impl AppendOrPrepend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum VarComparison {
|
|
||||||
Indistinct,
|
|
||||||
Distinct,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub enum Level {
|
pub enum Level {
|
||||||
Deep,
|
Deep,
|
||||||
@@ -128,10 +124,82 @@ impl ChunkType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)] //, PartialOrd, PartialEq, Eq, Hash)]
|
||||||
|
pub(crate) struct BranchNumber {
|
||||||
|
pub(crate) branch_num: Rational,
|
||||||
|
pub(crate) delta: Rational,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for BranchNumber {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
branch_num: Rational::from(0),
|
||||||
|
delta: Rational::from(1u64 << 31),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<BranchNumber> for BranchNumber {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, rhs: &BranchNumber) -> bool {
|
||||||
|
self.branch_num == rhs.branch_num
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for BranchNumber {}
|
||||||
|
|
||||||
|
impl Hash for BranchNumber {
|
||||||
|
#[inline(always)]
|
||||||
|
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
||||||
|
self.branch_num.hash(hasher)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd<BranchNumber> for BranchNumber {
|
||||||
|
#[inline]
|
||||||
|
fn partial_cmp(&self, rhs: &BranchNumber) -> Option<Ordering> {
|
||||||
|
self.branch_num.partial_cmp(&rhs.branch_num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BranchNumber {
|
||||||
|
pub(crate) fn has_as_subbranch(&self, other: &Self) -> bool {
|
||||||
|
other.delta <= self.delta
|
||||||
|
&& other.branch_num >= self.branch_num
|
||||||
|
&& other.branch_num < &self.branch_num + &self.delta
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn split(&self) -> BranchNumber {
|
||||||
|
BranchNumber {
|
||||||
|
branch_num: self.branch_num.clone() + &self.delta / Rational::from(2),
|
||||||
|
delta: &self.delta / Rational::from(4),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn incr_by_delta(&self) -> BranchNumber {
|
||||||
|
BranchNumber {
|
||||||
|
branch_num: self.branch_num.clone() + &self.delta,
|
||||||
|
delta: self.delta.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn halve_delta(&self) -> BranchNumber {
|
||||||
|
BranchNumber {
|
||||||
|
branch_num: self.branch_num.clone(),
|
||||||
|
delta: &self.delta / Rational::from(2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ChunkedTerms {
|
pub enum ChunkedTerms {
|
||||||
Branch(Vec<VecDeque<ChunkedTerms>>),
|
Branch {
|
||||||
Chunk { terms: VecDeque<QueryTerm> },
|
branch_nums: Vec<BranchNumber>,
|
||||||
|
arms: Vec<VecDeque<ChunkedTerms>>,
|
||||||
|
},
|
||||||
|
Chunk {
|
||||||
|
terms: VecDeque<QueryTerm>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -165,21 +233,22 @@ impl ChunkedTermVec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn reserve_branch(&mut self, capacity: usize) {
|
pub fn reserve_branch(&mut self, capacity: usize) {
|
||||||
self.chunk_vec
|
self.chunk_vec.push_back(ChunkedTerms::Branch {
|
||||||
.push_back(ChunkedTerms::Branch(Vec::with_capacity(capacity)));
|
branch_nums: Vec::with_capacity(capacity),
|
||||||
|
arms: Vec::with_capacity(capacity),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn add_chunk(&mut self) {
|
pub fn add_chunk(&mut self) {
|
||||||
let chunk = ChunkedTerms::Chunk {
|
self.chunk_vec.push_back(ChunkedTerms::Chunk {
|
||||||
terms: VecDeque::from(vec![]),
|
terms: VecDeque::from(vec![]),
|
||||||
};
|
});
|
||||||
self.chunk_vec.push_back(chunk);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_chunk_term(&mut self, term: QueryTerm) {
|
pub fn push_chunk_term(&mut self, term: QueryTerm) {
|
||||||
match self.chunk_vec.back_mut() {
|
match self.chunk_vec.back_mut() {
|
||||||
Some(ChunkedTerms::Branch(_)) => {
|
Some(ChunkedTerms::Branch { .. }) => {
|
||||||
let chunk = ChunkedTerms::Chunk {
|
let chunk = ChunkedTerms::Chunk {
|
||||||
terms: VecDeque::from(vec![term]),
|
terms: VecDeque::from(vec![term]),
|
||||||
};
|
};
|
||||||
|
|||||||
356
src/heap_iter.rs
356
src/heap_iter.rs
@@ -1,21 +1,375 @@
|
|||||||
#![allow(clippy::new_without_default)] // annotating structs annotated with #[bitfield] doesn't work
|
#![allow(clippy::new_without_default)] // annotating structs annotated with #[bitfield] doesn't work
|
||||||
#![allow(unused_parens)] // see mthom/scryer-prolog#3092 and rust-lang/rust#147126
|
#![allow(unused_parens)] // see mthom/scryer-prolog#3092 and rust-lang/rust#147126
|
||||||
|
|
||||||
|
use crate::arena::Arena;
|
||||||
|
use crate::forms::Number;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) use crate::machine::gc::StacklessPreOrderHeapIter;
|
pub(crate) use crate::machine::gc::StacklessPreOrderHeapIter;
|
||||||
|
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
use crate::machine::cycle_detection::*;
|
use crate::machine::cycle_detection::*;
|
||||||
use crate::machine::heap::*;
|
use crate::machine::heap::*;
|
||||||
|
use crate::machine::machine_indices::TermOrderCategory;
|
||||||
use crate::machine::stack::*;
|
use crate::machine::stack::*;
|
||||||
|
use crate::parser::lexer::MachineState;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
use fxhash::FxBuildHasher;
|
||||||
|
use indexmap::IndexSet;
|
||||||
use scryer_modular_bitfield::prelude::*;
|
use scryer_modular_bitfield::prelude::*;
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
// iterate through the subterms of a pair of terms
|
||||||
|
// for as long as they structurally agree, reporting
|
||||||
|
// the earliest (pre-order) difference before returning
|
||||||
|
// None's and pairs of variables as the Iterator Item.
|
||||||
|
|
||||||
|
pub struct ParallelHeapIter<'a> {
|
||||||
|
stack: Vec<HeapCellValue>,
|
||||||
|
heap: &'a Heap,
|
||||||
|
arena: &'a Arena,
|
||||||
|
tabu_list: IndexSet<(usize, usize), FxBuildHasher>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ParallelHeapIter<'a> {
|
||||||
|
pub fn from(machine_st: &'a MachineState, h1: HeapCellValue, h2: HeapCellValue) -> Self {
|
||||||
|
Self {
|
||||||
|
stack: vec![h2, h1],
|
||||||
|
heap: &machine_st.heap,
|
||||||
|
arena: &machine_st.arena,
|
||||||
|
tabu_list: IndexSet::with_hasher(FxBuildHasher::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub enum TermPair {
|
||||||
|
Vars(usize, usize),
|
||||||
|
Less(HeapCellValue, HeapCellValue),
|
||||||
|
Greater(HeapCellValue, HeapCellValue),
|
||||||
|
Unordered(HeapCellValue, HeapCellValue),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParallelHeapIter<'_> {
|
||||||
|
#[inline]
|
||||||
|
fn parallel_cmp<Cmp: Ord>(
|
||||||
|
&mut self,
|
||||||
|
v1: Cmp,
|
||||||
|
v2: Cmp,
|
||||||
|
h1: HeapCellValue,
|
||||||
|
h2: HeapCellValue,
|
||||||
|
) -> Option<TermPair> {
|
||||||
|
match v1.cmp(&v2) {
|
||||||
|
Ordering::Greater => {
|
||||||
|
self.stack.clear();
|
||||||
|
Some(TermPair::Greater(h1, h2))
|
||||||
|
}
|
||||||
|
Ordering::Less => {
|
||||||
|
self.stack.clear();
|
||||||
|
Some(TermPair::Less(h1, h2))
|
||||||
|
}
|
||||||
|
Ordering::Equal => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! some_or_return {
|
||||||
|
($e:expr) => {
|
||||||
|
if let Some(x) = $e {
|
||||||
|
return Some(x);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for ParallelHeapIter<'_> {
|
||||||
|
type Item = TermPair;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
use crate::offset_table::F64Offset;
|
||||||
|
|
||||||
|
while let Some(s1) = self.stack.pop() {
|
||||||
|
let s1 = heap_bound_deref(self.heap, s1);
|
||||||
|
|
||||||
|
let s2 = self.stack.pop().unwrap();
|
||||||
|
let s2 = heap_bound_deref(self.heap, s2);
|
||||||
|
|
||||||
|
let v1 = heap_bound_store(self.heap, s1);
|
||||||
|
let v2 = heap_bound_store(self.heap, s2);
|
||||||
|
|
||||||
|
let order_cat_v1 = v1.order_category(self.heap);
|
||||||
|
let order_cat_v2 = v2.order_category(self.heap);
|
||||||
|
|
||||||
|
some_or_return!(self.parallel_cmp(order_cat_v1, order_cat_v2, v1, v2));
|
||||||
|
|
||||||
|
match order_cat_v1 {
|
||||||
|
Some(TermOrderCategory::Variable) => {
|
||||||
|
let v1 = v1.get_value() as usize;
|
||||||
|
let v2 = v2.get_value() as usize;
|
||||||
|
|
||||||
|
return Some(TermPair::Vars(v1, v2));
|
||||||
|
}
|
||||||
|
Some(TermOrderCategory::FloatingPoint) => {
|
||||||
|
let v1_offset = cell_as_f64_offset!(v1);
|
||||||
|
let v2_offset = cell_as_f64_offset!(v2);
|
||||||
|
|
||||||
|
let v1_f64 = self.arena.f64_tbl.get_entry(v1_offset);
|
||||||
|
let v2_f64 = self.arena.f64_tbl.get_entry(v2_offset);
|
||||||
|
|
||||||
|
some_or_return!(self.parallel_cmp(v1_f64, v2_f64, v1, v2));
|
||||||
|
}
|
||||||
|
Some(TermOrderCategory::Integer) => {
|
||||||
|
let v1_int = Number::try_from((v1, &self.arena.f64_tbl)).unwrap();
|
||||||
|
let v2_int = Number::try_from((v2, &self.arena.f64_tbl)).unwrap();
|
||||||
|
|
||||||
|
some_or_return!(self.parallel_cmp(v1_int, v2_int, v1, v2));
|
||||||
|
}
|
||||||
|
Some(TermOrderCategory::Atom) => {
|
||||||
|
read_heap_cell!(v1,
|
||||||
|
(HeapCellValueTag::Atom, (n1, _a1)) => {
|
||||||
|
read_heap_cell!(v2,
|
||||||
|
(HeapCellValueTag::Atom, (n2, _a2)) => {
|
||||||
|
some_or_return!(self.parallel_cmp(n1, n2, v1, v2));
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let n2 = cell_as_atom_cell!(self.heap[s])
|
||||||
|
.get_name();
|
||||||
|
|
||||||
|
some_or_return!(self.parallel_cmp(n1, n2, v1, v2));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let n1 = cell_as_atom_cell!(self.heap[s])
|
||||||
|
.get_name();
|
||||||
|
|
||||||
|
read_heap_cell!(v2,
|
||||||
|
(HeapCellValueTag::Atom, (n2, _a2)) => {
|
||||||
|
some_or_return!(self.parallel_cmp(n1, n2, v1, v2));
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let n2 = cell_as_atom_cell!(self.heap[s])
|
||||||
|
.get_name();
|
||||||
|
|
||||||
|
some_or_return!(self.parallel_cmp(n1, n2, v1, v2));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Some(TermOrderCategory::Compound) => {
|
||||||
|
read_heap_cell!(v1,
|
||||||
|
(HeapCellValueTag::Lis, l1) => {
|
||||||
|
read_heap_cell!(v2,
|
||||||
|
(HeapCellValueTag::PStrLoc, l2) => {
|
||||||
|
if self.tabu_list.contains(&(l1, l2)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tabu_list.insert((l1, l2));
|
||||||
|
|
||||||
|
// like the action of partial_string_to_stack here but the
|
||||||
|
// ordering of stack pushes is (crucially for comparison
|
||||||
|
// correctness) different.
|
||||||
|
let (c, succ_cell) = self.heap.last_str_char_and_tail(l2);
|
||||||
|
|
||||||
|
self.stack.push(succ_cell);
|
||||||
|
self.stack.push(heap_loc_as_cell!(l1 + 1));
|
||||||
|
|
||||||
|
self.stack.push(char_as_cell!(c));
|
||||||
|
self.stack.push(heap_loc_as_cell!(l1));
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Lis, l2) => {
|
||||||
|
if self.tabu_list.contains(&(l1, l2)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tabu_list.insert((l1, l2));
|
||||||
|
|
||||||
|
self.stack.push(self.heap[l2 + 1]);
|
||||||
|
self.stack.push(self.heap[l1 + 1]);
|
||||||
|
|
||||||
|
self.stack.push(self.heap[l2]);
|
||||||
|
self.stack.push(self.heap[l1]);
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Str, s2) => {
|
||||||
|
if self.tabu_list.contains(&(l1, s2)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (n2, a2) = cell_as_atom_cell!(self.heap[s2])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
some_or_return!(self.parallel_cmp((2, atom!(".")), (a2, n2), v1, v2));
|
||||||
|
|
||||||
|
self.tabu_list.insert((l1, s2));
|
||||||
|
|
||||||
|
self.stack.push(self.heap[s2 + 2]);
|
||||||
|
self.stack.push(self.heap[l1 + 1]);
|
||||||
|
|
||||||
|
self.stack.push(self.heap[s2 + 1]);
|
||||||
|
self.stack.push(self.heap[l1]);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::PStrLoc, l1) => {
|
||||||
|
read_heap_cell!(v2,
|
||||||
|
(HeapCellValueTag::PStrLoc, l2) => {
|
||||||
|
if self.tabu_list.contains(&(l1, l2)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.heap.compare_pstr_segments(l1, l2) {
|
||||||
|
PStrSegmentCmpResult::Continue(v1, v2) => {
|
||||||
|
self.tabu_list.insert((l1, l2));
|
||||||
|
|
||||||
|
self.stack.push(v1.offset_by(l1));
|
||||||
|
self.stack.push(v2.offset_by(l2));
|
||||||
|
}
|
||||||
|
PStrSegmentCmpResult::Less => {
|
||||||
|
self.stack.clear();
|
||||||
|
return Some(TermPair::Less(v1, v2));
|
||||||
|
}
|
||||||
|
PStrSegmentCmpResult::Greater => {
|
||||||
|
self.stack.clear();
|
||||||
|
return Some(TermPair::Greater(v1, v2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Lis, l2) => {
|
||||||
|
if self.tabu_list.contains(&(l1, l2)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tabu_list.insert((l1, l2));
|
||||||
|
|
||||||
|
let (c, succ_cell) = self.heap.last_str_char_and_tail(l1);
|
||||||
|
|
||||||
|
self.stack.push(succ_cell);
|
||||||
|
self.stack.push(heap_loc_as_cell!(l2 + 1));
|
||||||
|
|
||||||
|
self.stack.push(char_as_cell!(c));
|
||||||
|
self.stack.push(heap_loc_as_cell!(l2));
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Str, s2) => {
|
||||||
|
if self.tabu_list.contains(&(l1, s2)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tabu_list.insert((l1, s2));
|
||||||
|
|
||||||
|
let (n2, a2) = cell_as_atom_cell!(self.heap[s2])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
some_or_return!(self.parallel_cmp((2, atom!(".")), (a2, n2), v1, v2));
|
||||||
|
|
||||||
|
let (c, succ_cell) = self.heap.last_str_char_and_tail(l1);
|
||||||
|
|
||||||
|
self.stack.push(heap_loc_as_cell!(s2+2));
|
||||||
|
self.stack.push(succ_cell);
|
||||||
|
|
||||||
|
self.stack.push(heap_loc_as_cell!(s2+1));
|
||||||
|
self.stack.push(char_as_cell!(c));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Str, s1) => {
|
||||||
|
read_heap_cell!(v2,
|
||||||
|
(HeapCellValueTag::Str, s2) => {
|
||||||
|
if self.tabu_list.contains(&(s1, s2)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (n1, a1) = cell_as_atom_cell!(self.heap[s1])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
let (n2, a2) = cell_as_atom_cell!(self.heap[s2])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
some_or_return!(self.parallel_cmp((a1, n1), (a2, n2), v1, v2));
|
||||||
|
|
||||||
|
self.tabu_list.insert((s1, s2));
|
||||||
|
|
||||||
|
for idx in (1 .. a1+1).rev() {
|
||||||
|
self.stack.push(self.heap[s2+idx]);
|
||||||
|
self.stack.push(self.heap[s1+idx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Lis, l2) => {
|
||||||
|
if self.tabu_list.contains(&(s1, l2)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (n1, a1) = cell_as_atom_cell!(self.heap[s1])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
some_or_return!(self.parallel_cmp((a1, n1), (2, atom!(".")), v1, v2));
|
||||||
|
|
||||||
|
self.stack.push(self.heap[l2]);
|
||||||
|
self.stack.push(self.heap[s1+1]);
|
||||||
|
|
||||||
|
self.stack.push(self.heap[l2+1]);
|
||||||
|
self.stack.push(self.heap[s1+2]);
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::PStrLoc, l2) => {
|
||||||
|
if self.tabu_list.contains(&(s1, l2)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (n1, a1) = cell_as_atom_cell!(self.heap[s1])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
some_or_return!(self.parallel_cmp((a1, n1), (2, atom!(".")), v1, v2));
|
||||||
|
|
||||||
|
self.tabu_list.insert((s1, l2));
|
||||||
|
|
||||||
|
let (c, succ_cell) = self.heap.last_str_char_and_tail(l2);
|
||||||
|
|
||||||
|
self.stack.push(succ_cell);
|
||||||
|
self.stack.push(heap_loc_as_cell!(s1+2));
|
||||||
|
|
||||||
|
self.stack.push(char_as_cell!(c));
|
||||||
|
self.stack.push(heap_loc_as_cell!(s1+1));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return Some(TermPair::Unordered(v1, v2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn eager_stackful_preorder_iter(
|
pub fn eager_stackful_preorder_iter(
|
||||||
heap: &mut Heap,
|
heap: &mut Heap,
|
||||||
@@ -35,7 +389,7 @@ pub struct EagerStackfulPreOrderHeapIter<'a> {
|
|||||||
start_value: HeapCellValue,
|
start_value: HeapCellValue,
|
||||||
iter_stack: Vec<HeapCellValue>,
|
iter_stack: Vec<HeapCellValue>,
|
||||||
mark_phase: bool,
|
mark_phase: bool,
|
||||||
heap: &'a mut Heap,
|
pub heap: &'a mut Heap,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Drop for EagerStackfulPreOrderHeapIter<'a> {
|
impl<'a> Drop for EagerStackfulPreOrderHeapIter<'a> {
|
||||||
|
|||||||
@@ -726,7 +726,6 @@ impl Instruction {
|
|||||||
| &Instruction::CallDeleteAllAttributesFromVar
|
| &Instruction::CallDeleteAllAttributesFromVar
|
||||||
| &Instruction::CallUnattributedVar
|
| &Instruction::CallUnattributedVar
|
||||||
| &Instruction::CallGetDBRefs
|
| &Instruction::CallGetDBRefs
|
||||||
| &Instruction::CallKeySortWithConstantVarOrdering
|
|
||||||
| &Instruction::CallInferenceLimitExceeded
|
| &Instruction::CallInferenceLimitExceeded
|
||||||
| &Instruction::CallFetchGlobalVar
|
| &Instruction::CallFetchGlobalVar
|
||||||
| &Instruction::CallFirstStream
|
| &Instruction::CallFirstStream
|
||||||
@@ -986,7 +985,6 @@ impl Instruction {
|
|||||||
| &Instruction::ExecuteDeleteAllAttributesFromVar
|
| &Instruction::ExecuteDeleteAllAttributesFromVar
|
||||||
| &Instruction::ExecuteUnattributedVar
|
| &Instruction::ExecuteUnattributedVar
|
||||||
| &Instruction::ExecuteGetDBRefs
|
| &Instruction::ExecuteGetDBRefs
|
||||||
| &Instruction::ExecuteKeySortWithConstantVarOrdering
|
|
||||||
| &Instruction::ExecuteInferenceLimitExceeded
|
| &Instruction::ExecuteInferenceLimitExceeded
|
||||||
| &Instruction::ExecuteFetchGlobalVar
|
| &Instruction::ExecuteFetchGlobalVar
|
||||||
| &Instruction::ExecuteFirstStream
|
| &Instruction::ExecuteFirstStream
|
||||||
|
|||||||
@@ -319,15 +319,28 @@ pub(crate) fn breadth_first_iter(
|
|||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
enum ClauseIteratorState<'a> {
|
enum ClauseIteratorState<'a> {
|
||||||
RemainingChunks(&'a VecDeque<ChunkedTerms>, usize),
|
RemainingChunks(&'a VecDeque<ChunkedTerms>, usize),
|
||||||
RemainingBranches(&'a Vec<VecDeque<ChunkedTerms>>, usize),
|
RemainingBranches(
|
||||||
|
&'a Vec<BranchNumber>,
|
||||||
|
&'a Vec<VecDeque<ChunkedTerms>>,
|
||||||
|
usize,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) enum ClauseItem<'a> {
|
pub(crate) enum ClauseItem<'a> {
|
||||||
FirstBranch(usize),
|
FirstBranch {
|
||||||
NextBranch,
|
branch_num: &'a BranchNumber,
|
||||||
BranchEnd(usize),
|
num_branches: usize,
|
||||||
Chunk { terms: &'a VecDeque<QueryTerm> },
|
},
|
||||||
|
NextBranch {
|
||||||
|
branch_num: &'a BranchNumber,
|
||||||
|
},
|
||||||
|
BranchEnd {
|
||||||
|
depth: usize,
|
||||||
|
},
|
||||||
|
Chunk {
|
||||||
|
terms: &'a VecDeque<QueryTerm>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -338,8 +351,8 @@ pub(crate) struct ClauseIterator<'a> {
|
|||||||
|
|
||||||
fn state_from_chunked_terms(chunk_vec: &VecDeque<ChunkedTerms>) -> ClauseIteratorState<'_> {
|
fn state_from_chunked_terms(chunk_vec: &VecDeque<ChunkedTerms>) -> ClauseIteratorState<'_> {
|
||||||
if chunk_vec.len() == 1 {
|
if chunk_vec.len() == 1 {
|
||||||
if let Some(ChunkedTerms::Branch(ref branches)) = chunk_vec.front() {
|
if let Some(ChunkedTerms::Branch { branch_nums, arms }) = chunk_vec.front() {
|
||||||
return ClauseIteratorState::RemainingBranches(branches, 0);
|
return ClauseIteratorState::RemainingBranches(branch_nums, arms, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,7 +383,9 @@ impl<'a> ClauseIterator<'a> {
|
|||||||
|
|
||||||
while let Some(state) = self.state_stack.pop() {
|
while let Some(state) = self.state_stack.pop() {
|
||||||
match state {
|
match state {
|
||||||
ClauseIteratorState::RemainingBranches(terms, focus) if terms.len() == focus => {
|
ClauseIteratorState::RemainingBranches(_branch_nums, terms, focus)
|
||||||
|
if terms.len() == focus =>
|
||||||
|
{
|
||||||
depth += 1;
|
depth += 1;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -399,9 +414,9 @@ impl<'a> Iterator for ClauseIterator<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match &chunks[focus] {
|
match &chunks[focus] {
|
||||||
ChunkedTerms::Branch(branches) => {
|
ChunkedTerms::Branch { branch_nums, arms } => {
|
||||||
self.state_stack
|
self.state_stack
|
||||||
.push(ClauseIteratorState::RemainingBranches(branches, 0));
|
.push(ClauseIteratorState::RemainingBranches(branch_nums, arms, 0));
|
||||||
}
|
}
|
||||||
ChunkedTerms::Chunk { ref terms } => {
|
ChunkedTerms::Chunk { ref terms } => {
|
||||||
return Some(ClauseItem::Chunk { terms });
|
return Some(ClauseItem::Chunk { terms });
|
||||||
@@ -411,11 +426,15 @@ impl<'a> Iterator for ClauseIterator<'a> {
|
|||||||
ClauseIteratorState::RemainingChunks(chunks, focus) => {
|
ClauseIteratorState::RemainingChunks(chunks, focus) => {
|
||||||
debug_assert_eq!(chunks.len(), focus);
|
debug_assert_eq!(chunks.len(), focus);
|
||||||
}
|
}
|
||||||
ClauseIteratorState::RemainingBranches(branches, focus)
|
ClauseIteratorState::RemainingBranches(branch_nums, branches, focus)
|
||||||
if focus < branches.len() =>
|
if focus < branches.len() =>
|
||||||
{
|
{
|
||||||
self.state_stack
|
self.state_stack
|
||||||
.push(ClauseIteratorState::RemainingBranches(branches, focus + 1));
|
.push(ClauseIteratorState::RemainingBranches(
|
||||||
|
branch_nums,
|
||||||
|
branches,
|
||||||
|
focus + 1,
|
||||||
|
));
|
||||||
let state = state_from_chunked_terms(&branches[focus]);
|
let state = state_from_chunked_terms(&branches[focus]);
|
||||||
|
|
||||||
if let ClauseIteratorState::RemainingChunks(..) = &state {
|
if let ClauseIteratorState::RemainingChunks(..) = &state {
|
||||||
@@ -425,14 +444,21 @@ impl<'a> Iterator for ClauseIterator<'a> {
|
|||||||
self.state_stack.push(state);
|
self.state_stack.push(state);
|
||||||
|
|
||||||
return if focus == 0 {
|
return if focus == 0 {
|
||||||
Some(ClauseItem::FirstBranch(branches.len()))
|
Some(ClauseItem::FirstBranch {
|
||||||
|
branch_num: &branch_nums[0],
|
||||||
|
num_branches: branches.len(),
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
Some(ClauseItem::NextBranch)
|
Some(ClauseItem::NextBranch {
|
||||||
|
branch_num: &branch_nums[focus],
|
||||||
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
ClauseIteratorState::RemainingBranches(branches, focus) => {
|
ClauseIteratorState::RemainingBranches(_branch_nums, branches, focus) => {
|
||||||
debug_assert_eq!(branches.len(), focus);
|
debug_assert_eq!(branches.len(), focus);
|
||||||
return Some(ClauseItem::BranchEnd(self.branch_end_depth()));
|
return Some(ClauseItem::BranchEnd {
|
||||||
|
depth: self.branch_end_depth(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -944,65 +944,6 @@ findall(Template, Goal, Solutions0, Solutions1) :-
|
|||||||
builtins:findall_cleanup(LhLength, Error)
|
builtins:findall_cleanup(LhLength, Error)
|
||||||
).
|
).
|
||||||
|
|
||||||
:- non_counted_backtracking set_difference/3.
|
|
||||||
|
|
||||||
set_difference([X|Xs], [Y|Ys], Zs) :-
|
|
||||||
X == Y, !, set_difference(Xs, [Y|Ys], Zs).
|
|
||||||
set_difference([X|Xs], [Y|Ys], [X|Zs]) :-
|
|
||||||
X @< Y, !, set_difference(Xs, [Y|Ys], Zs).
|
|
||||||
set_difference([X|Xs], [Y|Ys], Zs) :-
|
|
||||||
X @> Y, !, set_difference([X|Xs], Ys, Zs).
|
|
||||||
set_difference([], _, []) :- !.
|
|
||||||
set_difference(Xs, [], Xs).
|
|
||||||
|
|
||||||
|
|
||||||
% variant/2 checks whether X is a variant of Y per the definition in
|
|
||||||
% 7.1.6.1 of the ISO standard.
|
|
||||||
|
|
||||||
:- non_counted_backtracking variant/4.
|
|
||||||
|
|
||||||
variant(X,Y,VPs,VPs0) :-
|
|
||||||
( var(X) ->
|
|
||||||
var(Y),
|
|
||||||
VPs = [X-Y|VPs0]
|
|
||||||
; var(Y) ->
|
|
||||||
false
|
|
||||||
; X =.. [FX | XArgs],
|
|
||||||
Y =.. [FX | YArgs],
|
|
||||||
lists:foldl('$call'(builtins:variant), XArgs, YArgs, VPs, VPs0)
|
|
||||||
).
|
|
||||||
|
|
||||||
:- non_counted_backtracking variant/2.
|
|
||||||
|
|
||||||
singleton([_]).
|
|
||||||
|
|
||||||
variant(X, Y) :-
|
|
||||||
variant(X,Y, VPs, []),
|
|
||||||
keysort(VPs, SVPs),
|
|
||||||
pairs:group_pairs_by_key(SVPs, SVPKs),
|
|
||||||
pairs:pairs_values(SVPKs, Vals),
|
|
||||||
lists:maplist('$call'(builtins:term_variables), Vals, Vs),
|
|
||||||
lists:maplist('$call'(builtins:singleton), Vs),
|
|
||||||
term_variables(Vs, YVars),
|
|
||||||
lists:length(SVPKs, N),
|
|
||||||
lists:length(YVars, N).
|
|
||||||
|
|
||||||
|
|
||||||
:- non_counted_backtracking group_by_variant/4.
|
|
||||||
|
|
||||||
group_by_variant([V2-S2 | Pairs], V1-S1, [S2 | Solutions], Pairs0) :-
|
|
||||||
variant(V1, V2),
|
|
||||||
!,
|
|
||||||
V1 = V2,
|
|
||||||
group_by_variant(Pairs, V2-S2, Solutions, Pairs0).
|
|
||||||
group_by_variant(Pairs, _, [], Pairs).
|
|
||||||
|
|
||||||
:- non_counted_backtracking group_by_variants/2.
|
|
||||||
|
|
||||||
group_by_variants([V-S|Pairs], [V-Solution|Solutions]) :-
|
|
||||||
group_by_variant([V-S|Pairs], V-S, Solution, Pairs0),
|
|
||||||
group_by_variants(Pairs0, Solutions).
|
|
||||||
group_by_variants([], []).
|
|
||||||
|
|
||||||
:- non_counted_backtracking iterate_variants/3.
|
:- non_counted_backtracking iterate_variants/3.
|
||||||
|
|
||||||
@@ -1035,9 +976,7 @@ findall_with_existential(Template, Goal, PairedSolutions, Witnesses0, Witnesses)
|
|||||||
( Goal1 = _ ^ _ ) ->
|
( Goal1 = _ ^ _ ) ->
|
||||||
rightmost_power(Goal1, Goal2, ExistentialVars0),
|
rightmost_power(Goal1, Goal2, ExistentialVars0),
|
||||||
term_variables(ExistentialVars0, ExistentialVars),
|
term_variables(ExistentialVars0, ExistentialVars),
|
||||||
sort(Witnesses0, Witnesses1),
|
lists:append(Witnesses0, Witnesses, ExistentialVars),
|
||||||
sort(ExistentialVars, ExistentialVars1),
|
|
||||||
set_difference(Witnesses1, ExistentialVars1, Witnesses),
|
|
||||||
expand_goal(M:Goal2, M, Goal3),
|
expand_goal(M:Goal2, M, Goal3),
|
||||||
findall(Witnesses-Template, Goal3, PairedSolutions)
|
findall(Witnesses-Template, Goal3, PairedSolutions)
|
||||||
; Witnesses = Witnesses0,
|
; Witnesses = Witnesses0,
|
||||||
@@ -1045,6 +984,34 @@ findall_with_existential(Template, Goal, PairedSolutions, Witnesses0, Witnesses)
|
|||||||
).
|
).
|
||||||
|
|
||||||
|
|
||||||
|
:- non_counted_backtracking split_by_variant/4.
|
||||||
|
|
||||||
|
:- non_counted_backtracking split_by_variant/3.
|
||||||
|
|
||||||
|
:- non_counted_backtracking unify_variant_variables/2.
|
||||||
|
|
||||||
|
split_by_variant([V2-S2 | Pairs], V1-S1, Solutions, Rest) :-
|
||||||
|
( V1 == V2 ->
|
||||||
|
Solutions = [S2 | Solutions1],
|
||||||
|
split_by_variant(Pairs, V1-S1, Solutions1, Rest)
|
||||||
|
; Solutions = [],
|
||||||
|
Rest = [V2-S2 | Pairs]
|
||||||
|
).
|
||||||
|
split_by_variant([], _, [], []).
|
||||||
|
|
||||||
|
split_by_variant([V-S|Pairs], Ws, Solutions) :-
|
||||||
|
split_by_variant(Pairs, V-S, Solutions0, Rest),
|
||||||
|
( Rest == [] -> V = Ws, Solutions = [S|Solutions0]
|
||||||
|
; V = Ws, Solutions = [S|Solutions0]
|
||||||
|
; split_by_variant(Rest, Ws, Solutions)
|
||||||
|
).
|
||||||
|
|
||||||
|
unify_variant_variables([], _Dict).
|
||||||
|
unify_variant_variables([V-_S|Pairs], Dict) :-
|
||||||
|
term_variables(V, VVars),
|
||||||
|
lists:append(VVars, _, Dict),
|
||||||
|
unify_variant_variables(Pairs, Dict).
|
||||||
|
|
||||||
:- meta_predicate(bagof(?, 0, ?)).
|
:- meta_predicate(bagof(?, 0, ?)).
|
||||||
|
|
||||||
:- non_counted_backtracking bagof/3.
|
:- non_counted_backtracking bagof/3.
|
||||||
@@ -1074,22 +1041,10 @@ bagof(Template, Goal, Solution) :-
|
|||||||
term_variables(Goal, GoalVars),
|
term_variables(Goal, GoalVars),
|
||||||
term_variables(TemplateVars+GoalVars, TGVs),
|
term_variables(TemplateVars+GoalVars, TGVs),
|
||||||
lists:append(TemplateVars, Witnesses0, TGVs),
|
lists:append(TemplateVars, Witnesses0, TGVs),
|
||||||
findall_with_existential(Template, Goal, PairedSolutions0, Witnesses0, Witnesses),
|
findall_with_existential(Template, Goal, PairedSolutions, Witnesses0, Witnesses),
|
||||||
keysort(PairedSolutions0, PairedSolutions),
|
unify_variant_variables(PairedSolutions, _Dict),
|
||||||
group_by_variants(PairedSolutions, GroupedSolutions),
|
keysort(PairedSolutions, PairedSolutions1),
|
||||||
iterate_variants(GroupedSolutions, Witnesses, Solution).
|
split_by_variant(PairedSolutions1, Witnesses, Solution).
|
||||||
|
|
||||||
:- non_counted_backtracking iterate_variants_and_sort/3.
|
|
||||||
|
|
||||||
iterate_variants_and_sort([V-Solution0|GroupSolutions], V, Solution) :-
|
|
||||||
sort(Solution0, Solution1),
|
|
||||||
Solution1 = Solution,
|
|
||||||
( GroupSolutions == [] -> !
|
|
||||||
; true
|
|
||||||
).
|
|
||||||
iterate_variants_and_sort([_|GroupSolutions], Ws, Solution) :-
|
|
||||||
iterate_variants_and_sort(GroupSolutions, Ws, Solution).
|
|
||||||
|
|
||||||
|
|
||||||
:- meta_predicate(setof(?, 0, ?)).
|
:- meta_predicate(setof(?, 0, ?)).
|
||||||
|
|
||||||
@@ -1112,10 +1067,10 @@ setof(Template, Goal, Solution) :-
|
|||||||
term_variables(Goal, GoalVars),
|
term_variables(Goal, GoalVars),
|
||||||
term_variables(TemplateVars+GoalVars, TGVs),
|
term_variables(TemplateVars+GoalVars, TGVs),
|
||||||
lists:append(TemplateVars, Witnesses0, TGVs),
|
lists:append(TemplateVars, Witnesses0, TGVs),
|
||||||
findall_with_existential(Template, Goal, PairedSolutions0, Witnesses0, Witnesses),
|
findall_with_existential(Template, Goal, PairedSolutions, Witnesses0, Witnesses),
|
||||||
'$keysort_with_constant_var_ordering'(PairedSolutions0, PairedSolutions), % see 7.2.1
|
unify_variant_variables(PairedSolutions, _Dict),
|
||||||
group_by_variants(PairedSolutions, GroupedSolutions),
|
sort(PairedSolutions, PairedSolutions1),
|
||||||
iterate_variants_and_sort(GroupedSolutions, Witnesses, Solution).
|
split_by_variant(PairedSolutions1, Witnesses, Solution).
|
||||||
|
|
||||||
% Clause retrieval and information.
|
% Clause retrieval and information.
|
||||||
|
|
||||||
|
|||||||
@@ -103,9 +103,8 @@ impl MachineState {
|
|||||||
.collect()
|
.collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
attr_vars.sort_unstable_by(|a1, a2| {
|
attr_vars
|
||||||
compare_term_test!(self, *a1, *a2).unwrap_or(Ordering::Less)
|
.sort_unstable_by(|a1, a2| self.compare_term_test(*a1, *a2).unwrap_or(Ordering::Less));
|
||||||
});
|
|
||||||
|
|
||||||
attr_vars.dedup();
|
attr_vars.dedup();
|
||||||
attr_vars
|
attr_vars
|
||||||
|
|||||||
@@ -6,79 +6,16 @@ use crate::machine::loader::*;
|
|||||||
use crate::machine::machine_errors::CompilationError;
|
use crate::machine::machine_errors::CompilationError;
|
||||||
use crate::machine::preprocessor::*;
|
use crate::machine::preprocessor::*;
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
use crate::parser::dashu::Rational;
|
|
||||||
use crate::variable_records::*;
|
use crate::variable_records::*;
|
||||||
|
|
||||||
use dashu::Integer;
|
use dashu::Integer;
|
||||||
use indexmap::{IndexMap, IndexSet};
|
use indexmap::{IndexMap, IndexSet};
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::cmp::Ordering;
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::Hash;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
#[derive(Debug, Clone)] //, PartialOrd, PartialEq, Eq, Hash)]
|
|
||||||
pub struct BranchNumber {
|
|
||||||
branch_num: Rational,
|
|
||||||
delta: Rational,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for BranchNumber {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
branch_num: Rational::from(1u64 << 63),
|
|
||||||
delta: Rational::from(1),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq<BranchNumber> for BranchNumber {
|
|
||||||
#[inline]
|
|
||||||
fn eq(&self, rhs: &BranchNumber) -> bool {
|
|
||||||
self.branch_num == rhs.branch_num
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for BranchNumber {}
|
|
||||||
|
|
||||||
impl Hash for BranchNumber {
|
|
||||||
#[inline(always)]
|
|
||||||
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
|
||||||
self.branch_num.hash(hasher)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd<BranchNumber> for BranchNumber {
|
|
||||||
#[inline]
|
|
||||||
fn partial_cmp(&self, rhs: &BranchNumber) -> Option<Ordering> {
|
|
||||||
self.branch_num.partial_cmp(&rhs.branch_num)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BranchNumber {
|
|
||||||
fn split(&self) -> BranchNumber {
|
|
||||||
BranchNumber {
|
|
||||||
branch_num: self.branch_num.clone() + &self.delta / Rational::from(2),
|
|
||||||
delta: &self.delta / Rational::from(4),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn incr_by_delta(&self) -> BranchNumber {
|
|
||||||
BranchNumber {
|
|
||||||
branch_num: self.branch_num.clone() + &self.delta,
|
|
||||||
delta: self.delta.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn halve_delta(&self) -> BranchNumber {
|
|
||||||
BranchNumber {
|
|
||||||
branch_num: self.branch_num.clone(),
|
|
||||||
delta: &self.delta / Rational::from(2),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct VarInfo {
|
pub struct VarInfo {
|
||||||
var_ptr: VarPtr,
|
var_ptr: VarPtr,
|
||||||
@@ -140,12 +77,13 @@ pub struct ClassifyInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum TraversalState {
|
enum TraversalState {
|
||||||
// construct a QueryTerm::Branch with number of disjuncts, reset
|
// pop the latest branch number from the root set and use it to construct a QueryTerm::Branch
|
||||||
// the chunk type to that of the chunk preceding the disjunct and the chunk_num.
|
// with number of disjuncts, reset the chunk type to that of the chunk preceding the disjunct
|
||||||
|
// and the chunk_num.
|
||||||
BuildDisjunct(usize),
|
BuildDisjunct(usize),
|
||||||
|
BuildFinalDisjunct(usize),
|
||||||
// add the last disjunct to a QueryTerm::Branch, continuing from
|
// add the last disjunct to a QueryTerm::Branch, continuing from
|
||||||
// where it leaves off.
|
// where it leaves off.
|
||||||
BuildFinalDisjunct(usize),
|
|
||||||
Fail,
|
Fail,
|
||||||
GetCutPoint { var_num: usize, prev_b: bool },
|
GetCutPoint { var_num: usize, prev_b: bool },
|
||||||
Cut { var_num: usize, is_global: bool },
|
Cut { var_num: usize, is_global: bool },
|
||||||
@@ -154,7 +92,6 @@ enum TraversalState {
|
|||||||
Term(Term),
|
Term(Term),
|
||||||
OverrideGlobalCutVar(usize),
|
OverrideGlobalCutVar(usize),
|
||||||
ResetGlobalCutVarOverride(Option<usize>),
|
ResetGlobalCutVarOverride(Option<usize>),
|
||||||
RemoveBranchNum, // pop the current_branch_num and from the root set.
|
|
||||||
AddBranchNum(BranchNumber), // set current_branch_num, add it to the root set
|
AddBranchNum(BranchNumber), // set current_branch_num, add it to the root set
|
||||||
RepBranchNum(BranchNumber), // replace current_branch_num and the latest in the root set
|
RepBranchNum(BranchNumber), // replace current_branch_num and the latest in the root set
|
||||||
}
|
}
|
||||||
@@ -199,7 +136,7 @@ impl VarData {
|
|||||||
VarAlloc::Perm(0, PermVarAllocation::Pending);
|
VarAlloc::Perm(0, PermVarAllocation::Pending);
|
||||||
|
|
||||||
match build_stack.front_mut() {
|
match build_stack.front_mut() {
|
||||||
Some(ChunkedTerms::Branch(_)) => {
|
Some(ChunkedTerms::Branch { .. }) => {
|
||||||
build_stack.push_front(ChunkedTerms::Chunk {
|
build_stack.push_front(ChunkedTerms::Chunk {
|
||||||
terms: VecDeque::from(vec![term]),
|
terms: VecDeque::from(vec![term]),
|
||||||
});
|
});
|
||||||
@@ -232,11 +169,16 @@ fn merge_branch_seq(branches: impl Iterator<Item = BranchInfo>) -> BranchInfo {
|
|||||||
branch_info
|
branch_info
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flatten_into_disjunct(build_stack: &mut ChunkedTermVec, preceding_len: usize) {
|
fn flatten_into_disjunct(
|
||||||
|
build_stack: &mut ChunkedTermVec,
|
||||||
|
branch_num: BranchNumber,
|
||||||
|
preceding_len: usize,
|
||||||
|
) {
|
||||||
let branch_vec = build_stack.drain(preceding_len + 1..).collect();
|
let branch_vec = build_stack.drain(preceding_len + 1..).collect();
|
||||||
|
|
||||||
if let ChunkedTerms::Branch(ref mut disjuncts) = &mut build_stack[preceding_len] {
|
if let ChunkedTerms::Branch { branch_nums, arms } = &mut build_stack[preceding_len] {
|
||||||
disjuncts.push(branch_vec);
|
branch_nums.push(branch_num);
|
||||||
|
arms.push(branch_vec);
|
||||||
} else {
|
} else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
@@ -477,9 +419,6 @@ impl VariableClassifier {
|
|||||||
self.root_set.insert(branch_num.clone());
|
self.root_set.insert(branch_num.clone());
|
||||||
self.current_branch_num = branch_num;
|
self.current_branch_num = branch_num;
|
||||||
}
|
}
|
||||||
TraversalState::RemoveBranchNum => {
|
|
||||||
self.root_set.pop();
|
|
||||||
}
|
|
||||||
TraversalState::RepBranchNum(branch_num) => {
|
TraversalState::RepBranchNum(branch_num) => {
|
||||||
self.root_set.pop();
|
self.root_set.pop();
|
||||||
self.root_set.insert(branch_num.clone());
|
self.root_set.insert(branch_num.clone());
|
||||||
@@ -488,14 +427,10 @@ impl VariableClassifier {
|
|||||||
TraversalState::ResetCallPolicy(call_policy) => {
|
TraversalState::ResetCallPolicy(call_policy) => {
|
||||||
self.call_policy = call_policy;
|
self.call_policy = call_policy;
|
||||||
}
|
}
|
||||||
TraversalState::BuildDisjunct(preceding_len) => {
|
TraversalState::BuildDisjunct(preceding_len)
|
||||||
flatten_into_disjunct(&mut build_stack, preceding_len);
|
| TraversalState::BuildFinalDisjunct(preceding_len) => {
|
||||||
|
let branch_num = self.root_set.pop().unwrap();
|
||||||
self.current_chunk_type = ChunkType::Mid;
|
flatten_into_disjunct(&mut build_stack, branch_num, preceding_len);
|
||||||
self.current_chunk_num += 1;
|
|
||||||
}
|
|
||||||
TraversalState::BuildFinalDisjunct(preceding_len) => {
|
|
||||||
flatten_into_disjunct(&mut build_stack, preceding_len);
|
|
||||||
|
|
||||||
self.current_chunk_type = ChunkType::Mid;
|
self.current_chunk_type = ChunkType::Mid;
|
||||||
self.current_chunk_num += 1;
|
self.current_chunk_num += 1;
|
||||||
@@ -636,7 +571,6 @@ impl VariableClassifier {
|
|||||||
|
|
||||||
for (term, branch_num) in iter.rev() {
|
for (term, branch_num) in iter.rev() {
|
||||||
state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
|
state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
|
||||||
state_stack.push(TraversalState::RemoveBranchNum);
|
|
||||||
state_stack.push(TraversalState::Term(term));
|
state_stack.push(TraversalState::Term(term));
|
||||||
state_stack.push(TraversalState::AddBranchNum(branch_num));
|
state_stack.push(TraversalState::AddBranchNum(branch_num));
|
||||||
}
|
}
|
||||||
@@ -655,20 +589,15 @@ impl VariableClassifier {
|
|||||||
let then_term = terms.pop().unwrap();
|
let then_term = terms.pop().unwrap();
|
||||||
let if_term = terms.pop().unwrap();
|
let if_term = terms.pop().unwrap();
|
||||||
|
|
||||||
let prev_b = if matches!(
|
let prev_b =
|
||||||
state_stack.last(),
|
if let Some(&TraversalState::BuildDisjunct(preceding_len)) =
|
||||||
Some(TraversalState::RemoveBranchNum)
|
state_stack.last()
|
||||||
) {
|
{
|
||||||
// check if the second-to-last element
|
// check if the second-to-last element
|
||||||
// is a regular BuildDisjunct, as we
|
// is a regular BuildDisjunct, as we
|
||||||
// don't want to add GetPrevLevel in
|
// don't want to add GetPrevLevel in
|
||||||
// case of a TrustMe.
|
// case of a TrustMe.
|
||||||
match state_stack.iter().rev().nth(1) {
|
|
||||||
Some(&TraversalState::BuildDisjunct(preceding_len)) => {
|
|
||||||
preceding_len + 1 == build_stack.len()
|
preceding_len + 1 == build_stack.len()
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
@@ -690,14 +619,21 @@ impl VariableClassifier {
|
|||||||
let not_term = terms.pop().unwrap();
|
let not_term = terms.pop().unwrap();
|
||||||
let build_stack_len = build_stack.len();
|
let build_stack_len = build_stack.len();
|
||||||
|
|
||||||
|
let first_branch_num = self.current_branch_num.split();
|
||||||
|
let second_branch_num = first_branch_num.incr_by_delta();
|
||||||
|
|
||||||
build_stack.reserve_branch(2);
|
build_stack.reserve_branch(2);
|
||||||
|
|
||||||
|
state_stack.push(TraversalState::RepBranchNum(
|
||||||
|
self.current_branch_num.halve_delta(),
|
||||||
|
));
|
||||||
state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len));
|
state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len));
|
||||||
state_stack.push(TraversalState::Term(Term::Clause(
|
state_stack.push(TraversalState::Term(Term::Clause(
|
||||||
Cell::default(),
|
Cell::default(),
|
||||||
atom!("$succeed"),
|
atom!("$succeed"),
|
||||||
vec![],
|
vec![],
|
||||||
)));
|
)));
|
||||||
|
state_stack.push(TraversalState::AddBranchNum(second_branch_num));
|
||||||
state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
|
state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
|
||||||
state_stack.push(TraversalState::Fail);
|
state_stack.push(TraversalState::Fail);
|
||||||
state_stack.push(TraversalState::CutPrev(self.var_num));
|
state_stack.push(TraversalState::CutPrev(self.var_num));
|
||||||
@@ -710,6 +646,7 @@ impl VariableClassifier {
|
|||||||
var_num: self.var_num,
|
var_num: self.var_num,
|
||||||
prev_b: false,
|
prev_b: false,
|
||||||
});
|
});
|
||||||
|
state_stack.push(TraversalState::AddBranchNum(first_branch_num));
|
||||||
|
|
||||||
self.current_chunk_type = ChunkType::Mid;
|
self.current_chunk_type = ChunkType::Mid;
|
||||||
self.current_chunk_num += 1;
|
self.current_chunk_num += 1;
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
let atom = match compare_term_test!(self, a2, a3) {
|
let atom = match self.compare_term_test(a2, a3) {
|
||||||
Some(Ordering::Greater) => {
|
Some(Ordering::Greater) => {
|
||||||
atom!(">")
|
atom!(">")
|
||||||
}
|
}
|
||||||
@@ -151,15 +151,12 @@ impl MachineState {
|
|||||||
let stub_gen = || functor_stub(atom!("sort"), 2);
|
let stub_gen = || functor_stub(atom!("sort"), 2);
|
||||||
let mut list = self.try_from_list(self.registers[1], stub_gen)?;
|
let mut list = self.try_from_list(self.registers[1], stub_gen)?;
|
||||||
|
|
||||||
list.sort_unstable_by(|v1, v2| {
|
list.sort_unstable_by(|v1, v2| self.compare_term_test(*v1, *v2).unwrap_or(Ordering::Less));
|
||||||
compare_term_test!(self, *v1, *v2).unwrap_or(Ordering::Less)
|
list.dedup_by(|v1, v2| self.compare_term_test(*v1, *v2) == Some(Ordering::Equal));
|
||||||
});
|
|
||||||
|
|
||||||
list.dedup_by(|v1, v2| compare_term_test!(self, *v1, *v2) == Some(Ordering::Equal));
|
|
||||||
|
|
||||||
let heap_addr = resource_error_call_result!(
|
let heap_addr = resource_error_call_result!(
|
||||||
self,
|
self,
|
||||||
sized_iter_to_heap_list(&mut self.heap, list.len(), list.into_iter(),)
|
sized_iter_to_heap_list(&mut self.heap, list.len(), list.into_iter())
|
||||||
);
|
);
|
||||||
|
|
||||||
let target_addr = self.registers[2];
|
let target_addr = self.registers[2];
|
||||||
@@ -167,7 +164,7 @@ impl MachineState {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn keysort(&mut self, var_comparison: VarComparison) -> CallResult {
|
fn keysort(&mut self) -> CallResult {
|
||||||
self.check_keysort_errors()?;
|
self.check_keysort_errors()?;
|
||||||
|
|
||||||
let stub_gen = || functor_stub(atom!("keysort"), 2);
|
let stub_gen = || functor_stub(atom!("keysort"), 2);
|
||||||
@@ -176,13 +173,11 @@ impl MachineState {
|
|||||||
let mut key_pairs = Vec::with_capacity(list.len());
|
let mut key_pairs = Vec::with_capacity(list.len());
|
||||||
|
|
||||||
for val in list {
|
for val in list {
|
||||||
let key = self.project_onto_key(val)?;
|
let (key, _) = self.key_val_pair(val)?;
|
||||||
key_pairs.push((key, val));
|
key_pairs.push((key, val));
|
||||||
}
|
}
|
||||||
|
|
||||||
key_pairs.sort_by(|a1, a2| {
|
key_pairs.sort_by(|a1, a2| self.compare_term_test(a1.0, a2.0).unwrap_or(Ordering::Less));
|
||||||
compare_term_test!(self, a1.0, a2.0, var_comparison).unwrap_or(Ordering::Less)
|
|
||||||
});
|
|
||||||
|
|
||||||
let heap_addr = resource_error_call_result!(
|
let heap_addr = resource_error_call_result!(
|
||||||
self,
|
self,
|
||||||
@@ -2034,8 +2029,7 @@ impl Machine {
|
|||||||
let a1 = self.machine_st.registers[1];
|
let a1 = self.machine_st.registers[1];
|
||||||
let a2 = self.machine_st.registers[2];
|
let a2 = self.machine_st.registers[2];
|
||||||
|
|
||||||
if let Some(Ordering::Greater) = compare_term_test!(self.machine_st, a1, a2)
|
if let Some(Ordering::Greater) = self.machine_st.compare_term_test(a1, a2) {
|
||||||
{
|
|
||||||
self.machine_st.p += 1;
|
self.machine_st.p += 1;
|
||||||
} else {
|
} else {
|
||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
@@ -2045,8 +2039,7 @@ impl Machine {
|
|||||||
let a1 = self.machine_st.registers[1];
|
let a1 = self.machine_st.registers[1];
|
||||||
let a2 = self.machine_st.registers[2];
|
let a2 = self.machine_st.registers[2];
|
||||||
|
|
||||||
if let Some(Ordering::Greater) = compare_term_test!(self.machine_st, a1, a2)
|
if let Some(Ordering::Greater) = self.machine_st.compare_term_test(a1, a2) {
|
||||||
{
|
|
||||||
self.machine_st.p = self.machine_st.cp;
|
self.machine_st.p = self.machine_st.cp;
|
||||||
} else {
|
} else {
|
||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
@@ -2056,7 +2049,7 @@ impl Machine {
|
|||||||
let a1 = self.machine_st.registers[1];
|
let a1 = self.machine_st.registers[1];
|
||||||
let a2 = self.machine_st.registers[2];
|
let a2 = self.machine_st.registers[2];
|
||||||
|
|
||||||
if let Some(Ordering::Less) = compare_term_test!(self.machine_st, a1, a2) {
|
if let Some(Ordering::Less) = self.machine_st.compare_term_test(a1, a2) {
|
||||||
self.machine_st.p += 1;
|
self.machine_st.p += 1;
|
||||||
} else {
|
} else {
|
||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
@@ -2066,7 +2059,7 @@ impl Machine {
|
|||||||
let a1 = self.machine_st.registers[1];
|
let a1 = self.machine_st.registers[1];
|
||||||
let a2 = self.machine_st.registers[2];
|
let a2 = self.machine_st.registers[2];
|
||||||
|
|
||||||
if let Some(Ordering::Less) = compare_term_test!(self.machine_st, a1, a2) {
|
if let Some(Ordering::Less) = self.machine_st.compare_term_test(a1, a2) {
|
||||||
self.machine_st.p = self.machine_st.cp;
|
self.machine_st.p = self.machine_st.cp;
|
||||||
} else {
|
} else {
|
||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
@@ -2076,7 +2069,7 @@ impl Machine {
|
|||||||
let a1 = self.machine_st.registers[1];
|
let a1 = self.machine_st.registers[1];
|
||||||
let a2 = self.machine_st.registers[2];
|
let a2 = self.machine_st.registers[2];
|
||||||
|
|
||||||
match compare_term_test!(self.machine_st, a1, a2) {
|
match self.machine_st.compare_term_test(a1, a2) {
|
||||||
Some(Ordering::Greater | Ordering::Equal) => {
|
Some(Ordering::Greater | Ordering::Equal) => {
|
||||||
self.machine_st.p += 1;
|
self.machine_st.p += 1;
|
||||||
}
|
}
|
||||||
@@ -2089,7 +2082,7 @@ impl Machine {
|
|||||||
let a1 = self.machine_st.registers[1];
|
let a1 = self.machine_st.registers[1];
|
||||||
let a2 = self.machine_st.registers[2];
|
let a2 = self.machine_st.registers[2];
|
||||||
|
|
||||||
match compare_term_test!(self.machine_st, a1, a2) {
|
match self.machine_st.compare_term_test(a1, a2) {
|
||||||
Some(Ordering::Greater | Ordering::Equal) => {
|
Some(Ordering::Greater | Ordering::Equal) => {
|
||||||
self.machine_st.p = self.machine_st.cp;
|
self.machine_st.p = self.machine_st.cp;
|
||||||
}
|
}
|
||||||
@@ -2102,7 +2095,7 @@ impl Machine {
|
|||||||
let a1 = self.machine_st.registers[1];
|
let a1 = self.machine_st.registers[1];
|
||||||
let a2 = self.machine_st.registers[2];
|
let a2 = self.machine_st.registers[2];
|
||||||
|
|
||||||
match compare_term_test!(self.machine_st, a1, a2) {
|
match self.machine_st.compare_term_test(a1, a2) {
|
||||||
Some(Ordering::Less | Ordering::Equal) => {
|
Some(Ordering::Less | Ordering::Equal) => {
|
||||||
self.machine_st.p += 1;
|
self.machine_st.p += 1;
|
||||||
}
|
}
|
||||||
@@ -2115,7 +2108,7 @@ impl Machine {
|
|||||||
let a1 = self.machine_st.registers[1];
|
let a1 = self.machine_st.registers[1];
|
||||||
let a2 = self.machine_st.registers[2];
|
let a2 = self.machine_st.registers[2];
|
||||||
|
|
||||||
match compare_term_test!(self.machine_st, a1, a2) {
|
match self.machine_st.compare_term_test(a1, a2) {
|
||||||
Some(Ordering::Less | Ordering::Equal) => {
|
Some(Ordering::Less | Ordering::Equal) => {
|
||||||
self.machine_st.p = self.machine_st.cp;
|
self.machine_st.p = self.machine_st.cp;
|
||||||
}
|
}
|
||||||
@@ -2188,7 +2181,7 @@ impl Machine {
|
|||||||
let a1 = self.machine_st.registers[1];
|
let a1 = self.machine_st.registers[1];
|
||||||
let a2 = self.machine_st.registers[2];
|
let a2 = self.machine_st.registers[2];
|
||||||
|
|
||||||
if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) {
|
if let Some(Ordering::Equal) = self.machine_st.compare_term_test(a1, a2) {
|
||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
} else {
|
} else {
|
||||||
self.machine_st.p += 1;
|
self.machine_st.p += 1;
|
||||||
@@ -2198,7 +2191,7 @@ impl Machine {
|
|||||||
let a1 = self.machine_st.registers[1];
|
let a1 = self.machine_st.registers[1];
|
||||||
let a2 = self.machine_st.registers[2];
|
let a2 = self.machine_st.registers[2];
|
||||||
|
|
||||||
if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) {
|
if let Some(Ordering::Equal) = self.machine_st.compare_term_test(a1, a2) {
|
||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
} else {
|
} else {
|
||||||
self.machine_st.p = self.machine_st.cp;
|
self.machine_st.p = self.machine_st.cp;
|
||||||
@@ -2213,19 +2206,11 @@ impl Machine {
|
|||||||
step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
|
step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
|
||||||
}
|
}
|
||||||
&Instruction::DefaultCallKeySort => {
|
&Instruction::DefaultCallKeySort => {
|
||||||
try_or_throw!(
|
try_or_throw!(self.machine_st, self.machine_st.keysort(), continue);
|
||||||
self.machine_st,
|
|
||||||
self.machine_st.keysort(VarComparison::Distinct),
|
|
||||||
continue
|
|
||||||
);
|
|
||||||
step_or_fail!(self.machine_st, self.machine_st.p += 1);
|
step_or_fail!(self.machine_st, self.machine_st.p += 1);
|
||||||
}
|
}
|
||||||
&Instruction::DefaultExecuteKeySort => {
|
&Instruction::DefaultExecuteKeySort => {
|
||||||
try_or_throw!(
|
try_or_throw!(self.machine_st, self.machine_st.keysort(), continue);
|
||||||
self.machine_st,
|
|
||||||
self.machine_st.keysort(VarComparison::Distinct),
|
|
||||||
continue
|
|
||||||
);
|
|
||||||
|
|
||||||
if self.machine_st.fail {
|
if self.machine_st.fail {
|
||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
@@ -2323,8 +2308,7 @@ impl Machine {
|
|||||||
let a1 = self.machine_st.registers[1];
|
let a1 = self.machine_st.registers[1];
|
||||||
let a2 = self.machine_st.registers[2];
|
let a2 = self.machine_st.registers[2];
|
||||||
|
|
||||||
if let Some(Ordering::Greater) = compare_term_test!(self.machine_st, a1, a2)
|
if let Some(Ordering::Greater) = self.machine_st.compare_term_test(a1, a2) {
|
||||||
{
|
|
||||||
increment_call_count!(self.machine_st);
|
increment_call_count!(self.machine_st);
|
||||||
self.machine_st.p += 1;
|
self.machine_st.p += 1;
|
||||||
} else {
|
} else {
|
||||||
@@ -2335,8 +2319,7 @@ impl Machine {
|
|||||||
let a1 = self.machine_st.registers[1];
|
let a1 = self.machine_st.registers[1];
|
||||||
let a2 = self.machine_st.registers[2];
|
let a2 = self.machine_st.registers[2];
|
||||||
|
|
||||||
if let Some(Ordering::Greater) = compare_term_test!(self.machine_st, a1, a2)
|
if let Some(Ordering::Greater) = self.machine_st.compare_term_test(a1, a2) {
|
||||||
{
|
|
||||||
increment_call_count!(self.machine_st);
|
increment_call_count!(self.machine_st);
|
||||||
self.machine_st.p = self.machine_st.cp;
|
self.machine_st.p = self.machine_st.cp;
|
||||||
} else {
|
} else {
|
||||||
@@ -2347,7 +2330,7 @@ impl Machine {
|
|||||||
let a1 = self.machine_st.registers[1];
|
let a1 = self.machine_st.registers[1];
|
||||||
let a2 = self.machine_st.registers[2];
|
let a2 = self.machine_st.registers[2];
|
||||||
|
|
||||||
if let Some(Ordering::Less) = compare_term_test!(self.machine_st, a1, a2) {
|
if let Some(Ordering::Less) = self.machine_st.compare_term_test(a1, a2) {
|
||||||
increment_call_count!(self.machine_st);
|
increment_call_count!(self.machine_st);
|
||||||
self.machine_st.p += 1;
|
self.machine_st.p += 1;
|
||||||
} else {
|
} else {
|
||||||
@@ -2358,7 +2341,7 @@ impl Machine {
|
|||||||
let a1 = self.machine_st.registers[1];
|
let a1 = self.machine_st.registers[1];
|
||||||
let a2 = self.machine_st.registers[2];
|
let a2 = self.machine_st.registers[2];
|
||||||
|
|
||||||
if let Some(Ordering::Less) = compare_term_test!(self.machine_st, a1, a2) {
|
if let Some(Ordering::Less) = self.machine_st.compare_term_test(a1, a2) {
|
||||||
increment_call_count!(self.machine_st);
|
increment_call_count!(self.machine_st);
|
||||||
self.machine_st.p = self.machine_st.cp;
|
self.machine_st.p = self.machine_st.cp;
|
||||||
} else {
|
} else {
|
||||||
@@ -2369,7 +2352,7 @@ impl Machine {
|
|||||||
let a1 = self.machine_st.registers[1];
|
let a1 = self.machine_st.registers[1];
|
||||||
let a2 = self.machine_st.registers[2];
|
let a2 = self.machine_st.registers[2];
|
||||||
|
|
||||||
match compare_term_test!(self.machine_st, a1, a2) {
|
match self.machine_st.compare_term_test(a1, a2) {
|
||||||
Some(Ordering::Greater | Ordering::Equal) => {
|
Some(Ordering::Greater | Ordering::Equal) => {
|
||||||
increment_call_count!(self.machine_st);
|
increment_call_count!(self.machine_st);
|
||||||
self.machine_st.p += 1;
|
self.machine_st.p += 1;
|
||||||
@@ -2383,7 +2366,7 @@ impl Machine {
|
|||||||
let a1 = self.machine_st.registers[1];
|
let a1 = self.machine_st.registers[1];
|
||||||
let a2 = self.machine_st.registers[2];
|
let a2 = self.machine_st.registers[2];
|
||||||
|
|
||||||
match compare_term_test!(self.machine_st, a1, a2) {
|
match self.machine_st.compare_term_test(a1, a2) {
|
||||||
Some(Ordering::Greater | Ordering::Equal) => {
|
Some(Ordering::Greater | Ordering::Equal) => {
|
||||||
increment_call_count!(self.machine_st);
|
increment_call_count!(self.machine_st);
|
||||||
self.machine_st.p = self.machine_st.cp;
|
self.machine_st.p = self.machine_st.cp;
|
||||||
@@ -2397,7 +2380,7 @@ impl Machine {
|
|||||||
let a1 = self.machine_st.registers[1];
|
let a1 = self.machine_st.registers[1];
|
||||||
let a2 = self.machine_st.registers[2];
|
let a2 = self.machine_st.registers[2];
|
||||||
|
|
||||||
match compare_term_test!(self.machine_st, a1, a2) {
|
match self.machine_st.compare_term_test(a1, a2) {
|
||||||
Some(Ordering::Less | Ordering::Equal) => {
|
Some(Ordering::Less | Ordering::Equal) => {
|
||||||
increment_call_count!(self.machine_st);
|
increment_call_count!(self.machine_st);
|
||||||
self.machine_st.p += 1;
|
self.machine_st.p += 1;
|
||||||
@@ -2411,7 +2394,7 @@ impl Machine {
|
|||||||
let a1 = self.machine_st.registers[1];
|
let a1 = self.machine_st.registers[1];
|
||||||
let a2 = self.machine_st.registers[2];
|
let a2 = self.machine_st.registers[2];
|
||||||
|
|
||||||
match compare_term_test!(self.machine_st, a1, a2) {
|
match self.machine_st.compare_term_test(a1, a2) {
|
||||||
Some(Ordering::Less | Ordering::Equal) => {
|
Some(Ordering::Less | Ordering::Equal) => {
|
||||||
increment_call_count!(self.machine_st);
|
increment_call_count!(self.machine_st);
|
||||||
self.machine_st.p = self.machine_st.cp;
|
self.machine_st.p = self.machine_st.cp;
|
||||||
@@ -2503,7 +2486,7 @@ impl Machine {
|
|||||||
let a1 = self.machine_st.registers[1];
|
let a1 = self.machine_st.registers[1];
|
||||||
let a2 = self.machine_st.registers[2];
|
let a2 = self.machine_st.registers[2];
|
||||||
|
|
||||||
if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) {
|
if let Some(Ordering::Equal) = self.machine_st.compare_term_test(a1, a2) {
|
||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
} else {
|
} else {
|
||||||
increment_call_count!(self.machine_st);
|
increment_call_count!(self.machine_st);
|
||||||
@@ -2514,7 +2497,7 @@ impl Machine {
|
|||||||
let a1 = self.machine_st.registers[1];
|
let a1 = self.machine_st.registers[1];
|
||||||
let a2 = self.machine_st.registers[2];
|
let a2 = self.machine_st.registers[2];
|
||||||
|
|
||||||
if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) {
|
if let Some(Ordering::Equal) = self.machine_st.compare_term_test(a1, a2) {
|
||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
} else {
|
} else {
|
||||||
increment_call_count!(self.machine_st);
|
increment_call_count!(self.machine_st);
|
||||||
@@ -2542,11 +2525,7 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
&Instruction::CallKeySort => {
|
&Instruction::CallKeySort => {
|
||||||
try_or_throw!(
|
try_or_throw!(self.machine_st, self.machine_st.keysort(), continue);
|
||||||
self.machine_st,
|
|
||||||
self.machine_st.keysort(VarComparison::Distinct),
|
|
||||||
continue
|
|
||||||
);
|
|
||||||
|
|
||||||
if self.machine_st.fail {
|
if self.machine_st.fail {
|
||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
@@ -2556,39 +2535,7 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
&Instruction::ExecuteKeySort => {
|
&Instruction::ExecuteKeySort => {
|
||||||
try_or_throw!(
|
try_or_throw!(self.machine_st, self.machine_st.keysort(), continue);
|
||||||
self.machine_st,
|
|
||||||
self.machine_st.keysort(VarComparison::Distinct),
|
|
||||||
continue
|
|
||||||
);
|
|
||||||
|
|
||||||
if self.machine_st.fail {
|
|
||||||
self.machine_st.backtrack();
|
|
||||||
} else {
|
|
||||||
increment_call_count!(self.machine_st);
|
|
||||||
self.machine_st.p = self.machine_st.cp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&Instruction::CallKeySortWithConstantVarOrdering => {
|
|
||||||
try_or_throw!(
|
|
||||||
self.machine_st,
|
|
||||||
self.machine_st.keysort(VarComparison::Indistinct),
|
|
||||||
continue
|
|
||||||
);
|
|
||||||
|
|
||||||
if self.machine_st.fail {
|
|
||||||
self.machine_st.backtrack();
|
|
||||||
} else {
|
|
||||||
increment_call_count!(self.machine_st);
|
|
||||||
self.machine_st.p += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&Instruction::ExecuteKeySortWithConstantVarOrdering => {
|
|
||||||
try_or_throw!(
|
|
||||||
self.machine_st,
|
|
||||||
self.machine_st.keysort(VarComparison::Indistinct),
|
|
||||||
continue
|
|
||||||
);
|
|
||||||
|
|
||||||
if self.machine_st.fail {
|
if self.machine_st.fail {
|
||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use crate::machine::copier::*;
|
|||||||
use crate::machine::heap::AllocError;
|
use crate::machine::heap::AllocError;
|
||||||
use crate::machine::heap::*;
|
use crate::machine::heap::*;
|
||||||
use crate::machine::machine_errors::*;
|
use crate::machine::machine_errors::*;
|
||||||
use crate::machine::machine_indices::*;
|
|
||||||
use crate::machine::machine_state::*;
|
use crate::machine::machine_state::*;
|
||||||
use crate::machine::partial_string::*;
|
use crate::machine::partial_string::*;
|
||||||
use crate::machine::stack::*;
|
use crate::machine::stack::*;
|
||||||
@@ -17,8 +16,6 @@ use crate::parser::ast::*;
|
|||||||
use crate::parser::dashu::{Integer, Rational};
|
use crate::parser::dashu::{Integer, Rational};
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
|
||||||
use indexmap::IndexSet;
|
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
@@ -380,347 +377,6 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compare_term_test(&mut self, var_comparison: VarComparison) -> Option<Ordering> {
|
|
||||||
let mut tabu_list = IndexSet::new();
|
|
||||||
|
|
||||||
while let Some(s1) = self.pdl.pop() {
|
|
||||||
let s1 = self.deref(s1);
|
|
||||||
|
|
||||||
let s2 = self.pdl.pop().unwrap();
|
|
||||||
let s2 = self.deref(s2);
|
|
||||||
|
|
||||||
if s1 == s2 {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let v1 = self.store(s1);
|
|
||||||
let v2 = self.store(s2);
|
|
||||||
|
|
||||||
let order_cat_v1 = v1.order_category(&self.heap);
|
|
||||||
let order_cat_v2 = v2.order_category(&self.heap);
|
|
||||||
|
|
||||||
if order_cat_v1 != order_cat_v2 {
|
|
||||||
self.pdl.clear();
|
|
||||||
return Some(order_cat_v1.cmp(&order_cat_v2));
|
|
||||||
}
|
|
||||||
|
|
||||||
match order_cat_v1 {
|
|
||||||
Some(TermOrderCategory::Variable) => {
|
|
||||||
if let VarComparison::Distinct = var_comparison {
|
|
||||||
let v1 = v1.as_var().unwrap();
|
|
||||||
let v2 = v2.as_var().unwrap();
|
|
||||||
|
|
||||||
if v1 != v2 {
|
|
||||||
self.pdl.clear();
|
|
||||||
return Some(v1.cmp(&v2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(TermOrderCategory::FloatingPoint) => {
|
|
||||||
let v1 = cell_as_f64_offset!(v1);
|
|
||||||
let v2 = cell_as_f64_offset!(v2);
|
|
||||||
|
|
||||||
let v1 = self.arena.f64_tbl.get_entry(v1);
|
|
||||||
let v2 = self.arena.f64_tbl.get_entry(v2);
|
|
||||||
|
|
||||||
if v1 != v2 {
|
|
||||||
self.pdl.clear();
|
|
||||||
return Some(v1.cmp(&v2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(TermOrderCategory::Integer) => {
|
|
||||||
let v1 = Number::try_from((v1, &self.arena.f64_tbl)).unwrap();
|
|
||||||
let v2 = Number::try_from((v2, &self.arena.f64_tbl)).unwrap();
|
|
||||||
|
|
||||||
if v1 != v2 {
|
|
||||||
self.pdl.clear();
|
|
||||||
return Some(v1.cmp(&v2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(TermOrderCategory::Atom) => {
|
|
||||||
read_heap_cell!(v1,
|
|
||||||
(HeapCellValueTag::Atom, (n1, _a1)) => {
|
|
||||||
read_heap_cell!(v2,
|
|
||||||
(HeapCellValueTag::Atom, (n2, _a2)) => {
|
|
||||||
if n1 != n2 {
|
|
||||||
self.pdl.clear();
|
|
||||||
return Some(n1.cmp(&n2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Str, s) => {
|
|
||||||
let n2 = cell_as_atom_cell!(self.heap[s])
|
|
||||||
.get_name();
|
|
||||||
|
|
||||||
if n1 != n2 {
|
|
||||||
self.pdl.clear();
|
|
||||||
return Some(n1.cmp(&n2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Str, s) => {
|
|
||||||
let n1 = cell_as_atom_cell!(self.heap[s])
|
|
||||||
.get_name();
|
|
||||||
|
|
||||||
read_heap_cell!(v2,
|
|
||||||
(HeapCellValueTag::Atom, (n2, _a2)) => {
|
|
||||||
if n1 != n2 {
|
|
||||||
self.pdl.clear();
|
|
||||||
return Some(n1.cmp(&n2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Str, s) => {
|
|
||||||
let n2 = cell_as_atom_cell!(self.heap[s])
|
|
||||||
.get_name();
|
|
||||||
|
|
||||||
if n1 != n2 {
|
|
||||||
self.pdl.clear();
|
|
||||||
return Some(n1.cmp(&n2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Some(TermOrderCategory::Compound) => {
|
|
||||||
read_heap_cell!(v1,
|
|
||||||
(HeapCellValueTag::Lis, l1) => {
|
|
||||||
read_heap_cell!(v2,
|
|
||||||
(HeapCellValueTag::PStrLoc, l2) => {
|
|
||||||
if tabu_list.contains(&(l1, l2)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
tabu_list.insert((l1, l2));
|
|
||||||
|
|
||||||
// like the action of
|
|
||||||
// partial_string_to_pdl here but
|
|
||||||
// the ordering of PDL pushes is
|
|
||||||
// (crucially for comparison
|
|
||||||
// correctness) different.
|
|
||||||
let (c, succ_cell) = self.heap.last_str_char_and_tail(l2);
|
|
||||||
|
|
||||||
self.pdl.push(succ_cell);
|
|
||||||
self.pdl.push(heap_loc_as_cell!(l1 + 1));
|
|
||||||
|
|
||||||
self.pdl.push(char_as_cell!(c));
|
|
||||||
self.pdl.push(heap_loc_as_cell!(l1));
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Lis, l2) => {
|
|
||||||
if tabu_list.contains(&(l1, l2)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
tabu_list.insert((l1, l2));
|
|
||||||
|
|
||||||
self.pdl.push(self.heap[l2 + 1]);
|
|
||||||
self.pdl.push(self.heap[l1 + 1]);
|
|
||||||
|
|
||||||
self.pdl.push(self.heap[l2]);
|
|
||||||
self.pdl.push(self.heap[l1]);
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Str, s2) => {
|
|
||||||
if tabu_list.contains(&(l1, s2)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (name, arity) = cell_as_atom_cell!(self.heap[s2])
|
|
||||||
.get_name_and_arity();
|
|
||||||
|
|
||||||
match (2, atom!(".")).cmp(&(arity, name)) {
|
|
||||||
Ordering::Equal => {
|
|
||||||
tabu_list.insert((l1, s2));
|
|
||||||
|
|
||||||
self.pdl.push(self.heap[s2 + 2]);
|
|
||||||
self.pdl.push(self.heap[l1 + 1]);
|
|
||||||
|
|
||||||
self.pdl.push(self.heap[s2 + 1]);
|
|
||||||
self.pdl.push(self.heap[l1]);
|
|
||||||
}
|
|
||||||
ordering => {
|
|
||||||
self.pdl.clear();
|
|
||||||
return Some(ordering);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::PStrLoc, l1) => {
|
|
||||||
read_heap_cell!(v2,
|
|
||||||
(HeapCellValueTag::PStrLoc, l2) => {
|
|
||||||
if tabu_list.contains(&(l1, l2)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
tabu_list.insert((l1, l2));
|
|
||||||
|
|
||||||
match self.heap.compare_pstr_segments(l1, l2) {
|
|
||||||
PStrSegmentCmpResult::Continue(v1, v2) => {
|
|
||||||
self.pdl.push(v1.offset_by(l1));
|
|
||||||
self.pdl.push(v2.offset_by(l2));
|
|
||||||
}
|
|
||||||
PStrSegmentCmpResult::Less => {
|
|
||||||
self.pdl.clear();
|
|
||||||
return Some(Ordering::Less);
|
|
||||||
}
|
|
||||||
PStrSegmentCmpResult::Greater => {
|
|
||||||
self.pdl.clear();
|
|
||||||
return Some(Ordering::Greater);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Lis, l2) => {
|
|
||||||
if tabu_list.contains(&(l1, l2)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
tabu_list.insert((l1, l2));
|
|
||||||
|
|
||||||
let (c, succ_cell) = self.heap.last_str_char_and_tail(l1);
|
|
||||||
|
|
||||||
self.pdl.push(succ_cell);
|
|
||||||
self.pdl.push(heap_loc_as_cell!(l2 + 1));
|
|
||||||
|
|
||||||
self.pdl.push(char_as_cell!(c));
|
|
||||||
self.pdl.push(heap_loc_as_cell!(l2));
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Str, s2) => {
|
|
||||||
if tabu_list.contains(&(l1, s2)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
tabu_list.insert((l1, s2));
|
|
||||||
|
|
||||||
let (n2, a2) = cell_as_atom_cell!(self.heap[s2])
|
|
||||||
.get_name_and_arity();
|
|
||||||
|
|
||||||
match (2, atom!(".")).cmp(&(a2,n2)) {
|
|
||||||
Ordering::Equal => {
|
|
||||||
let (c, succ_cell) = self.heap.last_str_char_and_tail(l1);
|
|
||||||
|
|
||||||
self.pdl.push(heap_loc_as_cell!(s2+2));
|
|
||||||
self.pdl.push(succ_cell);
|
|
||||||
|
|
||||||
self.pdl.push(heap_loc_as_cell!(s2+1));
|
|
||||||
self.pdl.push(char_as_cell!(c));
|
|
||||||
}
|
|
||||||
ordering => {
|
|
||||||
self.pdl.clear();
|
|
||||||
return Some(ordering);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Str, s1) => {
|
|
||||||
read_heap_cell!(v2,
|
|
||||||
(HeapCellValueTag::Str, s2) => {
|
|
||||||
if tabu_list.contains(&(s1, s2)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (n1, a1) = cell_as_atom_cell!(self.heap[s1])
|
|
||||||
.get_name_and_arity();
|
|
||||||
|
|
||||||
let (n2, a2) = cell_as_atom_cell!(self.heap[s2])
|
|
||||||
.get_name_and_arity();
|
|
||||||
|
|
||||||
match (a1,n1).cmp(&(a2, n2)) {
|
|
||||||
Ordering::Equal => {
|
|
||||||
tabu_list.insert((s1, s2));
|
|
||||||
|
|
||||||
for idx in (1 .. a1+1).rev() {
|
|
||||||
self.pdl.push(self.heap[s2+idx]);
|
|
||||||
self.pdl.push(self.heap[s1+idx]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ordering => {
|
|
||||||
self.pdl.clear();
|
|
||||||
return Some(ordering);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Lis, l2) => {
|
|
||||||
if tabu_list.contains(&(s1, l2)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
tabu_list.insert((s1, l2));
|
|
||||||
|
|
||||||
let (n1, a1) = cell_as_atom_cell!(self.heap[s1])
|
|
||||||
.get_name_and_arity();
|
|
||||||
|
|
||||||
match (a1,n1).cmp(&(2, atom!("."))) {
|
|
||||||
Ordering::Equal => {
|
|
||||||
self.pdl.push(self.heap[l2]);
|
|
||||||
self.pdl.push(self.heap[s1+1]);
|
|
||||||
|
|
||||||
self.pdl.push(self.heap[l2+1]);
|
|
||||||
self.pdl.push(self.heap[s1+2]);
|
|
||||||
}
|
|
||||||
ordering => {
|
|
||||||
self.pdl.clear();
|
|
||||||
return Some(ordering);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::PStrLoc, l2) => {
|
|
||||||
let (n1, a1) = cell_as_atom_cell!(self.heap[s1])
|
|
||||||
.get_name_and_arity();
|
|
||||||
|
|
||||||
match (a1,n1).cmp(&(2, atom!("."))) {
|
|
||||||
Ordering::Equal => {
|
|
||||||
let (c, succ_cell) = self.heap.last_str_char_and_tail(l2);
|
|
||||||
|
|
||||||
self.pdl.push(succ_cell);
|
|
||||||
self.pdl.push(heap_loc_as_cell!(s1+2));
|
|
||||||
|
|
||||||
self.pdl.push(char_as_cell!(c));
|
|
||||||
self.pdl.push(heap_loc_as_cell!(s1+1));
|
|
||||||
}
|
|
||||||
ordering => {
|
|
||||||
self.pdl.clear();
|
|
||||||
return Some(ordering);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
if v1 != v2 {
|
|
||||||
self.pdl.clear();
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(Ordering::Equal)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn setup_call_n_init_goal_info(
|
pub(crate) fn setup_call_n_init_goal_info(
|
||||||
&mut self,
|
&mut self,
|
||||||
goal: HeapCellValue,
|
goal: HeapCellValue,
|
||||||
@@ -891,16 +547,32 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// returns true on failure, false on success.
|
// returns true on failure, false on success.
|
||||||
pub fn eq_test(&mut self, h1: HeapCellValue, h2: HeapCellValue) -> bool {
|
pub fn eq_test(&self, h1: HeapCellValue, h2: HeapCellValue) -> bool {
|
||||||
if h1 == h2 {
|
if h1 == h2 {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
compare_term_test!(self, h1, h2)
|
self.compare_term_test(h1, h2)
|
||||||
.map(|o| o != Ordering::Equal)
|
.map(|o| !o.is_eq())
|
||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn compare_term_test(&self, h1: HeapCellValue, h2: HeapCellValue) -> Option<Ordering> {
|
||||||
|
for term_pair in ParallelHeapIter::from(self, h1, h2) {
|
||||||
|
match term_pair {
|
||||||
|
TermPair::Vars(v1_offset, v2_offset) if v1_offset != v2_offset => {
|
||||||
|
return Some(v1_offset.cmp(&v2_offset));
|
||||||
|
}
|
||||||
|
TermPair::Less(..) => return Some(Ordering::Less),
|
||||||
|
TermPair::Greater(..) => return Some(Ordering::Greater),
|
||||||
|
TermPair::Unordered(cell_1, cell_2) if cell_1 != cell_2 => return None,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Ordering::Equal)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn try_functor_compound_case(&mut self, name: Atom, arity: usize) {
|
fn try_functor_compound_case(&mut self, name: Atom, arity: usize) {
|
||||||
self.try_functor_unify_components(atom_as_cell!(name), arity);
|
self.try_functor_unify_components(atom_as_cell!(name), arity);
|
||||||
@@ -1262,7 +934,10 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// see 8.4.4.3 of Draft Technical Corrigendum 2 for an error guide.
|
// see 8.4.4.3 of Draft Technical Corrigendum 2 for an error guide.
|
||||||
pub fn project_onto_key(&mut self, value: HeapCellValue) -> Result<HeapCellValue, MachineStub> {
|
pub fn key_val_pair(
|
||||||
|
&mut self,
|
||||||
|
value: HeapCellValue,
|
||||||
|
) -> Result<(HeapCellValue, HeapCellValue), MachineStub> {
|
||||||
let stub_gen = || functor_stub(atom!("keysort"), 2);
|
let stub_gen = || functor_stub(atom!("keysort"), 2);
|
||||||
let store_v = self.store(self.deref(value));
|
let store_v = self.store(self.deref(value));
|
||||||
|
|
||||||
@@ -1276,7 +951,7 @@ impl MachineState {
|
|||||||
let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity();
|
let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity();
|
||||||
|
|
||||||
if name == atom!("-") && arity == 2 {
|
if name == atom!("-") && arity == 2 {
|
||||||
Ok(heap_loc_as_cell!(s + 1))
|
Ok((heap_loc_as_cell!(s+1), heap_loc_as_cell!(s+2)))
|
||||||
} else {
|
} else {
|
||||||
let err = self.type_error(ValidType::Pair, self.heap[s]);
|
let err = self.type_error(ValidType::Pair, self.heap[s]);
|
||||||
Err(self.error_form(err, stub_gen()))
|
Err(self.error_form(err, stub_gen()))
|
||||||
|
|||||||
@@ -581,56 +581,44 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(wam, wam.heap[0], wam.heap[1]),
|
wam.compare_term_test(wam.heap[0], wam.heap[1]),
|
||||||
Some(Ordering::Less)
|
Some(Ordering::Less)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(wam, wam.heap[1], wam.heap[0]),
|
wam.compare_term_test(wam.heap[1], wam.heap[0]),
|
||||||
Some(Ordering::Greater)
|
Some(Ordering::Greater)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(wam, wam.heap[0], wam.heap[0]),
|
wam.compare_term_test(wam.heap[0], wam.heap[0]),
|
||||||
Some(Ordering::Equal)
|
Some(Ordering::Equal)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(wam, wam.heap[1], wam.heap[1]),
|
wam.compare_term_test(wam.heap[1], wam.heap[1]),
|
||||||
Some(Ordering::Equal)
|
Some(Ordering::Equal)
|
||||||
);
|
);
|
||||||
|
|
||||||
let cstr_cell = wam.heap.allocate_cstr("string").unwrap();
|
let cstr_cell = wam.heap.allocate_cstr("string").unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(wam, atom_as_cell!(atom!("atom")), cstr_cell),
|
wam.compare_term_test(atom_as_cell!(atom!("atom")), cstr_cell),
|
||||||
Some(Ordering::Less)
|
Some(Ordering::Less)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(
|
wam.compare_term_test(atom_as_cell!(atom!("atom")), atom_as_cell!(atom!("atom"))),
|
||||||
wam,
|
|
||||||
atom_as_cell!(atom!("atom")),
|
|
||||||
atom_as_cell!(atom!("atom"))
|
|
||||||
),
|
|
||||||
Some(Ordering::Equal)
|
Some(Ordering::Equal)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(
|
wam.compare_term_test(atom_as_cell!(atom!("atom")), atom_as_cell!(atom!("aaa"))),
|
||||||
wam,
|
|
||||||
atom_as_cell!(atom!("atom")),
|
|
||||||
atom_as_cell!(atom!("aaa"))
|
|
||||||
),
|
|
||||||
Some(Ordering::Greater)
|
Some(Ordering::Greater)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(
|
wam.compare_term_test(fixnum_as_cell!(Fixnum::build_with(6)), heap_loc_as_cell!(1)),
|
||||||
wam,
|
|
||||||
fixnum_as_cell!(Fixnum::build_with(6)),
|
|
||||||
heap_loc_as_cell!(1)
|
|
||||||
),
|
|
||||||
Some(Ordering::Greater)
|
Some(Ordering::Greater)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -644,12 +632,12 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(0)),
|
wam.compare_term_test(str_loc_as_cell!(0), str_loc_as_cell!(0)),
|
||||||
Some(Ordering::Equal)
|
Some(Ordering::Equal)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(wam, heap_loc_as_cell!(0), atom_as_cell!(atom!("a"))),
|
wam.compare_term_test(str_loc_as_cell!(0), atom_as_cell!(atom!("a"))),
|
||||||
Some(Ordering::Greater)
|
Some(Ordering::Greater)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -676,23 +664,22 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(wam, heap_loc_as_cell!(7), heap_loc_as_cell!(7)),
|
wam.compare_term_test(heap_loc_as_cell!(7), heap_loc_as_cell!(7)),
|
||||||
Some(Ordering::Equal)
|
Some(Ordering::Equal)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(7)),
|
wam.compare_term_test(heap_loc_as_cell!(0), heap_loc_as_cell!(7)),
|
||||||
Some(Ordering::Greater)
|
Some(Ordering::Greater)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(wam, empty_list_as_cell!(), heap_loc_as_cell!(7)),
|
wam.compare_term_test(empty_list_as_cell!(), heap_loc_as_cell!(7)),
|
||||||
Some(Ordering::Less)
|
Some(Ordering::Less)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(
|
wam.compare_term_test(
|
||||||
wam,
|
|
||||||
empty_list_as_cell!(),
|
empty_list_as_cell!(),
|
||||||
fixnum_as_cell!(Fixnum::build_with(1))
|
fixnum_as_cell!(Fixnum::build_with(1))
|
||||||
),
|
),
|
||||||
@@ -702,29 +689,29 @@ mod tests {
|
|||||||
let cstr_cell = wam.heap.allocate_cstr("string").unwrap();
|
let cstr_cell = wam.heap.allocate_cstr("string").unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(wam, empty_list_as_cell!(), cstr_cell),
|
wam.compare_term_test(empty_list_as_cell!(), cstr_cell),
|
||||||
Some(Ordering::Less)
|
Some(Ordering::Less)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(wam, empty_list_as_cell!(), atom_as_cell!(atom!("atom"))),
|
wam.compare_term_test(empty_list_as_cell!(), atom_as_cell!(atom!("atom"))),
|
||||||
Some(Ordering::Less)
|
Some(Ordering::Less)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(wam, atom_as_cell!(atom!("atom")), empty_list_as_cell!()),
|
wam.compare_term_test(atom_as_cell!(atom!("atom")), empty_list_as_cell!()),
|
||||||
Some(Ordering::Greater)
|
Some(Ordering::Greater)
|
||||||
);
|
);
|
||||||
|
|
||||||
let one_p_one = HeapCellValue::from(float_alloc!(1.1, &mut wam.arena));
|
let one_p_one = HeapCellValue::from(float_alloc!(1.1, &mut wam.arena));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(wam, one_p_one, fixnum_as_cell!(Fixnum::build_with(1))),
|
wam.compare_term_test(one_p_one, fixnum_as_cell!(Fixnum::build_with(1))),
|
||||||
Some(Ordering::Less)
|
Some(Ordering::Less)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(wam, fixnum_as_cell!(Fixnum::build_with(1)), one_p_one),
|
wam.compare_term_test(fixnum_as_cell!(Fixnum::build_with(1)), one_p_one),
|
||||||
Some(Ordering::Greater)
|
Some(Ordering::Greater)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ use rand::{Rng, SeedableRng};
|
|||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
|
|
||||||
use fxhash::{FxBuildHasher, FxHasher};
|
use fxhash::{FxBuildHasher, FxHasher};
|
||||||
use indexmap::IndexSet;
|
use indexmap::*;
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
@@ -925,7 +925,7 @@ impl MachineState {
|
|||||||
&mut self.lifted_heap,
|
&mut self.lifted_heap,
|
||||||
);
|
);
|
||||||
|
|
||||||
let pstr_boundary = copy_term(copy_ball_term, copy_target, AttrVarPolicy::DeepCopy)?;
|
let pstr_boundary = copy_term(copy_ball_term, copy_target, AttrVarPolicy::StripAttributes)?;
|
||||||
|
|
||||||
Ok(FindallCopyInfo {
|
Ok(FindallCopyInfo {
|
||||||
offset: threshold + lh_offset + 2,
|
offset: threshold + lh_offset + 2,
|
||||||
|
|||||||
@@ -426,21 +426,6 @@ macro_rules! unify_with_occurs_check {
|
|||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! compare_term_test {
|
|
||||||
($machine_st:expr, $e1:expr, $e2:expr) => {{
|
|
||||||
$machine_st.pdl.push($e2);
|
|
||||||
$machine_st.pdl.push($e1);
|
|
||||||
|
|
||||||
$machine_st.compare_term_test(VarComparison::Distinct)
|
|
||||||
}};
|
|
||||||
($machine_st:expr, $e1:expr, $e2:expr, $var_comparison:expr) => {{
|
|
||||||
$machine_st.pdl.push($e2);
|
|
||||||
$machine_st.pdl.push($e1);
|
|
||||||
|
|
||||||
$machine_st.compare_term_test($var_comparison)
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! step_or_resource_error {
|
macro_rules! step_or_resource_error {
|
||||||
($machine_st:expr, $val:expr) => {{
|
($machine_st:expr, $val:expr) => {{
|
||||||
match $val {
|
match $val {
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ test_queries_on_builtins :-
|
|||||||
\+ float([1,2,_]),
|
\+ float([1,2,_]),
|
||||||
\+ (X is 3 rdiv 4, float(X)),
|
\+ (X is 3 rdiv 4, float(X)),
|
||||||
\+ \+ (X is 3 rdiv 4, rational(X)),
|
\+ \+ (X is 3 rdiv 4, rational(X)),
|
||||||
\+ rational(3),
|
rational(3),
|
||||||
\+ rational(f(_)),
|
\+ rational(f(_)),
|
||||||
\+ rational("sdfa"),
|
\+ rational("sdfa"),
|
||||||
\+ rational(atom),
|
\+ rational(atom),
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
use crate::forms::GenContext;
|
use crate::forms::{BranchNumber, GenContext};
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
|
|
||||||
use bit_set::*;
|
use bit_set::*;
|
||||||
use fxhash::FxBuildHasher;
|
use fxhash::FxBuildHasher;
|
||||||
use indexmap::{IndexMap, IndexSet};
|
use indexmap::{IndexMap, IndexSet};
|
||||||
|
use num_order::NumOrd;
|
||||||
|
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -13,20 +15,19 @@ pub struct TempVarData {
|
|||||||
pub(crate) conflict_set: BitSet<usize>,
|
pub(crate) conflict_set: BitSet<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct BranchDesignator {
|
pub struct BranchDesignator {
|
||||||
pub branch_stack_num: usize,
|
pub branch_num: BranchNumber,
|
||||||
pub branch_num: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BranchDesignator {
|
impl BranchDesignator {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_sub_branch(&self) -> bool {
|
pub fn is_sub_branch(&self) -> bool {
|
||||||
self.branch_stack_num > 0
|
self.branch_num.branch_num.num_gt(&0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum VarSafetyStatus {
|
pub enum VarSafetyStatus {
|
||||||
Needed,
|
Needed,
|
||||||
// which branch planted the last unsafe guarded instruction? It may still be needed.
|
// which branch planted the last unsafe guarded instruction? It may still be needed.
|
||||||
@@ -35,27 +36,27 @@ pub enum VarSafetyStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl VarSafetyStatus {
|
impl VarSafetyStatus {
|
||||||
pub(crate) fn unneeded(current_branch: BranchDesignator) -> Self {
|
pub(crate) fn unneeded(current_branch: &BranchDesignator) -> Self {
|
||||||
if current_branch.is_sub_branch() {
|
if current_branch.is_sub_branch() {
|
||||||
VarSafetyStatus::LocallyUnneeded(current_branch)
|
VarSafetyStatus::LocallyUnneeded(current_branch.clone())
|
||||||
} else {
|
} else {
|
||||||
VarSafetyStatus::GloballyUnneeded
|
VarSafetyStatus::GloballyUnneeded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn needed_if(needed: bool, branch_designator: BranchDesignator) -> Self {
|
pub(crate) fn needed_if(needed: bool, branch_designator: &BranchDesignator) -> Self {
|
||||||
if needed {
|
if needed {
|
||||||
VarSafetyStatus::Needed
|
VarSafetyStatus::Needed
|
||||||
} else if branch_designator.branch_stack_num == 0 {
|
} else if branch_designator.branch_num.branch_num.num_eq(&0) {
|
||||||
VarSafetyStatus::GloballyUnneeded
|
VarSafetyStatus::GloballyUnneeded
|
||||||
} else {
|
} else {
|
||||||
VarSafetyStatus::LocallyUnneeded(branch_designator)
|
VarSafetyStatus::LocallyUnneeded(branch_designator.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum PermVarAllocation {
|
pub enum PermVarAllocation {
|
||||||
Done {
|
Done {
|
||||||
shallow_safety: VarSafetyStatus,
|
shallow_safety: VarSafetyStatus,
|
||||||
|
|||||||
Reference in New Issue
Block a user