Merge pull request #3211 from mthom/setof_correction_and_opt

Correct and optimize setof/3 and bagof/3
This commit is contained in:
Mark Thom
2026-01-14 22:07:10 -07:00
committed by GitHub
17 changed files with 699 additions and 772 deletions

View File

@@ -643,11 +643,6 @@ enum SystemClauseType {
UnattributedVar,
#[strum_discriminants(strum(props(Arity = "4", Name = "$get_db_refs")))]
GetDBRefs,
#[strum_discriminants(strum(props(
Arity = "2",
Name = "$keysort_with_constant_var_ordering"
)))]
KeySortWithConstantVarOrdering,
#[strum_discriminants(strum(props(Arity = "0", Name = "$inference_limit_exceeded")))]
InferenceLimitExceeded,
#[strum_discriminants(strum(props(Arity = "1", Name = "$argv")))]

View File

@@ -639,7 +639,10 @@ impl CodeGenerator {
}
},
InlinedClauseType::IsRational(..) => match terms[0] {
Term::Literal(_, Literal::Rational(_)) => {
Term::Literal(
_,
Literal::Rational(_) | Literal::Fixnum(_) | Literal::Integer(_),
) => {
instr!("$succeed")
}
Term::Var(ref vr, ref name) => {
@@ -679,10 +682,13 @@ impl CodeGenerator {
}
},
InlinedClauseType::IsNumber(..) => match terms[0] {
Term::Literal(_, Literal::F64(..))
| Term::Literal(_, Literal::Rational(_))
| Term::Literal(_, Literal::Integer(_))
| Term::Literal(_, Literal::Fixnum(_)) => {
Term::Literal(
_,
Literal::F64(..)
| Literal::Rational(_)
| Literal::Integer(_)
| Literal::Fixnum(_),
) => {
instr!("$succeed")
}
Term::Var(ref vr, ref name) => {
@@ -988,20 +994,27 @@ impl CodeGenerator {
self.marker.in_tail_position = false;
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();
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();
}
ClauseItem::NextBranch => {
ClauseItem::NextBranch { branch_num } => {
branch_code_stack.add_new_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() {
let subsumed_hits =
branch_code_stack.push_missing_vars(depth, &mut self.marker);

View File

@@ -1,6 +1,6 @@
use crate::allocator::*;
use crate::codegen::SubsumedBranchHits;
use crate::forms::{GenContext, Level};
use crate::forms::{BranchNumber, GenContext, Level};
use crate::instructions::*;
use crate::machine::disjuncts::VarData;
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 deep_safety: BitSet<usize>,
pub num_branches: usize,
pub current_branch: usize,
pub current_branch_idx: usize,
pub current_branch_num: BranchNumber,
pub subsumed_hits: SubsumedBranchHits,
}
impl BranchOccurrences {
fn new(num_branches: usize) -> Self {
fn new(current_branch_num: BranchNumber, num_branches: usize) -> Self {
Self {
hits: BranchHits::with_hasher(FxBuildHasher::default()),
shallow_safety: BitSet::default(),
deep_safety: BitSet::default(),
num_branches,
current_branch: 0,
current_branch_idx: 0,
current_branch_num,
subsumed_hits: SubsumedBranchHits::with_hasher(FxBuildHasher::default()),
}
}
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 entry = self
@@ -49,7 +51,7 @@ impl BranchOccurrences {
.entry(var_num)
.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);
}
}
@@ -76,19 +78,6 @@ impl DerefMut for 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(
&self,
safety: &VarSafetyStatus,
@@ -96,9 +85,9 @@ impl BranchStack {
) -> bool {
match safety {
VarSafetyStatus::Needed => false,
VarSafetyStatus::LocallyUnneeded(planter_branch) => {
self.branch_subsumes(planter_branch, branch)
}
VarSafetyStatus::LocallyUnneeded(planter_branch) => planter_branch
.branch_num
.has_as_subbranch(&branch.branch_num),
VarSafetyStatus::GloballyUnneeded => true,
}
}
@@ -109,27 +98,24 @@ impl BranchStack {
}
}
pub(crate) fn add_branch_stack(&mut self, num_branches: usize) {
self.push(BranchOccurrences::new(num_branches));
pub(crate) fn add_branch_stack(&mut self, branch_num: BranchNumber, num_branches: usize) {
self.push(BranchOccurrences::new(branch_num, num_branches));
}
pub(crate) fn current_branch_designator(&self) -> BranchDesignator {
let branch_stack_num = self.len();
let branch_num = self
.last()
.map(|occurrences| occurrences.current_branch)
.unwrap_or(0);
.map(|occurrences| occurrences.current_branch_num.clone())
.unwrap_or_else(|| BranchNumber::default());
BranchDesignator {
branch_stack_num,
branch_num,
}
BranchDesignator { branch_num }
}
#[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();
branch_occurrences.current_branch += 1;
branch_occurrences.current_branch_idx += 1;
branch_occurrences.current_branch_num = branch_num;
}
#[inline]
@@ -235,12 +221,12 @@ impl DebrayAllocator {
VarAlloc::Perm(_, allocation) => {
let shallow_safety = VarSafetyStatus::needed_if(
shallow_safety.contains(var_num),
branch_designator,
&branch_designator,
);
let deep_safety = VarSafetyStatus::needed_if(
deep_safety.contains(var_num),
branch_designator,
&branch_designator,
);
if running_count < num_occurrences {
@@ -531,11 +517,11 @@ impl DebrayAllocator {
..
},
) => {
*deep_safety = VarSafetyStatus::unneeded(branch_designator);
*shallow_safety = VarSafetyStatus::unneeded(branch_designator);
*deep_safety = VarSafetyStatus::unneeded(&branch_designator);
*shallow_safety = VarSafetyStatus::unneeded(&branch_designator);
}
VarAlloc::Temp { safety, .. } => {
*safety = VarSafetyStatus::unneeded(branch_designator);
*safety = VarSafetyStatus::unneeded(&branch_designator);
}
_ => {
unreachable!()
@@ -557,8 +543,8 @@ impl DebrayAllocator {
) => {
// GetVariable in head chunk is considered safe.
if lvl == Level::Deep {
*deep_safety = VarSafetyStatus::unneeded(branch_designator);
*shallow_safety = VarSafetyStatus::unneeded(branch_designator);
*deep_safety = VarSafetyStatus::unneeded(&branch_designator);
*shallow_safety = VarSafetyStatus::unneeded(&branch_designator);
} else if term_loc == GenContext::Head {
*shallow_safety = VarSafetyStatus::GloballyUnneeded;
} 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)
} else {
*shallow_safety = VarSafetyStatus::unneeded(branch_designator);
*shallow_safety = VarSafetyStatus::unneeded(&branch_designator);
Target::unsafe_argument_to_value(r, arg_c)
}
}
@@ -640,7 +626,7 @@ impl DebrayAllocator {
{
Target::subterm_to_value(r)
} else {
*deep_safety = VarSafetyStatus::unneeded(branch_designator);
*deep_safety = VarSafetyStatus::unneeded(&branch_designator);
Target::unsafe_subterm_to_value(r)
}
}
@@ -651,7 +637,7 @@ impl DebrayAllocator {
{
Target::subterm_to_value(r)
} else {
*safety = VarSafetyStatus::unneeded(branch_designator);
*safety = VarSafetyStatus::unneeded(&branch_designator);
Target::unsafe_subterm_to_value(r)
}
}

View File

@@ -18,9 +18,11 @@ use indexmap::{IndexMap, IndexSet};
use ordered_float::OrderedFloat;
use std::cell::Cell;
use std::cmp::Ordering;
use std::collections::VecDeque;
use std::convert::TryFrom;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::{AddAssign, Deref, DerefMut};
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)]
pub enum Level {
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)]
pub enum ChunkedTerms {
Branch(Vec<VecDeque<ChunkedTerms>>),
Chunk { terms: VecDeque<QueryTerm> },
Branch {
branch_nums: Vec<BranchNumber>,
arms: Vec<VecDeque<ChunkedTerms>>,
},
Chunk {
terms: VecDeque<QueryTerm>,
},
}
#[derive(Debug)]
@@ -165,21 +233,22 @@ impl ChunkedTermVec {
}
pub fn reserve_branch(&mut self, capacity: usize) {
self.chunk_vec
.push_back(ChunkedTerms::Branch(Vec::with_capacity(capacity)));
self.chunk_vec.push_back(ChunkedTerms::Branch {
branch_nums: Vec::with_capacity(capacity),
arms: Vec::with_capacity(capacity),
});
}
#[inline]
pub fn add_chunk(&mut self) {
let chunk = ChunkedTerms::Chunk {
self.chunk_vec.push_back(ChunkedTerms::Chunk {
terms: VecDeque::from(vec![]),
};
self.chunk_vec.push_back(chunk);
});
}
pub fn push_chunk_term(&mut self, term: QueryTerm) {
match self.chunk_vec.back_mut() {
Some(ChunkedTerms::Branch(_)) => {
Some(ChunkedTerms::Branch { .. }) => {
let chunk = ChunkedTerms::Chunk {
terms: VecDeque::from(vec![term]),
};

View File

@@ -1,21 +1,375 @@
#![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
use crate::arena::Arena;
use crate::forms::Number;
#[cfg(test)]
pub(crate) use crate::machine::gc::StacklessPreOrderHeapIter;
use crate::atom_table::*;
use crate::machine::cycle_detection::*;
use crate::machine::heap::*;
use crate::machine::machine_indices::TermOrderCategory;
use crate::machine::stack::*;
use crate::parser::lexer::MachineState;
use crate::types::*;
use core::marker::PhantomData;
use fxhash::FxBuildHasher;
use indexmap::IndexSet;
use scryer_modular_bitfield::prelude::*;
use std::cmp::Ordering;
use std::ops::Deref;
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)]
pub fn eager_stackful_preorder_iter(
heap: &mut Heap,
@@ -35,7 +389,7 @@ pub struct EagerStackfulPreOrderHeapIter<'a> {
start_value: HeapCellValue,
iter_stack: Vec<HeapCellValue>,
mark_phase: bool,
heap: &'a mut Heap,
pub heap: &'a mut Heap,
}
impl<'a> Drop for EagerStackfulPreOrderHeapIter<'a> {

View File

@@ -726,7 +726,6 @@ impl Instruction {
| &Instruction::CallDeleteAllAttributesFromVar
| &Instruction::CallUnattributedVar
| &Instruction::CallGetDBRefs
| &Instruction::CallKeySortWithConstantVarOrdering
| &Instruction::CallInferenceLimitExceeded
| &Instruction::CallFetchGlobalVar
| &Instruction::CallFirstStream
@@ -986,7 +985,6 @@ impl Instruction {
| &Instruction::ExecuteDeleteAllAttributesFromVar
| &Instruction::ExecuteUnattributedVar
| &Instruction::ExecuteGetDBRefs
| &Instruction::ExecuteKeySortWithConstantVarOrdering
| &Instruction::ExecuteInferenceLimitExceeded
| &Instruction::ExecuteFetchGlobalVar
| &Instruction::ExecuteFirstStream

View File

@@ -319,15 +319,28 @@ pub(crate) fn breadth_first_iter(
#[derive(Debug, Copy, Clone)]
enum ClauseIteratorState<'a> {
RemainingChunks(&'a VecDeque<ChunkedTerms>, usize),
RemainingBranches(&'a Vec<VecDeque<ChunkedTerms>>, usize),
RemainingBranches(
&'a Vec<BranchNumber>,
&'a Vec<VecDeque<ChunkedTerms>>,
usize,
),
}
#[derive(Debug, Clone)]
pub(crate) enum ClauseItem<'a> {
FirstBranch(usize),
NextBranch,
BranchEnd(usize),
Chunk { terms: &'a VecDeque<QueryTerm> },
FirstBranch {
branch_num: &'a BranchNumber,
num_branches: usize,
},
NextBranch {
branch_num: &'a BranchNumber,
},
BranchEnd {
depth: usize,
},
Chunk {
terms: &'a VecDeque<QueryTerm>,
},
}
#[derive(Debug)]
@@ -338,8 +351,8 @@ pub(crate) struct ClauseIterator<'a> {
fn state_from_chunked_terms(chunk_vec: &VecDeque<ChunkedTerms>) -> ClauseIteratorState<'_> {
if chunk_vec.len() == 1 {
if let Some(ChunkedTerms::Branch(ref branches)) = chunk_vec.front() {
return ClauseIteratorState::RemainingBranches(branches, 0);
if let Some(ChunkedTerms::Branch { branch_nums, arms }) = chunk_vec.front() {
return ClauseIteratorState::RemainingBranches(branch_nums, arms, 0);
}
}
@@ -370,7 +383,9 @@ impl<'a> ClauseIterator<'a> {
while let Some(state) = self.state_stack.pop() {
match state {
ClauseIteratorState::RemainingBranches(terms, focus) if terms.len() == focus => {
ClauseIteratorState::RemainingBranches(_branch_nums, terms, focus)
if terms.len() == focus =>
{
depth += 1;
}
_ => {
@@ -399,9 +414,9 @@ impl<'a> Iterator for ClauseIterator<'a> {
}
match &chunks[focus] {
ChunkedTerms::Branch(branches) => {
ChunkedTerms::Branch { branch_nums, arms } => {
self.state_stack
.push(ClauseIteratorState::RemainingBranches(branches, 0));
.push(ClauseIteratorState::RemainingBranches(branch_nums, arms, 0));
}
ChunkedTerms::Chunk { ref terms } => {
return Some(ClauseItem::Chunk { terms });
@@ -411,11 +426,15 @@ impl<'a> Iterator for ClauseIterator<'a> {
ClauseIteratorState::RemainingChunks(chunks, focus) => {
debug_assert_eq!(chunks.len(), focus);
}
ClauseIteratorState::RemainingBranches(branches, focus)
ClauseIteratorState::RemainingBranches(branch_nums, branches, focus)
if focus < branches.len() =>
{
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]);
if let ClauseIteratorState::RemainingChunks(..) = &state {
@@ -425,14 +444,21 @@ impl<'a> Iterator for ClauseIterator<'a> {
self.state_stack.push(state);
return if focus == 0 {
Some(ClauseItem::FirstBranch(branches.len()))
Some(ClauseItem::FirstBranch {
branch_num: &branch_nums[0],
num_branches: branches.len(),
})
} 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);
return Some(ClauseItem::BranchEnd(self.branch_end_depth()));
return Some(ClauseItem::BranchEnd {
depth: self.branch_end_depth(),
});
}
}
}

View File

@@ -944,65 +944,6 @@ findall(Template, Goal, Solutions0, Solutions1) :-
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.
@@ -1035,9 +976,7 @@ findall_with_existential(Template, Goal, PairedSolutions, Witnesses0, Witnesses)
( Goal1 = _ ^ _ ) ->
rightmost_power(Goal1, Goal2, ExistentialVars0),
term_variables(ExistentialVars0, ExistentialVars),
sort(Witnesses0, Witnesses1),
sort(ExistentialVars, ExistentialVars1),
set_difference(Witnesses1, ExistentialVars1, Witnesses),
lists:append(Witnesses0, Witnesses, ExistentialVars),
expand_goal(M:Goal2, M, Goal3),
findall(Witnesses-Template, Goal3, PairedSolutions)
; 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, ?)).
:- non_counted_backtracking bagof/3.
@@ -1074,22 +1041,10 @@ bagof(Template, Goal, Solution) :-
term_variables(Goal, GoalVars),
term_variables(TemplateVars+GoalVars, TGVs),
lists:append(TemplateVars, Witnesses0, TGVs),
findall_with_existential(Template, Goal, PairedSolutions0, Witnesses0, Witnesses),
keysort(PairedSolutions0, PairedSolutions),
group_by_variants(PairedSolutions, GroupedSolutions),
iterate_variants(GroupedSolutions, 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).
findall_with_existential(Template, Goal, PairedSolutions, Witnesses0, Witnesses),
unify_variant_variables(PairedSolutions, _Dict),
keysort(PairedSolutions, PairedSolutions1),
split_by_variant(PairedSolutions1, Witnesses, Solution).
:- meta_predicate(setof(?, 0, ?)).
@@ -1112,10 +1067,10 @@ setof(Template, Goal, Solution) :-
term_variables(Goal, GoalVars),
term_variables(TemplateVars+GoalVars, TGVs),
lists:append(TemplateVars, Witnesses0, TGVs),
findall_with_existential(Template, Goal, PairedSolutions0, Witnesses0, Witnesses),
'$keysort_with_constant_var_ordering'(PairedSolutions0, PairedSolutions), % see 7.2.1
group_by_variants(PairedSolutions, GroupedSolutions),
iterate_variants_and_sort(GroupedSolutions, Witnesses, Solution).
findall_with_existential(Template, Goal, PairedSolutions, Witnesses0, Witnesses),
unify_variant_variables(PairedSolutions, _Dict),
sort(PairedSolutions, PairedSolutions1),
split_by_variant(PairedSolutions1, Witnesses, Solution).
% Clause retrieval and information.

View File

@@ -103,9 +103,8 @@ impl MachineState {
.collect()
};
attr_vars.sort_unstable_by(|a1, a2| {
compare_term_test!(self, *a1, *a2).unwrap_or(Ordering::Less)
});
attr_vars
.sort_unstable_by(|a1, a2| self.compare_term_test(*a1, *a2).unwrap_or(Ordering::Less));
attr_vars.dedup();
attr_vars

View File

@@ -6,79 +6,16 @@ use crate::machine::loader::*;
use crate::machine::machine_errors::CompilationError;
use crate::machine::preprocessor::*;
use crate::parser::ast::*;
use crate::parser::dashu::Rational;
use crate::variable_records::*;
use dashu::Integer;
use indexmap::{IndexMap, IndexSet};
use std::cell::Cell;
use std::cmp::Ordering;
use std::collections::VecDeque;
use std::hash::{Hash, Hasher};
use std::hash::Hash;
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)]
pub struct VarInfo {
var_ptr: VarPtr,
@@ -140,12 +77,13 @@ pub struct ClassifyInfo {
}
enum TraversalState {
// construct a QueryTerm::Branch with number of disjuncts, reset
// the chunk type to that of the chunk preceding the disjunct and the chunk_num.
// pop the latest branch number from the root set and use it to construct a QueryTerm::Branch
// with number of disjuncts, reset the chunk type to that of the chunk preceding the disjunct
// and the chunk_num.
BuildDisjunct(usize),
BuildFinalDisjunct(usize),
// add the last disjunct to a QueryTerm::Branch, continuing from
// where it leaves off.
BuildFinalDisjunct(usize),
Fail,
GetCutPoint { var_num: usize, prev_b: bool },
Cut { var_num: usize, is_global: bool },
@@ -154,7 +92,6 @@ enum TraversalState {
Term(Term),
OverrideGlobalCutVar(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
RepBranchNum(BranchNumber), // replace current_branch_num and the latest in the root set
}
@@ -199,7 +136,7 @@ impl VarData {
VarAlloc::Perm(0, PermVarAllocation::Pending);
match build_stack.front_mut() {
Some(ChunkedTerms::Branch(_)) => {
Some(ChunkedTerms::Branch { .. }) => {
build_stack.push_front(ChunkedTerms::Chunk {
terms: VecDeque::from(vec![term]),
});
@@ -232,11 +169,16 @@ fn merge_branch_seq(branches: impl Iterator<Item = BranchInfo>) -> BranchInfo {
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();
if let ChunkedTerms::Branch(ref mut disjuncts) = &mut build_stack[preceding_len] {
disjuncts.push(branch_vec);
if let ChunkedTerms::Branch { branch_nums, arms } = &mut build_stack[preceding_len] {
branch_nums.push(branch_num);
arms.push(branch_vec);
} else {
unreachable!();
}
@@ -477,9 +419,6 @@ impl VariableClassifier {
self.root_set.insert(branch_num.clone());
self.current_branch_num = branch_num;
}
TraversalState::RemoveBranchNum => {
self.root_set.pop();
}
TraversalState::RepBranchNum(branch_num) => {
self.root_set.pop();
self.root_set.insert(branch_num.clone());
@@ -488,14 +427,10 @@ impl VariableClassifier {
TraversalState::ResetCallPolicy(call_policy) => {
self.call_policy = call_policy;
}
TraversalState::BuildDisjunct(preceding_len) => {
flatten_into_disjunct(&mut build_stack, preceding_len);
self.current_chunk_type = ChunkType::Mid;
self.current_chunk_num += 1;
}
TraversalState::BuildFinalDisjunct(preceding_len) => {
flatten_into_disjunct(&mut build_stack, preceding_len);
TraversalState::BuildDisjunct(preceding_len)
| TraversalState::BuildFinalDisjunct(preceding_len) => {
let branch_num = self.root_set.pop().unwrap();
flatten_into_disjunct(&mut build_stack, branch_num, preceding_len);
self.current_chunk_type = ChunkType::Mid;
self.current_chunk_num += 1;
@@ -636,7 +571,6 @@ impl VariableClassifier {
for (term, branch_num) in iter.rev() {
state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
state_stack.push(TraversalState::RemoveBranchNum);
state_stack.push(TraversalState::Term(term));
state_stack.push(TraversalState::AddBranchNum(branch_num));
}
@@ -655,23 +589,18 @@ impl VariableClassifier {
let then_term = terms.pop().unwrap();
let if_term = terms.pop().unwrap();
let prev_b = if matches!(
state_stack.last(),
Some(TraversalState::RemoveBranchNum)
) {
// check if the second-to-last element
// is a regular BuildDisjunct, as we
// don't want to add GetPrevLevel in
// case of a TrustMe.
match state_stack.iter().rev().nth(1) {
Some(&TraversalState::BuildDisjunct(preceding_len)) => {
preceding_len + 1 == build_stack.len()
}
_ => false,
}
} else {
false
};
let prev_b =
if let Some(&TraversalState::BuildDisjunct(preceding_len)) =
state_stack.last()
{
// check if the second-to-last element
// is a regular BuildDisjunct, as we
// don't want to add GetPrevLevel in
// case of a TrustMe.
preceding_len + 1 == build_stack.len()
} else {
false
};
state_stack.push(TraversalState::Term(then_term));
state_stack.push(TraversalState::Cut {
@@ -690,14 +619,21 @@ impl VariableClassifier {
let not_term = terms.pop().unwrap();
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);
state_stack.push(TraversalState::RepBranchNum(
self.current_branch_num.halve_delta(),
));
state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len));
state_stack.push(TraversalState::Term(Term::Clause(
Cell::default(),
atom!("$succeed"),
vec![],
)));
state_stack.push(TraversalState::AddBranchNum(second_branch_num));
state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
state_stack.push(TraversalState::Fail);
state_stack.push(TraversalState::CutPrev(self.var_num));
@@ -710,6 +646,7 @@ impl VariableClassifier {
var_num: self.var_num,
prev_b: false,
});
state_stack.push(TraversalState::AddBranchNum(first_branch_num));
self.current_chunk_type = ChunkType::Mid;
self.current_chunk_num += 1;

View File

@@ -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) => {
atom!(">")
}
@@ -151,15 +151,12 @@ impl MachineState {
let stub_gen = || functor_stub(atom!("sort"), 2);
let mut list = self.try_from_list(self.registers[1], stub_gen)?;
list.sort_unstable_by(|v1, v2| {
compare_term_test!(self, *v1, *v2).unwrap_or(Ordering::Less)
});
list.dedup_by(|v1, v2| compare_term_test!(self, *v1, *v2) == Some(Ordering::Equal));
list.sort_unstable_by(|v1, v2| self.compare_term_test(*v1, *v2).unwrap_or(Ordering::Less));
list.dedup_by(|v1, v2| self.compare_term_test(*v1, *v2) == Some(Ordering::Equal));
let heap_addr = resource_error_call_result!(
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];
@@ -167,7 +164,7 @@ impl MachineState {
Ok(())
}
fn keysort(&mut self, var_comparison: VarComparison) -> CallResult {
fn keysort(&mut self) -> CallResult {
self.check_keysort_errors()?;
let stub_gen = || functor_stub(atom!("keysort"), 2);
@@ -176,13 +173,11 @@ impl MachineState {
let mut key_pairs = Vec::with_capacity(list.len());
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.sort_by(|a1, a2| {
compare_term_test!(self, a1.0, a2.0, var_comparison).unwrap_or(Ordering::Less)
});
key_pairs.sort_by(|a1, a2| self.compare_term_test(a1.0, a2.0).unwrap_or(Ordering::Less));
let heap_addr = resource_error_call_result!(
self,
@@ -2034,8 +2029,7 @@ impl Machine {
let a1 = self.machine_st.registers[1];
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;
} else {
self.machine_st.backtrack();
@@ -2045,8 +2039,7 @@ impl Machine {
let a1 = self.machine_st.registers[1];
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;
} else {
self.machine_st.backtrack();
@@ -2056,7 +2049,7 @@ impl Machine {
let a1 = self.machine_st.registers[1];
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;
} else {
self.machine_st.backtrack();
@@ -2066,7 +2059,7 @@ impl Machine {
let a1 = self.machine_st.registers[1];
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;
} else {
self.machine_st.backtrack();
@@ -2076,7 +2069,7 @@ impl Machine {
let a1 = self.machine_st.registers[1];
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) => {
self.machine_st.p += 1;
}
@@ -2089,7 +2082,7 @@ impl Machine {
let a1 = self.machine_st.registers[1];
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) => {
self.machine_st.p = self.machine_st.cp;
}
@@ -2102,7 +2095,7 @@ impl Machine {
let a1 = self.machine_st.registers[1];
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) => {
self.machine_st.p += 1;
}
@@ -2115,7 +2108,7 @@ impl Machine {
let a1 = self.machine_st.registers[1];
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) => {
self.machine_st.p = self.machine_st.cp;
}
@@ -2188,7 +2181,7 @@ impl Machine {
let a1 = self.machine_st.registers[1];
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();
} else {
self.machine_st.p += 1;
@@ -2198,7 +2191,7 @@ impl Machine {
let a1 = self.machine_st.registers[1];
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();
} else {
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);
}
&Instruction::DefaultCallKeySort => {
try_or_throw!(
self.machine_st,
self.machine_st.keysort(VarComparison::Distinct),
continue
);
try_or_throw!(self.machine_st, self.machine_st.keysort(), continue);
step_or_fail!(self.machine_st, self.machine_st.p += 1);
}
&Instruction::DefaultExecuteKeySort => {
try_or_throw!(
self.machine_st,
self.machine_st.keysort(VarComparison::Distinct),
continue
);
try_or_throw!(self.machine_st, self.machine_st.keysort(), continue);
if self.machine_st.fail {
self.machine_st.backtrack();
@@ -2323,8 +2308,7 @@ impl Machine {
let a1 = self.machine_st.registers[1];
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);
self.machine_st.p += 1;
} else {
@@ -2335,8 +2319,7 @@ impl Machine {
let a1 = self.machine_st.registers[1];
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);
self.machine_st.p = self.machine_st.cp;
} else {
@@ -2347,7 +2330,7 @@ impl Machine {
let a1 = self.machine_st.registers[1];
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);
self.machine_st.p += 1;
} else {
@@ -2358,7 +2341,7 @@ impl Machine {
let a1 = self.machine_st.registers[1];
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);
self.machine_st.p = self.machine_st.cp;
} else {
@@ -2369,7 +2352,7 @@ impl Machine {
let a1 = self.machine_st.registers[1];
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) => {
increment_call_count!(self.machine_st);
self.machine_st.p += 1;
@@ -2383,7 +2366,7 @@ impl Machine {
let a1 = self.machine_st.registers[1];
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) => {
increment_call_count!(self.machine_st);
self.machine_st.p = self.machine_st.cp;
@@ -2397,7 +2380,7 @@ impl Machine {
let a1 = self.machine_st.registers[1];
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) => {
increment_call_count!(self.machine_st);
self.machine_st.p += 1;
@@ -2411,7 +2394,7 @@ impl Machine {
let a1 = self.machine_st.registers[1];
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) => {
increment_call_count!(self.machine_st);
self.machine_st.p = self.machine_st.cp;
@@ -2503,7 +2486,7 @@ impl Machine {
let a1 = self.machine_st.registers[1];
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();
} else {
increment_call_count!(self.machine_st);
@@ -2514,7 +2497,7 @@ impl Machine {
let a1 = self.machine_st.registers[1];
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();
} else {
increment_call_count!(self.machine_st);
@@ -2542,11 +2525,7 @@ impl Machine {
}
}
&Instruction::CallKeySort => {
try_or_throw!(
self.machine_st,
self.machine_st.keysort(VarComparison::Distinct),
continue
);
try_or_throw!(self.machine_st, self.machine_st.keysort(), continue);
if self.machine_st.fail {
self.machine_st.backtrack();
@@ -2556,39 +2535,7 @@ impl Machine {
}
}
&Instruction::ExecuteKeySort => {
try_or_throw!(
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
);
try_or_throw!(self.machine_st, self.machine_st.keysort(), continue);
if self.machine_st.fail {
self.machine_st.backtrack();

View File

@@ -7,7 +7,6 @@ use crate::machine::copier::*;
use crate::machine::heap::AllocError;
use crate::machine::heap::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::*;
use crate::machine::partial_string::*;
use crate::machine::stack::*;
@@ -17,8 +16,6 @@ use crate::parser::ast::*;
use crate::parser::dashu::{Integer, Rational};
use crate::types::*;
use indexmap::IndexSet;
use std::cmp::Ordering;
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(
&mut self,
goal: HeapCellValue,
@@ -891,16 +547,32 @@ impl MachineState {
}
// 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 {
return false;
}
compare_term_test!(self, h1, h2)
.map(|o| o != Ordering::Equal)
self.compare_term_test(h1, h2)
.map(|o| !o.is_eq())
.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)]
fn try_functor_compound_case(&mut self, name: Atom, arity: usize) {
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.
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 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();
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 {
let err = self.type_error(ValidType::Pair, self.heap[s]);
Err(self.error_form(err, stub_gen()))

View File

@@ -581,56 +581,44 @@ mod tests {
});
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)
);
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)
);
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)
);
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)
);
let cstr_cell = wam.heap.allocate_cstr("string").unwrap();
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)
);
assert_eq!(
compare_term_test!(
wam,
atom_as_cell!(atom!("atom")),
atom_as_cell!(atom!("atom"))
),
wam.compare_term_test(atom_as_cell!(atom!("atom")), atom_as_cell!(atom!("atom"))),
Some(Ordering::Equal)
);
assert_eq!(
compare_term_test!(
wam,
atom_as_cell!(atom!("atom")),
atom_as_cell!(atom!("aaa"))
),
wam.compare_term_test(atom_as_cell!(atom!("atom")), atom_as_cell!(atom!("aaa"))),
Some(Ordering::Greater)
);
assert_eq!(
compare_term_test!(
wam,
fixnum_as_cell!(Fixnum::build_with(6)),
heap_loc_as_cell!(1)
),
wam.compare_term_test(fixnum_as_cell!(Fixnum::build_with(6)), heap_loc_as_cell!(1)),
Some(Ordering::Greater)
);
@@ -644,12 +632,12 @@ mod tests {
});
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)
);
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)
);
@@ -676,23 +664,22 @@ mod tests {
});
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)
);
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)
);
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)
);
assert_eq!(
compare_term_test!(
wam,
wam.compare_term_test(
empty_list_as_cell!(),
fixnum_as_cell!(Fixnum::build_with(1))
),
@@ -702,29 +689,29 @@ mod tests {
let cstr_cell = wam.heap.allocate_cstr("string").unwrap();
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)
);
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)
);
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)
);
let one_p_one = HeapCellValue::from(float_alloc!(1.1, &mut wam.arena));
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)
);
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)
);
}

View File

@@ -38,7 +38,7 @@ use rand::{Rng, SeedableRng};
use ordered_float::OrderedFloat;
use fxhash::{FxBuildHasher, FxHasher};
use indexmap::IndexSet;
use indexmap::*;
use std::cell::Cell;
use std::cmp::Ordering;
@@ -925,7 +925,7 @@ impl MachineState {
&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 {
offset: threshold + lh_offset + 2,

View File

@@ -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 {
($machine_st:expr, $val:expr) => {{
match $val {

View File

@@ -46,7 +46,7 @@ test_queries_on_builtins :-
\+ float([1,2,_]),
\+ (X is 3 rdiv 4, float(X)),
\+ \+ (X is 3 rdiv 4, rational(X)),
\+ rational(3),
rational(3),
\+ rational(f(_)),
\+ rational("sdfa"),
\+ rational(atom),

View File

@@ -1,9 +1,11 @@
use crate::forms::GenContext;
use crate::forms::{BranchNumber, GenContext};
use crate::parser::ast::*;
use bit_set::*;
use fxhash::FxBuildHasher;
use indexmap::{IndexMap, IndexSet};
use num_order::NumOrd;
use std::ops::{Deref, DerefMut};
#[derive(Debug, Clone)]
@@ -13,20 +15,19 @@ pub struct TempVarData {
pub(crate) conflict_set: BitSet<usize>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BranchDesignator {
pub branch_stack_num: usize,
pub branch_num: usize,
pub branch_num: BranchNumber,
}
impl BranchDesignator {
#[inline]
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 {
Needed,
// which branch planted the last unsafe guarded instruction? It may still be needed.
@@ -35,27 +36,27 @@ pub enum 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() {
VarSafetyStatus::LocallyUnneeded(current_branch)
VarSafetyStatus::LocallyUnneeded(current_branch.clone())
} else {
VarSafetyStatus::GloballyUnneeded
}
}
#[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 {
VarSafetyStatus::Needed
} else if branch_designator.branch_stack_num == 0 {
} else if branch_designator.branch_num.branch_num.num_eq(&0) {
VarSafetyStatus::GloballyUnneeded
} else {
VarSafetyStatus::LocallyUnneeded(branch_designator)
VarSafetyStatus::LocallyUnneeded(branch_designator.clone())
}
}
}
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone)]
pub enum PermVarAllocation {
Done {
shallow_safety: VarSafetyStatus,