Merge branch 'compiling_disj'
This commit is contained in:
787
Cargo.lock
generated
787
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,8 @@ to-syn-value_derive = "0.1.0"
|
|||||||
walkdir = "2"
|
walkdir = "2"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
bit-set = "0.5.3"
|
||||||
|
bitvec = "1"
|
||||||
cpu-time = "1.0.0"
|
cpu-time = "1.0.0"
|
||||||
crossterm = "0.20.0"
|
crossterm = "0.20.0"
|
||||||
dirs-next = "2.0.0"
|
dirs-next = "2.0.0"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,10 @@
|
|||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
use crate::temp_v;
|
|
||||||
|
|
||||||
use crate::fixtures::*;
|
|
||||||
use crate::forms::*;
|
use crate::forms::*;
|
||||||
use crate::instructions::*;
|
use crate::instructions::*;
|
||||||
use crate::machine::machine_indices::*;
|
|
||||||
use crate::targets::*;
|
use crate::targets::*;
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
pub(crate) trait Allocator {
|
pub(crate) trait Allocator {
|
||||||
fn new() -> Self;
|
fn new() -> Self;
|
||||||
@@ -17,7 +13,7 @@ pub(crate) trait Allocator {
|
|||||||
&mut self,
|
&mut self,
|
||||||
lvl: Level,
|
lvl: Level,
|
||||||
context: GenContext,
|
context: GenContext,
|
||||||
code: &mut Code,
|
code: &mut CodeDeque,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn mark_non_var<'a, Target: CompilationTarget<'a>>(
|
fn mark_non_var<'a, Target: CompilationTarget<'a>>(
|
||||||
@@ -25,83 +21,71 @@ pub(crate) trait Allocator {
|
|||||||
lvl: Level,
|
lvl: Level,
|
||||||
context: GenContext,
|
context: GenContext,
|
||||||
cell: &'a Cell<RegType>,
|
cell: &'a Cell<RegType>,
|
||||||
code: &mut Code,
|
code: &mut CodeDeque,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
|
fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
var_name: Rc<String>,
|
var_num: usize,
|
||||||
lvl: Level,
|
lvl: Level,
|
||||||
cell: &'a Cell<VarReg>,
|
cell: &'a Cell<VarReg>,
|
||||||
term_loc: GenContext,
|
term_loc: GenContext,
|
||||||
code: &mut Code,
|
code: &mut CodeDeque,
|
||||||
r: RegType,
|
r: RegType,
|
||||||
is_new_var: bool,
|
is_new_var: bool,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType;
|
||||||
|
|
||||||
fn mark_var<'a, Target: CompilationTarget<'a>>(
|
fn mark_var<'a, Target: CompilationTarget<'a>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
var_name: Rc<String>,
|
var_num: usize,
|
||||||
lvl: Level,
|
lvl: Level,
|
||||||
cell: &'a Cell<VarReg>,
|
cell: &'a Cell<VarReg>,
|
||||||
context: GenContext,
|
context: GenContext,
|
||||||
code: &mut Code,
|
code: &mut CodeDeque,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn reset(&mut self);
|
fn reset(&mut self);
|
||||||
fn reset_contents(&mut self) {}
|
|
||||||
fn reset_arg(&mut self, arg_num: usize);
|
fn reset_arg(&mut self, arg_num: usize);
|
||||||
fn reset_at_head(&mut self, args: &Vec<Term>);
|
fn reset_at_head(&mut self, args: &Vec<Term>);
|
||||||
|
fn reset_contents(&mut self);
|
||||||
|
|
||||||
fn advance_arg(&mut self);
|
fn advance_arg(&mut self);
|
||||||
|
|
||||||
|
/*
|
||||||
fn bindings(&self) -> &AllocVarDict;
|
fn bindings(&self) -> &AllocVarDict;
|
||||||
fn bindings_mut(&mut self) -> &mut AllocVarDict;
|
fn bindings_mut(&mut self) -> &mut AllocVarDict;
|
||||||
|
|
||||||
fn take_bindings(self) -> AllocVarDict;
|
fn take_bindings(self) -> AllocVarDict;
|
||||||
|
*/
|
||||||
|
|
||||||
fn max_reg_allocated(&self) -> usize;
|
fn max_reg_allocated(&self) -> usize;
|
||||||
|
|
||||||
|
// TODO: wha.. why?? grrr. it drains the VarStatus data from vs (which it owns!)
|
||||||
|
// into self.bindings and perm_vs after all is computed (i.e. vs.populate_restricting_sets()
|
||||||
|
// and vs.set_perm_vals(has_deep_cut) have both been called).
|
||||||
|
/*
|
||||||
fn drain_var_data<'a>(
|
fn drain_var_data<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
vs: VariableFixtures<'a>,
|
vs: VariableFixtures,
|
||||||
num_of_chunks: usize,
|
num_of_chunks: usize,
|
||||||
) -> VariableFixtures<'a> {
|
) -> VariableFixtures {
|
||||||
let mut perm_vs = VariableFixtures::new();
|
let mut perm_vs = VariableFixtures::new();
|
||||||
|
|
||||||
for (var, (var_status, cells)) in vs.into_iter() {
|
for (var, var_status) in vs.into_iter() {
|
||||||
match var_status {
|
match var_status {
|
||||||
VarStatus::Temp(chunk_num, tvd) => {
|
VarStatus::Temp(chunk_num, tvd) => {
|
||||||
self.bindings_mut()
|
self.bindings_mut()
|
||||||
.insert(var.clone(), VarData::Temp(chunk_num, 0, tvd));
|
.insert(var.clone(), VarAlloc::Temp(chunk_num, 0, tvd));
|
||||||
|
|
||||||
if chunk_num + 1 == num_of_chunks {
|
|
||||||
perm_vs.insert_last_chunk_temp_var(var);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
VarStatus::Perm(_) => {
|
VarStatus::Perm(_) => {
|
||||||
self.bindings_mut().insert(var.clone(), VarData::Perm(0));
|
self.bindings_mut().insert(var.clone(), VarAlloc::Perm(0));
|
||||||
perm_vs.insert(var, (var_status, cells));
|
perm_vs.insert(var, var_status);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
perm_vs
|
perm_vs
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
fn get(&self, var: Rc<String>) -> RegType {
|
|
||||||
self.bindings()
|
|
||||||
.get(&var)
|
|
||||||
.map_or(temp_v!(0), |v| v.as_reg_type())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_unbound(&self, var: Rc<String>) -> bool {
|
|
||||||
self.get(var).reg_num() == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn record_register(&mut self, var: Rc<String>, r: RegType) {
|
|
||||||
match self.bindings_mut().get_mut(&var).unwrap() {
|
|
||||||
&mut VarData::Temp(_, ref mut s, _) => *s = r.reg_num(),
|
|
||||||
&mut VarData::Perm(ref mut s) => *s = r.reg_num(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ use std::convert::TryFrom;
|
|||||||
use std::f64;
|
use std::f64;
|
||||||
use std::num::FpCategory;
|
use std::num::FpCategory;
|
||||||
use std::ops::Div;
|
use std::ops::Div;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
@@ -53,7 +52,7 @@ pub(crate) struct ArithInstructionIterator<'a> {
|
|||||||
state_stack: Vec<TermIterState<'a>>,
|
state_stack: Vec<TermIterState<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) type ArithCont = (Code, Option<ArithmeticTerm>);
|
pub(crate) type ArithCont = (CodeDeque, Option<ArithmeticTerm>);
|
||||||
|
|
||||||
impl<'a> ArithInstructionIterator<'a> {
|
impl<'a> ArithInstructionIterator<'a> {
|
||||||
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
||||||
@@ -74,7 +73,7 @@ impl<'a> ArithInstructionIterator<'a> {
|
|||||||
2,
|
2,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Term::Var(cell, var) => TermIterState::Var(Level::Shallow, cell, var.clone()),
|
Term::Var(cell, var_ptr) => TermIterState::Var(Level::Shallow, cell, var_ptr.clone()),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(ArithInstructionIterator {
|
Ok(ArithInstructionIterator {
|
||||||
@@ -87,7 +86,7 @@ impl<'a> ArithInstructionIterator<'a> {
|
|||||||
pub(crate) enum ArithTermRef<'a> {
|
pub(crate) enum ArithTermRef<'a> {
|
||||||
Literal(&'a Literal),
|
Literal(&'a Literal),
|
||||||
Op(Atom, usize), // name, arity.
|
Op(Atom, usize), // name, arity.
|
||||||
Var(Level, &'a Cell<VarReg>, Rc<String>),
|
Var(Level, &'a Cell<VarReg>, VarPtr),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for ArithInstructionIterator<'a> {
|
impl<'a> Iterator for ArithInstructionIterator<'a> {
|
||||||
@@ -115,8 +114,8 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(c))),
|
TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(c))),
|
||||||
TermIterState::Var(lvl, cell, var) => {
|
TermIterState::Var(lvl, cell, var_ptr) => {
|
||||||
return Some(Ok(ArithTermRef::Var(lvl, cell, var.clone())));
|
return Some(Ok(ArithTermRef::Var(lvl, cell, var_ptr)));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Some(Err(ArithmeticError::NonEvaluableFunctor(
|
return Some(Err(ArithmeticError::NonEvaluableFunctor(
|
||||||
@@ -308,43 +307,48 @@ impl<'a> ArithmeticEvaluator<'a> {
|
|||||||
term_loc: GenContext,
|
term_loc: GenContext,
|
||||||
arg: usize,
|
arg: usize,
|
||||||
) -> Result<ArithCont, ArithmeticError> {
|
) -> Result<ArithCont, ArithmeticError> {
|
||||||
let mut code = vec![];
|
let mut code = CodeDeque::new();
|
||||||
let mut iter = src.iter()?;
|
let mut iter = src.iter()?;
|
||||||
|
|
||||||
while let Some(term_ref) = iter.next() {
|
while let Some(term_ref) = iter.next() {
|
||||||
match term_ref? {
|
match term_ref? {
|
||||||
ArithTermRef::Literal(c) => push_literal(&mut self.interm, c)?,
|
ArithTermRef::Literal(c) => push_literal(&mut self.interm, c)?,
|
||||||
ArithTermRef::Var(lvl, cell, name) => {
|
ArithTermRef::Var(lvl, cell, name) => {
|
||||||
|
let var_num = name.to_var_num().unwrap();
|
||||||
|
|
||||||
let r = if lvl == Level::Shallow {
|
let r = if lvl == Level::Shallow {
|
||||||
self.marker.mark_non_callable(
|
self.marker.mark_non_callable(
|
||||||
name.clone(),
|
var_num,
|
||||||
arg,
|
arg,
|
||||||
term_loc,
|
term_loc,
|
||||||
cell,
|
cell,
|
||||||
&mut code,
|
&mut code,
|
||||||
)
|
)
|
||||||
} else if term_loc.is_last() || cell.get().norm().reg_num() == 0 {
|
} else if term_loc.is_last() || cell.get().norm().reg_num() == 0 {
|
||||||
if let Some(r) = self.marker.get_binding(&name) {
|
let r = self.marker.get_binding(var_num);
|
||||||
r
|
|
||||||
} else {
|
if r.reg_num() == 0 {
|
||||||
self.marker.mark_var::<QueryInstruction>(
|
self.marker.mark_var::<QueryInstruction>(
|
||||||
name.clone(),
|
var_num,
|
||||||
lvl,
|
lvl,
|
||||||
cell,
|
cell,
|
||||||
term_loc,
|
term_loc,
|
||||||
&mut code,
|
&mut code,
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
self.marker.get_binding(&name).unwrap()
|
self.marker.increment_running_count(var_num);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r
|
||||||
} else {
|
} else {
|
||||||
|
self.marker.increment_running_count(var_num);
|
||||||
cell.get().norm()
|
cell.get().norm()
|
||||||
};
|
};
|
||||||
|
|
||||||
self.interm.push(ArithmeticTerm::Reg(r));
|
self.interm.push(ArithmeticTerm::Reg(r));
|
||||||
}
|
}
|
||||||
ArithTermRef::Op(name, arity) => {
|
ArithTermRef::Op(name, arity) => {
|
||||||
code.push(self.instr_from_clause(name, arity)?);
|
code.push_back(self.instr_from_clause(name, arity)?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
829
src/codegen.rs
829
src/codegen.rs
File diff suppressed because it is too large
Load Diff
@@ -1,43 +1,198 @@
|
|||||||
use indexmap::IndexMap;
|
|
||||||
|
|
||||||
use crate::allocator::*;
|
use crate::allocator::*;
|
||||||
use crate::fixtures::*;
|
use crate::codegen::SubsumedBranchHits;
|
||||||
use crate::forms::Level;
|
use crate::forms::Level;
|
||||||
use crate::instructions::*;
|
use crate::instructions::*;
|
||||||
use crate::machine::machine_indices::*;
|
use crate::machine::disjuncts::VarData;
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
use crate::targets::*;
|
use crate::targets::*;
|
||||||
|
use crate::variable_records::*;
|
||||||
|
|
||||||
use crate::temp_v;
|
use bit_set::*;
|
||||||
|
use bitvec::prelude::*;
|
||||||
use fxhash::FxBuildHasher;
|
use fxhash::FxBuildHasher;
|
||||||
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::VecDeque;
|
||||||
use std::rc::Rc;
|
|
||||||
|
pub type BranchHits = IndexMap<usize, BitVec, FxBuildHasher>; // key: var_num, value: branch arm occurrences.
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct BranchOccurrences {
|
||||||
|
pub hits: BranchHits,
|
||||||
|
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 subsumed_hits: SubsumedBranchHits,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BranchOccurrences {
|
||||||
|
fn new(num_branches: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
hits: BranchHits::with_hasher(FxBuildHasher::default()),
|
||||||
|
shallow_safety: BitSet::default(),
|
||||||
|
deep_safety: BitSet::default(),
|
||||||
|
num_branches,
|
||||||
|
current_branch: 0,
|
||||||
|
subsumed_hits: SubsumedBranchHits::with_hasher(FxBuildHasher::default()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct DebrayAllocator {
|
pub(crate) struct DebrayAllocator {
|
||||||
bindings: IndexMap<Rc<String>, VarData, FxBuildHasher>,
|
pub(crate) var_data: VarData, // var_data replaces bindings.
|
||||||
|
pub(crate) branch_stack: Vec<BranchOccurrences>,
|
||||||
|
pub(crate) in_tail_position: bool,
|
||||||
|
// bindings: IndexMap<usize, VarWitness, FxBuildHasher>, // VarNum -> VarWitness
|
||||||
arg_c: usize,
|
arg_c: usize,
|
||||||
temp_lb: usize,
|
temp_lb: usize,
|
||||||
|
perm_lb: usize,
|
||||||
arity: usize, // 0 if not at head.
|
arity: usize, // 0 if not at head.
|
||||||
contents: IndexMap<usize, Rc<String>, FxBuildHasher>,
|
shallow_temp_mappings: IndexMap<usize, usize, FxBuildHasher>,
|
||||||
in_use: BTreeSet<usize>,
|
in_use: BitSet<usize>, // deep and non-var allocations
|
||||||
free_list: Vec<usize>,
|
temp_free_list: Vec<usize>,
|
||||||
|
perm_free_list: VecDeque<(usize, usize)>, // chunk_num, var_num
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DebrayAllocator {
|
impl DebrayAllocator {
|
||||||
fn is_curr_arg_distinct_from(&self, var: &String) -> bool {
|
pub(crate) fn add_branch_occurrence(&mut self, var_num: usize) {
|
||||||
match self.contents.get(&self.arg_c) {
|
if let Some(occurrences) = self.branch_stack.last_mut() {
|
||||||
Some(t_var) if **t_var != *var => true,
|
debug_assert!(occurrences.current_branch < occurrences.num_branches);
|
||||||
|
|
||||||
|
let num_branches = occurrences.num_branches;
|
||||||
|
|
||||||
|
let entry = occurrences.hits.entry(var_num)
|
||||||
|
.or_insert_with(|| BitVec::repeat(false, num_branches));
|
||||||
|
|
||||||
|
entry.set(occurrences.current_branch, true);
|
||||||
|
occurrences.subsumed_hits.insert(var_num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_branch_stack(&mut self, num_branches: usize) {
|
||||||
|
self.branch_stack.push(BranchOccurrences::new(num_branches));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn current_branch_designator(&self) -> BranchDesignator {
|
||||||
|
let num_branches = self.branch_stack.len();
|
||||||
|
let current_branch = self.branch_stack.last()
|
||||||
|
.map(|occurrences| occurrences.current_branch)
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
BranchDesignator((num_branches, current_branch))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_branch(&mut self) {
|
||||||
|
let branch_designator = self.current_branch_designator();
|
||||||
|
let branch_occurrences = self.branch_stack.last_mut().unwrap();
|
||||||
|
|
||||||
|
for var_num in branch_occurrences.subsumed_hits.drain(..) {
|
||||||
|
match &mut self.var_data.records[var_num].allocation {
|
||||||
|
VarAlloc::Perm(_, ref mut allocation) => {
|
||||||
|
match allocation {
|
||||||
|
PermVarAllocation::Done { shallow_safety, deep_safety, .. } => {
|
||||||
|
if !shallow_safety.is_unneeded(branch_designator) {
|
||||||
|
branch_occurrences.shallow_safety.insert(var_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !deep_safety.is_unneeded(branch_designator) {
|
||||||
|
branch_occurrences.deep_safety.insert(var_num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*allocation = PermVarAllocation::Pending;
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn incr_current_branch(&mut self) {
|
||||||
|
let branch_occurrences = self.branch_stack.last_mut().unwrap();
|
||||||
|
branch_occurrences.current_branch += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn drain_branches(&mut self, depth: usize) -> std::vec::Drain<BranchOccurrences> {
|
||||||
|
let start_idx = self.branch_stack.len() - depth;
|
||||||
|
self.branch_stack.drain(start_idx ..)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn pop_branch(&mut self, depth: usize, subsumed_hits: SubsumedBranchHits) {
|
||||||
|
let removed_branches = self.drain_branches(depth);
|
||||||
|
|
||||||
|
let (deep_safety, shallow_safety) = removed_branches
|
||||||
|
.into_iter()
|
||||||
|
.fold((BitSet::default(), BitSet::default()),
|
||||||
|
|(mut deep_safety, mut shallow_safety), branch_occurrences| {
|
||||||
|
deep_safety.union_with(&branch_occurrences.deep_safety);
|
||||||
|
shallow_safety.union_with(&branch_occurrences.shallow_safety);
|
||||||
|
|
||||||
|
(deep_safety, shallow_safety)
|
||||||
|
});
|
||||||
|
|
||||||
|
let branch_designator = self.current_branch_designator();
|
||||||
|
|
||||||
|
let (deep_safety, shallow_safety) = match self.branch_stack.last_mut() {
|
||||||
|
Some(latest_branch) => {
|
||||||
|
latest_branch.deep_safety.union_with(&deep_safety);
|
||||||
|
latest_branch.shallow_safety.union_with(&shallow_safety);
|
||||||
|
|
||||||
|
(&latest_branch.deep_safety, &latest_branch.shallow_safety)
|
||||||
|
}
|
||||||
|
None => (&deep_safety, &shallow_safety)
|
||||||
|
};
|
||||||
|
|
||||||
|
for var_num in subsumed_hits.iter().cloned() {
|
||||||
|
let running_count = self.var_data.records[var_num].running_count;
|
||||||
|
let num_occurrences = self.var_data.records[var_num].num_occurrences;
|
||||||
|
|
||||||
|
match &mut self.var_data.records[var_num].allocation {
|
||||||
|
VarAlloc::Perm(_, allocation) => {
|
||||||
|
let shallow_safety = VarSafetyStatus::needed_if(
|
||||||
|
shallow_safety.contains(var_num),
|
||||||
|
branch_designator,
|
||||||
|
);
|
||||||
|
|
||||||
|
let deep_safety = VarSafetyStatus::needed_if(
|
||||||
|
deep_safety.contains(var_num),
|
||||||
|
branch_designator,
|
||||||
|
);
|
||||||
|
|
||||||
|
if running_count < num_occurrences {
|
||||||
|
*allocation = PermVarAllocation::Done { shallow_safety, deep_safety };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.branch_stack.len() > 0 {
|
||||||
|
for var_num in subsumed_hits {
|
||||||
|
self.add_branch_occurrence(var_num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_curr_arg_distinct_from(&self, var_num: usize) -> bool {
|
||||||
|
match self.shallow_temp_mappings.get(&self.arg_c).cloned() {
|
||||||
|
Some(t_var) => t_var != var_num,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn occurs_shallowly_in_head(&self, var: &String, r: usize) -> bool {
|
fn occurs_shallowly_in_head(&self, var_num: usize, r: usize) -> bool {
|
||||||
match self.bindings.get(var).unwrap() {
|
match &self.var_data.records[var_num].allocation {
|
||||||
&VarData::Temp(_, _, ref tvd) => tvd.use_set.contains(&(GenContext::Head, r)),
|
VarAlloc::Temp { temp_var_data, term_loc: GenContext::Head, .. } => {
|
||||||
|
temp_var_data.use_set.contains(&(GenContext::Head, r))
|
||||||
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -45,13 +200,13 @@ impl DebrayAllocator {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn is_in_use(&self, r: usize) -> bool {
|
fn is_in_use(&self, r: usize) -> bool {
|
||||||
let in_use_range = r <= self.arity && r >= self.arg_c;
|
let in_use_range = r <= self.arity && r >= self.arg_c;
|
||||||
in_use_range || self.in_use.contains(&r)
|
in_use_range || self.in_use.contains(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_with_cr(&self, var: &String) -> usize {
|
fn alloc_with_cr(&self, var_num: usize) -> usize {
|
||||||
match self.bindings.get(var) {
|
match &self.var_data.records[var_num].allocation {
|
||||||
Some(&VarData::Temp(_, _, ref tvd)) => {
|
VarAlloc::Temp { temp_var_data, .. } => {
|
||||||
for &(_, reg) in tvd.use_set.iter() {
|
for &(_, reg) in temp_var_data.use_set.iter() {
|
||||||
if !self.is_in_use(reg) {
|
if !self.is_in_use(reg) {
|
||||||
return reg;
|
return reg;
|
||||||
}
|
}
|
||||||
@@ -61,7 +216,7 @@ impl DebrayAllocator {
|
|||||||
|
|
||||||
for reg in self.temp_lb.. {
|
for reg in self.temp_lb.. {
|
||||||
if !self.is_in_use(reg) {
|
if !self.is_in_use(reg) {
|
||||||
if !tvd.no_use_set.contains(®) {
|
if !temp_var_data.no_use_set.contains(reg) {
|
||||||
result = reg;
|
result = reg;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -74,10 +229,10 @@ impl DebrayAllocator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_with_ca(&self, var: &String) -> usize {
|
fn alloc_with_ca(&self, var_num: usize) -> usize {
|
||||||
match self.bindings.get(var) {
|
match &self.var_data.records[var_num].allocation {
|
||||||
Some(&VarData::Temp(_, _, ref tvd)) => {
|
VarAlloc::Temp { temp_var_data, .. } => {
|
||||||
for &(_, reg) in tvd.use_set.iter() {
|
for &(_, reg) in temp_var_data.use_set.iter() {
|
||||||
if !self.is_in_use(reg) {
|
if !self.is_in_use(reg) {
|
||||||
return reg;
|
return reg;
|
||||||
}
|
}
|
||||||
@@ -87,8 +242,8 @@ impl DebrayAllocator {
|
|||||||
|
|
||||||
for reg in self.temp_lb.. {
|
for reg in self.temp_lb.. {
|
||||||
if !self.is_in_use(reg) {
|
if !self.is_in_use(reg) {
|
||||||
if !tvd.no_use_set.contains(®) {
|
if !temp_var_data.no_use_set.contains(reg) {
|
||||||
if !tvd.conflict_set.contains(®) {
|
if !temp_var_data.conflict_set.contains(reg) {
|
||||||
result = reg;
|
result = reg;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -102,22 +257,25 @@ impl DebrayAllocator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_in_last_goal_hint(&self, chunk_num: usize) -> Option<(Rc<String>, usize)> {
|
fn alloc_in_last_goal_hint(&self, chunk_num: usize) -> Option<(usize, usize)> {
|
||||||
// we want to allocate a register to the k^{th} parameter, par_k.
|
// we want to allocate a register to the k^{th} parameter, par_k.
|
||||||
// par_k may not be a temporary variable.
|
// par_k may not be a temporary variable.
|
||||||
let k = self.arg_c;
|
let k = self.arg_c;
|
||||||
|
|
||||||
match self.contents.get(&k) {
|
match self.shallow_temp_mappings.get(&k).cloned() {
|
||||||
Some(t_var) => {
|
Some(t_var) => {
|
||||||
// suppose this branch fires. then t_var is a
|
// suppose this branch fires. then t_var is a
|
||||||
// temp. var. belonging to the current chunk.
|
// temp. var. belonging to the current chunk.
|
||||||
// consider its use set. T == par_k iff
|
// consider its use set. T == par_k iff
|
||||||
// (GenContext::Last(_), k) is in t_var.use_set.
|
// (GenContext::Last(_), k) is in t_var.use_set.
|
||||||
|
|
||||||
let tvd = self.bindings.get(t_var).unwrap();
|
match &self.var_data.records[t_var].allocation {
|
||||||
if let &VarData::Temp(_, _, ref tvd) = tvd {
|
VarAlloc::Temp { temp_var_data, .. } => {
|
||||||
if !tvd.use_set.contains(&(GenContext::Last(chunk_num), k)) {
|
if !temp_var_data.use_set.contains(&(GenContext::Last(chunk_num), k)) {
|
||||||
return Some((t_var.clone(), self.alloc_with_ca(t_var)));
|
return Some((t_var, self.alloc_with_ca(t_var)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,21 +288,21 @@ impl DebrayAllocator {
|
|||||||
fn evacuate_arg<'a, Target: CompilationTarget<'a>>(
|
fn evacuate_arg<'a, Target: CompilationTarget<'a>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
chunk_num: usize,
|
chunk_num: usize,
|
||||||
code: &mut Code,
|
code: &mut CodeDeque,
|
||||||
) {
|
) {
|
||||||
match self.alloc_in_last_goal_hint(chunk_num) {
|
match self.alloc_in_last_goal_hint(chunk_num) {
|
||||||
Some((var, r)) => {
|
Some((var_num, r)) => {
|
||||||
let k = self.arg_c;
|
let k = self.arg_c;
|
||||||
|
|
||||||
if r != k {
|
if r != k {
|
||||||
let r = RegType::Temp(r);
|
let r = RegType::Temp(r);
|
||||||
|
|
||||||
code.push(Target::move_to_register(r, k));
|
code.push_back(Target::move_to_register(r, k));
|
||||||
|
|
||||||
self.contents.swap_remove(&k);
|
self.shallow_temp_mappings.swap_remove(&k);
|
||||||
self.contents.insert(r.reg_num(), var.clone());
|
self.shallow_temp_mappings.insert(r.reg_num(), var_num);
|
||||||
|
|
||||||
self.record_register(var, r);
|
self.var_data.records[var_num].allocation.set_register(r.reg_num());
|
||||||
self.in_use.insert(r.reg_num());
|
self.in_use.insert(r.reg_num());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -154,27 +312,27 @@ impl DebrayAllocator {
|
|||||||
|
|
||||||
fn alloc_reg_to_var<'a, Target: CompilationTarget<'a>>(
|
fn alloc_reg_to_var<'a, Target: CompilationTarget<'a>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
var: &String,
|
var_num: usize,
|
||||||
lvl: Level,
|
lvl: Level,
|
||||||
term_loc: GenContext,
|
term_loc: GenContext,
|
||||||
target: &mut Vec<Instruction>,
|
target: &mut CodeDeque,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
match term_loc {
|
match term_loc {
|
||||||
GenContext::Head => {
|
GenContext::Head => {
|
||||||
if let Level::Shallow = lvl {
|
if let Level::Shallow = lvl {
|
||||||
self.evacuate_arg::<Target>(0, target);
|
self.evacuate_arg::<Target>(0, target);
|
||||||
self.alloc_with_cr(var)
|
self.alloc_with_cr(var_num)
|
||||||
} else {
|
} else {
|
||||||
self.alloc_with_ca(var)
|
self.alloc_with_ca(var_num)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GenContext::Mid(_) => self.alloc_with_ca(var),
|
GenContext::Mid(_) => self.alloc_with_ca(var_num),
|
||||||
GenContext::Last(chunk_num) => {
|
GenContext::Last(chunk_num) => {
|
||||||
if let Level::Shallow = lvl {
|
if let Level::Shallow = lvl {
|
||||||
self.evacuate_arg::<Target>(chunk_num, target);
|
self.evacuate_arg::<Target>(chunk_num, target);
|
||||||
self.alloc_with_cr(var)
|
self.alloc_with_cr(var_num)
|
||||||
} else {
|
} else {
|
||||||
self.alloc_with_ca(var)
|
self.alloc_with_ca(var_num)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -183,15 +341,15 @@ impl DebrayAllocator {
|
|||||||
fn alloc_reg_to_non_var(&mut self) -> usize {
|
fn alloc_reg_to_non_var(&mut self) -> usize {
|
||||||
let mut final_index = 0;
|
let mut final_index = 0;
|
||||||
|
|
||||||
while let Some(r) = self.free_list.pop() {
|
while let Some(r) = self.temp_free_list.pop() {
|
||||||
if !self.in_use.contains(&r) {
|
if !self.is_in_use(r) {
|
||||||
self.in_use.insert(r);
|
self.in_use.insert(r);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for index in self.temp_lb.. {
|
for index in self.temp_lb.. {
|
||||||
if !self.in_use.contains(&index) {
|
if !self.in_use.contains(index) {
|
||||||
final_index = index;
|
final_index = index;
|
||||||
self.in_use.insert(final_index);
|
self.in_use.insert(final_index);
|
||||||
break;
|
break;
|
||||||
@@ -202,38 +360,219 @@ impl DebrayAllocator {
|
|||||||
final_index
|
final_index
|
||||||
}
|
}
|
||||||
|
|
||||||
fn in_place(&self, var: &String, term_loc: GenContext, r: RegType, k: usize) -> bool {
|
fn in_place(&self, var_num: usize, term_loc: GenContext, r: RegType, k: usize) -> bool {
|
||||||
match term_loc {
|
match term_loc {
|
||||||
GenContext::Head if !r.is_perm() => r.reg_num() == k,
|
GenContext::Head if !r.is_perm() => r.reg_num() == k,
|
||||||
_ => match self.bindings().get(var).unwrap() {
|
_ => {
|
||||||
&VarData::Temp(_, o, _) if r.reg_num() == k => o == k,
|
match &self.var_data.records[var_num].allocation {
|
||||||
_ => false,
|
&VarAlloc::Temp { temp_reg, .. } if r.reg_num() == k =>
|
||||||
|
temp_reg == k,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_to_free_list(&mut self, r: RegType) {
|
fn alloc_perm_var(&mut self, var_num: usize, chunk_num: usize) -> usize {
|
||||||
|
let p = if let Some(p) = self.pop_free_perm(chunk_num) {
|
||||||
|
p
|
||||||
|
} else {
|
||||||
|
let p = self.perm_lb;
|
||||||
|
self.perm_lb += 1;
|
||||||
|
|
||||||
|
p
|
||||||
|
};
|
||||||
|
|
||||||
|
self.var_data.records[var_num].allocation = VarAlloc::Perm(p, PermVarAllocation::done());
|
||||||
|
p
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_reg_to_free_list(&mut self, r: RegType) {
|
||||||
if let RegType::Temp(r) = r {
|
if let RegType::Temp(r) = r {
|
||||||
self.in_use.remove(&r);
|
self.in_use.remove(r);
|
||||||
self.free_list.push(r);
|
self.temp_free_list.push(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset_free_list(&mut self) {
|
pub fn reset_free_list(&mut self) {
|
||||||
self.free_list.clear();
|
self.temp_free_list.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn get_binding(&self, var_num: usize) -> RegType {
|
||||||
|
self.var_data.records[var_num].allocation.as_reg_type()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn num_perm_vars(&self) -> usize {
|
||||||
|
self.perm_lb - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn increment_running_count(&mut self, var_num: usize) {
|
||||||
|
self.var_data.records[var_num].running_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_perm_to_free_list(&mut self, chunk_num: usize, var_num: usize) {
|
||||||
|
match &self.var_data.records[var_num].allocation {
|
||||||
|
VarAlloc::Perm(..) => {
|
||||||
|
self.perm_free_list.push_back((chunk_num, var_num));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_free_perm(&mut self, chunk_num: usize) -> Option<usize> {
|
||||||
|
while let Some((perm_chunk_num, var_num)) = self.perm_free_list.front().cloned() {
|
||||||
|
if chunk_num > perm_chunk_num {
|
||||||
|
self.perm_free_list.pop_front();
|
||||||
|
|
||||||
|
match &mut self.var_data.records[var_num].allocation {
|
||||||
|
VarAlloc::Perm(p, PermVarAllocation::Pending) if *p > 0 => {
|
||||||
|
return Some(std::mem::replace(p, 0));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn free_var(&mut self, chunk_num: usize, var_num: usize) {
|
||||||
|
match &mut self.var_data.records[var_num].allocation {
|
||||||
|
VarAlloc::Perm(_, allocation) => {
|
||||||
|
*allocation = PermVarAllocation::Pending;
|
||||||
|
self.add_perm_to_free_list(chunk_num, var_num);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn mark_safe_var_unconditionally(&mut self, var_num: usize) {
|
||||||
|
let branch_designator = self.current_branch_designator();
|
||||||
|
|
||||||
|
match &mut self.var_data.records[var_num].allocation {
|
||||||
|
VarAlloc::Perm(_, PermVarAllocation::Done { deep_safety, shallow_safety, .. }) => {
|
||||||
|
*deep_safety = VarSafetyStatus::unneeded(branch_designator);
|
||||||
|
*shallow_safety = VarSafetyStatus::unneeded(branch_designator);
|
||||||
|
}
|
||||||
|
VarAlloc::Temp { safety, .. } => {
|
||||||
|
*safety = VarSafetyStatus::unneeded(branch_designator);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_safe_var(&mut self, var_num: usize, lvl: Level, term_loc: GenContext) {
|
||||||
|
let branch_designator = self.current_branch_designator();
|
||||||
|
|
||||||
|
match &mut self.var_data.records[var_num].allocation {
|
||||||
|
VarAlloc::Perm(_, PermVarAllocation::Done { deep_safety, shallow_safety, .. }) => {
|
||||||
|
// GetVariable in head chunk is considered safe.
|
||||||
|
if lvl == Level::Deep {
|
||||||
|
*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).cloned() {
|
||||||
|
match &mut self.var_data.records[temp_var_num].allocation {
|
||||||
|
VarAlloc::Temp { ref mut to_perm_var_num, .. } => {
|
||||||
|
*to_perm_var_num = Some(var_num);
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VarAlloc::Temp { ref mut safety, .. } => {
|
||||||
|
*safety = VarSafetyStatus::GloballyUnneeded;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn argument_to_value<'a, Target: CompilationTarget<'a>>(
|
||||||
|
&mut self,
|
||||||
|
var_num: usize,
|
||||||
|
r: RegType,
|
||||||
|
arg_c: usize,
|
||||||
|
) -> Instruction {
|
||||||
|
let branch_designator = self.current_branch_designator();
|
||||||
|
|
||||||
|
match &mut self.var_data.records[var_num].allocation {
|
||||||
|
VarAlloc::Perm(_, PermVarAllocation::Done { ref mut shallow_safety, .. }) => {
|
||||||
|
if !self.in_tail_position || shallow_safety.is_unneeded(branch_designator) {
|
||||||
|
Target::argument_to_value(r, arg_c)
|
||||||
|
} else {
|
||||||
|
*shallow_safety = VarSafetyStatus::unneeded(branch_designator);
|
||||||
|
Target::unsafe_argument_to_value(r, arg_c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VarAlloc::Temp { ref mut safety, .. } => {
|
||||||
|
if safety.is_unneeded(branch_designator) {
|
||||||
|
Target::argument_to_value(r, arg_c)
|
||||||
|
} else {
|
||||||
|
*safety = VarSafetyStatus::GloballyUnneeded;
|
||||||
|
Target::unsafe_argument_to_value(r, arg_c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn subterm_to_value<'a, Target: CompilationTarget<'a>>(
|
||||||
|
&mut self,
|
||||||
|
var_num: usize,
|
||||||
|
r: RegType,
|
||||||
|
) -> Instruction {
|
||||||
|
let branch_designator = self.current_branch_designator();
|
||||||
|
|
||||||
|
match &mut self.var_data.records[var_num].allocation {
|
||||||
|
VarAlloc::Perm(_, PermVarAllocation::Done { ref mut deep_safety, .. }) => {
|
||||||
|
if deep_safety.is_unneeded(branch_designator) {
|
||||||
|
Target::subterm_to_value(r)
|
||||||
|
} else {
|
||||||
|
*deep_safety = VarSafetyStatus::unneeded(branch_designator);
|
||||||
|
Target::unsafe_subterm_to_value(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VarAlloc::Temp { ref mut safety, .. } => {
|
||||||
|
if safety.is_unneeded(branch_designator) {
|
||||||
|
Target::subterm_to_value(r)
|
||||||
|
} else {
|
||||||
|
*safety = VarSafetyStatus::unneeded(branch_designator);
|
||||||
|
Target::unsafe_subterm_to_value(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Allocator for DebrayAllocator {
|
impl Allocator for DebrayAllocator {
|
||||||
fn new() -> DebrayAllocator {
|
fn new() -> DebrayAllocator {
|
||||||
DebrayAllocator {
|
Self {
|
||||||
|
var_data: VarData::default(),
|
||||||
|
in_tail_position: false,
|
||||||
arity: 0,
|
arity: 0,
|
||||||
arg_c: 1,
|
arg_c: 1,
|
||||||
temp_lb: 1,
|
temp_lb: 1,
|
||||||
bindings: IndexMap::with_hasher(FxBuildHasher::default()),
|
perm_lb: 1,
|
||||||
contents: IndexMap::with_hasher(FxBuildHasher::default()),
|
shallow_temp_mappings: IndexMap::with_hasher(FxBuildHasher::default()),
|
||||||
in_use: BTreeSet::new(),
|
in_use: BitSet::default(),
|
||||||
free_list: vec![],
|
temp_free_list: vec![],
|
||||||
|
perm_free_list: VecDeque::new(),
|
||||||
|
branch_stack: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,12 +580,12 @@ impl Allocator for DebrayAllocator {
|
|||||||
&mut self,
|
&mut self,
|
||||||
lvl: Level,
|
lvl: Level,
|
||||||
term_loc: GenContext,
|
term_loc: GenContext,
|
||||||
code: &mut Code,
|
code: &mut CodeDeque,
|
||||||
) {
|
) {
|
||||||
let r = RegType::Temp(self.alloc_reg_to_non_var());
|
let r = RegType::Temp(self.alloc_reg_to_non_var());
|
||||||
|
|
||||||
match lvl {
|
match lvl {
|
||||||
Level::Deep => code.push(Target::subterm_to_variable(r)),
|
Level::Deep => code.push_back(Target::subterm_to_variable(r)),
|
||||||
Level::Root | Level::Shallow => {
|
Level::Root | Level::Shallow => {
|
||||||
let k = self.arg_c;
|
let k = self.arg_c;
|
||||||
|
|
||||||
@@ -256,7 +595,7 @@ impl Allocator for DebrayAllocator {
|
|||||||
|
|
||||||
self.arg_c += 1;
|
self.arg_c += 1;
|
||||||
|
|
||||||
code.push(Target::argument_to_variable(r, k));
|
code.push_back(Target::argument_to_variable(r, k));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -266,7 +605,7 @@ impl Allocator for DebrayAllocator {
|
|||||||
lvl: Level,
|
lvl: Level,
|
||||||
term_loc: GenContext,
|
term_loc: GenContext,
|
||||||
cell: &'a Cell<RegType>,
|
cell: &'a Cell<RegType>,
|
||||||
code: &mut Code,
|
code: &mut CodeDeque,
|
||||||
) {
|
) {
|
||||||
let r = cell.get();
|
let r = cell.get();
|
||||||
|
|
||||||
@@ -293,39 +632,49 @@ impl Allocator for DebrayAllocator {
|
|||||||
|
|
||||||
fn mark_var<'a, Target: CompilationTarget<'a>>(
|
fn mark_var<'a, Target: CompilationTarget<'a>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
var: Rc<String>,
|
var_num: usize,
|
||||||
lvl: Level,
|
lvl: Level,
|
||||||
cell: &'a Cell<VarReg>,
|
cell: &'a Cell<VarReg>,
|
||||||
term_loc: GenContext,
|
term_loc: GenContext,
|
||||||
code: &mut Code,
|
code: &mut CodeDeque,
|
||||||
) {
|
) {
|
||||||
let (r, is_new_var) = match self.get(var.clone()) {
|
let (r, is_new_var) = match self.get_binding(var_num) {
|
||||||
RegType::Temp(0) => {
|
RegType::Temp(0) => {
|
||||||
// here, r is temporary *and* unassigned.
|
let o = self.alloc_reg_to_var::<Target>(var_num, lvl, term_loc, code);
|
||||||
let o = self.alloc_reg_to_var::<Target>(&var, lvl, term_loc, code);
|
|
||||||
cell.set(VarReg::Norm(RegType::Temp(o)));
|
cell.set(VarReg::Norm(RegType::Temp(o)));
|
||||||
|
|
||||||
(RegType::Temp(o), true)
|
(RegType::Temp(o), true)
|
||||||
}
|
}
|
||||||
RegType::Perm(0) => {
|
RegType::Perm(0) => {
|
||||||
let pr = cell.get().norm();
|
let p = self.alloc_perm_var(var_num, term_loc.chunk_num());
|
||||||
self.record_register(var.clone(), pr);
|
(RegType::Perm(p), true)
|
||||||
|
}
|
||||||
|
r @ RegType::Perm(_) => {
|
||||||
|
let is_new_var = match &mut self.var_data.records[var_num].allocation {
|
||||||
|
VarAlloc::Perm(_, allocation) => if allocation.pending() {
|
||||||
|
*allocation = PermVarAllocation::done();
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
},
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
(pr, true)
|
(r, is_new_var)
|
||||||
}
|
}
|
||||||
r => (r, false),
|
r => (r, false),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.mark_reserved_var::<Target>(var, lvl, cell, term_loc, code, r, is_new_var);
|
self.mark_reserved_var::<Target>(var_num, lvl, cell, term_loc, code, r, is_new_var);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
|
fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
var: Rc<String>,
|
var_num: usize,
|
||||||
lvl: Level,
|
lvl: Level,
|
||||||
cell: &'a Cell<VarReg>,
|
cell: &'a Cell<VarReg>,
|
||||||
term_loc: GenContext,
|
term_loc: GenContext,
|
||||||
code: &mut Code,
|
code: &mut CodeDeque,
|
||||||
r: RegType,
|
r: RegType,
|
||||||
is_new_var: bool,
|
is_new_var: bool,
|
||||||
) {
|
) {
|
||||||
@@ -333,86 +682,99 @@ impl Allocator for DebrayAllocator {
|
|||||||
Level::Root | Level::Shallow => {
|
Level::Root | Level::Shallow => {
|
||||||
let k = self.arg_c;
|
let k = self.arg_c;
|
||||||
|
|
||||||
if self.is_curr_arg_distinct_from(&var) {
|
if self.is_curr_arg_distinct_from(var_num) {
|
||||||
self.evacuate_arg::<Target>(term_loc.chunk_num(), code);
|
self.evacuate_arg::<Target>(term_loc.chunk_num(), code);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.arg_c += 1;
|
|
||||||
|
|
||||||
cell.set(VarReg::ArgAndNorm(r, k));
|
cell.set(VarReg::ArgAndNorm(r, k));
|
||||||
|
|
||||||
if !self.in_place(&var, term_loc, r, k) {
|
if !self.in_place(var_num, term_loc, r, k) {
|
||||||
if is_new_var {
|
if is_new_var {
|
||||||
code.push(Target::argument_to_variable(r, k));
|
self.mark_safe_var(var_num, lvl, term_loc);
|
||||||
|
code.push_back(Target::argument_to_variable(r, k));
|
||||||
} else {
|
} else {
|
||||||
code.push(Target::argument_to_value(r, k));
|
code.push_back(self.argument_to_value::<Target>(var_num, r, k));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.arg_c += 1;
|
||||||
}
|
}
|
||||||
Level::Deep if is_new_var => {
|
Level::Deep if is_new_var => {
|
||||||
if let GenContext::Head = term_loc {
|
if let GenContext::Head = term_loc {
|
||||||
if self.occurs_shallowly_in_head(&var, r.reg_num()) {
|
if self.occurs_shallowly_in_head(var_num, r.reg_num()) {
|
||||||
code.push(Target::subterm_to_value(r));
|
code.push_back(self.subterm_to_value::<Target>(var_num, r));
|
||||||
} else {
|
} else {
|
||||||
code.push(Target::subterm_to_variable(r));
|
self.mark_safe_var(var_num, lvl, term_loc);
|
||||||
|
code.push_back(Target::subterm_to_variable(r));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
code.push(Target::subterm_to_variable(r));
|
self.mark_safe_var(var_num, lvl, term_loc);
|
||||||
|
code.push_back(Target::subterm_to_variable(r));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Level::Deep => code.push(Target::subterm_to_value(r)),
|
Level::Deep => code.push_back(self.subterm_to_value::<Target>(var_num, r)),
|
||||||
};
|
}
|
||||||
|
|
||||||
|
let o = r.reg_num();
|
||||||
|
|
||||||
if !r.is_perm() {
|
if !r.is_perm() {
|
||||||
let o = r.reg_num();
|
self.shallow_temp_mappings.insert(o, var_num);
|
||||||
|
} else if r.is_perm() && is_new_var {
|
||||||
|
self.add_branch_occurrence(var_num);
|
||||||
|
}
|
||||||
|
|
||||||
self.contents.insert(o, var.clone());
|
let record = &mut self.var_data.records[var_num];
|
||||||
self.record_register(var.clone(), r);
|
|
||||||
self.in_use.insert(o);
|
record.allocation.set_register(o);
|
||||||
|
|
||||||
|
if record.running_count < record.num_occurrences {
|
||||||
|
record.running_count += 1;
|
||||||
|
} else {
|
||||||
|
self.free_var(term_loc.chunk_num(), var_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.in_use.insert(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType {
|
||||||
|
match self.get_binding(var_num) {
|
||||||
|
RegType::Perm(0) | RegType::Temp(0) => {
|
||||||
|
RegType::Perm(self.alloc_perm_var(var_num, chunk_num))
|
||||||
|
}
|
||||||
|
r => r,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset(&mut self) {
|
fn reset(&mut self) {
|
||||||
self.bindings.clear();
|
self.perm_lb = 1;
|
||||||
self.contents.clear();
|
self.shallow_temp_mappings.clear();
|
||||||
self.in_use.clear();
|
self.in_use.clear();
|
||||||
self.free_list.clear();
|
self.temp_free_list.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset_contents(&mut self) {
|
fn reset_contents(&mut self) {
|
||||||
self.contents.clear();
|
|
||||||
self.in_use.clear();
|
self.in_use.clear();
|
||||||
self.free_list.clear();
|
self.shallow_temp_mappings.clear();
|
||||||
|
self.temp_free_list.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn advance_arg(&mut self) {
|
fn advance_arg(&mut self) {
|
||||||
self.arg_c += 1;
|
self.arg_c += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bindings(&self) -> &AllocVarDict {
|
|
||||||
&self.bindings
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bindings_mut(&mut self) -> &mut AllocVarDict {
|
|
||||||
&mut self.bindings
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_bindings(self) -> AllocVarDict {
|
|
||||||
self.bindings
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset_at_head(&mut self, args: &Vec<Term>) {
|
fn reset_at_head(&mut self, args: &Vec<Term>) {
|
||||||
self.reset_arg(args.len());
|
self.reset_arg(args.len());
|
||||||
self.arity = args.len();
|
self.arity = args.len();
|
||||||
|
|
||||||
for (idx, arg) in args.iter().enumerate() {
|
for (idx, arg) in args.iter().enumerate() {
|
||||||
if let &Term::Var(_, ref var) = arg {
|
if let &Term::Var(_, ref var) = arg {
|
||||||
let r = self.get(var.clone());
|
let var_num = var.to_var_num().unwrap();
|
||||||
|
let r = self.get_binding(var_num);
|
||||||
|
|
||||||
if !r.is_perm() && r.reg_num() == 0 {
|
if !r.is_perm() && r.reg_num() == 0 {
|
||||||
self.in_use.insert(idx + 1);
|
self.in_use.insert(idx + 1);
|
||||||
self.contents.insert(idx + 1, var.clone());
|
self.shallow_temp_mappings.insert(idx + 1, var_num);
|
||||||
self.record_register(var.clone(), temp_v!(idx + 1));
|
self.var_data.records[var_num].allocation.set_register(idx + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
436
src/fixtures.rs
436
src/fixtures.rs
@@ -1,436 +0,0 @@
|
|||||||
use crate::parser::ast::*;
|
|
||||||
|
|
||||||
use crate::forms::*;
|
|
||||||
use crate::instructions::*;
|
|
||||||
use crate::iterators::*;
|
|
||||||
|
|
||||||
use indexmap::{IndexMap, IndexSet};
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::collections::BTreeSet;
|
|
||||||
use std::mem::swap;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
// labeled with chunk numbers.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) enum VarStatus {
|
|
||||||
Perm(usize),
|
|
||||||
Temp(usize, TempVarData), // Perm(chunk_num) | Temp(chunk_num, _)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) type OccurrenceSet = BTreeSet<(GenContext, usize)>;
|
|
||||||
|
|
||||||
// Perm: 0 initially, a stack register once processed.
|
|
||||||
// Temp: labeled with chunk_num and temp offset (unassigned if 0).
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) enum VarData {
|
|
||||||
Perm(usize),
|
|
||||||
Temp(usize, usize, TempVarData),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VarData {
|
|
||||||
pub(crate) fn as_reg_type(&self) -> RegType {
|
|
||||||
match self {
|
|
||||||
&VarData::Temp(_, r, _) => RegType::Temp(r),
|
|
||||||
&VarData::Perm(r) => RegType::Perm(r),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) struct TempVarData {
|
|
||||||
pub(crate) last_term_arity: usize,
|
|
||||||
pub(crate) use_set: OccurrenceSet,
|
|
||||||
pub(crate) no_use_set: BTreeSet<usize>,
|
|
||||||
pub(crate) conflict_set: BTreeSet<usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TempVarData {
|
|
||||||
pub(crate) fn new(last_term_arity: usize) -> Self {
|
|
||||||
TempVarData {
|
|
||||||
last_term_arity: last_term_arity,
|
|
||||||
use_set: BTreeSet::new(),
|
|
||||||
no_use_set: BTreeSet::new(),
|
|
||||||
conflict_set: BTreeSet::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn uses_reg(&self, reg: usize) -> bool {
|
|
||||||
for &(_, nreg) in self.use_set.iter() {
|
|
||||||
if reg == nreg {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn populate_conflict_set(&mut self) {
|
|
||||||
if self.last_term_arity > 0 {
|
|
||||||
let arity = self.last_term_arity;
|
|
||||||
let mut conflict_set: BTreeSet<usize> = (1..arity).collect();
|
|
||||||
|
|
||||||
for &(_, reg) in self.use_set.iter() {
|
|
||||||
conflict_set.remove(®);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.conflict_set = conflict_set;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type VariableFixture<'a> = (VarStatus, Vec<&'a Cell<VarReg>>);
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) struct VariableFixtures<'a> {
|
|
||||||
perm_vars: IndexMap<Rc<String>, VariableFixture<'a>>,
|
|
||||||
last_chunk_temp_vars: IndexSet<Rc<String>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> VariableFixtures<'a> {
|
|
||||||
pub(crate) fn new() -> Self {
|
|
||||||
VariableFixtures {
|
|
||||||
perm_vars: IndexMap::new(),
|
|
||||||
last_chunk_temp_vars: IndexSet::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn insert(&mut self, var: Rc<String>, vs: VariableFixture<'a>) {
|
|
||||||
self.perm_vars.insert(var, vs);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn insert_last_chunk_temp_var(&mut self, var: Rc<String>) {
|
|
||||||
self.last_chunk_temp_vars.insert(var);
|
|
||||||
}
|
|
||||||
|
|
||||||
// computes no_use and conflict sets for all temp vars.
|
|
||||||
pub(crate) fn populate_restricting_sets(&mut self) {
|
|
||||||
// three stages:
|
|
||||||
// 1. move the use sets of each variable to a local IndexMap, use_set
|
|
||||||
// (iterate mutably, swap mutable refs).
|
|
||||||
// 2. drain use_set. For each use set of U, add into the
|
|
||||||
// no-use sets of appropriate variables T =/= U.
|
|
||||||
// 3. Move the use sets back to their original locations in the fixture.
|
|
||||||
// Compute the conflict set of u.
|
|
||||||
|
|
||||||
// 1.
|
|
||||||
let mut use_sets: IndexMap<Rc<String>, OccurrenceSet> = IndexMap::new();
|
|
||||||
|
|
||||||
for (var, &mut (ref mut var_status, _)) in self.iter_mut() {
|
|
||||||
if let &mut VarStatus::Temp(_, ref mut var_data) = var_status {
|
|
||||||
let mut use_set = OccurrenceSet::new();
|
|
||||||
|
|
||||||
swap(&mut var_data.use_set, &mut use_set);
|
|
||||||
use_sets.insert((*var).clone(), use_set);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (u, use_set) in use_sets.drain(..) {
|
|
||||||
// 2.
|
|
||||||
for &(term_loc, reg) in use_set.iter() {
|
|
||||||
if let GenContext::Last(cn_u) = term_loc {
|
|
||||||
for (ref t, &mut (ref mut var_status, _)) in self.iter_mut() {
|
|
||||||
if let &mut VarStatus::Temp(cn_t, ref mut t_data) = var_status {
|
|
||||||
if cn_u == cn_t && *u != ***t {
|
|
||||||
if !t_data.uses_reg(reg) {
|
|
||||||
t_data.no_use_set.insert(reg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3.
|
|
||||||
match self.get_mut(u).unwrap() {
|
|
||||||
&mut (VarStatus::Temp(_, ref mut u_data), _) => {
|
|
||||||
u_data.use_set = use_set;
|
|
||||||
u_data.populate_conflict_set();
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_mut(&mut self, u: Rc<String>) -> Option<&mut VariableFixture<'a>> {
|
|
||||||
self.perm_vars.get_mut(&u)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn iter_mut(&mut self) -> indexmap::map::IterMut<Rc<String>, VariableFixture<'a>> {
|
|
||||||
self.perm_vars.iter_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn record_temp_info(&mut self, tvd: &mut TempVarData, arg_c: usize, term_loc: GenContext) {
|
|
||||||
match term_loc {
|
|
||||||
GenContext::Head | GenContext::Last(_) => {
|
|
||||||
tvd.use_set.insert((term_loc, arg_c));
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn vars_above_threshold(&self, index: usize) -> usize {
|
|
||||||
let mut var_count = 0;
|
|
||||||
|
|
||||||
for &(ref var_status, _) in self.values() {
|
|
||||||
if let &VarStatus::Perm(i) = var_status {
|
|
||||||
if i > index {
|
|
||||||
var_count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var_count
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn mark_vars_in_chunk<I>(&mut self, iter: I, lt_arity: usize, term_loc: GenContext)
|
|
||||||
where
|
|
||||||
I: Iterator<Item = TermRef<'a>>,
|
|
||||||
{
|
|
||||||
let chunk_num = term_loc.chunk_num();
|
|
||||||
let mut arg_c = 1;
|
|
||||||
|
|
||||||
for term_ref in iter {
|
|
||||||
if let &TermRef::Var(lvl, cell, ref var) = &term_ref {
|
|
||||||
let mut status = self.perm_vars.swap_remove(var).unwrap_or((
|
|
||||||
VarStatus::Temp(chunk_num, TempVarData::new(lt_arity)),
|
|
||||||
Vec::new(),
|
|
||||||
));
|
|
||||||
|
|
||||||
status.1.push(cell);
|
|
||||||
|
|
||||||
match status.0 {
|
|
||||||
VarStatus::Temp(cn, ref mut tvd) if cn == chunk_num => {
|
|
||||||
if let Level::Shallow = lvl {
|
|
||||||
self.record_temp_info(tvd, arg_c, term_loc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => status.0 = VarStatus::Perm(chunk_num),
|
|
||||||
};
|
|
||||||
|
|
||||||
self.perm_vars.insert(var.clone(), status);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Level::Shallow = term_ref.level() {
|
|
||||||
arg_c += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn into_iter(self) -> indexmap::map::IntoIter<Rc<String>, VariableFixture<'a>> {
|
|
||||||
self.perm_vars.into_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn values(&self) -> indexmap::map::Values<Rc<String>, VariableFixture<'a>> {
|
|
||||||
self.perm_vars.values()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn size(&self) -> usize {
|
|
||||||
self.perm_vars.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn set_perm_vals(&self, has_deep_cuts: bool) {
|
|
||||||
let mut values_vec: Vec<_> = self
|
|
||||||
.values()
|
|
||||||
.filter_map(|ref v| match &v.0 {
|
|
||||||
&VarStatus::Perm(i) => Some((i, &v.1)),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
values_vec.sort_by_key(|ref v| v.0);
|
|
||||||
|
|
||||||
let offset = has_deep_cuts as usize;
|
|
||||||
|
|
||||||
for (i, (_, cells)) in values_vec.into_iter().rev().enumerate() {
|
|
||||||
for cell in cells {
|
|
||||||
cell.set(VarReg::Norm(RegType::Perm(i + 1 + offset)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) struct UnsafeVarMarker {
|
|
||||||
pub(crate) unsafe_perm_vars: IndexMap<usize, usize>,
|
|
||||||
pub(crate) unsafe_temp_vars: IndexSet<usize>,
|
|
||||||
pub(crate) safe_perm_vars: IndexSet<usize>,
|
|
||||||
pub(crate) safe_temp_vars: IndexSet<usize>,
|
|
||||||
pub(crate) temp_vars_to_perm_vars: IndexMap<usize, usize>,
|
|
||||||
pub(crate) perm_vars_to_temp_vars: IndexMap<usize, usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UnsafeVarMarker {
|
|
||||||
pub(crate) fn new() -> Self {
|
|
||||||
UnsafeVarMarker {
|
|
||||||
unsafe_perm_vars: IndexMap::new(),
|
|
||||||
unsafe_temp_vars: IndexSet::new(),
|
|
||||||
safe_perm_vars: IndexSet::new(),
|
|
||||||
safe_temp_vars: IndexSet::new(),
|
|
||||||
temp_vars_to_perm_vars: IndexMap::new(),
|
|
||||||
perm_vars_to_temp_vars: IndexMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn from_fact_vars(safe_vars: IndexSet<RegType>) -> Self {
|
|
||||||
let mut unsafe_var_marker = Self::new();
|
|
||||||
|
|
||||||
for r in safe_vars {
|
|
||||||
unsafe_var_marker.mark_var_as_safe(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe_var_marker
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_var_as_safe(&mut self, r: RegType) {
|
|
||||||
match r {
|
|
||||||
RegType::Temp(t) => {
|
|
||||||
self.safe_temp_vars.insert(t);
|
|
||||||
}
|
|
||||||
RegType::Perm(p) => {
|
|
||||||
self.safe_perm_vars.insert(p);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_var_as_unsafe(&mut self, r: RegType, phase: usize) {
|
|
||||||
match r {
|
|
||||||
RegType::Temp(t) => {
|
|
||||||
self.unsafe_temp_vars.insert(t);
|
|
||||||
}
|
|
||||||
RegType::Perm(p) => {
|
|
||||||
self.unsafe_perm_vars.insert(p, phase);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns true if the instruction at *query_instr cannot be
|
|
||||||
// changed by mark_unsafe_vars.
|
|
||||||
fn mark_safe_vars(&mut self, query_instr: &Instruction) -> bool {
|
|
||||||
match query_instr {
|
|
||||||
&Instruction::PutVariable(r @ RegType::Temp(_), _) |
|
|
||||||
&Instruction::SetVariable(r) => {
|
|
||||||
self.mark_var_as_safe(r);
|
|
||||||
true
|
|
||||||
}
|
|
||||||
&Instruction::PutVariable(RegType::Perm(p), t) => {
|
|
||||||
self.temp_vars_to_perm_vars.insert(t, p);
|
|
||||||
true
|
|
||||||
}
|
|
||||||
&Instruction::CallIs(RegType::Temp(t), ..) => {
|
|
||||||
if let Some(p) = self.temp_vars_to_perm_vars.get(&t) {
|
|
||||||
self.mark_var_as_safe(RegType::Perm(*p));
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_phase(&mut self, query_instr: &Instruction, phase: usize) {
|
|
||||||
match query_instr {
|
|
||||||
&Instruction::PutValue(r @ RegType::Perm(_), _) |
|
|
||||||
&Instruction::SetValue(r) => {
|
|
||||||
self.mark_var_as_unsafe(r, phase);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_unsafe_perm_vars(&mut self, query_instr: &mut Instruction, phase: usize) {
|
|
||||||
match query_instr {
|
|
||||||
&mut Instruction::PutValue(RegType::Perm(p), arg)
|
|
||||||
if !self.safe_perm_vars.contains(&p) => {
|
|
||||||
if let Some(ph) = self.unsafe_perm_vars.swap_remove(&p) {
|
|
||||||
if ph == phase {
|
|
||||||
*query_instr = Instruction::PutUnsafeValue(p, arg);
|
|
||||||
self.perm_vars_to_temp_vars.insert(p, arg);
|
|
||||||
} else {
|
|
||||||
self.unsafe_perm_vars.insert(p, ph);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&mut Instruction::SetValue(r @ RegType::Perm(p)) =>
|
|
||||||
if let Some(t) = self.perm_vars_to_temp_vars.get(&p) {
|
|
||||||
*query_instr = Instruction::SetValue(RegType::Temp(*t));
|
|
||||||
} else {
|
|
||||||
*query_instr = Instruction::SetLocalValue(r);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_unsafe_temp_vars(&mut self, query_instr: &mut Instruction) {
|
|
||||||
match query_instr {
|
|
||||||
&mut Instruction::SetValue(r @ RegType::Temp(t))
|
|
||||||
if !self.safe_temp_vars.contains(&t) => {
|
|
||||||
*query_instr = Instruction::SetLocalValue(r);
|
|
||||||
|
|
||||||
self.safe_temp_vars.insert(t);
|
|
||||||
self.unsafe_temp_vars.remove(&t);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear_temp_vars(&mut self) {
|
|
||||||
self.safe_temp_vars.clear();
|
|
||||||
self.unsafe_temp_vars.clear();
|
|
||||||
self.temp_vars_to_perm_vars.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn mark_unsafe_instrs(&mut self, code: &mut Code) {
|
|
||||||
if code.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut code_index = 0;
|
|
||||||
|
|
||||||
for phase in 0.. {
|
|
||||||
while code[code_index].is_query_instr() {
|
|
||||||
let query_instr = &mut code[code_index];
|
|
||||||
|
|
||||||
if !self.mark_safe_vars(query_instr) {
|
|
||||||
self.mark_phase(query_instr, phase);
|
|
||||||
self.mark_unsafe_temp_vars(query_instr);
|
|
||||||
}
|
|
||||||
|
|
||||||
code_index += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while code_index < code.len() && !code[code_index].is_query_instr() {
|
|
||||||
self.mark_safe_vars(&code[code_index]);
|
|
||||||
code_index += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.clear_temp_vars();
|
|
||||||
|
|
||||||
if code_index >= code.len() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
code_index = 0;
|
|
||||||
|
|
||||||
for phase in 0.. {
|
|
||||||
while code[code_index].is_query_instr() {
|
|
||||||
let query_instr = &mut code[code_index];
|
|
||||||
self.mark_unsafe_perm_vars(query_instr, phase);
|
|
||||||
code_index += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensure phase->instruction assignments match those of
|
|
||||||
// the previous for loop.
|
|
||||||
while code_index < code.len() && !code[code_index].is_query_instr() {
|
|
||||||
code_index += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if code_index >= code.len() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
172
src/forms.rs
172
src/forms.rs
@@ -1,6 +1,7 @@
|
|||||||
use crate::arena::*;
|
use crate::arena::*;
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
use crate::instructions::*;
|
use crate::instructions::*;
|
||||||
|
use crate::machine::disjuncts::VarData;
|
||||||
use crate::machine::heap::*;
|
use crate::machine::heap::*;
|
||||||
use crate::machine::loader::PredicateQueue;
|
use crate::machine::loader::PredicateQueue;
|
||||||
use crate::machine::machine_errors::*;
|
use crate::machine::machine_errors::*;
|
||||||
@@ -19,26 +20,23 @@ use std::cell::Cell;
|
|||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::AddAssign;
|
use std::ops::{AddAssign, Deref, DerefMut};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use crate::{is_infix, is_postfix};
|
use crate::{is_infix, is_postfix};
|
||||||
|
|
||||||
pub type PredicateKey = (Atom, usize); // name, arity.
|
pub type PredicateKey = (Atom, usize); // name, arity.
|
||||||
|
|
||||||
pub type Predicate = Vec<PredicateClause>;
|
/*
|
||||||
|
|
||||||
// vars of predicate, toplevel offset. Vec<Term> is always a vector
|
// vars of predicate, toplevel offset. Vec<Term> is always a vector
|
||||||
// of vars (we get their adjoining cells this way).
|
// of vars (we get their adjoining cells this way).
|
||||||
pub type JumpStub = Vec<Term>;
|
pub type JumpStub = Vec<Term>;
|
||||||
|
*/
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
pub enum TopLevel {
|
pub enum TopLevel {
|
||||||
Fact(Term), // Term, line_num, col_num
|
Fact(Fact, VarData), // Term, line_num, col_num
|
||||||
Predicate(Predicate),
|
Rule(Rule, VarData), // Rule, line_num, col_num
|
||||||
Query(Vec<QueryTerm>),
|
|
||||||
Rule(Rule), // Rule, line_num, col_num
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
@@ -57,7 +55,7 @@ impl AppendOrPrepend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub enum Level {
|
pub enum Level {
|
||||||
Deep,
|
Deep,
|
||||||
Root,
|
Root,
|
||||||
@@ -79,38 +77,144 @@ pub enum CallPolicy {
|
|||||||
Counted,
|
Counted,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub enum ChunkType {
|
||||||
|
Head,
|
||||||
|
Mid,
|
||||||
|
Last,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum RootIterationPolicy {
|
||||||
|
Iterated,
|
||||||
|
NotIterated,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RootIterationPolicy {
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn iterable(&self) -> bool {
|
||||||
|
if let RootIterationPolicy::Iterated = self {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChunkType {
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn to_gen_context(self, chunk_num: usize) -> GenContext {
|
||||||
|
match self {
|
||||||
|
ChunkType::Head => GenContext::Head,
|
||||||
|
ChunkType::Mid => GenContext::Mid(chunk_num),
|
||||||
|
ChunkType::Last => GenContext::Last(chunk_num),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn is_last(self) -> bool {
|
||||||
|
self == ChunkType::Last
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ChunkedTerms {
|
||||||
|
Branch(Vec<VecDeque<ChunkedTerms>>),
|
||||||
|
Chunk(VecDeque<QueryTerm>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ChunkedTermVec {
|
||||||
|
pub chunk_vec: VecDeque<ChunkedTerms>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for ChunkedTermVec {
|
||||||
|
type Target = VecDeque<ChunkedTerms>;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.chunk_vec
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for ChunkedTermVec {
|
||||||
|
#[inline(always)]
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.chunk_vec
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChunkedTermVec {
|
||||||
|
#[inline]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { chunk_vec: VecDeque::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reserve_branch(&mut self, capacity: usize) {
|
||||||
|
self.chunk_vec.push_back(ChunkedTerms::Branch(Vec::with_capacity(capacity)));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_branch_arm(&mut self, branch: VecDeque<ChunkedTerms>) {
|
||||||
|
match self.chunk_vec.back_mut().unwrap() {
|
||||||
|
ChunkedTerms::Branch(branches) => {
|
||||||
|
branches.push(branch);
|
||||||
|
}
|
||||||
|
ChunkedTerms::Chunk(_) => {
|
||||||
|
self.chunk_vec.push_back(ChunkedTerms::Branch(vec![branch]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn add_chunk(&mut self) {
|
||||||
|
self.chunk_vec.push_back(ChunkedTerms::Chunk(VecDeque::from(vec![])));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_chunk_term(&mut self, term: QueryTerm) {
|
||||||
|
match self.chunk_vec.back_mut() {
|
||||||
|
Some(ChunkedTerms::Branch(_)) => {
|
||||||
|
self.chunk_vec.push_back(ChunkedTerms::Chunk(VecDeque::from(vec![term])));
|
||||||
|
}
|
||||||
|
Some(ChunkedTerms::Chunk(chunk)) => {
|
||||||
|
chunk.push_back(term);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
self.chunk_vec.push_back(ChunkedTerms::Chunk(VecDeque::from(vec![term])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum QueryTerm {
|
pub enum QueryTerm {
|
||||||
// register, clause type, subterms, clause call policy.
|
// register, clause type, subterms, clause call policy.
|
||||||
Clause(Cell<RegType>, ClauseType, Vec<Term>, CallPolicy),
|
Clause(Cell<RegType>, ClauseType, Vec<Term>, CallPolicy),
|
||||||
BlockedCut, // a cut which is 'blocked by letters', like the P term in P -> Q.
|
Fail,
|
||||||
UnblockedCut(Cell<VarReg>),
|
LocalCut(usize), // var_num
|
||||||
GetLevelAndUnify(Cell<VarReg>, Rc<String>),
|
GlobalCut(usize), // var_num
|
||||||
Jump(JumpStub),
|
GetCutPoint { var_num: usize, prev_b: bool },
|
||||||
|
GetLevel(usize), // var_num
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QueryTerm {
|
impl QueryTerm {
|
||||||
pub(crate) fn set_call_policy(&mut self, cp: CallPolicy) {
|
|
||||||
match self {
|
|
||||||
&mut QueryTerm::Clause(_, _, _, ref mut clause_cp) => *clause_cp = cp,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn arity(&self) -> usize {
|
pub(crate) fn arity(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
&QueryTerm::Clause(_, _, ref subterms, ..) => subterms.len(),
|
&QueryTerm::Clause(_, _, ref subterms, ..) => subterms.len(),
|
||||||
&QueryTerm::BlockedCut | &QueryTerm::UnblockedCut(..) => 0,
|
&QueryTerm::GetLevel(_) | &QueryTerm::GetCutPoint { .. } => 1,
|
||||||
&QueryTerm::Jump(ref vars) => vars.len(),
|
_ => 0,
|
||||||
&QueryTerm::GetLevelAndUnify(..) => 1,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
|
pub struct Fact {
|
||||||
|
pub(crate) head: Term,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Rule {
|
pub struct Rule {
|
||||||
pub(crate) head: (Atom, Vec<Term>, QueryTerm),
|
pub(crate) head: (Atom, Vec<Term>),
|
||||||
pub(crate) clauses: Vec<QueryTerm>,
|
pub(crate) clauses: ChunkedTermVec,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Hash)]
|
#[derive(Clone, Debug, Hash)]
|
||||||
@@ -201,29 +305,29 @@ impl ClauseInfo for Rule {
|
|||||||
impl ClauseInfo for PredicateClause {
|
impl ClauseInfo for PredicateClause {
|
||||||
fn name(&self) -> Option<Atom> {
|
fn name(&self) -> Option<Atom> {
|
||||||
match self {
|
match self {
|
||||||
&PredicateClause::Fact(ref term, ..) => term.name(),
|
&PredicateClause::Fact(ref term, ..) => term.head.name(),
|
||||||
&PredicateClause::Rule(ref rule, ..) => rule.name(),
|
&PredicateClause::Rule(ref rule, ..) => rule.name(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn arity(&self) -> usize {
|
fn arity(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
&PredicateClause::Fact(ref term, ..) => term.arity(),
|
&PredicateClause::Fact(ref term, ..) => term.head.arity(),
|
||||||
&PredicateClause::Rule(ref rule, ..) => rule.arity(),
|
&PredicateClause::Rule(ref rule, ..) => rule.arity(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
pub enum PredicateClause {
|
pub enum PredicateClause {
|
||||||
Fact(Term),
|
Fact(Fact, VarData),
|
||||||
Rule(Rule),
|
Rule(Rule, VarData),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PredicateClause {
|
impl PredicateClause {
|
||||||
pub(crate) fn args(&self) -> Option<&[Term]> {
|
pub(crate) fn args(&self) -> Option<&[Term]> {
|
||||||
match self {
|
match self {
|
||||||
PredicateClause::Fact(term, ..) => match term {
|
PredicateClause::Fact(term, ..) => match &term.head {
|
||||||
Term::Clause(_, _, args) => Some(&args),
|
Term::Clause(_, _, args) => Some(&args),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -481,7 +481,7 @@ pub struct HCPrinter<'a, Outputter> {
|
|||||||
state_stack: Vec<TokenOrRedirect>,
|
state_stack: Vec<TokenOrRedirect>,
|
||||||
toplevel_spec: Option<DirectedOp>,
|
toplevel_spec: Option<DirectedOp>,
|
||||||
last_item_idx: usize,
|
last_item_idx: usize,
|
||||||
pub var_names: IndexMap<HeapCellValue, Rc<String>>,
|
pub var_names: IndexMap<HeapCellValue, VarPtr>,
|
||||||
pub numbervars_offset: Integer,
|
pub numbervars_offset: Integer,
|
||||||
pub numbervars: bool,
|
pub numbervars: bool,
|
||||||
pub quoted: bool,
|
pub quoted: bool,
|
||||||
@@ -815,7 +815,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
if let Some(var) = self.var_names.get(&cell) {
|
if let Some(var) = self.var_names.get(&cell) {
|
||||||
read_heap_cell!(cell,
|
read_heap_cell!(cell,
|
||||||
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
|
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
|
||||||
return Some(format!("{}", var.as_str()));
|
return Some(var.borrow().to_string());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.iter.push_stack(h);
|
self.iter.push_stack(h);
|
||||||
@@ -858,10 +858,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
// short-circuits handle_heap_term.
|
// short-circuits handle_heap_term.
|
||||||
// self.iter.pop_stack();
|
// self.iter.pop_stack();
|
||||||
|
|
||||||
let var_str = var.as_str();
|
let var_str = var.borrow().to_string();
|
||||||
|
|
||||||
push_space_if_amb!(self, var_str, {
|
push_space_if_amb!(self, &var_str, {
|
||||||
append_str!(self, var_str);
|
append_str!(self, &var_str);
|
||||||
});
|
});
|
||||||
|
|
||||||
None
|
None
|
||||||
@@ -873,8 +873,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
Some(var) => {
|
Some(var) => {
|
||||||
// If the term is bound to a named variable,
|
// If the term is bound to a named variable,
|
||||||
// print the variable's name to output.
|
// print the variable's name to output.
|
||||||
push_space_if_amb!(self, &var, {
|
let var_str = var.borrow().to_string();
|
||||||
append_str!(self, &var);
|
|
||||||
|
push_space_if_amb!(self, &var_str, {
|
||||||
|
append_str!(self, &var_str);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@@ -1739,9 +1741,7 @@ mod tests {
|
|||||||
heap_loc_as_cell!(0)
|
heap_loc_as_cell!(0)
|
||||||
);
|
);
|
||||||
|
|
||||||
printer
|
printer.var_names.insert(list_loc_as_cell!(1), VarPtr::from("L"));
|
||||||
.var_names
|
|
||||||
.insert(list_loc_as_cell!(1), Rc::new("L".to_string()));
|
|
||||||
|
|
||||||
let output = printer.print();
|
let output = printer.print();
|
||||||
|
|
||||||
@@ -1808,9 +1808,7 @@ mod tests {
|
|||||||
heap_loc_as_cell!(0)
|
heap_loc_as_cell!(0)
|
||||||
);
|
);
|
||||||
|
|
||||||
printer
|
printer.var_names.insert(list_loc_as_cell!(1), VarPtr::from("L"));
|
||||||
.var_names
|
|
||||||
.insert(list_loc_as_cell!(1), Rc::new("L".to_string()));
|
|
||||||
|
|
||||||
let output = printer.print();
|
let output = printer.print();
|
||||||
|
|
||||||
|
|||||||
360
src/iterators.rs
360
src/iterators.rs
@@ -5,9 +5,7 @@ use crate::parser::ast::*;
|
|||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::fmt;
|
|
||||||
use std::iter::*;
|
use std::iter::*;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -18,34 +16,36 @@ pub(crate) enum TermRef<'a> {
|
|||||||
Clause(Level, &'a Cell<RegType>, Atom, &'a Vec<Term>),
|
Clause(Level, &'a Cell<RegType>, Atom, &'a Vec<Term>),
|
||||||
PartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
|
PartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
|
||||||
CompleteString(Level, &'a Cell<RegType>, Atom),
|
CompleteString(Level, &'a Cell<RegType>, Atom),
|
||||||
Var(Level, &'a Cell<VarReg>, Rc<String>),
|
Var(Level, &'a Cell<VarReg>, VarPtr),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
impl<'a> TermRef<'a> {
|
impl<'a> TermRef<'a> {
|
||||||
pub(crate) fn level(self) -> Level {
|
pub(crate) fn level(&self) -> Level {
|
||||||
match self {
|
match self {
|
||||||
TermRef::AnonVar(lvl)
|
TermRef::AnonVar(lvl) |
|
||||||
| TermRef::Cons(lvl, ..)
|
TermRef::Cons(lvl, ..) |
|
||||||
| TermRef::Literal(lvl, ..)
|
TermRef::Literal(lvl, ..) |
|
||||||
| TermRef::Var(lvl, ..)
|
TermRef::Var(lvl, ..) |
|
||||||
| TermRef::Clause(lvl, ..)
|
TermRef::Clause(lvl, ..) |
|
||||||
| TermRef::CompleteString(lvl, ..)
|
TermRef::CompleteString(lvl, ..) |
|
||||||
| TermRef::PartialString(lvl, ..) => lvl,
|
TermRef::PartialString(lvl, ..) => *lvl,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum TermIterState<'a> {
|
pub(crate) enum TermIterState<'a> {
|
||||||
AnonVar(Level),
|
AnonVar(Level),
|
||||||
Literal(Level, &'a Cell<RegType>, &'a Literal),
|
|
||||||
Clause(Level, usize, &'a Cell<RegType>, Atom, &'a Vec<Term>),
|
Clause(Level, usize, &'a Cell<RegType>, Atom, &'a Vec<Term>),
|
||||||
|
Literal(Level, &'a Cell<RegType>, &'a Literal),
|
||||||
InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||||
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||||
InitialPartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
|
InitialPartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
|
||||||
FinalPartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
|
FinalPartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
|
||||||
CompleteString(Level, &'a Cell<RegType>, Atom),
|
CompleteString(Level, &'a Cell<RegType>, Atom),
|
||||||
Var(Level, &'a Cell<VarReg>, Rc<String>),
|
Var(Level, &'a Cell<VarReg>, VarPtr),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TermIterState<'a> {
|
impl<'a> TermIterState<'a> {
|
||||||
@@ -65,7 +65,7 @@ impl<'a> TermIterState<'a> {
|
|||||||
Term::CompleteString(cell, atom) => {
|
Term::CompleteString(cell, atom) => {
|
||||||
TermIterState::CompleteString(lvl, cell, *atom)
|
TermIterState::CompleteString(lvl, cell, *atom)
|
||||||
}
|
}
|
||||||
Term::Var(cell, var) => TermIterState::Var(lvl, cell, var.clone()),
|
Term::Var(cell, var_ptr) => TermIterState::Var(lvl, cell, var_ptr.clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,10 +77,10 @@ pub(crate) struct QueryIterator<'a> {
|
|||||||
|
|
||||||
impl<'a> QueryIterator<'a> {
|
impl<'a> QueryIterator<'a> {
|
||||||
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
||||||
self.state_stack
|
self.state_stack.push(TermIterState::subterm_to_state(lvl, term));
|
||||||
.push(TermIterState::subterm_to_state(lvl, term));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
fn from_rule_head_clause(terms: &'a Vec<Term>) -> Self {
|
fn from_rule_head_clause(terms: &'a Vec<Term>) -> Self {
|
||||||
let state_stack = terms
|
let state_stack = terms
|
||||||
.iter()
|
.iter()
|
||||||
@@ -90,6 +90,7 @@ impl<'a> QueryIterator<'a> {
|
|||||||
|
|
||||||
QueryIterator { state_stack }
|
QueryIterator { state_stack }
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
fn from_term(term: &'a Term) -> Self {
|
fn from_term(term: &'a Term) -> Self {
|
||||||
let state = match term {
|
let state = match term {
|
||||||
@@ -106,7 +107,7 @@ impl<'a> QueryIterator<'a> {
|
|||||||
*name,
|
*name,
|
||||||
terms,
|
terms,
|
||||||
),
|
),
|
||||||
Term::Var(cell, var) => TermIterState::Var(Level::Root, cell, var.clone()),
|
Term::Var(cell, var_ptr) => TermIterState::Var(Level::Root, cell, var_ptr.clone()),
|
||||||
};
|
};
|
||||||
|
|
||||||
QueryIterator {
|
QueryIterator {
|
||||||
@@ -114,46 +115,24 @@ impl<'a> QueryIterator<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(term: &'a QueryTerm) -> Self {
|
fn extend_state(&mut self, lvl: Level, term: &'a QueryTerm) {
|
||||||
match term {
|
match term {
|
||||||
&QueryTerm::Clause(ref cell, ClauseType::CallN(_), ref terms, _) => {
|
&QueryTerm::Clause(ref cell, ClauseType::CallN(_), ref terms, _) => {
|
||||||
let state = TermIterState::Clause(Level::Root, 1, cell, atom!("$call"), terms);
|
self.state_stack.push(TermIterState::Clause(lvl, 1, cell, atom!("$call"), terms));
|
||||||
QueryIterator {
|
|
||||||
state_stack: vec![state],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
&QueryTerm::Clause(ref cell, ref ct, ref terms, _) => {
|
&QueryTerm::Clause(ref cell, ref ct, ref terms, _) => {
|
||||||
let state = TermIterState::Clause(Level::Root, 0, cell, ct.name(), terms);
|
self.state_stack.push(TermIterState::Clause(lvl, 0, cell, ct.name(), terms));
|
||||||
QueryIterator {
|
|
||||||
state_stack: vec![state],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
&QueryTerm::UnblockedCut(ref cell) => {
|
_ => {
|
||||||
let state = TermIterState::Var(Level::Root, cell, Rc::new("!".to_string()));
|
|
||||||
QueryIterator {
|
|
||||||
state_stack: vec![state],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
&QueryTerm::GetLevelAndUnify(ref cell, ref var) => {
|
|
||||||
let state = TermIterState::Var(Level::Root, cell, var.clone());
|
|
||||||
QueryIterator {
|
|
||||||
state_stack: vec![state],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&QueryTerm::Jump(ref vars) => {
|
|
||||||
let state_stack = vars
|
|
||||||
.iter()
|
|
||||||
.rev()
|
|
||||||
.map(|t| TermIterState::subterm_to_state(Level::Shallow, t))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
QueryIterator { state_stack }
|
|
||||||
}
|
|
||||||
&QueryTerm::BlockedCut => QueryIterator {
|
|
||||||
state_stack: vec![],
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new(term: &'a QueryTerm) -> Self {
|
||||||
|
let mut iter = QueryIterator { state_stack: vec![] };
|
||||||
|
iter.extend_state(Level::Root, term);
|
||||||
|
iter
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for QueryIterator<'a> {
|
impl<'a> Iterator for QueryIterator<'a> {
|
||||||
@@ -212,8 +191,8 @@ impl<'a> Iterator for QueryIterator<'a> {
|
|||||||
TermIterState::Literal(lvl, cell, constant) => {
|
TermIterState::Literal(lvl, cell, constant) => {
|
||||||
return Some(TermRef::Literal(lvl, cell, constant));
|
return Some(TermRef::Literal(lvl, cell, constant));
|
||||||
}
|
}
|
||||||
TermIterState::Var(lvl, cell, var) => {
|
TermIterState::Var(lvl, cell, var_ptr) => {
|
||||||
return Some(TermRef::Var(lvl, cell, var));
|
return Some(TermRef::Var(lvl, cell, var_ptr));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -225,7 +204,7 @@ impl<'a> Iterator for QueryIterator<'a> {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct FactIterator<'a> {
|
pub(crate) struct FactIterator<'a> {
|
||||||
state_queue: VecDeque<TermIterState<'a>>,
|
state_queue: VecDeque<TermIterState<'a>>,
|
||||||
iterable_root: bool,
|
iterable_root: RootIterationPolicy,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FactIterator<'a> {
|
impl<'a> FactIterator<'a> {
|
||||||
@@ -242,11 +221,11 @@ impl<'a> FactIterator<'a> {
|
|||||||
|
|
||||||
FactIterator {
|
FactIterator {
|
||||||
state_queue,
|
state_queue,
|
||||||
iterable_root: false,
|
iterable_root: RootIterationPolicy::NotIterated,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(term: &'a Term, iterable_root: bool) -> Self {
|
fn new(term: &'a Term, iterable_root: RootIterationPolicy) -> Self {
|
||||||
let states = match term {
|
let states = match term {
|
||||||
Term::AnonVar => {
|
Term::AnonVar => {
|
||||||
vec![TermIterState::AnonVar(Level::Root)]
|
vec![TermIterState::AnonVar(Level::Root)]
|
||||||
@@ -278,8 +257,8 @@ impl<'a> FactIterator<'a> {
|
|||||||
Term::Literal(cell, constant) => {
|
Term::Literal(cell, constant) => {
|
||||||
vec![TermIterState::Literal(Level::Root, cell, constant)]
|
vec![TermIterState::Literal(Level::Root, cell, constant)]
|
||||||
}
|
}
|
||||||
Term::Var(cell, var) => {
|
Term::Var(cell, var_ptr) => {
|
||||||
vec![TermIterState::Var(Level::Root, cell, var.clone())]
|
vec![TermIterState::Var(Level::Root, cell, var_ptr.clone())]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -305,7 +284,7 @@ impl<'a> Iterator for FactIterator<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match lvl {
|
match lvl {
|
||||||
Level::Root if !self.iterable_root => continue,
|
Level::Root if !self.iterable_root.iterable() => continue,
|
||||||
_ => return Some(TermRef::Clause(lvl, cell, name, child_terms)),
|
_ => return Some(TermRef::Clause(lvl, cell, name, child_terms)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -325,8 +304,8 @@ impl<'a> Iterator for FactIterator<'a> {
|
|||||||
TermIterState::Literal(lvl, cell, constant) => {
|
TermIterState::Literal(lvl, cell, constant) => {
|
||||||
return Some(TermRef::Literal(lvl, cell, constant))
|
return Some(TermRef::Literal(lvl, cell, constant))
|
||||||
}
|
}
|
||||||
TermIterState::Var(lvl, cell, var) => {
|
TermIterState::Var(lvl, cell, var_ptr) => {
|
||||||
return Some(TermRef::Var(lvl, cell, var));
|
return Some(TermRef::Var(lvl, cell, var_ptr));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -340,193 +319,130 @@ pub(crate) fn post_order_iter<'a>(term: &'a Term) -> QueryIterator<'a> {
|
|||||||
QueryIterator::from_term(term)
|
QueryIterator::from_term(term)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn breadth_first_iter<'a>(term: &'a Term, iterable_root: bool) -> FactIterator<'a> {
|
pub(crate) fn breadth_first_iter<'a>(term: &'a Term, iterable_root: RootIterationPolicy) -> FactIterator<'a> {
|
||||||
FactIterator::new(term, iterable_root)
|
FactIterator::new(term, iterable_root)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
enum ClauseIteratorState<'a> {
|
||||||
|
RemainingChunks(&'a VecDeque<ChunkedTerms>, usize),
|
||||||
|
RemainingBranches(&'a Vec<VecDeque<ChunkedTerms>>, usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) enum ClauseItem<'a> {
|
||||||
|
FirstBranch(usize),
|
||||||
|
NextBranch,
|
||||||
|
BranchEnd(usize),
|
||||||
|
Chunk(&'a VecDeque<QueryTerm>),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum ChunkedTerm<'a> {
|
pub(crate) struct ClauseIterator<'a> {
|
||||||
HeadClause(Atom, &'a Vec<Term>),
|
state_stack: Vec<ClauseIteratorState<'a>>,
|
||||||
BodyTerm(&'a QueryTerm),
|
remaining_chunks_on_stack: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn query_term_post_order_iter<'a>(query_term: &'a QueryTerm) -> QueryIterator<'a> {
|
fn state_from_chunked_terms<'a>(chunk_vec: &'a VecDeque<ChunkedTerms>) -> ClauseIteratorState<'a> {
|
||||||
QueryIterator::new(query_term)
|
if chunk_vec.len() == 1 {
|
||||||
}
|
if let Some(ChunkedTerms::Branch(ref branches)) = chunk_vec.front() {
|
||||||
|
return ClauseIteratorState::RemainingBranches(branches, 0);
|
||||||
impl<'a> ChunkedTerm<'a> {
|
|
||||||
pub(crate) fn post_order_iter(&self) -> QueryIterator<'a> {
|
|
||||||
match self {
|
|
||||||
&ChunkedTerm::BodyTerm(qt) => QueryIterator::new(qt),
|
|
||||||
&ChunkedTerm::HeadClause(_, terms) => QueryIterator::from_rule_head_clause(terms),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClauseIteratorState::RemainingChunks(chunk_vec, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contains_cut_var<'a, Iter: Iterator<Item = &'a Term>>(terms: Iter) -> bool {
|
impl<'a> ClauseIterator<'a> {
|
||||||
for term in terms {
|
pub fn new(clauses: &'a ChunkedTermVec) -> Self {
|
||||||
if let &Term::Var(_, ref var) = term {
|
match state_from_chunked_terms(&clauses.chunk_vec) {
|
||||||
if var.as_str() == "!" {
|
state @ ClauseIteratorState::RemainingBranches(..) => {
|
||||||
return true;
|
Self {
|
||||||
|
state_stack: vec![state],
|
||||||
|
remaining_chunks_on_stack: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state @ ClauseIteratorState::RemainingChunks(..) => {
|
||||||
|
Self {
|
||||||
|
state_stack: vec![state],
|
||||||
|
remaining_chunks_on_stack: 1,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
#[inline(always)]
|
||||||
}
|
pub fn in_tail_position(&self) -> bool {
|
||||||
|
self.remaining_chunks_on_stack == 0
|
||||||
pub(crate) struct ChunkedIterator<'a> {
|
|
||||||
pub(crate) chunk_num: usize,
|
|
||||||
iter: Box<dyn Iterator<Item = ChunkedTerm<'a>> + 'a>,
|
|
||||||
deep_cut_encountered: bool,
|
|
||||||
cut_var_in_head: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> fmt::Debug for ChunkedIterator<'a> {
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
fmt.debug_struct("ChunkedIterator")
|
|
||||||
.field("chunk_num", &self.chunk_num)
|
|
||||||
// Hacky solution.
|
|
||||||
.field("iter", &"Box<dyn Iterator<Item = ChunkedTerm<'a>> + 'a>")
|
|
||||||
.field("deep_cut_encountered", &self.deep_cut_encountered)
|
|
||||||
.field("cut_var_in_head", &self.cut_var_in_head)
|
|
||||||
.finish()
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
type ChunkedIteratorItem<'a> = (usize, usize, Vec<ChunkedTerm<'a>>);
|
fn branch_end_depth(&mut self) -> usize {
|
||||||
type RuleBodyIteratorItem<'a> = (usize, usize, Vec<&'a QueryTerm>);
|
let mut depth = 1;
|
||||||
|
|
||||||
impl<'a> ChunkedIterator<'a> {
|
while let Some(state) = self.state_stack.pop() {
|
||||||
pub(crate) fn rule_body_iter(self) -> Box<dyn Iterator<Item = RuleBodyIteratorItem<'a>> + 'a> {
|
match state {
|
||||||
Box::new(self.filter_map(|(cn, lt_arity, terms)| {
|
ClauseIteratorState::RemainingBranches(terms, focus) if terms.len() == focus => {
|
||||||
let filtered_terms: Vec<_> = terms
|
depth += 1;
|
||||||
.into_iter()
|
}
|
||||||
.filter_map(|ct| match ct {
|
_ => {
|
||||||
ChunkedTerm::BodyTerm(qt) => Some(qt),
|
self.state_stack.push(state);
|
||||||
_ => None,
|
break;
|
||||||
})
|
}
|
||||||
.collect();
|
|
||||||
|
|
||||||
if filtered_terms.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some((cn, lt_arity, filtered_terms))
|
|
||||||
}
|
}
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn from_rule_body(p1: &'a QueryTerm, clauses: &'a Vec<QueryTerm>) -> Self {
|
|
||||||
let inner_iter = Box::new(once(ChunkedTerm::BodyTerm(p1)));
|
|
||||||
let iter = inner_iter.chain(clauses.iter().map(|t| ChunkedTerm::BodyTerm(t)));
|
|
||||||
|
|
||||||
ChunkedIterator {
|
|
||||||
chunk_num: 0,
|
|
||||||
iter: Box::new(iter),
|
|
||||||
deep_cut_encountered: false,
|
|
||||||
cut_var_in_head: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn from_rule(rule: &'a Rule) -> Self {
|
|
||||||
let &Rule {
|
|
||||||
head: (ref name, ref args, ref p1),
|
|
||||||
ref clauses,
|
|
||||||
} = rule;
|
|
||||||
|
|
||||||
let iter = once(ChunkedTerm::HeadClause(name.clone(), args));
|
|
||||||
let inner_iter = Box::new(once(ChunkedTerm::BodyTerm(p1)));
|
|
||||||
let iter = iter.chain(inner_iter.chain(clauses.iter().map(|t| ChunkedTerm::BodyTerm(t))));
|
|
||||||
|
|
||||||
ChunkedIterator {
|
|
||||||
chunk_num: 0,
|
|
||||||
iter: Box::new(iter),
|
|
||||||
deep_cut_encountered: false,
|
|
||||||
cut_var_in_head: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn encountered_deep_cut(&self) -> bool {
|
|
||||||
self.deep_cut_encountered
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_chunk(&mut self, term: ChunkedTerm<'a>) -> (usize, usize, Vec<ChunkedTerm<'a>>) {
|
|
||||||
let mut arity = 0;
|
|
||||||
let mut item = Some(term);
|
|
||||||
let mut result = Vec::new();
|
|
||||||
|
|
||||||
while let Some(term) = item {
|
|
||||||
match term {
|
|
||||||
ChunkedTerm::HeadClause(_, terms) => {
|
|
||||||
if contains_cut_var(terms.iter()) {
|
|
||||||
self.cut_var_in_head = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
result.push(term);
|
|
||||||
}
|
|
||||||
ChunkedTerm::BodyTerm(&QueryTerm::Jump(ref vars)) => {
|
|
||||||
result.push(term);
|
|
||||||
arity = vars.len();
|
|
||||||
|
|
||||||
if contains_cut_var(vars.iter()) && !self.cut_var_in_head {
|
|
||||||
self.deep_cut_encountered = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ChunkedTerm::BodyTerm(&QueryTerm::BlockedCut) => {
|
|
||||||
result.push(term);
|
|
||||||
|
|
||||||
if self.chunk_num > 0 {
|
|
||||||
self.deep_cut_encountered = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ChunkedTerm::BodyTerm(&QueryTerm::GetLevelAndUnify(..)) => {
|
|
||||||
self.deep_cut_encountered = true;
|
|
||||||
|
|
||||||
result.push(term);
|
|
||||||
arity = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ChunkedTerm::BodyTerm(&QueryTerm::UnblockedCut(..)) => {
|
|
||||||
self.deep_cut_encountered = true;
|
|
||||||
result.push(term);
|
|
||||||
}
|
|
||||||
ChunkedTerm::BodyTerm(&QueryTerm::Clause(_, ClauseType::Inlined(_), ..)) => {
|
|
||||||
result.push(term)
|
|
||||||
}
|
|
||||||
ChunkedTerm::BodyTerm(&QueryTerm::Clause(
|
|
||||||
_,
|
|
||||||
ClauseType::CallN(_),
|
|
||||||
ref subterms,
|
|
||||||
_,
|
|
||||||
)) => {
|
|
||||||
result.push(term);
|
|
||||||
arity = subterms.len() + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ChunkedTerm::BodyTerm(qt) => {
|
|
||||||
result.push(term);
|
|
||||||
arity = qt.arity();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
item = self.iter.next();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let chunk_num = self.chunk_num;
|
depth
|
||||||
self.chunk_num += 1;
|
|
||||||
|
|
||||||
(chunk_num, arity, result)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for ChunkedIterator<'a> {
|
impl<'a> Iterator for ClauseIterator<'a> {
|
||||||
// the chunk number, last term arity, and vector of references.
|
type Item = ClauseItem<'a>;
|
||||||
type Item = ChunkedIteratorItem<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
self.iter.next().map(|term| self.take_chunk(term))
|
while let Some(state) = self.state_stack.pop() {
|
||||||
|
match state {
|
||||||
|
ClauseIteratorState::RemainingChunks(chunks, focus) if focus < chunks.len() => {
|
||||||
|
if focus + 1 < chunks.len() {
|
||||||
|
self.state_stack.push(ClauseIteratorState::RemainingChunks(chunks, focus + 1));
|
||||||
|
} else {
|
||||||
|
self.remaining_chunks_on_stack -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
match &chunks[focus] {
|
||||||
|
ChunkedTerms::Branch(branches) => {
|
||||||
|
self.state_stack.push(ClauseIteratorState::RemainingBranches(branches, 0));
|
||||||
|
}
|
||||||
|
ChunkedTerms::Chunk(chunk) => {
|
||||||
|
return Some(ClauseItem::Chunk(chunk));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ClauseIteratorState::RemainingChunks(chunks, focus) => {
|
||||||
|
debug_assert_eq!(chunks.len(), focus);
|
||||||
|
}
|
||||||
|
ClauseIteratorState::RemainingBranches(branches, focus) if focus < branches.len() => {
|
||||||
|
self.state_stack.push(ClauseIteratorState::RemainingBranches(&branches, focus + 1));
|
||||||
|
let state = state_from_chunked_terms(&branches[focus]);
|
||||||
|
|
||||||
|
if let ClauseIteratorState::RemainingChunks(..) = &state {
|
||||||
|
self.remaining_chunks_on_stack += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.state_stack.push(state);
|
||||||
|
|
||||||
|
return if focus == 0 {
|
||||||
|
Some(ClauseItem::FirstBranch(branches.len()))
|
||||||
|
} else {
|
||||||
|
Some(ClauseItem::NextBranch)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
ClauseIteratorState::RemainingBranches(branches, focus) => {
|
||||||
|
debug_assert_eq!(branches.len(), focus);
|
||||||
|
return Some(ClauseItem::BranchEnd(self.branch_end_depth()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ mod arithmetic;
|
|||||||
pub mod codegen;
|
pub mod codegen;
|
||||||
mod debray_allocator;
|
mod debray_allocator;
|
||||||
mod ffi;
|
mod ffi;
|
||||||
mod fixtures;
|
mod variable_records;
|
||||||
mod forms;
|
mod forms;
|
||||||
mod heap_iter;
|
mod heap_iter;
|
||||||
pub mod heap_print;
|
pub mod heap_print;
|
||||||
|
|||||||
@@ -218,13 +218,13 @@ fail :- '$fail'.
|
|||||||
%% \+(Goal)
|
%% \+(Goal)
|
||||||
%
|
%
|
||||||
% True iff Goal fails
|
% True iff Goal fails
|
||||||
\+ G :- call(G), !, false.
|
\+ G :- call(G), !, '$fail'.
|
||||||
\+ _.
|
\+ _.
|
||||||
|
|
||||||
%% \=(?X, ?Y)
|
%% \=(?X, ?Y)
|
||||||
%
|
%
|
||||||
% True iff X and Y can't be unified
|
% True iff X and Y can't be unified
|
||||||
X \= X :- !, false.
|
X \= X :- !, '$fail'.
|
||||||
_ \= _.
|
_ \= _.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -513,10 +513,12 @@ portray_clause(Stream, Term) :-
|
|||||||
phrase_to_stream(portray_clause_(Term), Stream),
|
phrase_to_stream(portray_clause_(Term), Stream),
|
||||||
flush_output(Stream).
|
flush_output(Stream).
|
||||||
|
|
||||||
|
% called once.
|
||||||
portray_clause_(Term) -->
|
portray_clause_(Term) -->
|
||||||
{ unique_variable_names(Term, VNs) },
|
{ unique_variable_names(Term, VNs) },
|
||||||
portray_(Term, VNs), ".\n".
|
portray_(Term, VNs), ".\n".
|
||||||
|
|
||||||
|
% mysteriously called twice, the second time with the truncated B3.
|
||||||
unique_variable_names(Term, VNs) :-
|
unique_variable_names(Term, VNs) :-
|
||||||
term_variables(Term, Vs),
|
term_variables(Term, Vs),
|
||||||
foldl(var_name, Vs, VNs, 0, _).
|
foldl(var_name, Vs, VNs, 0, _).
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ scc_helper(_, _, _) :-
|
|||||||
|
|
||||||
run_cleaners_with_handling :-
|
run_cleaners_with_handling :-
|
||||||
'$get_scc_cleaner'(C),
|
'$get_scc_cleaner'(C),
|
||||||
'$get_level'(B),
|
'$get_cp'(B),
|
||||||
catch(C, _, true),
|
catch(C, _, true),
|
||||||
'$set_cp_by_default'(B),
|
'$set_cp_by_default'(B),
|
||||||
run_cleaners_with_handling.
|
run_cleaners_with_handling.
|
||||||
@@ -186,7 +186,7 @@ run_cleaners_with_handling :-
|
|||||||
|
|
||||||
run_cleaners_without_handling(Cp) :-
|
run_cleaners_without_handling(Cp) :-
|
||||||
'$get_scc_cleaner'(C),
|
'$get_scc_cleaner'(C),
|
||||||
'$get_level'(B),
|
'$get_cp'(B),
|
||||||
call(C),
|
call(C),
|
||||||
'$set_cp_by_default'(B),
|
'$set_cp_by_default'(B),
|
||||||
run_cleaners_without_handling(Cp).
|
run_cleaners_without_handling(Cp).
|
||||||
@@ -258,7 +258,7 @@ call_with_inference_limit(_, _, R, Bb, B) :-
|
|||||||
'$remove_inference_counter'(B, _),
|
'$remove_inference_counter'(B, _),
|
||||||
( '$get_ball'(Ball),
|
( '$get_ball'(Ball),
|
||||||
'$push_ball_stack',
|
'$push_ball_stack',
|
||||||
'$get_level'(Cp),
|
'$get_cp'(Cp),
|
||||||
'$set_cp_by_default'(Cp)
|
'$set_cp_by_default'(Cp)
|
||||||
; '$remove_call_policy_check'(B),
|
; '$remove_call_policy_check'(B),
|
||||||
'$fail'
|
'$fail'
|
||||||
|
|||||||
@@ -541,6 +541,7 @@ open_file(Path, Stream) :-
|
|||||||
)
|
)
|
||||||
).
|
).
|
||||||
|
|
||||||
|
|
||||||
use_module(Module, Exports, Evacuable) :-
|
use_module(Module, Exports, Evacuable) :-
|
||||||
( var(Module) ->
|
( var(Module) ->
|
||||||
instantiation_error(load/1)
|
instantiation_error(load/1)
|
||||||
@@ -562,12 +563,11 @@ use_module(Module, Exports, Evacuable) :-
|
|||||||
stream_property(Stream, file_name(PathFileName)),
|
stream_property(Stream, file_name(PathFileName)),
|
||||||
file_load(Stream, PathFileName, Subevacuable),
|
file_load(Stream, PathFileName, Subevacuable),
|
||||||
'$use_module'(Evacuable, Subevacuable, Exports)
|
'$use_module'(Evacuable, Subevacuable, Exports)
|
||||||
; type_error(atom, Library, load/1)
|
; type_error(atom, Module, load/1)
|
||||||
)
|
)
|
||||||
).
|
).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
check_predicate_property(meta_predicate, Module, Name, Arity, MetaPredicateTerm) :-
|
check_predicate_property(meta_predicate, Module, Name, Arity, MetaPredicateTerm) :-
|
||||||
'$meta_predicate_property'(Module, Name, Arity, MetaPredicateTerm).
|
'$meta_predicate_property'(Module, Name, Arity, MetaPredicateTerm).
|
||||||
check_predicate_property(built_in, _, Name, Arity, built_in) :-
|
check_predicate_property(built_in, _, Name, Arity, built_in) :-
|
||||||
|
|||||||
@@ -23,13 +23,9 @@ fn capture_offset(line: &Instruction, index: usize, stack: &mut Vec<usize>) -> b
|
|||||||
{
|
{
|
||||||
stack.push(index + offset);
|
stack.push(index + offset);
|
||||||
}
|
}
|
||||||
&Instruction::JmpByCall(_, offset, _) => {
|
&Instruction::JmpByCall(offset) => {
|
||||||
stack.push(index + offset);
|
stack.push(index + offset);
|
||||||
}
|
}
|
||||||
&Instruction::JmpByExecute(_, offset, _) => {
|
|
||||||
stack.push(index + offset);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
&Instruction::Proceed => {
|
&Instruction::Proceed => {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,60 +44,6 @@ pub(super) fn bootstrapping_compile(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// throw errors if declaration or query found.
|
|
||||||
pub(super) fn compile_relation(
|
|
||||||
cg: &mut CodeGenerator,
|
|
||||||
tl: &TopLevel,
|
|
||||||
) -> Result<Code, CompilationError> {
|
|
||||||
match tl {
|
|
||||||
&TopLevel::Query(_) => Err(CompilationError::ExpectedRel),
|
|
||||||
&TopLevel::Predicate(ref clauses) => cg.compile_predicate(&clauses),
|
|
||||||
&TopLevel::Fact(ref fact, ..) => cg.compile_fact(fact),
|
|
||||||
&TopLevel::Rule(ref rule, ..) => cg.compile_rule(rule),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn compile_appendix(
|
|
||||||
code: &mut Code,
|
|
||||||
mut queue: VecDeque<TopLevel>,
|
|
||||||
jmp_by_locs: Vec<usize>,
|
|
||||||
non_counted_bt: bool,
|
|
||||||
atom_tbl: &mut AtomTable,
|
|
||||||
) -> Result<(), CompilationError> {
|
|
||||||
let mut jmp_by_locs = VecDeque::from(jmp_by_locs);
|
|
||||||
|
|
||||||
while let Some(jmp_by_offset) = jmp_by_locs.pop_front() {
|
|
||||||
let code_len = code.len();
|
|
||||||
|
|
||||||
match &mut code[jmp_by_offset] {
|
|
||||||
&mut Instruction::JmpByCall(_, ref mut offset, ..) |
|
|
||||||
&mut Instruction::JmpByExecute(_, ref mut offset, ..) => {
|
|
||||||
*offset = code_len - jmp_by_offset;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// false because the inner predicate is a one-off, hence not extensible.
|
|
||||||
let settings = CodeGenSettings {
|
|
||||||
global_clock_tick: None,
|
|
||||||
is_extensible: false,
|
|
||||||
non_counted_bt,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut cg = CodeGenerator::new(atom_tbl, settings);
|
|
||||||
|
|
||||||
let tl = queue.pop_front().unwrap();
|
|
||||||
let decl_code = compile_relation(&mut cg, &tl)?;
|
|
||||||
|
|
||||||
jmp_by_locs.extend(cg.jmp_by_locs.into_iter().map(|offset| offset + code.len()));
|
|
||||||
code.extend(decl_code.into_iter());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lower_bound_of_target_clause(skeleton: &PredicateSkeleton, target_pos: usize) -> usize {
|
fn lower_bound_of_target_clause(skeleton: &PredicateSkeleton, target_pos: usize) -> usize {
|
||||||
if target_pos == 0 {
|
if target_pos == 0 {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1342,22 +1288,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
let mut preprocessor = Preprocessor::new(settings);
|
let mut preprocessor = Preprocessor::new(settings);
|
||||||
|
|
||||||
let clause = self.try_term_to_tl(term, &mut preprocessor)?;
|
let clause = self.try_term_to_tl(term, &mut preprocessor)?;
|
||||||
let queue = preprocessor.parse_queue(self)?;
|
// let queue = preprocessor.parse_queue(self)?;
|
||||||
|
|
||||||
let mut cg = CodeGenerator::new(
|
let mut cg = CodeGenerator::new(
|
||||||
&mut LS::machine_st(&mut self.payload).atom_tbl,
|
&mut LS::machine_st(&mut self.payload).atom_tbl,
|
||||||
settings,
|
settings,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut clause_code = cg.compile_predicate(&vec![clause])?;
|
let clause_code = cg.compile_predicate(vec![clause])?;
|
||||||
|
|
||||||
compile_appendix(
|
|
||||||
&mut clause_code,
|
|
||||||
queue,
|
|
||||||
cg.jmp_by_locs,
|
|
||||||
settings.non_counted_bt,
|
|
||||||
cg.atom_tbl,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(StandaloneCompileResult {
|
Ok(StandaloneCompileResult {
|
||||||
clause_code,
|
clause_code,
|
||||||
@@ -1385,22 +1323,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
clauses.push(self.try_term_to_tl(term, &mut preprocessor)?);
|
clauses.push(self.try_term_to_tl(term, &mut preprocessor)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
let queue = preprocessor.parse_queue(self)?;
|
|
||||||
|
|
||||||
let mut cg = CodeGenerator::new(
|
let mut cg = CodeGenerator::new(
|
||||||
&mut LS::machine_st(&mut self.payload).atom_tbl,
|
&mut LS::machine_st(&mut self.payload).atom_tbl,
|
||||||
settings,
|
settings,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut code = cg.compile_predicate(&clauses)?;
|
let mut code = cg.compile_predicate(clauses)?;
|
||||||
|
|
||||||
compile_appendix(
|
|
||||||
&mut code,
|
|
||||||
queue,
|
|
||||||
cg.jmp_by_locs,
|
|
||||||
settings.non_counted_bt,
|
|
||||||
cg.atom_tbl,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if settings.is_extensible {
|
if settings.is_extensible {
|
||||||
let mut clause_clause_locs = VecDeque::new();
|
let mut clause_clause_locs = VecDeque::new();
|
||||||
|
|||||||
829
src/machine/disjuncts.rs
Normal file
829
src/machine/disjuncts.rs
Normal file
@@ -0,0 +1,829 @@
|
|||||||
|
use crate::atom_table::*;
|
||||||
|
use crate::forms::*;
|
||||||
|
use crate::instructions::*;
|
||||||
|
use crate::iterators::*;
|
||||||
|
use crate::machine::loader::*;
|
||||||
|
use crate::machine::machine_errors::CompilationError;
|
||||||
|
use crate::machine::preprocessor::*;
|
||||||
|
use crate::parser::ast::*;
|
||||||
|
use crate::parser::rug::Rational;
|
||||||
|
use crate::variable_records::*;
|
||||||
|
|
||||||
|
use indexmap::{IndexMap, IndexSet};
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
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(1usize << 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,
|
||||||
|
chunk_type: ChunkType,
|
||||||
|
classify_info: ClassifyInfo,
|
||||||
|
lvl: Level,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct ChunkInfo {
|
||||||
|
chunk_num: usize,
|
||||||
|
term_loc: GenContext,
|
||||||
|
// pointer to incidence, term occurrence arity.
|
||||||
|
vars: Vec<VarInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BranchArm {
|
||||||
|
pub arm_terms: Vec<QueryTerm>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct BranchInfo {
|
||||||
|
branch_num: BranchNumber,
|
||||||
|
chunks: Vec<ChunkInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BranchInfo {
|
||||||
|
fn new(branch_num: BranchNumber) -> Self {
|
||||||
|
Self { branch_num, chunks: vec![] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type BranchMapInt = IndexMap<VarPtr, Vec<BranchInfo>>;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct BranchMap(BranchMapInt);
|
||||||
|
|
||||||
|
impl Deref for BranchMap {
|
||||||
|
type Target = BranchMapInt;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn deref(&self) -> &BranchMapInt {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for BranchMap {
|
||||||
|
#[inline(always)]
|
||||||
|
fn deref_mut(&mut self) -> &mut BranchMapInt {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type RootSet = IndexSet<BranchNumber>;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub struct ClassifyInfo {
|
||||||
|
arg_c: usize,
|
||||||
|
arity: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
BuildDisjunct(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 },
|
||||||
|
ResetCallPolicy(CallPolicy),
|
||||||
|
Term(Term),
|
||||||
|
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
|
||||||
|
// SetChunkType(ChunkType), // consider remaining terms as belonging to a last chunk
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct VariableClassifier {
|
||||||
|
call_policy: CallPolicy,
|
||||||
|
current_branch_num: BranchNumber,
|
||||||
|
current_chunk_num: usize,
|
||||||
|
current_chunk_type: ChunkType,
|
||||||
|
branch_map: BranchMap,
|
||||||
|
var_num: usize,
|
||||||
|
root_set: RootSet,
|
||||||
|
global_cut_var_num: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct VarData {
|
||||||
|
pub records: VariableRecords,
|
||||||
|
pub global_cut_var_num: Option<usize>,
|
||||||
|
pub allocates: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VarData {
|
||||||
|
fn emit_initial_get_level(&mut self, build_stack: &mut ChunkedTermVec) {
|
||||||
|
let global_cut_var_num =
|
||||||
|
if let &Some(global_cut_var_num) = &self.global_cut_var_num {
|
||||||
|
match &self.records[global_cut_var_num].allocation {
|
||||||
|
VarAlloc::Perm(..) => Some(global_cut_var_num),
|
||||||
|
VarAlloc::Temp { term_loc, .. } if term_loc.chunk_num() > 0 => {
|
||||||
|
Some(global_cut_var_num)
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(global_cut_var_num) = global_cut_var_num {
|
||||||
|
let term = QueryTerm::GetLevel(global_cut_var_num);
|
||||||
|
self.records[global_cut_var_num].allocation = VarAlloc::Perm(0, PermVarAllocation::Pending);
|
||||||
|
|
||||||
|
match build_stack.front_mut() {
|
||||||
|
Some(ChunkedTerms::Branch(_)) => {
|
||||||
|
build_stack.push_front(ChunkedTerms::Chunk(VecDeque::from(vec![term])));
|
||||||
|
}
|
||||||
|
Some(ChunkedTerms::Chunk(chunk)) => {
|
||||||
|
chunk.push_front(term);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type ClassifyFactResult = (Term, VarData);
|
||||||
|
pub type ClassifyRuleResult = (Term, ChunkedTermVec, VarData);
|
||||||
|
|
||||||
|
fn merge_branch_seq<Iter: Iterator<Item = BranchInfo>>(branches: Iter) -> BranchInfo {
|
||||||
|
let mut branch_info = BranchInfo::new(BranchNumber::default());
|
||||||
|
|
||||||
|
for mut branch in branches {
|
||||||
|
branch_info.branch_num = branch.branch_num;
|
||||||
|
|
||||||
|
/*
|
||||||
|
if let Some(last_chunk) = branch_info.chunks.last_mut() {
|
||||||
|
if let Some(first_moved_chunk) = branch.chunks.first_mut() {
|
||||||
|
if last_chunk.chunk_num == first_moved_chunk.chunk_num {
|
||||||
|
last_chunk.vars.extend(first_moved_chunk.vars.drain(..));
|
||||||
|
branch_info.chunks.extend(branch.chunks.drain(1 ..));
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
branch_info.chunks.extend(branch.chunks.drain(..));
|
||||||
|
}
|
||||||
|
|
||||||
|
branch_info.branch_num.delta *= 2;
|
||||||
|
branch_info.branch_num.branch_num -= &branch_info.branch_num.delta;
|
||||||
|
|
||||||
|
branch_info
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flatten_into_disjunct(build_stack: &mut ChunkedTermVec, 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);
|
||||||
|
} else {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VariableClassifier {
|
||||||
|
pub fn new(call_policy: CallPolicy) -> Self {
|
||||||
|
Self {
|
||||||
|
call_policy,
|
||||||
|
current_branch_num: BranchNumber::default(),
|
||||||
|
current_chunk_num: 0,
|
||||||
|
current_chunk_type: ChunkType::Head,
|
||||||
|
branch_map: BranchMap(BranchMapInt::new()),
|
||||||
|
root_set: RootSet::new(),
|
||||||
|
var_num: 0,
|
||||||
|
global_cut_var_num: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn classify_fact(mut self, term: Term) -> Result<ClassifyFactResult, CompilationError> {
|
||||||
|
self.classify_head_variables(&term)?;
|
||||||
|
Ok((term, self.branch_map.separate_and_classify_variables(
|
||||||
|
self.var_num,
|
||||||
|
self.global_cut_var_num,
|
||||||
|
self.current_chunk_num,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn classify_rule<'a, LS: LoadState<'a>>(
|
||||||
|
mut self,
|
||||||
|
loader: &mut Loader<'a, LS>,
|
||||||
|
head: Term,
|
||||||
|
body: Term,
|
||||||
|
) -> Result<ClassifyRuleResult, CompilationError> {
|
||||||
|
self.classify_head_variables(&head)?;
|
||||||
|
self.root_set.insert(self.current_branch_num.clone());
|
||||||
|
|
||||||
|
let mut query_terms = self.classify_body_variables(loader, body)?;
|
||||||
|
|
||||||
|
self.merge_branches();
|
||||||
|
|
||||||
|
let mut var_data = self.branch_map.separate_and_classify_variables(
|
||||||
|
self.var_num,
|
||||||
|
self.global_cut_var_num,
|
||||||
|
self.current_chunk_num,
|
||||||
|
);
|
||||||
|
|
||||||
|
var_data.emit_initial_get_level(&mut query_terms);
|
||||||
|
|
||||||
|
Ok((head, query_terms, var_data))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn merge_branches(&mut self) {
|
||||||
|
for branches in self.branch_map.values_mut() {
|
||||||
|
let mut old_branches = std::mem::replace(branches, vec![]);
|
||||||
|
|
||||||
|
while let Some(last_branch_num) = old_branches.last().map(|bi| &bi.branch_num) {
|
||||||
|
let mut old_branches_len = old_branches.len();
|
||||||
|
|
||||||
|
for (rev_idx, bi) in old_branches.iter().rev().enumerate() {
|
||||||
|
if &bi.branch_num > last_branch_num {
|
||||||
|
old_branches_len = old_branches.len() - rev_idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let iter = old_branches.drain(old_branches_len - 1 ..);
|
||||||
|
branches.push(merge_branch_seq(iter));
|
||||||
|
}
|
||||||
|
|
||||||
|
branches.reverse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_set_chunk_at_inlined_boundary(&mut self) -> bool {
|
||||||
|
if self.current_chunk_type.is_last() {
|
||||||
|
self.current_chunk_type = ChunkType::Mid;
|
||||||
|
self.current_chunk_num += 1;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_set_chunk_at_call_boundary(&mut self) -> bool {
|
||||||
|
if self.current_chunk_type.is_last() {
|
||||||
|
self.current_chunk_num += 1;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
self.current_chunk_type = ChunkType::Last;
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn probe_body_term(&mut self, arg_c: usize, arity: usize, term: &Term) {
|
||||||
|
let classify_info = ClassifyInfo { arg_c, arity };
|
||||||
|
|
||||||
|
// second arg is true to iterate the root, which may be a variable
|
||||||
|
for term_ref in breadth_first_iter(term, RootIterationPolicy::Iterated) {
|
||||||
|
if let TermRef::Var(lvl, _, var_ptr) = term_ref {
|
||||||
|
// root terms are shallow here (since we're iterating a
|
||||||
|
// body term) so take the child level.
|
||||||
|
let lvl = lvl.child_level();
|
||||||
|
self.probe_body_var(VarInfo {
|
||||||
|
var_ptr,
|
||||||
|
lvl,
|
||||||
|
classify_info,
|
||||||
|
chunk_type: self.current_chunk_type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn probe_body_var(&mut self, var_info: VarInfo) {
|
||||||
|
let term_loc = self.current_chunk_type.to_gen_context(self.current_chunk_num);
|
||||||
|
|
||||||
|
let branch_info_v = self.branch_map.entry(var_info.var_ptr.clone())
|
||||||
|
.or_insert_with(|| vec![]);
|
||||||
|
|
||||||
|
let needs_new_branch = if let Some(last_bi) = branch_info_v.last() {
|
||||||
|
!self.root_set.contains(&last_bi.branch_num)
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
};
|
||||||
|
|
||||||
|
if needs_new_branch {
|
||||||
|
branch_info_v.push(BranchInfo::new(self.current_branch_num.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let branch_info = branch_info_v.last_mut().unwrap();
|
||||||
|
|
||||||
|
let needs_new_chunk = if let Some(last_ci) = branch_info.chunks.last() {
|
||||||
|
last_ci.chunk_num != self.current_chunk_num
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
};
|
||||||
|
|
||||||
|
if needs_new_chunk {
|
||||||
|
branch_info.chunks.push(ChunkInfo {
|
||||||
|
chunk_num: self.current_chunk_num,
|
||||||
|
term_loc,
|
||||||
|
vars: vec![],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let chunk_info = branch_info.chunks.last_mut().unwrap();
|
||||||
|
chunk_info.vars.push(var_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn probe_in_situ_var(&mut self, var_num: usize) {
|
||||||
|
let classify_info = ClassifyInfo { arg_c: 1, arity: 1 };
|
||||||
|
|
||||||
|
let var_info = VarInfo {
|
||||||
|
var_ptr: VarPtr::from(Var::InSitu(var_num)),
|
||||||
|
classify_info,
|
||||||
|
chunk_type: self.current_chunk_type,
|
||||||
|
lvl: Level::Shallow,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.probe_body_var(var_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn classify_head_variables(&mut self, term: &Term) -> Result<(), CompilationError> {
|
||||||
|
match term {
|
||||||
|
Term::Clause(..) | Term::Literal(_, Literal::Atom(_)) => {
|
||||||
|
}
|
||||||
|
_ => return Err(CompilationError::InvalidRuleHead),
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut classify_info = ClassifyInfo { arg_c: 1, arity: term.arity() };
|
||||||
|
|
||||||
|
match term {
|
||||||
|
Term::Clause(_, _, terms) => {
|
||||||
|
for term in terms.into_iter() {
|
||||||
|
for term_ref in breadth_first_iter(term, RootIterationPolicy::Iterated) {
|
||||||
|
if let TermRef::Var(lvl, _, var_ptr) = term_ref {
|
||||||
|
// a body term, so we need the child level here.
|
||||||
|
let lvl = lvl.child_level();
|
||||||
|
|
||||||
|
// the body of the if let here is an inlined
|
||||||
|
// "probe_head_var". note the difference between it
|
||||||
|
// and "probe_body_var".
|
||||||
|
let branch_info_v = self.branch_map.entry(var_ptr.clone())
|
||||||
|
.or_insert_with(|| vec![]);
|
||||||
|
|
||||||
|
let needs_new_branch = branch_info_v.is_empty();
|
||||||
|
|
||||||
|
if needs_new_branch {
|
||||||
|
branch_info_v.push(BranchInfo::new(self.current_branch_num.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let branch_info = branch_info_v.last_mut().unwrap();
|
||||||
|
let needs_new_chunk = branch_info.chunks.is_empty();
|
||||||
|
|
||||||
|
if needs_new_chunk {
|
||||||
|
branch_info.chunks.push(ChunkInfo {
|
||||||
|
chunk_num: self.current_chunk_num,
|
||||||
|
term_loc: GenContext::Head,
|
||||||
|
vars: vec![],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let chunk_info = branch_info.chunks.last_mut().unwrap();
|
||||||
|
let var_info = VarInfo {
|
||||||
|
var_ptr,
|
||||||
|
classify_info,
|
||||||
|
chunk_type: self.current_chunk_type,
|
||||||
|
lvl,
|
||||||
|
};
|
||||||
|
|
||||||
|
chunk_info.vars.push(var_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
classify_info.arg_c += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn classify_body_variables<'a, LS: LoadState<'a>>(
|
||||||
|
&mut self,
|
||||||
|
loader: &mut Loader<'a, LS>,
|
||||||
|
term: Term,
|
||||||
|
) -> Result<ChunkedTermVec, CompilationError> {
|
||||||
|
let mut state_stack = vec![TraversalState::Term(term)];
|
||||||
|
let mut build_stack = ChunkedTermVec::new();
|
||||||
|
|
||||||
|
self.current_chunk_type = ChunkType::Mid;
|
||||||
|
|
||||||
|
while let Some(traversal_st) = state_stack.pop() {
|
||||||
|
match traversal_st {
|
||||||
|
TraversalState::AddBranchNum(branch_num) => {
|
||||||
|
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());
|
||||||
|
self.current_branch_num = branch_num;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
|
||||||
|
self.current_chunk_type = ChunkType::Mid;
|
||||||
|
self.current_chunk_num += 1;
|
||||||
|
}
|
||||||
|
TraversalState::GetCutPoint { var_num, prev_b } => {
|
||||||
|
if self.try_set_chunk_at_inlined_boundary() {
|
||||||
|
build_stack.add_chunk();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.probe_in_situ_var(var_num);
|
||||||
|
build_stack.push_chunk_term(QueryTerm::GetCutPoint { var_num, prev_b });
|
||||||
|
}
|
||||||
|
TraversalState::Cut { var_num, is_global } => {
|
||||||
|
if self.try_set_chunk_at_inlined_boundary() {
|
||||||
|
build_stack.add_chunk();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.probe_in_situ_var(var_num);
|
||||||
|
|
||||||
|
build_stack.push_chunk_term(
|
||||||
|
if is_global {
|
||||||
|
QueryTerm::GlobalCut(var_num)
|
||||||
|
} else {
|
||||||
|
QueryTerm::LocalCut(var_num)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
TraversalState::Fail => {
|
||||||
|
build_stack.push_chunk_term(QueryTerm::Fail);
|
||||||
|
}
|
||||||
|
TraversalState::Term(term) => {
|
||||||
|
// return true iff new chunk should be added.
|
||||||
|
let update_chunk_data = |classifier: &mut Self, predicate_name, arity| {
|
||||||
|
if ClauseType::is_inlined(predicate_name, arity) {
|
||||||
|
classifier.try_set_chunk_at_inlined_boundary()
|
||||||
|
} else {
|
||||||
|
classifier.try_set_chunk_at_call_boundary()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match term {
|
||||||
|
Term::Clause(_, atom!(","), mut terms) if terms.len() == 2 => {
|
||||||
|
let tail = terms.pop().unwrap();
|
||||||
|
let head = terms.pop().unwrap();
|
||||||
|
|
||||||
|
let iter = unfold_by_str(tail, atom!(","))
|
||||||
|
.into_iter()
|
||||||
|
.rev()
|
||||||
|
.chain(std::iter::once(head))
|
||||||
|
.map(TraversalState::Term);
|
||||||
|
|
||||||
|
state_stack.extend(iter);
|
||||||
|
}
|
||||||
|
Term::Clause(_, atom!(";"), mut terms) if terms.len() == 2 => {
|
||||||
|
let tail = terms.pop().unwrap();
|
||||||
|
let head = terms.pop().unwrap();
|
||||||
|
|
||||||
|
let first_branch_num = self.current_branch_num.split();
|
||||||
|
let branches: Vec<_> = std::iter::once(head)
|
||||||
|
.chain(unfold_by_str(tail, atom!(";")).into_iter())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut branch_numbers = vec![first_branch_num];
|
||||||
|
|
||||||
|
for idx in 1 .. branches.len() {
|
||||||
|
let succ_branch_number = branch_numbers[idx - 1].incr_by_delta();
|
||||||
|
|
||||||
|
branch_numbers.push(if idx + 1 < branches.len() {
|
||||||
|
succ_branch_number.split()
|
||||||
|
} else {
|
||||||
|
succ_branch_number
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let build_stack_len = build_stack.len();
|
||||||
|
build_stack.reserve_branch(branches.len());
|
||||||
|
|
||||||
|
state_stack.push(TraversalState::RepBranchNum(
|
||||||
|
self.current_branch_num.halve_delta(),
|
||||||
|
));
|
||||||
|
|
||||||
|
let iter = branches.into_iter().zip(branch_numbers.into_iter());
|
||||||
|
let final_disjunct_loc = state_stack.len();
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let TraversalState::BuildDisjunct(build_stack_len) = state_stack[final_disjunct_loc] {
|
||||||
|
state_stack[final_disjunct_loc] = TraversalState::BuildFinalDisjunct(build_stack_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Term::Clause(_, atom!("->"), mut terms) if terms.len() == 2 => {
|
||||||
|
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.
|
||||||
|
matches!(state_stack.iter().rev().nth(1), Some(TraversalState::BuildDisjunct(..)))
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
state_stack.push(TraversalState::Term(then_term));
|
||||||
|
state_stack.push(TraversalState::Cut { var_num: self.var_num, is_global: false });
|
||||||
|
state_stack.push(TraversalState::Term(if_term));
|
||||||
|
state_stack.push(TraversalState::GetCutPoint { var_num: self.var_num, prev_b });
|
||||||
|
|
||||||
|
self.var_num += 1;
|
||||||
|
}
|
||||||
|
Term::Clause(_, atom!("\\+"), mut terms) if terms.len() == 1 => {
|
||||||
|
let not_term = terms.pop().unwrap();
|
||||||
|
let build_stack_len = build_stack.len();
|
||||||
|
|
||||||
|
build_stack.reserve_branch(2);
|
||||||
|
|
||||||
|
state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len));
|
||||||
|
state_stack.push(TraversalState::Term(Term::Clause(Cell::default(), atom!("$succeed"), vec![])));
|
||||||
|
state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
|
||||||
|
state_stack.push(TraversalState::Fail);
|
||||||
|
state_stack.push(TraversalState::Cut { var_num: self.var_num, is_global: false });
|
||||||
|
state_stack.push(TraversalState::Term(not_term));
|
||||||
|
state_stack.push(TraversalState::GetCutPoint { var_num: self.var_num, prev_b: true });
|
||||||
|
|
||||||
|
self.var_num += 1;
|
||||||
|
}
|
||||||
|
Term::Clause(_, atom!(":"), mut terms) if terms.len() == 2 => {
|
||||||
|
let predicate_name = terms.pop().unwrap();
|
||||||
|
let module_name = terms.pop().unwrap();
|
||||||
|
|
||||||
|
match (module_name, predicate_name) {
|
||||||
|
(
|
||||||
|
Term::Literal(_, Literal::Atom(module_name)),
|
||||||
|
Term::Literal(_, Literal::Atom(predicate_name)),
|
||||||
|
) => {
|
||||||
|
if update_chunk_data(self, predicate_name, 0) {
|
||||||
|
build_stack.add_chunk();
|
||||||
|
}
|
||||||
|
|
||||||
|
build_stack.push_chunk_term(
|
||||||
|
qualified_clause_to_query_term(
|
||||||
|
loader,
|
||||||
|
module_name,
|
||||||
|
predicate_name,
|
||||||
|
vec![],
|
||||||
|
self.call_policy,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
(
|
||||||
|
Term::Literal(_, Literal::Atom(module_name)),
|
||||||
|
Term::Clause(_, name, terms),
|
||||||
|
) => {
|
||||||
|
if update_chunk_data(self, name, terms.len()) {
|
||||||
|
build_stack.add_chunk();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (arg_c, term) in terms.iter().enumerate() {
|
||||||
|
self.probe_body_term(arg_c + 1, terms.len(), term);
|
||||||
|
}
|
||||||
|
|
||||||
|
build_stack.push_chunk_term(
|
||||||
|
qualified_clause_to_query_term(
|
||||||
|
loader,
|
||||||
|
module_name,
|
||||||
|
name,
|
||||||
|
terms,
|
||||||
|
self.call_policy,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
(module_name, predicate_name) => {
|
||||||
|
if update_chunk_data(self, atom!("call"), 2) {
|
||||||
|
build_stack.add_chunk();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.probe_body_term(1, 0, &module_name);
|
||||||
|
self.probe_body_term(2, 0, &predicate_name);
|
||||||
|
|
||||||
|
terms.push(module_name);
|
||||||
|
terms.push(predicate_name);
|
||||||
|
|
||||||
|
build_stack.push_chunk_term(
|
||||||
|
clause_to_query_term(
|
||||||
|
loader,
|
||||||
|
atom!("call"),
|
||||||
|
vec![Term::Clause(Cell::default(), atom!(":"), terms)],
|
||||||
|
self.call_policy,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Term::Clause(_, atom!("$call_with_inference_counting"), mut terms) if terms.len() == 1 => {
|
||||||
|
state_stack.push(TraversalState::ResetCallPolicy(self.call_policy));
|
||||||
|
state_stack.push(TraversalState::Term(terms.pop().unwrap()));
|
||||||
|
|
||||||
|
self.call_policy = CallPolicy::Counted;
|
||||||
|
}
|
||||||
|
Term::Clause(_, name, terms) => {
|
||||||
|
if update_chunk_data(self, name, terms.len()) {
|
||||||
|
build_stack.add_chunk();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (arg_c, term) in terms.iter().enumerate() {
|
||||||
|
self.probe_body_term(arg_c + 1, terms.len(), term);
|
||||||
|
}
|
||||||
|
|
||||||
|
build_stack.push_chunk_term(
|
||||||
|
clause_to_query_term(
|
||||||
|
loader,
|
||||||
|
name,
|
||||||
|
terms,
|
||||||
|
self.call_policy,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Term::Literal(_, Literal::Atom(atom!("!")) | Literal::Char('!')) => {
|
||||||
|
if self.global_cut_var_num.is_none() {
|
||||||
|
self.global_cut_var_num = Some(self.var_num);
|
||||||
|
self.var_num += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.probe_in_situ_var(self.global_cut_var_num.unwrap());
|
||||||
|
|
||||||
|
state_stack.push(TraversalState::Cut {
|
||||||
|
var_num: self.global_cut_var_num.unwrap(),
|
||||||
|
is_global: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Term::Literal(_, Literal::Atom(name)) => {
|
||||||
|
if update_chunk_data(self, name, 0) {
|
||||||
|
build_stack.add_chunk();
|
||||||
|
}
|
||||||
|
|
||||||
|
build_stack.push_chunk_term(
|
||||||
|
clause_to_query_term(
|
||||||
|
loader,
|
||||||
|
name,
|
||||||
|
vec![],
|
||||||
|
self.call_policy,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(CompilationError::InadmissibleQueryTerm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(build_stack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BranchMap {
|
||||||
|
pub fn separate_and_classify_variables(
|
||||||
|
&mut self,
|
||||||
|
var_num: usize,
|
||||||
|
global_cut_var_num: Option<usize>,
|
||||||
|
current_chunk_num: usize,
|
||||||
|
) -> VarData {
|
||||||
|
let mut var_data = VarData {
|
||||||
|
records: VariableRecords::new(var_num),
|
||||||
|
global_cut_var_num,
|
||||||
|
allocates: current_chunk_num > 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (var, branches) in self.iter_mut() {
|
||||||
|
let (mut var_num, var_num_incr) =
|
||||||
|
if let Var::InSitu(var_num) = *var.borrow() {
|
||||||
|
(var_num, false)
|
||||||
|
} else {
|
||||||
|
(var_data.records.len(), true)
|
||||||
|
};
|
||||||
|
|
||||||
|
for branch in branches.iter_mut() {
|
||||||
|
if var_num_incr {
|
||||||
|
var_num = var_data.records.len();
|
||||||
|
var_data.records.push(VariableRecord::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
if branch.chunks.len() <= 1 { // true iff var is a temporary variable.
|
||||||
|
debug_assert_eq!(branch.chunks.len(), 1);
|
||||||
|
|
||||||
|
let chunk = &mut branch.chunks[0];
|
||||||
|
let mut temp_var_data = TempVarData::new();
|
||||||
|
|
||||||
|
for var_info in chunk.vars.iter_mut() {
|
||||||
|
if var_info.lvl == Level::Shallow {
|
||||||
|
let term_loc = var_info.chunk_type.to_gen_context(chunk.chunk_num);
|
||||||
|
temp_var_data.use_set.insert((term_loc, var_info.classify_info.arg_c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var_data.records[var_num].allocation = VarAlloc::Temp {
|
||||||
|
term_loc: chunk.term_loc,
|
||||||
|
temp_reg: 0,
|
||||||
|
temp_var_data,
|
||||||
|
safety: VarSafetyStatus::Needed,
|
||||||
|
to_perm_var_num: None,
|
||||||
|
};
|
||||||
|
} // else VarAlloc is already a Perm variant, as it's the default.
|
||||||
|
|
||||||
|
for chunk in branch.chunks.iter_mut() {
|
||||||
|
var_data.records[var_num].num_occurrences += chunk.vars.len();
|
||||||
|
|
||||||
|
for var_info in chunk.vars.iter_mut() {
|
||||||
|
var_info.var_ptr.set(Var::Generated(var_num));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var_data.records.populate_restricting_sets();
|
||||||
|
var_data
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -441,13 +441,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
term: Term,
|
term: Term,
|
||||||
preprocessor: &mut Preprocessor,
|
preprocessor: &mut Preprocessor,
|
||||||
) -> Result<PredicateClause, SessionError> {
|
) -> Result<PredicateClause, SessionError> {
|
||||||
let tl = preprocessor.try_term_to_tl(self, term, CutContext::BlocksCuts)?;
|
let tl = preprocessor.try_term_to_tl(self, term)?;
|
||||||
|
|
||||||
Ok(match tl {
|
Ok(match tl {
|
||||||
TopLevel::Fact(fact) => PredicateClause::Fact(fact),
|
TopLevel::Fact(fact, var_data) => PredicateClause::Fact(fact, var_data),
|
||||||
TopLevel::Rule(rule) => PredicateClause::Rule(rule),
|
TopLevel::Rule(rule, var_data) => PredicateClause::Rule(rule, var_data),
|
||||||
TopLevel::Query(_) => return Err(SessionError::QueryCannotBeDefinedAsFact),
|
|
||||||
_ => unreachable!(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ use std::convert::TryFrom;
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The loader compiles Prolog terms read from a TermStream instance,
|
* The loader compiles Prolog terms read from a TermStream instance,
|
||||||
@@ -465,6 +464,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn read_term_from_heap(&mut self, r: RegType) -> Result<Term, SessionError> {
|
||||||
|
let machine_st = LS::machine_st(&mut self.payload);
|
||||||
|
machine_st.read_term_from_heap(r)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn load(mut self) -> Result<LS::Evacuable, SessionError> {
|
pub(crate) fn load(mut self) -> Result<LS::Evacuable, SessionError> {
|
||||||
while let Some(decl) = self.dequeue_terms()? {
|
while let Some(decl) = self.dequeue_terms()? {
|
||||||
self.load_decl(decl)?;
|
self.load_decl(decl)?;
|
||||||
@@ -531,106 +535,6 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn read_term_from_heap(&mut self, heap_term_loc: RegType) -> Result<Term, SessionError> {
|
|
||||||
let machine_st = LS::machine_st(&mut self.payload);
|
|
||||||
let term_addr = machine_st[heap_term_loc];
|
|
||||||
|
|
||||||
let mut term_stack = vec![];
|
|
||||||
let mut iter = stackful_post_order_iter(&mut machine_st.heap, &mut machine_st.stack, term_addr);
|
|
||||||
|
|
||||||
while let Some(addr) = iter.next() {
|
|
||||||
let addr = unmark_cell_bits!(addr);
|
|
||||||
|
|
||||||
read_heap_cell!(addr,
|
|
||||||
(HeapCellValueTag::Lis) => {
|
|
||||||
use crate::parser::parser::as_partial_string;
|
|
||||||
|
|
||||||
let tail = term_stack.pop().unwrap();
|
|
||||||
let head = term_stack.pop().unwrap();
|
|
||||||
|
|
||||||
match as_partial_string(head, tail) {
|
|
||||||
Ok((string, Some(tail))) => {
|
|
||||||
term_stack.push(Term::PartialString(Cell::default(), string, tail));
|
|
||||||
}
|
|
||||||
Ok((string, None)) => {
|
|
||||||
let atom = machine_st.atom_tbl.build_with(&string);
|
|
||||||
term_stack.push(Term::CompleteString(Cell::default(), atom));
|
|
||||||
}
|
|
||||||
Err(cons_term) => term_stack.push(cons_term),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, h) => {
|
|
||||||
let offset_string = format!("_{}", h);
|
|
||||||
term_stack.push(Term::Var(Cell::default(), Rc::new(offset_string)));
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Cons | HeapCellValueTag::CStr | HeapCellValueTag::Fixnum |
|
|
||||||
HeapCellValueTag::Char | HeapCellValueTag::F64) => {
|
|
||||||
term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap()));
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
|
||||||
let h = iter.focus().value() as usize;
|
|
||||||
let mut arity = arity;
|
|
||||||
|
|
||||||
if iter.heap.len() > h + arity + 1 {
|
|
||||||
let value = iter.heap[h + arity + 1];
|
|
||||||
|
|
||||||
if let Some(idx) = get_structure_index(value) {
|
|
||||||
// in the second condition, arity == 0,
|
|
||||||
// meaning idx cannot pertain to this atom
|
|
||||||
// if it is the direct subterm of a larger
|
|
||||||
// structure.
|
|
||||||
if arity > 0 || !iter.direct_subterm_of_str(h) {
|
|
||||||
term_stack.push(
|
|
||||||
Term::Literal(Cell::default(), Literal::CodeIndex(idx))
|
|
||||||
);
|
|
||||||
|
|
||||||
arity += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if arity == 0 {
|
|
||||||
term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name)));
|
|
||||||
} else {
|
|
||||||
let subterms = term_stack
|
|
||||||
.drain(term_stack.len() - arity ..)
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
term_stack.push(Term::Clause(Cell::default(), name, subterms));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::PStr, atom) => {
|
|
||||||
let tail = term_stack.pop().unwrap();
|
|
||||||
|
|
||||||
if let Term::Literal(_, Literal::Atom(atom!("[]"))) = &tail {
|
|
||||||
term_stack.push(Term::CompleteString(Cell::default(), atom));
|
|
||||||
} else {
|
|
||||||
term_stack.push(Term::PartialString(
|
|
||||||
Cell::default(),
|
|
||||||
atom.as_str().to_owned(),
|
|
||||||
Box::new(tail),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::PStrLoc, h) => {
|
|
||||||
let atom = cell_as_atom_cell!(iter.heap[h]).get_name();
|
|
||||||
let tail = term_stack.pop().unwrap();
|
|
||||||
|
|
||||||
term_stack.push(Term::PartialString(
|
|
||||||
Cell::default(),
|
|
||||||
atom.as_str().to_owned(),
|
|
||||||
Box::new(tail),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
debug_assert!(term_stack.len() == 1);
|
|
||||||
Ok(term_stack.pop().unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset_machine(&mut self) {
|
fn reset_machine(&mut self) {
|
||||||
while let Some(record) = self.payload.retraction_info.records.pop() {
|
while let Some(record) = self.payload.retraction_info.records.pop() {
|
||||||
match record {
|
match record {
|
||||||
@@ -1143,7 +1047,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
r: RegType,
|
r: RegType,
|
||||||
) -> Result<IndexSet<ModuleExport>, SessionError> {
|
) -> Result<IndexSet<ModuleExport>, SessionError> {
|
||||||
let export_list = self.read_term_from_heap(r)?;
|
let machine_st = LS::machine_st(&mut self.payload);
|
||||||
|
|
||||||
|
let export_list = machine_st.read_term_from_heap(r)?;
|
||||||
let atom_tbl = &mut LS::machine_st(&mut self.payload).atom_tbl;
|
let atom_tbl = &mut LS::machine_st(&mut self.payload).atom_tbl;
|
||||||
let export_list = setup_module_export_list(export_list, atom_tbl)?;
|
let export_list = setup_module_export_list(export_list, atom_tbl)?;
|
||||||
|
|
||||||
@@ -1493,6 +1399,106 @@ impl<'a> MachinePreludeView<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MachineState {
|
||||||
|
pub(super) fn read_term_from_heap(&mut self, r: RegType) -> Result<Term, SessionError> {
|
||||||
|
let term_addr = self[r];
|
||||||
|
|
||||||
|
let mut term_stack = vec![];
|
||||||
|
let mut iter = stackful_post_order_iter(&mut self.heap, &mut self.stack, term_addr);
|
||||||
|
|
||||||
|
while let Some(addr) = iter.next() {
|
||||||
|
let addr = unmark_cell_bits!(addr);
|
||||||
|
|
||||||
|
read_heap_cell!(addr,
|
||||||
|
(HeapCellValueTag::Lis) => {
|
||||||
|
use crate::parser::parser::as_partial_string;
|
||||||
|
|
||||||
|
let tail = term_stack.pop().unwrap();
|
||||||
|
let head = term_stack.pop().unwrap();
|
||||||
|
|
||||||
|
match as_partial_string(head, tail) {
|
||||||
|
Ok((string, Some(tail))) => {
|
||||||
|
term_stack.push(Term::PartialString(Cell::default(), string, tail));
|
||||||
|
}
|
||||||
|
Ok((string, None)) => {
|
||||||
|
let atom = self.atom_tbl.build_with(&string);
|
||||||
|
term_stack.push(Term::CompleteString(Cell::default(), atom));
|
||||||
|
}
|
||||||
|
Err(cons_term) => term_stack.push(cons_term),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, h) => {
|
||||||
|
term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("_{}", h))));
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Cons | HeapCellValueTag::CStr | HeapCellValueTag::Fixnum |
|
||||||
|
HeapCellValueTag::Char | HeapCellValueTag::F64) => {
|
||||||
|
term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap()));
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||||
|
let h = iter.focus().value() as usize;
|
||||||
|
let mut arity = arity;
|
||||||
|
|
||||||
|
if iter.heap.len() > h + arity + 1 {
|
||||||
|
let value = iter.heap[h + arity + 1];
|
||||||
|
|
||||||
|
if let Some(idx) = get_structure_index(value) {
|
||||||
|
// in the second condition, arity == 0,
|
||||||
|
// meaning idx cannot pertain to this atom
|
||||||
|
// if it is the direct subterm of a larger
|
||||||
|
// structure.
|
||||||
|
if arity > 0 || !iter.direct_subterm_of_str(h) {
|
||||||
|
term_stack.push(
|
||||||
|
Term::Literal(Cell::default(), Literal::CodeIndex(idx))
|
||||||
|
);
|
||||||
|
|
||||||
|
arity += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if arity == 0 {
|
||||||
|
term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name)));
|
||||||
|
} else {
|
||||||
|
let subterms = term_stack
|
||||||
|
.drain(term_stack.len() - arity ..)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
term_stack.push(Term::Clause(Cell::default(), name, subterms));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::PStr, atom) => {
|
||||||
|
let tail = term_stack.pop().unwrap();
|
||||||
|
|
||||||
|
if let Term::Literal(_, Literal::Atom(atom!("[]"))) = &tail {
|
||||||
|
term_stack.push(Term::CompleteString(Cell::default(), atom));
|
||||||
|
} else {
|
||||||
|
term_stack.push(Term::PartialString(
|
||||||
|
Cell::default(),
|
||||||
|
atom.as_str().to_owned(),
|
||||||
|
Box::new(tail),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::PStrLoc, h) => {
|
||||||
|
let atom = cell_as_atom_cell!(iter.heap[h]).get_name();
|
||||||
|
let tail = term_stack.pop().unwrap();
|
||||||
|
|
||||||
|
term_stack.push(Term::PartialString(
|
||||||
|
Cell::default(),
|
||||||
|
atom.as_str().to_owned(),
|
||||||
|
Box::new(tail),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_assert!(term_stack.len() == 1);
|
||||||
|
Ok(term_stack.pop().unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Machine {
|
impl Machine {
|
||||||
pub(crate) fn use_module(&mut self) -> CallResult {
|
pub(crate) fn use_module(&mut self) -> CallResult {
|
||||||
let subevacuable_addr = self
|
let subevacuable_addr = self
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ use crate::parser::ast::*;
|
|||||||
|
|
||||||
use crate::arena::*;
|
use crate::arena::*;
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
use crate::fixtures::*;
|
|
||||||
use crate::forms::*;
|
use crate::forms::*;
|
||||||
use crate::machine::loader::*;
|
use crate::machine::loader::*;
|
||||||
use crate::machine::machine_state::*;
|
use crate::machine::machine_state::*;
|
||||||
@@ -16,7 +15,6 @@ use modular_bitfield::specifiers::*;
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
@@ -228,8 +226,8 @@ impl CodeIndex {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) type HeapVarDict = IndexMap<Rc<String>, HeapCellValue, FxBuildHasher>;
|
pub(crate) type HeapVarDict = IndexMap<VarPtr, HeapCellValue, FxBuildHasher>;
|
||||||
pub(crate) type AllocVarDict = IndexMap<Rc<String>, VarData, FxBuildHasher>;
|
// pub(crate) type AllocVarDict = IndexMap<Var, VarAlloc, FxBuildHasher>;
|
||||||
|
|
||||||
pub(crate) type GlobalVarDir = IndexMap<Atom, (Ball, Option<HeapCellValue>), FxBuildHasher>;
|
pub(crate) type GlobalVarDir = IndexMap<Atom, (Ball, Option<HeapCellValue>), FxBuildHasher>;
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ use indexmap::IndexMap;
|
|||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1];
|
pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1];
|
||||||
|
|
||||||
@@ -501,13 +500,13 @@ impl MachineState {
|
|||||||
pub fn read_term(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult {
|
pub fn read_term(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult {
|
||||||
fn push_var_eq_functors<'a>(
|
fn push_var_eq_functors<'a>(
|
||||||
heap: &mut Heap,
|
heap: &mut Heap,
|
||||||
iter: impl Iterator<Item = (&'a Rc<String>, &'a HeapCellValue)>,
|
iter: impl Iterator<Item = (&'a VarPtr, &'a HeapCellValue)>,
|
||||||
atom_tbl: &mut AtomTable,
|
atom_tbl: &mut AtomTable,
|
||||||
) -> Vec<HeapCellValue> {
|
) -> Vec<HeapCellValue> {
|
||||||
let mut list_of_var_eqs = vec![];
|
let mut list_of_var_eqs = vec![];
|
||||||
|
|
||||||
for (var, binding) in iter {
|
for (var, binding) in iter {
|
||||||
let var_atom = atom_tbl.build_with(&var);
|
let var_atom = atom_tbl.build_with(&var.borrow().to_string());
|
||||||
let h = heap.len();
|
let h = heap.len();
|
||||||
|
|
||||||
heap.push(atom_as_cell!(atom!("="), 2));
|
heap.push(atom_as_cell!(atom!("="), 2));
|
||||||
@@ -673,7 +672,7 @@ impl MachineState {
|
|||||||
|
|
||||||
let printer = match self.try_from_list(self.registers[6], stub_gen) {
|
let printer = match self.try_from_list(self.registers[6], stub_gen) {
|
||||||
Ok(addrs) => {
|
Ok(addrs) => {
|
||||||
let mut var_names: IndexMap<HeapCellValue, Rc<String>> = IndexMap::new();
|
let mut var_names: IndexMap<HeapCellValue, VarPtr> = IndexMap::new();
|
||||||
|
|
||||||
for addr in addrs {
|
for addr in addrs {
|
||||||
read_heap_cell!(addr,
|
read_heap_cell!(addr,
|
||||||
@@ -691,18 +690,18 @@ impl MachineState {
|
|||||||
|
|
||||||
read_heap_cell!(atom,
|
read_heap_cell!(atom,
|
||||||
(HeapCellValueTag::Char, c) => {
|
(HeapCellValueTag::Char, c) => {
|
||||||
var_names.insert(var, Rc::new(c.to_string()));
|
var_names.insert(var, VarPtr::from(c.to_string()));
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Atom, (name, _arity)) => {
|
(HeapCellValueTag::Atom, (name, _arity)) => {
|
||||||
debug_assert_eq!(_arity, 0);
|
debug_assert_eq!(_arity, 0);
|
||||||
var_names.insert(var, Rc::new(name.as_str().to_owned()));
|
var_names.insert(var, VarPtr::from(name.as_str()));
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Str, s) => {
|
(HeapCellValueTag::Str, s) => {
|
||||||
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
||||||
.get_name_and_arity();
|
.get_name_and_arity();
|
||||||
|
|
||||||
debug_assert_eq!(arity, 0);
|
debug_assert_eq!(arity, 0);
|
||||||
var_names.insert(var, Rc::new(name.as_str().to_owned()));
|
var_names.insert(var, VarPtr::from(name.as_str()));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ pub mod machine_state;
|
|||||||
pub mod machine_state_impl;
|
pub mod machine_state_impl;
|
||||||
pub mod mock_wam;
|
pub mod mock_wam;
|
||||||
pub mod partial_string;
|
pub mod partial_string;
|
||||||
|
pub mod disjuncts;
|
||||||
pub mod preprocessor;
|
pub mod preprocessor;
|
||||||
pub mod stack;
|
pub mod stack;
|
||||||
pub mod streams;
|
pub mod streams;
|
||||||
@@ -67,7 +68,7 @@ pub struct Machine {
|
|||||||
pub(super) user_error: Stream,
|
pub(super) user_error: Stream,
|
||||||
pub(super) load_contexts: Vec<LoadContext>,
|
pub(super) load_contexts: Vec<LoadContext>,
|
||||||
pub(super) runtime: Runtime,
|
pub(super) runtime: Runtime,
|
||||||
pub(super) foreign_function_table: ForeignFunctionTable,
|
pub(super) foreign_function_table: ForeignFunctionTable,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -364,46 +365,46 @@ impl Machine {
|
|||||||
Instruction::BreakFromDispatchLoop,
|
Instruction::BreakFromDispatchLoop,
|
||||||
Instruction::InstallVerifyAttr,
|
Instruction::InstallVerifyAttr,
|
||||||
Instruction::VerifyAttrInterrupt,
|
Instruction::VerifyAttrInterrupt,
|
||||||
Instruction::ExecuteTermGreaterThan(0),
|
Instruction::ExecuteTermGreaterThan,
|
||||||
Instruction::ExecuteTermLessThan(0),
|
Instruction::ExecuteTermLessThan,
|
||||||
Instruction::ExecuteTermGreaterThanOrEqual(0),
|
Instruction::ExecuteTermGreaterThanOrEqual,
|
||||||
Instruction::ExecuteTermLessThanOrEqual(0),
|
Instruction::ExecuteTermLessThanOrEqual,
|
||||||
Instruction::ExecuteTermEqual(0),
|
Instruction::ExecuteTermEqual,
|
||||||
Instruction::ExecuteTermNotEqual(0),
|
Instruction::ExecuteTermNotEqual,
|
||||||
Instruction::ExecuteNumberGreaterThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
|
Instruction::ExecuteNumberGreaterThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
|
||||||
Instruction::ExecuteNumberLessThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
|
Instruction::ExecuteNumberLessThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
|
||||||
Instruction::ExecuteNumberGreaterThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
|
Instruction::ExecuteNumberGreaterThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
|
||||||
Instruction::ExecuteNumberLessThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
|
Instruction::ExecuteNumberLessThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
|
||||||
Instruction::ExecuteNumberEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
|
Instruction::ExecuteNumberEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
|
||||||
Instruction::ExecuteNumberNotEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
|
Instruction::ExecuteNumberNotEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
|
||||||
Instruction::ExecuteIs(temp_v!(1), ar_reg!(temp_v!(2)), 0),
|
Instruction::ExecuteIs(temp_v!(1), ar_reg!(temp_v!(2))),
|
||||||
Instruction::ExecuteAcyclicTerm(0),
|
Instruction::ExecuteAcyclicTerm,
|
||||||
Instruction::ExecuteArg(0),
|
Instruction::ExecuteArg,
|
||||||
Instruction::ExecuteCompare(0),
|
Instruction::ExecuteCompare,
|
||||||
Instruction::ExecuteCopyTerm(0),
|
Instruction::ExecuteCopyTerm,
|
||||||
Instruction::ExecuteFunctor(0),
|
Instruction::ExecuteFunctor,
|
||||||
Instruction::ExecuteGround(0),
|
Instruction::ExecuteGround,
|
||||||
Instruction::ExecuteKeySort(0),
|
Instruction::ExecuteKeySort,
|
||||||
Instruction::ExecuteRead(0),
|
Instruction::ExecuteRead,
|
||||||
Instruction::ExecuteSort(0),
|
Instruction::ExecuteSort,
|
||||||
Instruction::ExecuteN(1, 0),
|
Instruction::ExecuteN(1),
|
||||||
Instruction::ExecuteN(2, 0),
|
Instruction::ExecuteN(2),
|
||||||
Instruction::ExecuteN(3, 0),
|
Instruction::ExecuteN(3),
|
||||||
Instruction::ExecuteN(4, 0),
|
Instruction::ExecuteN(4),
|
||||||
Instruction::ExecuteN(5, 0),
|
Instruction::ExecuteN(5),
|
||||||
Instruction::ExecuteN(6, 0),
|
Instruction::ExecuteN(6),
|
||||||
Instruction::ExecuteN(7, 0),
|
Instruction::ExecuteN(7),
|
||||||
Instruction::ExecuteN(8, 0),
|
Instruction::ExecuteN(8),
|
||||||
Instruction::ExecuteN(9, 0),
|
Instruction::ExecuteN(9),
|
||||||
Instruction::ExecuteIsAtom(temp_v!(1), 0),
|
Instruction::ExecuteIsAtom(temp_v!(1)),
|
||||||
Instruction::ExecuteIsAtomic(temp_v!(1), 0),
|
Instruction::ExecuteIsAtomic(temp_v!(1)),
|
||||||
Instruction::ExecuteIsCompound(temp_v!(1), 0),
|
Instruction::ExecuteIsCompound(temp_v!(1)),
|
||||||
Instruction::ExecuteIsInteger(temp_v!(1), 0),
|
Instruction::ExecuteIsInteger(temp_v!(1)),
|
||||||
Instruction::ExecuteIsNumber(temp_v!(1), 0),
|
Instruction::ExecuteIsNumber(temp_v!(1)),
|
||||||
Instruction::ExecuteIsRational(temp_v!(1), 0),
|
Instruction::ExecuteIsRational(temp_v!(1)),
|
||||||
Instruction::ExecuteIsFloat(temp_v!(1), 0),
|
Instruction::ExecuteIsFloat(temp_v!(1)),
|
||||||
Instruction::ExecuteIsNonVar(temp_v!(1), 0),
|
Instruction::ExecuteIsNonVar(temp_v!(1)),
|
||||||
Instruction::ExecuteIsVar(temp_v!(1), 0)
|
Instruction::ExecuteIsVar(temp_v!(1))
|
||||||
].into_iter());
|
].into_iter());
|
||||||
|
|
||||||
for (p, instr) in self.code[impls_offset ..].iter().enumerate() {
|
for (p, instr) in self.code[impls_offset ..].iter().enumerate() {
|
||||||
@@ -689,6 +690,8 @@ impl Machine {
|
|||||||
fn try_call(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
|
fn try_call(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
|
||||||
let compiled_tl_index = idx.p() as usize;
|
let compiled_tl_index = idx.p() as usize;
|
||||||
|
|
||||||
|
// println!("calling {}/{}", name.as_str(), arity);
|
||||||
|
|
||||||
match idx.tag() {
|
match idx.tag() {
|
||||||
IndexPtrTag::DynamicUndefined => {
|
IndexPtrTag::DynamicUndefined => {
|
||||||
self.machine_st.fail = true;
|
self.machine_st.fail = true;
|
||||||
@@ -712,6 +715,8 @@ impl Machine {
|
|||||||
fn try_execute(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
|
fn try_execute(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
|
||||||
let compiled_tl_index = idx.p() as usize;
|
let compiled_tl_index = idx.p() as usize;
|
||||||
|
|
||||||
|
// println!("executing {}/{}", name.as_str(), arity);
|
||||||
|
|
||||||
match idx.tag() {
|
match idx.tag() {
|
||||||
IndexPtrTag::DynamicUndefined => {
|
IndexPtrTag::DynamicUndefined => {
|
||||||
self.machine_st.fail = true;
|
self.machine_st.fail = true;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use crate::atom_table::*;
|
|||||||
use crate::codegen::CodeGenSettings;
|
use crate::codegen::CodeGenSettings;
|
||||||
use crate::forms::*;
|
use crate::forms::*;
|
||||||
use crate::instructions::*;
|
use crate::instructions::*;
|
||||||
use crate::iterators::*;
|
use crate::machine::disjuncts::*;
|
||||||
use crate::machine::loader::*;
|
use crate::machine::loader::*;
|
||||||
use crate::machine::machine_errors::*;
|
use crate::machine::machine_errors::*;
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
@@ -10,35 +10,7 @@ use crate::parser::ast::*;
|
|||||||
use indexmap::IndexSet;
|
use indexmap::IndexSet;
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The preprocessor fabricates if-then-else ( .. -> ... ; ...)
|
|
||||||
* clauses into nameless standalone predicates, which it queues for
|
|
||||||
* later preprocessing and compilation. Fabricated predicates inherit
|
|
||||||
* explicit "cut variables" from the handwritten predicate
|
|
||||||
* surrounding their source if-then-else. They must be specially
|
|
||||||
* handled.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
pub(crate) enum CutContext {
|
|
||||||
BlocksCuts,
|
|
||||||
HasCutVariable,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn fold_by_str<I>(terms: I, mut term: Term, sym: Atom) -> Term
|
|
||||||
where
|
|
||||||
I: DoubleEndedIterator<Item = Term>,
|
|
||||||
{
|
|
||||||
for prec in terms.rev() {
|
|
||||||
term = Term::Clause(Cell::default(), sym, vec![prec, term]);
|
|
||||||
}
|
|
||||||
|
|
||||||
term
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn to_op_decl(
|
pub(crate) fn to_op_decl(
|
||||||
prec: u16,
|
prec: u16,
|
||||||
@@ -132,6 +104,13 @@ fn setup_module_export(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term {
|
||||||
|
let head_term = Term::Clause(Cell::default(), atom!(""), vars.iter().cloned().collect());
|
||||||
|
let rule = vec![head_term, body_term];
|
||||||
|
|
||||||
|
Term::Clause(Cell::default(), atom!(":-"), rule)
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn setup_module_export_list(
|
pub(super) fn setup_module_export_list(
|
||||||
mut export_list: Term,
|
mut export_list: Term,
|
||||||
atom_tbl: &mut AtomTable,
|
atom_tbl: &mut AtomTable,
|
||||||
@@ -325,110 +304,6 @@ fn setup_meta_predicate<'a, LS: LoadState<'a>>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, CompilationError> {
|
|
||||||
let mut clauses = vec![];
|
|
||||||
|
|
||||||
while let Some(tl) = tls.pop_front() {
|
|
||||||
match tl {
|
|
||||||
TopLevel::Query(_) if clauses.is_empty() && tls.is_empty() => {
|
|
||||||
return Ok(tl);
|
|
||||||
}
|
|
||||||
TopLevel::Query(_) => {
|
|
||||||
return Err(CompilationError::InconsistentEntry);
|
|
||||||
}
|
|
||||||
TopLevel::Fact(fact) => {
|
|
||||||
let clause = PredicateClause::Fact(fact);
|
|
||||||
clauses.push(clause);
|
|
||||||
}
|
|
||||||
TopLevel::Rule(rule) => {
|
|
||||||
let clause = PredicateClause::Rule(rule);
|
|
||||||
clauses.push(clause);
|
|
||||||
}
|
|
||||||
TopLevel::Predicate(predicate) => clauses.extend(predicate.into_iter()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if clauses.is_empty() {
|
|
||||||
Err(CompilationError::InconsistentEntry)
|
|
||||||
} else {
|
|
||||||
Ok(TopLevel::Predicate(clauses))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_cut_variables_as(terms: &mut Vec<Term>, name: Atom) {
|
|
||||||
for term in terms.iter_mut() {
|
|
||||||
match term {
|
|
||||||
&mut Term::Literal(_, Literal::Atom(ref mut var)) if *var == atom!("!") => {
|
|
||||||
*var = name;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_cut_variable(term: &mut Term) -> bool {
|
|
||||||
let cut_var_found = match term {
|
|
||||||
&mut Term::Literal(_, Literal::Atom(ref var)) if *var == atom!("!") => true,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if cut_var_found {
|
|
||||||
*term = Term::Var(Cell::default(), Rc::new(String::from("!")));
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_cut_variables(terms: &mut Vec<Term>) -> bool {
|
|
||||||
let mut found_cut_var = false;
|
|
||||||
|
|
||||||
for item in terms.iter_mut() {
|
|
||||||
found_cut_var = mark_cut_variable(item) || found_cut_var;
|
|
||||||
}
|
|
||||||
|
|
||||||
found_cut_var
|
|
||||||
}
|
|
||||||
|
|
||||||
// terms is a list of goals composing one clause in a (;) functor. it
|
|
||||||
// checks that the first (and only) of these clauses is a ->. if so,
|
|
||||||
// it expands its terms using a blocked_!.
|
|
||||||
fn check_for_internal_if_then(terms: &mut Vec<Term>) {
|
|
||||||
if terms.len() != 1 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(Term::Clause(_, name, ref subterms)) = terms.last() {
|
|
||||||
if *name != atom!("->") || source_arity(subterms) != 2 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(Term::Clause(_, _, mut subterms)) = terms.pop() {
|
|
||||||
let mut conq_terms = VecDeque::from(unfold_by_str(subterms.pop().unwrap(), atom!(",")));
|
|
||||||
let mut pre_cut_terms = VecDeque::from(unfold_by_str(subterms.pop().unwrap(), atom!(",")));
|
|
||||||
|
|
||||||
conq_terms.push_front(Term::Literal(
|
|
||||||
Cell::default(),
|
|
||||||
Literal::Atom(atom!("blocked_!")),
|
|
||||||
));
|
|
||||||
|
|
||||||
while let Some(term) = pre_cut_terms.pop_back() {
|
|
||||||
conq_terms.push_front(term);
|
|
||||||
}
|
|
||||||
|
|
||||||
let tail_term = conq_terms.pop_back().unwrap();
|
|
||||||
|
|
||||||
terms.push(fold_by_str(
|
|
||||||
conq_terms.into_iter(),
|
|
||||||
tail_term,
|
|
||||||
atom!(","),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
|
pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
|
||||||
loader: &mut Loader<'a, LS>,
|
loader: &mut Loader<'a, LS>,
|
||||||
mut terms: Vec<Term>,
|
mut terms: Vec<Term>,
|
||||||
@@ -570,7 +445,7 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clause_to_query_term<'a, LS: LoadState<'a>>(
|
pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>(
|
||||||
loader: &mut Loader<'a, LS>,
|
loader: &mut Loader<'a, LS>,
|
||||||
name: Atom,
|
name: Atom,
|
||||||
mut terms: Vec<Term>,
|
mut terms: Vec<Term>,
|
||||||
@@ -609,7 +484,7 @@ fn clause_to_query_term<'a, LS: LoadState<'a>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
|
pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
|
||||||
loader: &mut Loader<'a, LS>,
|
loader: &mut Loader<'a, LS>,
|
||||||
module_name: Atom,
|
module_name: Atom,
|
||||||
name: Atom,
|
name: Atom,
|
||||||
@@ -647,308 +522,58 @@ fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
|
|||||||
QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
|
QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_head(term: &Term) -> Vec<Term> {
|
|
||||||
let mut vars = IndexSet::new();
|
|
||||||
|
|
||||||
for term in post_order_iter(term) {
|
|
||||||
if let TermRef::Var(_, _, v) = term {
|
|
||||||
vars.insert(v.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vars.insert(Rc::new(String::from("!")));
|
|
||||||
vars.into_iter()
|
|
||||||
.map(|v| Term::Var(Cell::default(), v))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term {
|
|
||||||
let head_term = Term::Clause(Cell::default(), atom!(""), vars.iter().cloned().collect());
|
|
||||||
let rule = vec![head_term, body_term];
|
|
||||||
|
|
||||||
Term::Clause(Cell::default(), atom!(":-"), rule)
|
|
||||||
}
|
|
||||||
|
|
||||||
// the terms form the body of the rule. We create a head, by
|
|
||||||
// gathering variables from the body of terms and recording them
|
|
||||||
// in the head clause.
|
|
||||||
fn build_rule(body_term: Term) -> (JumpStub, VecDeque<Term>) {
|
|
||||||
// collect the vars of body_term into a head, return the num_vars
|
|
||||||
// (the arity) as well.
|
|
||||||
let vars = compute_head(&body_term);
|
|
||||||
let rule = build_rule_body(&vars, body_term);
|
|
||||||
|
|
||||||
(vars, VecDeque::from(vec![rule]))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_disjunct(body_term: Term) -> (JumpStub, VecDeque<Term>) {
|
|
||||||
let vars = compute_head(&body_term);
|
|
||||||
let results = unfold_by_str(body_term, atom!(";"))
|
|
||||||
.into_iter()
|
|
||||||
.map(|term| {
|
|
||||||
let mut subterms = unfold_by_str(term, atom!(","));
|
|
||||||
mark_cut_variables(&mut subterms);
|
|
||||||
|
|
||||||
check_for_internal_if_then(&mut subterms);
|
|
||||||
|
|
||||||
let term = subterms.pop().unwrap();
|
|
||||||
let clause = fold_by_str(subterms.into_iter(), term, atom!(","));
|
|
||||||
|
|
||||||
build_rule_body(&vars, clause)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
(vars, results)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_if_then(prec: Term, conq: Term) -> (JumpStub, VecDeque<Term>) {
|
|
||||||
let mut prec_seq = unfold_by_str(prec, atom!(","));
|
|
||||||
let comma_sym = atom!(",");
|
|
||||||
let cut_sym = Literal::Atom(atom!("!"));
|
|
||||||
|
|
||||||
prec_seq.push(Term::Literal(Cell::default(), cut_sym));
|
|
||||||
|
|
||||||
mark_cut_variables_as(&mut prec_seq, atom!("blocked_!"));
|
|
||||||
|
|
||||||
let mut conq_seq = unfold_by_str(conq, atom!(","));
|
|
||||||
|
|
||||||
mark_cut_variables(&mut conq_seq);
|
|
||||||
prec_seq.extend(conq_seq.into_iter());
|
|
||||||
|
|
||||||
let back_term = prec_seq.pop().unwrap();
|
|
||||||
let front_term = prec_seq.pop().unwrap();
|
|
||||||
|
|
||||||
let body_term = Term::Clause(
|
|
||||||
Cell::default(),
|
|
||||||
comma_sym,
|
|
||||||
vec![front_term, back_term],
|
|
||||||
);
|
|
||||||
|
|
||||||
build_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct Preprocessor {
|
pub(crate) struct Preprocessor {
|
||||||
queue: VecDeque<VecDeque<Term>>,
|
|
||||||
settings: CodeGenSettings,
|
settings: CodeGenSettings,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Preprocessor {
|
impl Preprocessor {
|
||||||
pub(super) fn new(settings: CodeGenSettings) -> Self {
|
pub(super) fn new(settings: CodeGenSettings) -> Self {
|
||||||
Preprocessor {
|
Preprocessor {
|
||||||
queue: VecDeque::new(),
|
|
||||||
settings,
|
settings,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_fact(&mut self, term: Term) -> Result<Term, CompilationError> {
|
fn setup_fact(&mut self, term: Term) -> Result<(Fact, VarData), CompilationError> {
|
||||||
match term {
|
match term {
|
||||||
Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => Ok(term),
|
Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => {
|
||||||
|
let classifier = VariableClassifier::new(
|
||||||
|
self.settings.default_call_policy(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let (head, var_data) = classifier.classify_fact(term)?;
|
||||||
|
Ok((Fact { head }, var_data))
|
||||||
|
}
|
||||||
_ => Err(CompilationError::InadmissibleFact),
|
_ => Err(CompilationError::InadmissibleFact),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_query_term<'a, LS: LoadState<'a>>(
|
|
||||||
&mut self,
|
|
||||||
loader: &mut Loader<'a, LS>,
|
|
||||||
term: Term,
|
|
||||||
) -> Result<QueryTerm, CompilationError> {
|
|
||||||
match term {
|
|
||||||
Term::Literal(_, Literal::Atom(name)) => {
|
|
||||||
if name == atom!("!") || name == atom!("blocked_!") {
|
|
||||||
Ok(QueryTerm::BlockedCut)
|
|
||||||
} else {
|
|
||||||
Ok(clause_to_query_term(
|
|
||||||
loader,
|
|
||||||
name,
|
|
||||||
vec![],
|
|
||||||
self.settings.default_call_policy(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Term::Literal(_, Literal::Char('!')) => Ok(QueryTerm::BlockedCut),
|
|
||||||
Term::Var(_, ref v) if v.as_str() == "!" => {
|
|
||||||
Ok(QueryTerm::UnblockedCut(Cell::default()))
|
|
||||||
}
|
|
||||||
Term::Clause(r, name, mut terms) => match (name, source_arity(&terms)) {
|
|
||||||
(atom!(";"), 2) => {
|
|
||||||
let term = Term::Clause(r, name, terms);
|
|
||||||
|
|
||||||
let (stub, clauses) = build_disjunct(term);
|
|
||||||
self.queue.push_back(clauses);
|
|
||||||
|
|
||||||
Ok(QueryTerm::Jump(stub))
|
|
||||||
}
|
|
||||||
(atom!("->"), 2) => {
|
|
||||||
let conq = terms.pop().unwrap();
|
|
||||||
let prec = terms.pop().unwrap();
|
|
||||||
|
|
||||||
let (stub, clauses) = build_if_then(prec, conq);
|
|
||||||
self.queue.push_back(clauses);
|
|
||||||
|
|
||||||
Ok(QueryTerm::Jump(stub))
|
|
||||||
}
|
|
||||||
(atom!("\\+"), 1) => {
|
|
||||||
terms.push(Term::Literal(
|
|
||||||
Cell::default(),
|
|
||||||
Literal::Atom(atom!("$fail")),
|
|
||||||
));
|
|
||||||
|
|
||||||
let conq = Term::Literal(Cell::default(), Literal::Atom(atom!("true")));
|
|
||||||
|
|
||||||
let prec = Term::Clause(Cell::default(), atom!("->"), terms);
|
|
||||||
let terms = vec![prec, conq];
|
|
||||||
|
|
||||||
let term = Term::Clause(Cell::default(), atom!(";"), terms);
|
|
||||||
let (stub, clauses) = build_disjunct(term);
|
|
||||||
|
|
||||||
debug_assert!(clauses.len() > 0);
|
|
||||||
self.queue.push_back(clauses);
|
|
||||||
|
|
||||||
Ok(QueryTerm::Jump(stub))
|
|
||||||
}
|
|
||||||
(atom!("$get_level"), 1) => {
|
|
||||||
if let Term::Var(_, ref var) = &terms[0] {
|
|
||||||
Ok(QueryTerm::GetLevelAndUnify(Cell::default(), var.clone()))
|
|
||||||
} else {
|
|
||||||
Err(CompilationError::InadmissibleQueryTerm)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(atom!(":"), 2) => {
|
|
||||||
let predicate_name = terms.pop().unwrap();
|
|
||||||
let module_name = terms.pop().unwrap();
|
|
||||||
|
|
||||||
match (module_name, predicate_name) {
|
|
||||||
(
|
|
||||||
Term::Literal(_, Literal::Atom(module_name)),
|
|
||||||
Term::Literal(_, Literal::Atom(predicate_name)),
|
|
||||||
) => Ok(qualified_clause_to_query_term(
|
|
||||||
loader,
|
|
||||||
module_name,
|
|
||||||
predicate_name,
|
|
||||||
vec![],
|
|
||||||
self.settings.default_call_policy(),
|
|
||||||
)),
|
|
||||||
(
|
|
||||||
Term::Literal(_, Literal::Atom(module_name)),
|
|
||||||
Term::Clause(_, name, terms),
|
|
||||||
) => Ok(qualified_clause_to_query_term(
|
|
||||||
loader,
|
|
||||||
module_name,
|
|
||||||
name,
|
|
||||||
terms,
|
|
||||||
self.settings.default_call_policy()
|
|
||||||
)),
|
|
||||||
(module_name, predicate_name) => {
|
|
||||||
terms.push(module_name);
|
|
||||||
terms.push(predicate_name);
|
|
||||||
|
|
||||||
Ok(clause_to_query_term(
|
|
||||||
loader,
|
|
||||||
atom!("call"),
|
|
||||||
vec![Term::Clause(r, name, terms)],
|
|
||||||
self.settings.default_call_policy(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Ok(clause_to_query_term(loader, name, terms,
|
|
||||||
self.settings.default_call_policy())),
|
|
||||||
},
|
|
||||||
Term::Var(..) => Ok(QueryTerm::Clause(
|
|
||||||
Cell::default(),
|
|
||||||
ClauseType::CallN(1),
|
|
||||||
vec![term],
|
|
||||||
self.settings.default_call_policy(),
|
|
||||||
)),
|
|
||||||
_ => Err(CompilationError::InadmissibleQueryTerm),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pre_query_term<'a, LS: LoadState<'a>>(
|
|
||||||
&mut self,
|
|
||||||
loader: &mut Loader<'a, LS>,
|
|
||||||
term: Term,
|
|
||||||
) -> Result<QueryTerm, CompilationError> {
|
|
||||||
match term {
|
|
||||||
Term::Clause(r, name, mut subterms) => {
|
|
||||||
if subterms.len() == 1 && name == atom!("$call_with_inference_counting") {
|
|
||||||
self.to_query_term(loader, subterms.pop().unwrap())
|
|
||||||
.map(|mut query_term| {
|
|
||||||
query_term.set_call_policy(CallPolicy::Counted);
|
|
||||||
query_term
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
let clause = Term::Clause(r, name, subterms);
|
|
||||||
self.to_query_term(loader, clause)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => self.to_query_term(loader, term),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_query<'a, LS: LoadState<'a>>(
|
|
||||||
&mut self,
|
|
||||||
loader: &mut Loader<'a, LS>,
|
|
||||||
terms: Vec<Term>,
|
|
||||||
cut_context: CutContext,
|
|
||||||
) -> Result<Vec<QueryTerm>, CompilationError> {
|
|
||||||
let mut query_terms = vec![];
|
|
||||||
let mut work_queue = VecDeque::from(terms);
|
|
||||||
|
|
||||||
while let Some(term) = work_queue.pop_front() {
|
|
||||||
let mut term = term;
|
|
||||||
|
|
||||||
if let Term::Clause(cell, name, terms) = term {
|
|
||||||
if name == atom!(",") && source_arity(&terms) == 2 {
|
|
||||||
let term = Term::Clause(cell, name, terms);
|
|
||||||
let mut subterms = unfold_by_str(term, atom!(","));
|
|
||||||
|
|
||||||
while let Some(subterm) = subterms.pop() {
|
|
||||||
work_queue.push_front(subterm);
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
term = Term::Clause(cell, name, terms);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let CutContext::HasCutVariable = cut_context {
|
|
||||||
mark_cut_variable(&mut term);
|
|
||||||
}
|
|
||||||
|
|
||||||
query_terms.push(self.pre_query_term(loader, term)?);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(query_terms)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_rule<'a, LS: LoadState<'a>>(
|
fn setup_rule<'a, LS: LoadState<'a>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
loader: &mut Loader<'a, LS>,
|
loader: &mut Loader<'a, LS>,
|
||||||
mut terms: Vec<Term>,
|
head: Term,
|
||||||
cut_context: CutContext,
|
body: Term,
|
||||||
) -> Result<Rule, CompilationError> {
|
) -> Result<(Rule, VarData), CompilationError> {
|
||||||
let post_head_terms: Vec<_> = terms.drain(1..).collect();
|
let classifier = VariableClassifier::new(
|
||||||
let mut query_terms = self.setup_query(loader, post_head_terms, cut_context)?;
|
self.settings.default_call_policy(),
|
||||||
|
);
|
||||||
|
|
||||||
let clauses = query_terms.drain(1..).collect();
|
let (head, clauses, var_data) = classifier.classify_rule(loader, head, body)?;
|
||||||
let qt = query_terms.pop().unwrap();
|
|
||||||
|
|
||||||
match terms.pop().unwrap() {
|
match head {
|
||||||
Term::Clause(_, name, terms) => Ok(Rule {
|
Term::Clause(_, name, terms) => Ok((Rule {
|
||||||
head: (name, terms, qt),
|
head: (name, terms),
|
||||||
clauses,
|
clauses,
|
||||||
}),
|
}, var_data)),
|
||||||
Term::Literal(_, Literal::Atom(name)) => Ok(Rule {
|
Term::Literal(_, Literal::Atom(name)) => Ok((Rule {
|
||||||
head: (name, vec![], qt),
|
head: (name, vec![]),
|
||||||
clauses,
|
clauses,
|
||||||
}),
|
}, var_data)),
|
||||||
_ => Err(CompilationError::InvalidRuleHead),
|
_ => Err(CompilationError::InvalidRuleHead),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
fn try_term_to_query<'a, LS: LoadState<'a>>(
|
fn try_term_to_query<'a, LS: LoadState<'a>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
loader: &mut Loader<'a, LS>,
|
loader: &mut Loader<'a, LS>,
|
||||||
@@ -961,63 +586,49 @@ impl Preprocessor {
|
|||||||
cut_context,
|
cut_context,
|
||||||
)?))
|
)?))
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>(
|
pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
loader: &mut Loader<'a, LS>,
|
loader: &mut Loader<'a, LS>,
|
||||||
term: Term,
|
term: Term,
|
||||||
cut_context: CutContext,
|
|
||||||
) -> Result<TopLevel, CompilationError> {
|
) -> Result<TopLevel, CompilationError> {
|
||||||
match term {
|
match term {
|
||||||
Term::Clause(r, name, terms) => {
|
Term::Clause(r, name, mut terms) => {
|
||||||
if name == atom!("?-") {
|
let is_rule = name == atom!(":-") && terms.len() == 2;
|
||||||
self.try_term_to_query(loader, terms, cut_context)
|
|
||||||
} else if name == atom!(":-") && terms.len() == 2 {
|
if is_rule {
|
||||||
Ok(TopLevel::Rule(self.setup_rule(
|
let tail = terms.pop().unwrap();
|
||||||
loader,
|
let head = terms.pop().unwrap();
|
||||||
terms,
|
|
||||||
cut_context,
|
let (rule, var_data) = self.setup_rule(loader, head, tail)?;
|
||||||
)?))
|
Ok(TopLevel::Rule(rule, var_data))
|
||||||
} else {
|
} else {
|
||||||
let term = Term::Clause(r, name, terms);
|
let term = Term::Clause(r, name, terms);
|
||||||
Ok(TopLevel::Fact(self.setup_fact(term)?))
|
let (fact, var_data) = self.setup_fact(term)?;
|
||||||
|
Ok(TopLevel::Fact(fact, var_data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
term => Ok(TopLevel::Fact(self.setup_fact(term)?)),
|
term => {
|
||||||
|
let (fact, var_data) = self.setup_fact(term)?;
|
||||||
|
Ok(TopLevel::Fact(fact, var_data))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
fn try_terms_to_tls<'a, I: IntoIterator<Item = Term>, LS: LoadState<'a>>(
|
fn try_terms_to_tls<'a, I: IntoIterator<Item = Term>, LS: LoadState<'a>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
loader: &mut Loader<'a, LS>,
|
loader: &mut Loader<'a, LS>,
|
||||||
terms: I,
|
terms: I,
|
||||||
cut_context: CutContext,
|
|
||||||
) -> Result<VecDeque<TopLevel>, CompilationError> {
|
) -> Result<VecDeque<TopLevel>, CompilationError> {
|
||||||
let mut results = VecDeque::new();
|
let mut results = VecDeque::new();
|
||||||
|
|
||||||
for term in terms.into_iter() {
|
for term in terms.into_iter() {
|
||||||
results.push_back(self.try_term_to_tl(loader, term, cut_context)?);
|
results.push_back(self.try_term_to_tl(loader, term)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(results)
|
Ok(results)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
pub(super) fn parse_queue<'a, LS: LoadState<'a>>(
|
|
||||||
&mut self,
|
|
||||||
loader: &mut Loader<'a, LS>,
|
|
||||||
) -> Result<VecDeque<TopLevel>, CompilationError> {
|
|
||||||
let mut queue = VecDeque::new();
|
|
||||||
|
|
||||||
while let Some(terms) = self.queue.pop_front() {
|
|
||||||
let clauses = merge_clauses(&mut self.try_terms_to_tls(
|
|
||||||
loader,
|
|
||||||
terms,
|
|
||||||
CutContext::HasCutVariable,
|
|
||||||
)?)?;
|
|
||||||
|
|
||||||
queue.push_back(clauses);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(queue)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ use std::net::{TcpListener, TcpStream, SocketAddr, ToSocketAddrs};
|
|||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
use std::ops::Sub;
|
use std::ops::Sub;
|
||||||
use std::process;
|
use std::process;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@@ -1445,7 +1444,7 @@ impl Machine {
|
|||||||
|
|
||||||
let vars: Vec<_> = vars
|
let vars: Vec<_> = vars
|
||||||
.union(&result.supp_vars) // difference + union does not cancel.
|
.union(&result.supp_vars) // difference + union does not cancel.
|
||||||
.map(|v| Term::Var(Cell::default(), Rc::new(format!("_{}", v.get_value()))))
|
.map(|v| Term::Var(Cell::default(), VarPtr::from(format!("_{}", v.get_value()))))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let helper_clause_loc = self.code.len();
|
let helper_clause_loc = self.code.len();
|
||||||
@@ -1655,8 +1654,8 @@ impl Machine {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn is_reset_cont_marker(&self, p: usize) -> bool {
|
pub(crate) fn is_reset_cont_marker(&self, p: usize) -> bool {
|
||||||
match &self.code[p] {
|
match &self.code[p] {
|
||||||
&Instruction::CallResetContinuationMarker(_) |
|
&Instruction::CallResetContinuationMarker |
|
||||||
&Instruction::ExecuteResetContinuationMarker(_) => true,
|
&Instruction::ExecuteResetContinuationMarker => true,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4941,9 +4940,7 @@ impl Machine {
|
|||||||
|
|
||||||
let p_functor = self.deref_register(2);
|
let p_functor = self.deref_register(2);
|
||||||
|
|
||||||
let p = to_local_code_ptr(&self.machine_st.heap, p_functor).unwrap();
|
let num_cells = self.machine_st.stack.index_and_frame(e).prelude.num_cells;
|
||||||
|
|
||||||
let num_cells = *self.code[p].perm_vars_mut().unwrap();
|
|
||||||
let mut addrs = vec![];
|
let mut addrs = vec![];
|
||||||
|
|
||||||
for idx in 1..num_cells + 1 {
|
for idx in 1..num_cells + 1 {
|
||||||
|
|||||||
@@ -540,23 +540,7 @@ macro_rules! functor_term {
|
|||||||
macro_rules! compare_number_instr {
|
macro_rules! compare_number_instr {
|
||||||
($cmp: expr, $at_1: expr, $at_2: expr) => {{
|
($cmp: expr, $at_1: expr, $at_2: expr) => {{
|
||||||
$cmp.set_terms($at_1, $at_2);
|
$cmp.set_terms($at_1, $at_2);
|
||||||
call_clause!(ClauseType::Inlined(InlinedClauseType::CompareNumber($cmp)), 0)
|
ClauseType::Inlined(InlinedClauseType::CompareNumber($cmp)).to_instr()
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! call_clause {
|
|
||||||
($clause_type:expr, $pvs:expr) => {{
|
|
||||||
let mut instr = $clause_type.to_instr();
|
|
||||||
instr.perm_vars_mut().map(|pvs| *pvs = $pvs);
|
|
||||||
instr
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! call_clause_by_default {
|
|
||||||
($clause_type:expr, $pvs:expr) => {{
|
|
||||||
let mut instr = $clause_type.to_instr().to_default();
|
|
||||||
instr.perm_vars_mut().map(|pvs| *pvs = $pvs);
|
|
||||||
instr
|
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ use crate::machine::machine_indices::*;
|
|||||||
use crate::parser::char_reader::*;
|
use crate::parser::char_reader::*;
|
||||||
use crate::types::HeapCellValueTag;
|
use crate::types::HeapCellValueTag;
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::{Cell, Ref, RefCell, RefMut};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::hash::Hash;
|
use std::hash::{Hash, Hasher};
|
||||||
use std::io::{Error as IOError};
|
use std::io::{Error as IOError};
|
||||||
use std::ops::Neg;
|
use std::ops::{Deref, Neg};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
@@ -227,7 +227,7 @@ macro_rules! perm_v {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub enum GenContext {
|
pub enum GenContext {
|
||||||
Head,
|
Head,
|
||||||
Mid(usize),
|
Mid(usize),
|
||||||
@@ -572,6 +572,110 @@ impl Literal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct VarPtr(Rc<RefCell<Var>>);
|
||||||
|
|
||||||
|
impl Hash for VarPtr {
|
||||||
|
#[inline(always)]
|
||||||
|
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
||||||
|
self.borrow().hash(hasher)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for VarPtr {
|
||||||
|
type Target = RefCell<Var>;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.0.deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VarPtr {
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn borrow(&self) -> Ref<'_, Var> {
|
||||||
|
self.0.borrow()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn borrow_mut(&self) -> RefMut<'_, Var> {
|
||||||
|
self.0.borrow_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn to_var_num(&self) -> Option<usize> {
|
||||||
|
match *self.borrow() {
|
||||||
|
Var::Generated(var_num) => Some(var_num),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set(&self, var: Var) {
|
||||||
|
let mut var_ref = self.borrow_mut();
|
||||||
|
*var_ref = var;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Var> for VarPtr {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(value: Var) -> VarPtr {
|
||||||
|
VarPtr(Rc::new(RefCell::new(value)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for VarPtr {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(value: String) -> VarPtr {
|
||||||
|
VarPtr::from(Var::from(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for VarPtr {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(value: &str) -> VarPtr {
|
||||||
|
VarPtr::from(value.to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum Var {
|
||||||
|
Generated(usize),
|
||||||
|
InSitu(usize),
|
||||||
|
Named(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for Var {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(value: String) -> Var {
|
||||||
|
Var::Named(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Var {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(value: &str) -> Var {
|
||||||
|
Var::Named(value.to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Var {
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn as_str(&self) -> Option<&str> {
|
||||||
|
match self {
|
||||||
|
Var::Named(value) => Some(&value),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn to_string(&self) -> String {
|
||||||
|
match self {
|
||||||
|
Var::InSitu(n) | Var::Generated(n) => format!("_{}", n),
|
||||||
|
Var::Named(value) => value.to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Term {
|
pub enum Term {
|
||||||
AnonVar,
|
AnonVar,
|
||||||
@@ -582,7 +686,7 @@ pub enum Term {
|
|||||||
// other PartialString variants in as_partial_string.
|
// other PartialString variants in as_partial_string.
|
||||||
PartialString(Cell<RegType>, String, Box<Term>),
|
PartialString(Cell<RegType>, String, Box<Term>),
|
||||||
CompleteString(Cell<RegType>, Atom),
|
CompleteString(Cell<RegType>, Atom),
|
||||||
Var(Cell<VarReg>, Rc<String>),
|
Var(Cell<VarReg>, VarPtr),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Term {
|
impl Term {
|
||||||
@@ -667,3 +771,30 @@ pub fn unfold_by_str(mut term: Term, s: Atom) -> Vec<Term> {
|
|||||||
terms.push(term);
|
terms.push(term);
|
||||||
terms
|
terms
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn unfold_by_str_ref_once(term: &Term, s: Atom) -> Option<(&Term, &Term)> {
|
||||||
|
if let Term::Clause(_, ref name, ref subterms) = term {
|
||||||
|
if name == &s && subterms.len() == 2 {
|
||||||
|
let fst = &subterms[0];
|
||||||
|
let snd = &subterms[1];
|
||||||
|
|
||||||
|
return Some((fst, snd));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unfold_by_str_ref(mut term: &Term, s: Atom) -> Vec<&Term> {
|
||||||
|
let mut terms = vec![];
|
||||||
|
|
||||||
|
while let Some((fst, snd)) = unfold_by_str_ref_once(&term, s) {
|
||||||
|
terms.push(fst);
|
||||||
|
term = snd;
|
||||||
|
}
|
||||||
|
|
||||||
|
terms.push(term);
|
||||||
|
terms
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ use crate::parser::rug::ops::NegAssign;
|
|||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
enum TokenType {
|
enum TokenType {
|
||||||
@@ -427,7 +426,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
if v.trim() == "_" {
|
if v.trim() == "_" {
|
||||||
self.terms.push(Term::AnonVar);
|
self.terms.push(Term::AnonVar);
|
||||||
} else {
|
} else {
|
||||||
self.terms.push(Term::Var(Cell::default(), Rc::new(v)));
|
self.terms.push(Term::Var(Cell::default(), VarPtr::from(v)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenType::Term
|
TokenType::Term
|
||||||
|
|||||||
@@ -317,7 +317,7 @@ impl<'a, 'b> TermWriter<'a, 'b> {
|
|||||||
fn write_term_to_heap(mut self, term: &'a Term) -> Result<TermWriteResult, CompilationError> {
|
fn write_term_to_heap(mut self, term: &'a Term) -> Result<TermWriteResult, CompilationError> {
|
||||||
let heap_loc = self.heap.len();
|
let heap_loc = self.heap.len();
|
||||||
|
|
||||||
for term in breadth_first_iter(term, true) {
|
for term in breadth_first_iter(term, RootIterationPolicy::Iterated) {
|
||||||
let h = self.heap.len();
|
let h = self.heap.len();
|
||||||
|
|
||||||
match &term {
|
match &term {
|
||||||
@@ -372,9 +372,9 @@ impl<'a, 'b> TermWriter<'a, 'b> {
|
|||||||
let addr = self.term_as_addr(&term, h);
|
let addr = self.term_as_addr(&term, h);
|
||||||
self.heap.push(addr);
|
self.heap.push(addr);
|
||||||
}
|
}
|
||||||
&TermRef::Var(Level::Root, _, ref var) => {
|
&TermRef::Var(Level::Root, _, ref var_ptr) => {
|
||||||
let addr = self.term_as_addr(&term, h);
|
let addr = self.term_as_addr(&term, h);
|
||||||
self.var_dict.insert(var.clone(), heap_loc_as_cell!(h));
|
self.var_dict.insert(var_ptr.clone(), heap_loc_as_cell!(h));
|
||||||
self.heap.push(addr);
|
self.heap.push(addr);
|
||||||
}
|
}
|
||||||
&TermRef::AnonVar(_) => {
|
&TermRef::AnonVar(_) => {
|
||||||
|
|||||||
@@ -29,11 +29,13 @@ pub(crate) trait CompilationTarget<'a> {
|
|||||||
|
|
||||||
fn argument_to_variable(r: RegType, r: usize) -> Instruction;
|
fn argument_to_variable(r: RegType, r: usize) -> Instruction;
|
||||||
fn argument_to_value(r: RegType, val: usize) -> Instruction;
|
fn argument_to_value(r: RegType, val: usize) -> Instruction;
|
||||||
|
fn unsafe_argument_to_value(r: RegType, val: usize) -> Instruction;
|
||||||
|
|
||||||
fn move_to_register(r: RegType, val: usize) -> Instruction;
|
fn move_to_register(r: RegType, val: usize) -> Instruction;
|
||||||
|
|
||||||
fn subterm_to_variable(r: RegType) -> Instruction;
|
fn subterm_to_variable(r: RegType) -> Instruction;
|
||||||
fn subterm_to_value(r: RegType) -> Instruction;
|
fn subterm_to_value(r: RegType) -> Instruction;
|
||||||
|
fn unsafe_subterm_to_value(r: RegType) -> Instruction;
|
||||||
|
|
||||||
fn clause_arg_to_instr(r: RegType) -> Instruction;
|
fn clause_arg_to_instr(r: RegType) -> Instruction;
|
||||||
}
|
}
|
||||||
@@ -42,7 +44,7 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
|
|||||||
type Iterator = FactIterator<'a>;
|
type Iterator = FactIterator<'a>;
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator {
|
fn iter(term: &'a Term) -> Self::Iterator {
|
||||||
breadth_first_iter(term, false) // do not iterate over the root clause if one exists.
|
breadth_first_iter(term, RootIterationPolicy::NotIterated)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
|
fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
|
||||||
@@ -95,6 +97,10 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
|
|||||||
Instruction::GetValue(arg, val)
|
Instruction::GetValue(arg, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn unsafe_argument_to_value(arg: RegType, val: usize) -> Instruction {
|
||||||
|
Instruction::GetValue(arg, val)
|
||||||
|
}
|
||||||
|
|
||||||
fn subterm_to_variable(val: RegType) -> Instruction {
|
fn subterm_to_variable(val: RegType) -> Instruction {
|
||||||
Instruction::UnifyVariable(val)
|
Instruction::UnifyVariable(val)
|
||||||
}
|
}
|
||||||
@@ -103,6 +109,10 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
|
|||||||
Instruction::UnifyValue(val)
|
Instruction::UnifyValue(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn unsafe_subterm_to_value(val: RegType) -> Instruction {
|
||||||
|
Instruction::UnifyLocalValue(val)
|
||||||
|
}
|
||||||
|
|
||||||
fn clause_arg_to_instr(val: RegType) -> Instruction {
|
fn clause_arg_to_instr(val: RegType) -> Instruction {
|
||||||
Instruction::UnifyVariable(val)
|
Instruction::UnifyVariable(val)
|
||||||
}
|
}
|
||||||
@@ -165,6 +175,13 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
|
|||||||
Instruction::PutValue(arg, val)
|
Instruction::PutValue(arg, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn unsafe_argument_to_value(arg: RegType, val: usize) -> Instruction {
|
||||||
|
match arg {
|
||||||
|
RegType::Perm(p) => Instruction::PutUnsafeValue(p, val),
|
||||||
|
RegType::Temp(_) => Instruction::PutValue(arg, val),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn subterm_to_variable(val: RegType) -> Instruction {
|
fn subterm_to_variable(val: RegType) -> Instruction {
|
||||||
Instruction::SetVariable(val)
|
Instruction::SetVariable(val)
|
||||||
}
|
}
|
||||||
@@ -173,6 +190,10 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
|
|||||||
Instruction::SetValue(val)
|
Instruction::SetValue(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn unsafe_subterm_to_value(val: RegType) -> Instruction {
|
||||||
|
Instruction::SetLocalValue(val)
|
||||||
|
}
|
||||||
|
|
||||||
fn clause_arg_to_instr(val: RegType) -> Instruction {
|
fn clause_arg_to_instr(val: RegType) -> Instruction {
|
||||||
Instruction::SetValue(val)
|
Instruction::SetValue(val)
|
||||||
}
|
}
|
||||||
|
|||||||
248
src/variable_records.rs
Normal file
248
src/variable_records.rs
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
use crate::parser::ast::*;
|
||||||
|
|
||||||
|
use bit_set::*;
|
||||||
|
use fxhash::FxBuildHasher;
|
||||||
|
use indexmap::{IndexMap, IndexSet};
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct TempVarData {
|
||||||
|
pub(crate) use_set: IndexSet<(GenContext, usize), FxBuildHasher>,
|
||||||
|
pub(crate) no_use_set: BitSet<usize>,
|
||||||
|
pub(crate) conflict_set: BitSet<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct BranchDesignator(pub (usize, usize));
|
||||||
|
|
||||||
|
impl BranchDesignator {
|
||||||
|
#[inline]
|
||||||
|
pub fn is_subbranch(&self) -> bool {
|
||||||
|
(self.0).0 > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn subsumes(&self, branch_designator: &Self) -> bool {
|
||||||
|
(self.0).0 < (branch_designator.0).0 || self == branch_designator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum VarSafetyStatus {
|
||||||
|
Needed,
|
||||||
|
// which branch planted the last unsafe guarded instruction? It may still be needed.
|
||||||
|
LocallyUnneeded(BranchDesignator),
|
||||||
|
GloballyUnneeded,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VarSafetyStatus {
|
||||||
|
pub(crate) fn unneeded(current_branch: BranchDesignator) -> Self {
|
||||||
|
if current_branch.is_subbranch() {
|
||||||
|
VarSafetyStatus::LocallyUnneeded(current_branch)
|
||||||
|
} else {
|
||||||
|
VarSafetyStatus::GloballyUnneeded
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn is_unneeded(&self, current_branch: BranchDesignator) -> bool {
|
||||||
|
match self {
|
||||||
|
&VarSafetyStatus::Needed => false,
|
||||||
|
&VarSafetyStatus::LocallyUnneeded(planter_branch) => planter_branch.subsumes(¤t_branch),
|
||||||
|
&VarSafetyStatus::GloballyUnneeded => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn needed_if(needed: bool, branch_designator: BranchDesignator) -> Self {
|
||||||
|
if needed {
|
||||||
|
VarSafetyStatus::Needed
|
||||||
|
} else if (branch_designator.0).0 == 0 {
|
||||||
|
VarSafetyStatus::GloballyUnneeded
|
||||||
|
} else {
|
||||||
|
VarSafetyStatus::LocallyUnneeded(branch_designator)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum PermVarAllocation {
|
||||||
|
Done { shallow_safety: VarSafetyStatus,
|
||||||
|
deep_safety: VarSafetyStatus },
|
||||||
|
Pending,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PermVarAllocation {
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn done() -> Self {
|
||||||
|
PermVarAllocation::Done {
|
||||||
|
shallow_safety: VarSafetyStatus::Needed,
|
||||||
|
deep_safety: VarSafetyStatus::Needed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn pending(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
&PermVarAllocation::Pending => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum VarAlloc {
|
||||||
|
Temp { term_loc: GenContext,
|
||||||
|
temp_reg: usize,
|
||||||
|
temp_var_data: TempVarData,
|
||||||
|
safety: VarSafetyStatus,
|
||||||
|
to_perm_var_num: Option<usize> },
|
||||||
|
Perm(usize, PermVarAllocation), // stack offset, allocation info
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VarAlloc {
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn as_reg_type(&self) -> RegType {
|
||||||
|
match self {
|
||||||
|
&VarAlloc::Temp { temp_reg, .. } => RegType::Temp(temp_reg),
|
||||||
|
&VarAlloc::Perm(r, _) => RegType::Perm(r),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn set_register(&mut self, reg_num: usize) {
|
||||||
|
match self {
|
||||||
|
VarAlloc::Perm(ref mut p, _) => *p = reg_num,
|
||||||
|
VarAlloc::Temp { ref mut temp_reg, .. } => *temp_reg = reg_num,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TempVarData {
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
TempVarData {
|
||||||
|
use_set: IndexSet::with_hasher(FxBuildHasher::default()),
|
||||||
|
no_use_set: BitSet::default(),
|
||||||
|
conflict_set: BitSet::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn uses_reg(&self, reg: usize) -> bool {
|
||||||
|
for &(_, nreg) in self.use_set.iter() {
|
||||||
|
if reg == nreg {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn populate_conflict_set(&mut self) {
|
||||||
|
let arity = self.use_set.len();
|
||||||
|
let mut conflict_set: BitSet<usize> = (1..arity).collect();
|
||||||
|
|
||||||
|
for &(_, idx) in &self.use_set {
|
||||||
|
conflict_set.remove(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.conflict_set = conflict_set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct VariableRecord {
|
||||||
|
pub allocation: VarAlloc,
|
||||||
|
pub num_occurrences: usize,
|
||||||
|
pub running_count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for VariableRecord {
|
||||||
|
fn default() -> Self {
|
||||||
|
VariableRecord {
|
||||||
|
allocation: VarAlloc::Perm(0, PermVarAllocation::Pending),
|
||||||
|
num_occurrences: 0,
|
||||||
|
running_count: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct VariableRecords(Vec<VariableRecord>);
|
||||||
|
|
||||||
|
impl Deref for VariableRecords {
|
||||||
|
type Target = Vec<VariableRecord>;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for VariableRecords {
|
||||||
|
#[inline(always)]
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VariableRecords {
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn new(num_records: usize) -> Self {
|
||||||
|
Self(vec![VariableRecord::default(); num_records])
|
||||||
|
}
|
||||||
|
|
||||||
|
// computes no_use and conflict sets for all temp vars.
|
||||||
|
pub(crate) fn populate_restricting_sets(&mut self) {
|
||||||
|
// three stages:
|
||||||
|
// 1. move the use sets of each variable to a local IndexMap, use_set
|
||||||
|
// (iterate mutably, swap mutable refs).
|
||||||
|
// 2. drain use_set. For each use set of U, add into the
|
||||||
|
// no-use sets of appropriate variables T =/= U.
|
||||||
|
// 3. Move the use sets back to their original locations in the fixture.
|
||||||
|
// Compute the conflict set of u.
|
||||||
|
|
||||||
|
// 1.
|
||||||
|
let mut use_sets: IndexMap<usize, IndexSet<(GenContext, usize), FxBuildHasher>> = IndexMap::new();
|
||||||
|
|
||||||
|
for (var_gen_index, record) in self.0.iter_mut().enumerate() {
|
||||||
|
match &mut record.allocation {
|
||||||
|
VarAlloc::Temp { temp_var_data, .. } => {
|
||||||
|
let use_set = std::mem::replace(
|
||||||
|
&mut temp_var_data.use_set,
|
||||||
|
IndexSet::with_hasher(FxBuildHasher::default()),
|
||||||
|
);
|
||||||
|
|
||||||
|
use_sets.insert(var_gen_index, use_set);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u, use_set) in use_sets.drain(..) {
|
||||||
|
// 2.
|
||||||
|
for &(term_loc, reg) in &use_set {
|
||||||
|
if let GenContext::Last(cn_u) = term_loc {
|
||||||
|
for (var_gen_index, record) in self.0.iter_mut().enumerate() {
|
||||||
|
match &mut record.allocation {
|
||||||
|
VarAlloc::Temp { term_loc, temp_var_data, .. } => {
|
||||||
|
if cn_u == term_loc.chunk_num() && u != var_gen_index {
|
||||||
|
if !temp_var_data.uses_reg(reg) {
|
||||||
|
temp_var_data.no_use_set.insert(reg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3.
|
||||||
|
if let VarAlloc::Temp{ temp_var_data, .. } = &mut self[u].allocation {
|
||||||
|
temp_var_data.use_set = use_set;
|
||||||
|
temp_var_data.populate_conflict_set();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user