remove Term
This commit is contained in:
@@ -192,9 +192,9 @@ enum ReplCodePtr {
|
||||
DynamicProperty,
|
||||
#[strum_discriminants(strum(props(Arity = "3", Name = "$abolish_clause")))]
|
||||
AbolishClause,
|
||||
#[strum_discriminants(strum(props(Arity = "3", Name = "$asserta")))]
|
||||
#[strum_discriminants(strum(props(Arity = "2", Name = "$asserta")))]
|
||||
Asserta,
|
||||
#[strum_discriminants(strum(props(Arity = "3", Name = "$assertz")))]
|
||||
#[strum_discriminants(strum(props(Arity = "2", Name = "$assertz")))]
|
||||
Assertz,
|
||||
#[strum_discriminants(strum(props(Arity = "4", Name = "$retract_clause")))]
|
||||
Retract,
|
||||
|
||||
@@ -4,8 +4,6 @@ use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
use crate::targets::*;
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
pub(crate) trait Allocator {
|
||||
fn new() -> Self;
|
||||
|
||||
@@ -19,22 +17,21 @@ pub(crate) trait Allocator {
|
||||
fn mark_non_var<'a, Target: CompilationTarget<'a>>(
|
||||
&mut self,
|
||||
lvl: Level,
|
||||
heap_loc: usize,
|
||||
context: GenContext,
|
||||
cell: &'a Cell<RegType>,
|
||||
code: &mut CodeDeque,
|
||||
);
|
||||
) -> RegType;
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
|
||||
&mut self,
|
||||
var_num: usize,
|
||||
lvl: Level,
|
||||
cell: &Cell<VarReg>,
|
||||
term_loc: GenContext,
|
||||
context: GenContext,
|
||||
code: &mut CodeDeque,
|
||||
r: RegType,
|
||||
is_new_var: bool,
|
||||
);
|
||||
) -> RegType;
|
||||
|
||||
fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType;
|
||||
|
||||
@@ -42,14 +39,13 @@ pub(crate) trait Allocator {
|
||||
&mut self,
|
||||
var_num: usize,
|
||||
lvl: Level,
|
||||
cell: &Cell<VarReg>,
|
||||
context: GenContext,
|
||||
code: &mut CodeDeque,
|
||||
);
|
||||
) -> RegType;
|
||||
|
||||
fn reset(&mut self);
|
||||
fn reset_arg(&mut self, arg_num: usize);
|
||||
fn reset_at_head(&mut self, args: &[Term]);
|
||||
fn reset_at_head(&mut self, term: &mut FocusedHeap, head_loc: usize);
|
||||
fn reset_contents(&mut self);
|
||||
|
||||
fn advance_arg(&mut self);
|
||||
|
||||
@@ -7,6 +7,8 @@ use crate::debray_allocator::*;
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
use crate::iterators::*;
|
||||
use crate::machine::stack::Stack;
|
||||
use crate::parser::ast::FocusedHeap;
|
||||
use crate::targets::QueryInstruction;
|
||||
use crate::types::*;
|
||||
|
||||
@@ -20,7 +22,6 @@ use dashu::base::BitTest;
|
||||
use num_order::NumOrd;
|
||||
use ordered_float::{Float, OrderedFloat};
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::cmp::{max, min, Ordering};
|
||||
use std::convert::TryFrom;
|
||||
use std::f64;
|
||||
@@ -51,13 +52,14 @@ impl Default for ArithmeticTerm {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type ArithCont = (CodeDeque, Option<ArithmeticTerm>);
|
||||
|
||||
/*
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ArithInstructionIterator<'a> {
|
||||
state_stack: Vec<TermIterState<'a>>,
|
||||
}
|
||||
|
||||
pub(crate) type ArithCont = (CodeDeque, Option<ArithmeticTerm>);
|
||||
|
||||
impl<'a> ArithInstructionIterator<'a> {
|
||||
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
||||
self.state_stack
|
||||
@@ -134,13 +136,6 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ArithmeticEvaluator<'a> {
|
||||
marker: &'a mut DebrayAllocator,
|
||||
interm: Vec<ArithmeticTerm>,
|
||||
interm_c: usize,
|
||||
}
|
||||
|
||||
pub(crate) trait ArithmeticTermIter<'a> {
|
||||
type Iter: Iterator<Item = Result<ArithTermRef<'a>, ArithmeticError>>;
|
||||
|
||||
@@ -154,23 +149,31 @@ impl<'a> ArithmeticTermIter<'a> for &'a Term {
|
||||
ArithInstructionIterator::from(self)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: &Literal) -> Result<(), ArithmeticError> {
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ArithmeticEvaluator<'a> {
|
||||
marker: &'a mut DebrayAllocator,
|
||||
interm: Vec<ArithmeticTerm>,
|
||||
interm_c: usize,
|
||||
}
|
||||
|
||||
fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: Literal) -> Result<(), ArithmeticError> {
|
||||
match c {
|
||||
Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(*n))),
|
||||
Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(*n))),
|
||||
Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(n))),
|
||||
Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(n))),
|
||||
Literal::Float(n) => interm.push(ArithmeticTerm::Number(Number::Float(*n.as_ptr()))),
|
||||
Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(*n))),
|
||||
Literal::Atom(name) if name == &atom!("e") => interm.push(ArithmeticTerm::Number(
|
||||
Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(n))),
|
||||
Literal::Atom(name) if name == atom!("e") => interm.push(ArithmeticTerm::Number(
|
||||
Number::Float(OrderedFloat(std::f64::consts::E)),
|
||||
)),
|
||||
Literal::Atom(name) if name == &atom!("pi") => interm.push(ArithmeticTerm::Number(
|
||||
Literal::Atom(name) if name == atom!("pi") => interm.push(ArithmeticTerm::Number(
|
||||
Number::Float(OrderedFloat(std::f64::consts::PI)),
|
||||
)),
|
||||
Literal::Atom(name) if name == &atom!("epsilon") => interm.push(ArithmeticTerm::Number(
|
||||
Literal::Atom(name) if name == atom!("epsilon") => interm.push(ArithmeticTerm::Number(
|
||||
Number::Float(OrderedFloat(f64::EPSILON)),
|
||||
)),
|
||||
_ => return Err(ArithmeticError::NonEvaluableFunctor(*c, 0)),
|
||||
_ => return Err(ArithmeticError::NonEvaluableFunctor(c, 0)),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -309,44 +312,57 @@ impl<'a> ArithmeticEvaluator<'a> {
|
||||
|
||||
pub(crate) fn compile_is(
|
||||
&mut self,
|
||||
src: &'a Term,
|
||||
term_loc: GenContext,
|
||||
src: &mut FocusedHeap,
|
||||
term_loc: usize,
|
||||
context: GenContext,
|
||||
arg: usize,
|
||||
) -> Result<ArithCont, ArithmeticError> {
|
||||
let mut code = CodeDeque::new();
|
||||
let mut stack = Stack::uninitialized();
|
||||
let mut iter = query_iterator::<false>(&mut src.heap, &mut stack, term_loc);
|
||||
|
||||
for term_ref in src.iter()? {
|
||||
match term_ref? {
|
||||
ArithTermRef::Literal(c) => push_literal(&mut self.interm, c)?,
|
||||
ArithTermRef::Var(lvl, cell, name) => {
|
||||
let var_num = name.to_var_num().unwrap();
|
||||
while let Some(term) = iter.next() {
|
||||
read_heap_cell!(term,
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
let lvl = iter.level();
|
||||
let var_ptr = src.var_locs.read_next_var_ptr_at_key(h).unwrap();
|
||||
let var_num = var_ptr.to_var_num().unwrap();
|
||||
let old_r = self.marker.get_var_binding(var_num);
|
||||
|
||||
let r = if lvl == Level::Shallow {
|
||||
self.marker
|
||||
.mark_non_callable(var_num, arg, term_loc, cell, &mut code)
|
||||
} else if term_loc.is_last() || cell.get().norm().reg_num() == 0 {
|
||||
let r = self.marker.get_binding(var_num);
|
||||
let r = if lvl == Level::Root {
|
||||
self.marker.mark_non_callable(var_num, arg, context, &mut code)
|
||||
} else if context.is_last() || old_r.reg_num() == 0 {
|
||||
let r = old_r;
|
||||
|
||||
if r.reg_num() == 0 {
|
||||
self.marker.mark_var::<QueryInstruction>(
|
||||
var_num, lvl, cell, term_loc, &mut code,
|
||||
);
|
||||
cell.get().norm()
|
||||
var_num, lvl, context, &mut code,
|
||||
)
|
||||
} else {
|
||||
self.marker.increment_running_count(var_num);
|
||||
r
|
||||
}
|
||||
} else {
|
||||
self.marker.increment_running_count(var_num);
|
||||
cell.get().norm()
|
||||
old_r
|
||||
};
|
||||
|
||||
self.interm.push(ArithmeticTerm::Reg(r));
|
||||
}
|
||||
ArithTermRef::Op(name, arity) => {
|
||||
code.push_back(self.instr_from_clause(name, arity)?);
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
if arity == 0 {
|
||||
push_literal(&mut self.interm, Literal::Atom(name))?;
|
||||
} else {
|
||||
code.push_back(self.instr_from_clause(name, arity)?);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
match Literal::try_from(term) {
|
||||
Ok(lit) => push_literal(&mut self.interm, lit)?,
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Ok((code, self.interm.pop()))
|
||||
|
||||
1114
src/codegen.rs
1114
src/codegen.rs
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,13 @@
|
||||
use crate::allocator::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::codegen::SubsumedBranchHits;
|
||||
use crate::forms::Level;
|
||||
use crate::instructions::*;
|
||||
use crate::machine::disjuncts::VarData;
|
||||
use crate::machine::heap::{heap_bound_deref, heap_bound_store};
|
||||
use crate::parser::ast::*;
|
||||
use crate::targets::*;
|
||||
use crate::types::*;
|
||||
use crate::variable_records::*;
|
||||
|
||||
use bit_set::*;
|
||||
@@ -12,7 +15,6 @@ use bitvec::prelude::*;
|
||||
use fxhash::FxBuildHasher;
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::VecDeque;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
@@ -152,6 +154,8 @@ pub(crate) struct DebrayAllocator {
|
||||
in_use: BitSet<usize>, // deep and non-var allocations
|
||||
temp_free_list: Vec<usize>,
|
||||
perm_free_list: VecDeque<(usize, usize)>, // chunk_num, var_num
|
||||
non_var_registers: IndexMap<usize, usize, FxBuildHasher>,
|
||||
non_var_register_heap_locs: IndexMap<usize, usize, FxBuildHasher>,
|
||||
}
|
||||
|
||||
impl DebrayAllocator {
|
||||
@@ -168,7 +172,7 @@ impl DebrayAllocator {
|
||||
|
||||
for var_num in subsumed_hits {
|
||||
match &mut self.var_data.records[var_num].allocation {
|
||||
VarAlloc::Perm(_, ref mut allocation) => {
|
||||
VarAlloc::Perm { ref mut allocation, .. } => {
|
||||
if let PermVarAllocation::Done {
|
||||
shallow_safety,
|
||||
deep_safety,
|
||||
@@ -229,7 +233,7 @@ impl DebrayAllocator {
|
||||
let num_occurrences = self.var_data.records[var_num].num_occurrences;
|
||||
|
||||
match &mut self.var_data.records[var_num].allocation {
|
||||
VarAlloc::Perm(_, allocation) => {
|
||||
VarAlloc::Perm { allocation, ..} => {
|
||||
let shallow_safety = VarSafetyStatus::needed_if(
|
||||
shallow_safety.contains(var_num),
|
||||
branch_designator,
|
||||
@@ -366,7 +370,7 @@ impl DebrayAllocator {
|
||||
&mut self,
|
||||
chunk_num: usize,
|
||||
code: &mut CodeDeque,
|
||||
) {
|
||||
) -> Option<RegType> {
|
||||
if let Some((var_num, r)) = self.alloc_in_last_goal_hint(chunk_num) {
|
||||
let k = self.arg_c;
|
||||
|
||||
@@ -382,8 +386,12 @@ impl DebrayAllocator {
|
||||
.allocation
|
||||
.set_register(r.reg_num());
|
||||
self.in_use.insert(r.reg_num());
|
||||
|
||||
return Some(r);
|
||||
}
|
||||
};
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn alloc_reg_to_var<'a, Target: CompilationTarget<'a>>(
|
||||
@@ -433,6 +441,7 @@ impl DebrayAllocator {
|
||||
}
|
||||
|
||||
self.temp_lb = final_index + 1;
|
||||
|
||||
final_index
|
||||
}
|
||||
|
||||
@@ -456,7 +465,11 @@ impl DebrayAllocator {
|
||||
p
|
||||
};
|
||||
|
||||
self.var_data.records[var_num].allocation = VarAlloc::Perm(p, PermVarAllocation::done());
|
||||
self.var_data.records[var_num].allocation = VarAlloc::Perm {
|
||||
reg: p,
|
||||
allocation: PermVarAllocation::done(),
|
||||
};
|
||||
|
||||
p
|
||||
}
|
||||
|
||||
@@ -472,10 +485,15 @@ impl DebrayAllocator {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_binding(&self, var_num: usize) -> RegType {
|
||||
pub fn get_var_binding(&self, var_num: usize) -> RegType {
|
||||
self.var_data.records[var_num].allocation.as_reg_type()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_non_var_binding(&self, heap_loc: usize) -> RegType {
|
||||
RegType::Temp(self.non_var_registers.get(&heap_loc).cloned().unwrap_or(0))
|
||||
}
|
||||
|
||||
pub fn num_perm_vars(&self) -> usize {
|
||||
self.perm_lb - 1
|
||||
}
|
||||
@@ -485,7 +503,7 @@ impl DebrayAllocator {
|
||||
}
|
||||
|
||||
fn add_perm_to_free_list(&mut self, chunk_num: usize, var_num: usize) {
|
||||
if let VarAlloc::Perm(..) = &self.var_data.records[var_num].allocation {
|
||||
if let VarAlloc::Perm { .. } = &self.var_data.records[var_num].allocation {
|
||||
self.perm_free_list.push_back((chunk_num, var_num));
|
||||
}
|
||||
}
|
||||
@@ -496,9 +514,10 @@ impl DebrayAllocator {
|
||||
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));
|
||||
}
|
||||
VarAlloc::Perm { reg: p, allocation: PermVarAllocation::Pending }
|
||||
if *p > 0 => {
|
||||
return Some(std::mem::replace(p, 0));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
@@ -510,9 +529,12 @@ impl DebrayAllocator {
|
||||
}
|
||||
|
||||
pub(crate) fn free_var(&mut self, chunk_num: usize, var_num: usize) {
|
||||
if let VarAlloc::Perm(_, allocation) = &mut self.var_data.records[var_num].allocation {
|
||||
*allocation = PermVarAllocation::Pending;
|
||||
self.add_perm_to_free_list(chunk_num, var_num);
|
||||
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);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -520,14 +542,14 @@ impl DebrayAllocator {
|
||||
let branch_designator = self.branch_stack.current_branch_designator();
|
||||
|
||||
match &mut self.var_data.records[var_num].allocation {
|
||||
VarAlloc::Perm(
|
||||
_,
|
||||
PermVarAllocation::Done {
|
||||
VarAlloc::Perm {
|
||||
allocation: PermVarAllocation::Done {
|
||||
deep_safety,
|
||||
shallow_safety,
|
||||
..
|
||||
},
|
||||
) => {
|
||||
..
|
||||
} => {
|
||||
*deep_safety = VarSafetyStatus::unneeded(branch_designator);
|
||||
*shallow_safety = VarSafetyStatus::unneeded(branch_designator);
|
||||
}
|
||||
@@ -542,14 +564,14 @@ impl DebrayAllocator {
|
||||
let branch_designator = self.branch_stack.current_branch_designator();
|
||||
|
||||
match &mut self.var_data.records[var_num].allocation {
|
||||
VarAlloc::Perm(
|
||||
_,
|
||||
PermVarAllocation::Done {
|
||||
VarAlloc::Perm {
|
||||
allocation: PermVarAllocation::Done {
|
||||
deep_safety,
|
||||
shallow_safety,
|
||||
..
|
||||
},
|
||||
) => {
|
||||
..
|
||||
} => {
|
||||
// GetVariable in head chunk is considered safe.
|
||||
if lvl == Level::Deep {
|
||||
*deep_safety = VarSafetyStatus::unneeded(branch_designator);
|
||||
@@ -586,13 +608,13 @@ impl DebrayAllocator {
|
||||
let branch_designator = self.branch_stack.current_branch_designator();
|
||||
|
||||
match &mut self.var_data.records[var_num].allocation {
|
||||
VarAlloc::Perm(
|
||||
_,
|
||||
PermVarAllocation::Done {
|
||||
VarAlloc::Perm {
|
||||
allocation: PermVarAllocation::Done {
|
||||
ref mut shallow_safety,
|
||||
..
|
||||
},
|
||||
) => {
|
||||
..
|
||||
} => {
|
||||
if !self.in_tail_position
|
||||
|| self
|
||||
.branch_stack
|
||||
@@ -622,13 +644,13 @@ impl DebrayAllocator {
|
||||
let branch_designator = self.branch_stack.current_branch_designator();
|
||||
|
||||
match &mut self.var_data.records[var_num].allocation {
|
||||
VarAlloc::Perm(
|
||||
_,
|
||||
PermVarAllocation::Done {
|
||||
VarAlloc::Perm {
|
||||
allocation: PermVarAllocation::Done {
|
||||
ref mut deep_safety,
|
||||
..
|
||||
},
|
||||
) => {
|
||||
..
|
||||
} => {
|
||||
if self
|
||||
.branch_stack
|
||||
.safety_unneeded_in_branch(deep_safety, &branch_designator)
|
||||
@@ -671,13 +693,15 @@ impl Allocator for DebrayAllocator {
|
||||
temp_free_list: vec![],
|
||||
perm_free_list: VecDeque::new(),
|
||||
branch_stack: BranchStack { stack: vec![] },
|
||||
non_var_registers: IndexMap::with_hasher(FxBuildHasher::default()),
|
||||
non_var_register_heap_locs: IndexMap::with_hasher(FxBuildHasher::default()),
|
||||
}
|
||||
}
|
||||
|
||||
fn mark_anon_var<'a, Target: CompilationTarget<'a>>(
|
||||
&mut self,
|
||||
lvl: Level,
|
||||
term_loc: GenContext,
|
||||
context: GenContext,
|
||||
code: &mut CodeDeque,
|
||||
) {
|
||||
let r = RegType::Temp(self.alloc_reg_to_non_var());
|
||||
@@ -687,7 +711,7 @@ impl Allocator for DebrayAllocator {
|
||||
Level::Root | Level::Shallow => {
|
||||
let k = self.arg_c;
|
||||
|
||||
if let GenContext::Last(chunk_num) = term_loc {
|
||||
if let GenContext::Last(chunk_num) = context {
|
||||
self.evacuate_arg::<Target>(chunk_num, code);
|
||||
}
|
||||
|
||||
@@ -701,55 +725,69 @@ impl Allocator for DebrayAllocator {
|
||||
fn mark_non_var<'a, Target: CompilationTarget<'a>>(
|
||||
&mut self,
|
||||
lvl: Level,
|
||||
term_loc: GenContext,
|
||||
cell: &'a Cell<RegType>,
|
||||
heap_loc: usize,
|
||||
context: GenContext,
|
||||
code: &mut CodeDeque,
|
||||
) {
|
||||
let r = cell.get();
|
||||
) -> RegType {
|
||||
let r = self.get_non_var_binding(heap_loc);
|
||||
|
||||
let r = match lvl {
|
||||
Level::Shallow => {
|
||||
let k = self.arg_c;
|
||||
|
||||
if let GenContext::Last(chunk_num) = term_loc {
|
||||
self.evacuate_arg::<Target>(chunk_num, code);
|
||||
if let GenContext::Last(chunk_num) = context {
|
||||
if let Some(new_r) = self.evacuate_arg::<Target>(chunk_num, code) {
|
||||
self.non_var_register_heap_locs
|
||||
.swap_remove(&k)
|
||||
.map(|old_heap_loc| {
|
||||
self.non_var_registers.insert(old_heap_loc, new_r.reg_num());
|
||||
self.non_var_register_heap_locs
|
||||
.insert(new_r.reg_num(), old_heap_loc);
|
||||
});
|
||||
|
||||
self.non_var_registers.insert(heap_loc, k);
|
||||
self.non_var_register_heap_locs.insert(k, heap_loc);
|
||||
}
|
||||
}
|
||||
|
||||
self.arg_c += 1;
|
||||
RegType::Temp(k)
|
||||
}
|
||||
_ if r.reg_num() == 0 => RegType::Temp(self.alloc_reg_to_non_var()),
|
||||
_ if r.reg_num() == 0 => {
|
||||
let r = RegType::Temp(self.alloc_reg_to_non_var());
|
||||
self.non_var_registers.insert(heap_loc, r.reg_num());
|
||||
self.non_var_register_heap_locs
|
||||
.insert(r.reg_num(), heap_loc);
|
||||
r
|
||||
}
|
||||
_ => {
|
||||
self.in_use.insert(r.reg_num());
|
||||
r
|
||||
}
|
||||
};
|
||||
|
||||
cell.set(r);
|
||||
r
|
||||
}
|
||||
|
||||
fn mark_var<'a, Target: CompilationTarget<'a>>(
|
||||
&mut self,
|
||||
var_num: usize,
|
||||
lvl: Level,
|
||||
cell: &Cell<VarReg>,
|
||||
term_loc: GenContext,
|
||||
context: GenContext,
|
||||
code: &mut CodeDeque,
|
||||
) {
|
||||
let (r, is_new_var) = match self.get_binding(var_num) {
|
||||
) -> RegType {
|
||||
let (r, is_new_var) = match self.get_var_binding(var_num) {
|
||||
RegType::Temp(0) => {
|
||||
let o = self.alloc_reg_to_var::<Target>(var_num, lvl, term_loc, code);
|
||||
cell.set(VarReg::Norm(RegType::Temp(o)));
|
||||
let o = self.alloc_reg_to_var::<Target>(var_num, lvl, context, code);
|
||||
(RegType::Temp(o), true)
|
||||
}
|
||||
RegType::Perm(0) => {
|
||||
let p = self.alloc_perm_var(var_num, term_loc.chunk_num());
|
||||
cell.set(VarReg::Norm(RegType::Perm(p)));
|
||||
let p = self.alloc_perm_var(var_num, context.chunk_num());
|
||||
(RegType::Perm(p), true)
|
||||
}
|
||||
r @ RegType::Perm(_) => {
|
||||
let is_new_var = match &mut self.var_data.records[var_num].allocation {
|
||||
VarAlloc::Perm(_, allocation) => {
|
||||
VarAlloc::Perm { allocation, .. } => {
|
||||
if allocation.pending() {
|
||||
*allocation = PermVarAllocation::done();
|
||||
true
|
||||
@@ -765,32 +803,29 @@ impl Allocator for DebrayAllocator {
|
||||
r => (r, false),
|
||||
};
|
||||
|
||||
self.mark_reserved_var::<Target>(var_num, lvl, cell, term_loc, code, r, is_new_var);
|
||||
self.mark_reserved_var::<Target>(var_num, lvl, context, code, r, is_new_var)
|
||||
}
|
||||
|
||||
fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
|
||||
&mut self,
|
||||
var_num: usize,
|
||||
lvl: Level,
|
||||
cell: &Cell<VarReg>,
|
||||
term_loc: GenContext,
|
||||
context: GenContext,
|
||||
code: &mut CodeDeque,
|
||||
r: RegType,
|
||||
is_new_var: bool,
|
||||
) {
|
||||
) -> RegType {
|
||||
match lvl {
|
||||
Level::Root | Level::Shallow => {
|
||||
let k = self.arg_c;
|
||||
|
||||
if self.is_curr_arg_distinct_from(var_num) {
|
||||
self.evacuate_arg::<Target>(term_loc.chunk_num(), code);
|
||||
self.evacuate_arg::<Target>(context.chunk_num(), code);
|
||||
}
|
||||
|
||||
cell.set(VarReg::ArgAndNorm(r, k));
|
||||
|
||||
if !self.in_place(var_num, term_loc, r, k) {
|
||||
if !self.in_place(var_num, context, r, k) {
|
||||
if is_new_var {
|
||||
self.mark_safe_var(var_num, lvl, term_loc);
|
||||
self.mark_safe_var(var_num, lvl, context);
|
||||
code.push_back(Target::argument_to_variable(r, k));
|
||||
} else {
|
||||
code.push_back(self.argument_to_value::<Target>(var_num, r, k));
|
||||
@@ -800,15 +835,15 @@ impl Allocator for DebrayAllocator {
|
||||
self.arg_c += 1;
|
||||
}
|
||||
Level::Deep if is_new_var => {
|
||||
if let GenContext::Head = term_loc {
|
||||
if let GenContext::Head = context {
|
||||
if self.occurs_shallowly_in_head(var_num, r.reg_num()) {
|
||||
code.push_back(self.subterm_to_value::<Target>(var_num, r));
|
||||
} else {
|
||||
self.mark_safe_var(var_num, lvl, term_loc);
|
||||
self.mark_safe_var(var_num, lvl, context);
|
||||
code.push_back(Target::subterm_to_variable(r));
|
||||
}
|
||||
} else {
|
||||
self.mark_safe_var(var_num, lvl, term_loc);
|
||||
self.mark_safe_var(var_num, lvl, context);
|
||||
code.push_back(Target::subterm_to_variable(r));
|
||||
}
|
||||
}
|
||||
@@ -830,14 +865,15 @@ impl Allocator for DebrayAllocator {
|
||||
if record.running_count < record.num_occurrences {
|
||||
record.running_count += 1;
|
||||
} else {
|
||||
self.free_var(term_loc.chunk_num(), var_num);
|
||||
self.free_var(context.chunk_num(), var_num);
|
||||
}
|
||||
|
||||
self.in_use.insert(o);
|
||||
r
|
||||
}
|
||||
|
||||
fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType {
|
||||
match self.get_binding(var_num) {
|
||||
match self.get_var_binding(var_num) {
|
||||
RegType::Perm(0) => RegType::Perm(self.alloc_perm_var(var_num, chunk_num)),
|
||||
RegType::Temp(0) => {
|
||||
let t = self.alloc_reg_to_non_var();
|
||||
@@ -861,6 +897,8 @@ impl Allocator for DebrayAllocator {
|
||||
fn reset(&mut self) {
|
||||
self.perm_lb = 1;
|
||||
self.shallow_temp_mappings.clear();
|
||||
self.non_var_registers.clear();
|
||||
self.non_var_register_heap_locs.clear();
|
||||
self.in_use.clear();
|
||||
self.temp_free_list.clear();
|
||||
}
|
||||
@@ -868,6 +906,8 @@ impl Allocator for DebrayAllocator {
|
||||
fn reset_contents(&mut self) {
|
||||
self.in_use.clear();
|
||||
self.shallow_temp_mappings.clear();
|
||||
self.non_var_registers.clear();
|
||||
self.non_var_register_heap_locs.clear();
|
||||
self.temp_free_list.clear();
|
||||
}
|
||||
|
||||
@@ -875,24 +915,44 @@ impl Allocator for DebrayAllocator {
|
||||
self.arg_c += 1;
|
||||
}
|
||||
|
||||
fn reset_at_head(&mut self, args: &[Term]) {
|
||||
self.reset_arg(args.len());
|
||||
self.arity = args.len();
|
||||
fn reset_at_head(&mut self, term: &mut FocusedHeap, head_loc: usize) {
|
||||
read_heap_cell!(term.deref_loc(head_loc),
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
let arity = cell_as_atom_cell!(term.heap[s]).get_arity();
|
||||
|
||||
for (idx, arg) in args.iter().enumerate() {
|
||||
if let Term::Var(_, ref var) = arg {
|
||||
let var_num = var.to_var_num().unwrap();
|
||||
let r = self.get_binding(var_num);
|
||||
self.reset_arg(arity);
|
||||
self.arity = arity;
|
||||
|
||||
if !r.is_perm() && r.reg_num() == 0 {
|
||||
self.in_use.insert(idx + 1);
|
||||
self.shallow_temp_mappings.insert(idx + 1, var_num);
|
||||
self.var_data.records[var_num]
|
||||
.allocation
|
||||
.set_register(idx + 1);
|
||||
for (idx, arg) in term.heap[s+1 .. s+arity+1].iter().cloned().enumerate() {
|
||||
if arg.is_var() {
|
||||
let var = heap_bound_store(
|
||||
&term.heap,
|
||||
heap_bound_deref(&term.heap, arg),
|
||||
);
|
||||
|
||||
if !var.is_var() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let h = var.get_value() as usize;
|
||||
let var_ptr = term.var_locs.peek_next_var_ptr_at_key(h).unwrap();
|
||||
let var_num = var_ptr.to_var_num().unwrap();
|
||||
let r = self.get_var_binding(var_num);
|
||||
|
||||
if !r.is_perm() && r.reg_num() == 0 {
|
||||
self.in_use.insert(idx + 1);
|
||||
self.shallow_temp_mappings.insert(idx + 1, var_num);
|
||||
self.var_data.records[var_num]
|
||||
.allocation
|
||||
.set_register(idx + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.reset_arg(0);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
fn reset_arg(&mut self, arity: usize) {
|
||||
|
||||
158
src/forms.rs
158
src/forms.rs
@@ -17,7 +17,6 @@ use fxhash::FxBuildHasher;
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use ordered_float::OrderedFloat;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::VecDeque;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
@@ -67,15 +66,6 @@ pub enum Level {
|
||||
Shallow,
|
||||
}
|
||||
|
||||
impl Level {
|
||||
pub(crate) fn child_level(self) -> Level {
|
||||
match self {
|
||||
Level::Root => Level::Shallow,
|
||||
_ => Level::Deep,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum CallPolicy {
|
||||
Default,
|
||||
@@ -89,19 +79,6 @@ pub enum ChunkType {
|
||||
Last,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RootIterationPolicy {
|
||||
Iterated,
|
||||
NotIterated,
|
||||
}
|
||||
|
||||
impl RootIterationPolicy {
|
||||
#[inline(always)]
|
||||
pub fn iterable(&self) -> bool {
|
||||
matches!(self, RootIterationPolicy::Iterated)
|
||||
}
|
||||
}
|
||||
|
||||
impl ChunkType {
|
||||
#[inline(always)]
|
||||
pub fn to_gen_context(self, chunk_num: usize) -> GenContext {
|
||||
@@ -183,34 +160,39 @@ impl ChunkedTermVec {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum QueryTerm {
|
||||
// register, clause type, subterms, clause call policy.
|
||||
Clause(Cell<RegType>, ClauseType, Vec<Term>, CallPolicy),
|
||||
Fail,
|
||||
LocalCut { var_num: usize, cut_prev: bool }, // var_num
|
||||
GlobalCut(usize), // var_num
|
||||
GetCutPoint { var_num: usize, prev_b: bool },
|
||||
GetLevel(usize), // var_num
|
||||
pub struct QueryClause {
|
||||
pub ct: ClauseType,
|
||||
pub arity: usize,
|
||||
pub term: HeapCellValue,
|
||||
pub code_indices: IndexMap<usize, CodeIndex, FxBuildHasher>,
|
||||
pub call_policy: CallPolicy,
|
||||
}
|
||||
|
||||
impl QueryTerm {
|
||||
pub(crate) fn arity(&self) -> usize {
|
||||
match self {
|
||||
QueryTerm::Clause(_, _, subterms, ..) => subterms.len(),
|
||||
&QueryTerm::GetLevel(_) | &QueryTerm::GetCutPoint { .. } => 1,
|
||||
_ => 0,
|
||||
}
|
||||
impl QueryClause {
|
||||
pub fn term_loc(&self) -> usize {
|
||||
self.term.get_value() as usize
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum QueryTerm {
|
||||
Clause(QueryClause),
|
||||
Fail,
|
||||
Succeed,
|
||||
LocalCut { var_num: usize, cut_prev: bool },
|
||||
GlobalCut(usize), // var_num
|
||||
GetCutPoint { var_num: usize, prev_b: bool },
|
||||
GetLevel(usize), // var_num
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Fact {
|
||||
pub(crate) head: Term,
|
||||
pub(crate) term: FocusedHeap,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Rule {
|
||||
pub(crate) head: (Atom, Vec<Term>),
|
||||
pub(crate) term: FocusedHeap,
|
||||
pub(crate) clauses: ChunkedTermVec,
|
||||
}
|
||||
|
||||
@@ -253,6 +235,53 @@ impl ClauseInfo for PredicateKey {
|
||||
}
|
||||
}
|
||||
|
||||
fn clause_name(heap: &[HeapCellValue], term_loc: usize) -> Option<Atom> {
|
||||
let name = term_name(heap, term_loc);
|
||||
|
||||
if Some(atom!(":-")) == name && 2 == term_arity(heap, term_loc) {
|
||||
term_nth_arg(heap, term_loc, 1).and_then(|arg_loc| term_name(heap, arg_loc))
|
||||
} else {
|
||||
name
|
||||
}
|
||||
}
|
||||
|
||||
fn clause_arity(heap: &[HeapCellValue], term_loc: usize) -> usize {
|
||||
let name = term_name(heap, term_loc);
|
||||
|
||||
if Some(atom!(":-")) == name && 2 == term_arity(heap, term_loc) {
|
||||
term_nth_arg(heap, term_loc, 1)
|
||||
.map(|arg_loc| term_arity(heap, arg_loc))
|
||||
.unwrap_or(0)
|
||||
} else {
|
||||
term_arity(heap, term_loc)
|
||||
}
|
||||
}
|
||||
|
||||
impl ClauseInfo for FocusedHeap {
|
||||
#[inline]
|
||||
fn name(&self) -> Option<Atom> {
|
||||
clause_name(&self.heap, self.focus)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn arity(&self) -> usize {
|
||||
clause_arity(&self.heap, self.focus)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ClauseInfo for FocusedHeapRefMut<'a> {
|
||||
#[inline]
|
||||
fn name(&self) -> Option<Atom> {
|
||||
clause_name(self.heap, self.focus)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn arity(&self) -> usize {
|
||||
clause_arity(self.heap, self.focus)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl ClauseInfo for Term {
|
||||
fn name(&self) -> Option<Atom> {
|
||||
match self {
|
||||
@@ -287,29 +316,30 @@ impl ClauseInfo for Term {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl ClauseInfo for Rule {
|
||||
fn name(&self) -> Option<Atom> {
|
||||
Some(self.head.0)
|
||||
self.term.name(self.term.focus)
|
||||
}
|
||||
|
||||
fn arity(&self) -> usize {
|
||||
self.head.1.len()
|
||||
self.term.arity(self.term.focus)
|
||||
}
|
||||
}
|
||||
|
||||
impl ClauseInfo for PredicateClause {
|
||||
fn name(&self) -> Option<Atom> {
|
||||
match self {
|
||||
PredicateClause::Fact(ref term, ..) => term.head.name(),
|
||||
PredicateClause::Rule(ref rule, ..) => rule.name(),
|
||||
PredicateClause::Fact(ref fact, ..) => fact.term.name(fact.term.focus),
|
||||
PredicateClause::Rule(ref rule, ..) => rule.term.name(rule.term.focus),
|
||||
}
|
||||
}
|
||||
|
||||
fn arity(&self) -> usize {
|
||||
match self {
|
||||
PredicateClause::Fact(ref term, ..) => term.head.arity(),
|
||||
PredicateClause::Rule(ref rule, ..) => rule.arity(),
|
||||
PredicateClause::Fact(ref fact, ..) => fact.term.arity(fact.term.focus),
|
||||
PredicateClause::Rule(ref rule, ..) => rule.term.arity(rule.term.focus),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,19 +351,31 @@ pub enum PredicateClause {
|
||||
}
|
||||
|
||||
impl PredicateClause {
|
||||
pub(crate) fn args(&self) -> Option<&[Term]> {
|
||||
match self {
|
||||
PredicateClause::Fact(term, ..) => match &term.head {
|
||||
Term::Clause(_, _, args) => Some(args),
|
||||
_ => None,
|
||||
},
|
||||
PredicateClause::Rule(rule, ..) => {
|
||||
if rule.head.1.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(&rule.head.1)
|
||||
}
|
||||
pub(crate) fn args(&self) -> Option<&[HeapCellValue]> {
|
||||
let (term, focus) = match self {
|
||||
PredicateClause::Fact(Fact { term }, _) => (term, term.focus),
|
||||
PredicateClause::Rule(Rule { term, .. }, _) => {
|
||||
let focus = term.nth_arg(term.focus, 1).unwrap();
|
||||
(term, focus)
|
||||
}
|
||||
};
|
||||
|
||||
let arity = term.arity(focus);
|
||||
|
||||
read_heap_cell!(term.deref_loc(focus),
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
Some(&term.heap[s+1 .. s+arity+1])
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn heap(&self) -> &[HeapCellValue] {
|
||||
match self {
|
||||
PredicateClause::Fact(ref fact, ..) => &fact.term.heap,
|
||||
PredicateClause::Rule(ref rule, ..) => &rule.term.heap,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
152
src/heap_iter.rs
152
src/heap_iter.rs
@@ -34,7 +34,7 @@ pub struct EagerStackfulPreOrderHeapIter<'a> {
|
||||
start_value: HeapCellValue,
|
||||
iter_stack: Vec<HeapCellValue>,
|
||||
mark_phase: bool,
|
||||
heap: &'a mut Heap,
|
||||
pub heap: &'a mut Heap,
|
||||
}
|
||||
|
||||
impl<'a> Drop for EagerStackfulPreOrderHeapIter<'a> {
|
||||
@@ -249,7 +249,7 @@ impl ListElisionPolicy for NonListElider {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StackfulPreOrderHeapIter<'a, ElideLists> {
|
||||
pub heap: &'a mut Vec<HeapCellValue>,
|
||||
pub heap: &'a mut [HeapCellValue],
|
||||
pub machine_stack: &'a mut Stack,
|
||||
stack: Vec<IterStackLoc>,
|
||||
h: IterStackLoc,
|
||||
@@ -265,11 +265,13 @@ impl<'a, ElideLists> Drop for StackfulPreOrderHeapIter<'a, ElideLists> {
|
||||
cell.set_mark_bit(false);
|
||||
}
|
||||
|
||||
self.heap.pop();
|
||||
// self.heap.pop();
|
||||
}
|
||||
}
|
||||
|
||||
pub trait FocusedHeapIter: Iterator<Item = HeapCellValue> {
|
||||
pub trait FocusedHeapIter:
|
||||
Deref<Target = [HeapCellValue]> + Iterator<Item = HeapCellValue>
|
||||
{
|
||||
fn focus(&self) -> IterStackLoc;
|
||||
}
|
||||
|
||||
@@ -282,6 +284,14 @@ impl<'a, ElideLists: ListElisionPolicy> FocusedHeapIter
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, ElideLists> Deref for StackfulPreOrderHeapIter<'a, ElideLists> {
|
||||
type Target = [HeapCellValue];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.heap
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, ElideLists> StackfulPreOrderHeapIter<'a, ElideLists> {
|
||||
#[inline]
|
||||
pub fn read_cell_mut(&mut self, loc: IterStackLoc) -> &mut HeapCellValue {
|
||||
@@ -358,9 +368,9 @@ impl<'a, ElideLists> StackfulPreOrderHeapIter<'a, ElideLists> {
|
||||
|
||||
impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists> {
|
||||
#[inline]
|
||||
fn new(heap: &'a mut Vec<HeapCellValue>, stack: &'a mut Stack, cell: HeapCellValue) -> Self {
|
||||
let h = IterStackLoc::iterable_loc(heap.len(), HeapOrStackTag::Heap);
|
||||
heap.push(cell);
|
||||
fn new(heap: &'a mut [HeapCellValue], stack: &'a mut Stack, root_loc: usize) -> Self {
|
||||
let h = IterStackLoc::iterable_loc(root_loc, HeapOrStackTag::Heap);
|
||||
// heap.push(cell);
|
||||
|
||||
Self {
|
||||
heap,
|
||||
@@ -501,6 +511,7 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'a, ElideLists: ListElisionPolicy> Iterator for StackfulPreOrderHeapIter<'a, ElideLists> {
|
||||
type Item = HeapCellValue;
|
||||
|
||||
@@ -524,9 +535,9 @@ pub(crate) fn cycle_detecting_stackless_preorder_iter(
|
||||
pub(crate) fn stackful_preorder_iter<'a, ElideLists: ListElisionPolicy>(
|
||||
heap: &'a mut Vec<HeapCellValue>,
|
||||
stack: &'a mut Stack,
|
||||
cell: HeapCellValue,
|
||||
root_loc: usize,
|
||||
) -> StackfulPreOrderHeapIter<'a, ElideLists> {
|
||||
StackfulPreOrderHeapIter::new(heap, stack, cell)
|
||||
StackfulPreOrderHeapIter::new(heap, stack, root_loc)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -538,7 +549,7 @@ pub(crate) struct PostOrderIterator<Iter: FocusedHeapIter> {
|
||||
}
|
||||
|
||||
impl<Iter: FocusedHeapIter> Deref for PostOrderIterator<Iter> {
|
||||
type Target = Iter;
|
||||
type Target = [HeapCellValue];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.base_iter
|
||||
@@ -610,6 +621,7 @@ impl<Iter: FocusedHeapIter> FocusedHeapIter for PostOrderIterator<Iter> {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl<Iter: FocusedHeapIter> PostOrderIterator<Iter> {
|
||||
/* return true if the term at heap offset idx_loc is a
|
||||
* direct/inlined subterm of a structure at the focus of
|
||||
@@ -631,6 +643,7 @@ impl<Iter: FocusedHeapIter> PostOrderIterator<Iter> {
|
||||
false
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
pub(crate) type LeftistPostOrderHeapIter<'a, ElideLists> =
|
||||
PostOrderIterator<StackfulPreOrderHeapIter<'a, ElideLists>>;
|
||||
@@ -657,9 +670,9 @@ impl<'a, ElideLists: ListElisionPolicy> LeftistPostOrderHeapIter<'a, ElideLists>
|
||||
pub(crate) fn stackful_post_order_iter<'a, ElideLists: ListElisionPolicy>(
|
||||
heap: &'a mut Heap,
|
||||
stack: &'a mut Stack,
|
||||
cell: HeapCellValue,
|
||||
root_loc: usize,
|
||||
) -> LeftistPostOrderHeapIter<'a, ElideLists> {
|
||||
PostOrderIterator::new(StackfulPreOrderHeapIter::new(heap, stack, cell))
|
||||
PostOrderIterator::new(StackfulPreOrderHeapIter::new(heap, stack, root_loc))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -1771,11 +1784,13 @@ mod tests {
|
||||
.heap
|
||||
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
|
||||
|
||||
wam.machine_st.heap.push(str_loc_as_cell!(0));
|
||||
|
||||
{
|
||||
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
str_loc_as_cell!(0),
|
||||
3,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@@ -1810,7 +1825,7 @@ mod tests {
|
||||
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
str_loc_as_cell!(0),
|
||||
4,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@@ -1842,7 +1857,7 @@ mod tests {
|
||||
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
heap_loc_as_cell!(0),
|
||||
0,
|
||||
);
|
||||
|
||||
let mut var = heap_loc_as_cell!(0);
|
||||
@@ -1869,7 +1884,7 @@ mod tests {
|
||||
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
heap_loc_as_cell!(0),
|
||||
1,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@@ -1893,7 +1908,7 @@ mod tests {
|
||||
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
heap_loc_as_cell!(0),
|
||||
0,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@@ -1929,7 +1944,7 @@ mod tests {
|
||||
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
heap_loc_as_cell!(0),
|
||||
0,
|
||||
);
|
||||
|
||||
// the cycle will be iterated twice before being detected.
|
||||
@@ -1951,7 +1966,15 @@ mod tests {
|
||||
);
|
||||
assert_eq!(
|
||||
unmark_cell_bits!(iter.next().unwrap()),
|
||||
heap_loc_as_cell!(0)
|
||||
list_loc_as_cell!(1)
|
||||
);
|
||||
assert_eq!(
|
||||
unmark_cell_bits!(iter.next().unwrap()),
|
||||
atom_as_cell!(a_atom)
|
||||
);
|
||||
assert_eq!(
|
||||
unmark_cell_bits!(iter.next().unwrap()),
|
||||
list_loc_as_cell!(3)
|
||||
);
|
||||
|
||||
assert_eq!(iter.next(), None);
|
||||
@@ -1961,7 +1984,7 @@ mod tests {
|
||||
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
heap_loc_as_cell!(0),
|
||||
0,
|
||||
);
|
||||
|
||||
// cut the iteration short to check that all cells are
|
||||
@@ -2000,7 +2023,7 @@ mod tests {
|
||||
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
heap_loc_as_cell!(0),
|
||||
0,
|
||||
);
|
||||
|
||||
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
|
||||
@@ -2025,7 +2048,7 @@ mod tests {
|
||||
let mut iter = stackful_preorder_iter::<NonListElider>(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
heap_loc_as_cell!(0),
|
||||
0,
|
||||
);
|
||||
|
||||
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
|
||||
@@ -2048,11 +2071,14 @@ mod tests {
|
||||
.heap
|
||||
.push(fixnum_as_cell!(Fixnum::build_with(0i64)));
|
||||
|
||||
let h = wam.machine_st.heap.len();
|
||||
wam.machine_st.heap.push(heap_loc_as_cell!(0));
|
||||
|
||||
{
|
||||
let mut iter = stackful_preorder_iter::<NonListElider>(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
pstr_loc_as_cell!(0),
|
||||
h,
|
||||
);
|
||||
|
||||
let pstr_offset_cell = pstr_offset_as_cell!(0);
|
||||
@@ -2078,16 +2104,20 @@ mod tests {
|
||||
}
|
||||
*/
|
||||
|
||||
wam.machine_st.heap.pop();
|
||||
wam.machine_st.heap.pop();
|
||||
wam.machine_st
|
||||
.heap
|
||||
.push(fixnum_as_cell!(Fixnum::build_with(1i64)));
|
||||
|
||||
let h = wam.machine_st.heap.len();
|
||||
wam.machine_st.heap.push(heap_loc_as_cell!(0));
|
||||
|
||||
{
|
||||
let mut iter = stackful_preorder_iter::<NonListElider>(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
pstr_loc_as_cell!(0),
|
||||
h,
|
||||
);
|
||||
|
||||
let pstr_offset_cell = pstr_offset_as_cell!(0);
|
||||
@@ -2127,11 +2157,14 @@ mod tests {
|
||||
|
||||
wam.machine_st.heap.extend(functor);
|
||||
|
||||
let h = wam.machine_st.heap.len();
|
||||
wam.machine_st.heap.push(heap_loc_as_cell!(0));
|
||||
|
||||
{
|
||||
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
heap_loc_as_cell!(0),
|
||||
h,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@@ -2194,7 +2227,7 @@ mod tests {
|
||||
let mut iter = stackful_preorder_iter::<NonListElider>(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
heap_loc_as_cell!(0),
|
||||
h,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@@ -2263,7 +2296,7 @@ mod tests {
|
||||
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
heap_loc_as_cell!(0),
|
||||
0,
|
||||
);
|
||||
|
||||
let mut cyclic_link = list_loc_as_cell!(1);
|
||||
@@ -2292,12 +2325,13 @@ mod tests {
|
||||
|
||||
wam.machine_st.heap.push(pstr_as_cell!(atom!("a string")));
|
||||
wam.machine_st.heap.push(empty_list_as_cell!());
|
||||
wam.machine_st.heap.push(pstr_loc_as_cell!(0));
|
||||
|
||||
{
|
||||
let mut iter = stackful_preorder_iter::<NonListElider>(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
heap_loc_as_cell!(0),
|
||||
2,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@@ -2325,11 +2359,14 @@ mod tests {
|
||||
wam.machine_st.heap.push(str_loc_as_cell!(4));
|
||||
wam.machine_st.heap.push(empty_list_as_cell!());
|
||||
|
||||
let h = wam.machine_st.heap.len();
|
||||
wam.machine_st.heap.push(heap_loc_as_cell!(0));
|
||||
|
||||
{
|
||||
let mut iter = stackful_preorder_iter::<NonListElider>(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
heap_loc_as_cell!(0),
|
||||
h,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@@ -2359,6 +2396,8 @@ mod tests {
|
||||
let a_atom = atom!("a");
|
||||
let b_atom = atom!("b");
|
||||
|
||||
wam.machine_st.heap.push(str_loc_as_cell!(1));
|
||||
|
||||
wam.machine_st
|
||||
.heap
|
||||
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
|
||||
@@ -2367,7 +2406,7 @@ mod tests {
|
||||
let mut iter = stackful_post_order_iter::<NonListElider>(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
str_loc_as_cell!(0),
|
||||
0,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@@ -2388,13 +2427,14 @@ mod tests {
|
||||
|
||||
wam.machine_st.heap.clear();
|
||||
|
||||
wam.machine_st.heap.push(str_loc_as_cell!(1));
|
||||
wam.machine_st.heap.extend(functor!(
|
||||
f_atom,
|
||||
[
|
||||
atom(a_atom),
|
||||
atom(b_atom),
|
||||
atom(a_atom),
|
||||
cell(str_loc_as_cell!(0))
|
||||
cell(str_loc_as_cell!(1))
|
||||
]
|
||||
));
|
||||
|
||||
@@ -2403,7 +2443,7 @@ mod tests {
|
||||
let mut iter = stackful_post_order_iter::<NonListElider>(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
str_loc_as_cell!(0),
|
||||
0,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@@ -2419,7 +2459,7 @@ mod tests {
|
||||
atom_as_cell!(a_atom)
|
||||
);
|
||||
|
||||
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0));
|
||||
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(1));
|
||||
|
||||
assert_eq!(
|
||||
unmark_cell_bits!(iter.next().unwrap()),
|
||||
@@ -2437,7 +2477,7 @@ mod tests {
|
||||
let mut iter = stackful_post_order_iter::<NonListElider>(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
heap_loc_as_cell!(0),
|
||||
0,
|
||||
);
|
||||
|
||||
let mut var = heap_loc_as_cell!(0);
|
||||
@@ -2464,7 +2504,7 @@ mod tests {
|
||||
let mut iter = stackful_post_order_iter::<NonListElider>(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
heap_loc_as_cell!(0),
|
||||
1,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@@ -2484,11 +2524,14 @@ mod tests {
|
||||
wam.machine_st.heap.push(atom_as_cell!(b_atom));
|
||||
wam.machine_st.heap.push(empty_list_as_cell!());
|
||||
|
||||
let h = wam.machine_st.heap.len();
|
||||
wam.machine_st.heap.push(heap_loc_as_cell!(0));
|
||||
|
||||
{
|
||||
let mut iter = stackful_post_order_iter::<NonListElider>(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
heap_loc_as_cell!(0),
|
||||
h,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@@ -2515,16 +2558,18 @@ mod tests {
|
||||
assert_eq!(iter.next(), None);
|
||||
}
|
||||
|
||||
wam.machine_st.heap.pop();
|
||||
wam.machine_st.heap.pop();
|
||||
|
||||
// now make the list cyclic.
|
||||
let h = wam.machine_st.heap.len();
|
||||
wam.machine_st.heap.push(heap_loc_as_cell!(0));
|
||||
|
||||
{
|
||||
let mut iter = stackful_post_order_iter::<NonListElider>(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
heap_loc_as_cell!(0),
|
||||
h,
|
||||
);
|
||||
|
||||
// the cycle will be iterated twice before being detected.
|
||||
@@ -2556,7 +2601,7 @@ mod tests {
|
||||
let mut iter = stackful_post_order_iter::<NonListElider>(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
heap_loc_as_cell!(0),
|
||||
0,
|
||||
);
|
||||
|
||||
// cut the iteration short to check that all cells are
|
||||
@@ -2591,11 +2636,15 @@ mod tests {
|
||||
put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl);
|
||||
let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
|
||||
|
||||
wam.machine_st.heap.push(pstr_loc_as_cell!(0));
|
||||
|
||||
let h = wam.machine_st.heap.len() - 1;
|
||||
|
||||
{
|
||||
let mut iter = stackful_post_order_iter::<NonListElider>(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
pstr_loc_as_cell!(0),
|
||||
h,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@@ -2608,6 +2657,7 @@ mod tests {
|
||||
assert_eq!(iter.next(), None);
|
||||
}
|
||||
|
||||
wam.machine_st.heap.pop();
|
||||
wam.machine_st.heap.pop();
|
||||
wam.machine_st.heap.push(pstr_loc_as_cell!(2));
|
||||
|
||||
@@ -2615,11 +2665,15 @@ mod tests {
|
||||
put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl);
|
||||
let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize];
|
||||
|
||||
wam.machine_st.heap.push(pstr_loc_as_cell!(0));
|
||||
|
||||
let h = wam.machine_st.heap.len() - 1;
|
||||
|
||||
{
|
||||
let mut iter = stackful_post_order_iter::<NonListElider>(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
pstr_loc_as_cell!(0),
|
||||
h,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@@ -2632,6 +2686,7 @@ mod tests {
|
||||
assert_eq!(iter.next(), None);
|
||||
}
|
||||
|
||||
wam.machine_st.heap.pop();
|
||||
wam.machine_st.heap.pop();
|
||||
wam.machine_st
|
||||
.heap
|
||||
@@ -2642,11 +2697,15 @@ mod tests {
|
||||
.heap
|
||||
.push(fixnum_as_cell!(Fixnum::build_with(0i64)));
|
||||
|
||||
wam.machine_st.heap.push(pstr_loc_as_cell!(0));
|
||||
|
||||
let h = wam.machine_st.heap.len() - 1;
|
||||
|
||||
{
|
||||
let mut iter = stackful_post_order_iter::<NonListElider>(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
pstr_loc_as_cell!(0),
|
||||
h,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@@ -2664,16 +2723,21 @@ mod tests {
|
||||
assert_eq!(iter.next(), None);
|
||||
}
|
||||
|
||||
wam.machine_st.heap.pop();
|
||||
wam.machine_st.heap.pop();
|
||||
wam.machine_st
|
||||
.heap
|
||||
.push(fixnum_as_cell!(Fixnum::build_with(1i64)));
|
||||
|
||||
wam.machine_st.heap.push(pstr_loc_as_cell!(0));
|
||||
|
||||
let h = wam.machine_st.heap.len() - 1;
|
||||
|
||||
{
|
||||
let mut iter = stackful_post_order_iter::<NonListElider>(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
pstr_loc_as_cell!(0),
|
||||
h,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@@ -2707,7 +2771,7 @@ mod tests {
|
||||
let mut iter = stackful_post_order_iter::<NonListElider>(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
heap_loc_as_cell!(0),
|
||||
0,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@@ -2771,7 +2835,7 @@ mod tests {
|
||||
let mut iter = stackful_post_order_iter::<NonListElider>(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.stack,
|
||||
heap_loc_as_cell!(0),
|
||||
0,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
|
||||
@@ -532,11 +532,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
stack: &'a mut Stack,
|
||||
op_dir: &'a OpDir,
|
||||
output: Outputter,
|
||||
cell: HeapCellValue,
|
||||
root_loc: usize,
|
||||
) -> Self {
|
||||
HCPrinter {
|
||||
outputter: output,
|
||||
iter: stackful_preorder_iter(heap, stack, cell),
|
||||
iter: stackful_preorder_iter(heap, stack, root_loc),
|
||||
atom_tbl,
|
||||
op_dir,
|
||||
state_stack: vec![],
|
||||
@@ -1841,6 +1841,8 @@ mod tests {
|
||||
.heap
|
||||
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
|
||||
|
||||
wam.machine_st.heap.push(str_loc_as_cell!(0));
|
||||
|
||||
{
|
||||
let printer = HCPrinter::new(
|
||||
&mut wam.machine_st.heap,
|
||||
@@ -1848,7 +1850,7 @@ mod tests {
|
||||
&mut wam.machine_st.stack,
|
||||
&wam.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
heap_loc_as_cell!(0),
|
||||
0,
|
||||
);
|
||||
|
||||
let output = printer.print();
|
||||
@@ -1870,6 +1872,9 @@ mod tests {
|
||||
]
|
||||
));
|
||||
|
||||
let h = wam.machine_st.heap.len();
|
||||
wam.machine_st.heap.push(str_loc_as_cell!(0));
|
||||
|
||||
{
|
||||
let printer = HCPrinter::new(
|
||||
&mut wam.machine_st.heap,
|
||||
@@ -1877,7 +1882,7 @@ mod tests {
|
||||
&mut wam.machine_st.stack,
|
||||
&wam.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
heap_loc_as_cell!(0),
|
||||
h,
|
||||
);
|
||||
|
||||
let output = printer.print();
|
||||
@@ -1901,7 +1906,7 @@ mod tests {
|
||||
&mut wam.machine_st.stack,
|
||||
&wam.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
heap_loc_as_cell!(0),
|
||||
0,
|
||||
);
|
||||
|
||||
let output = printer.print();
|
||||
@@ -1914,7 +1919,7 @@ mod tests {
|
||||
&mut wam.machine_st.stack,
|
||||
&wam.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
heap_loc_as_cell!(0),
|
||||
0,
|
||||
);
|
||||
|
||||
printer
|
||||
@@ -1947,7 +1952,7 @@ mod tests {
|
||||
&mut wam.machine_st.stack,
|
||||
&wam.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
heap_loc_as_cell!(0),
|
||||
0,
|
||||
);
|
||||
|
||||
let output = printer.print();
|
||||
@@ -1966,7 +1971,7 @@ mod tests {
|
||||
&mut wam.machine_st.stack,
|
||||
&wam.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
heap_loc_as_cell!(0),
|
||||
0,
|
||||
);
|
||||
|
||||
let output = printer.print();
|
||||
@@ -1983,7 +1988,7 @@ mod tests {
|
||||
&mut wam.machine_st.stack,
|
||||
&wam.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
heap_loc_as_cell!(0),
|
||||
0,
|
||||
);
|
||||
|
||||
printer
|
||||
@@ -2015,7 +2020,7 @@ mod tests {
|
||||
&mut wam.machine_st.stack,
|
||||
&wam.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
heap_loc_as_cell!(0),
|
||||
0,
|
||||
);
|
||||
|
||||
printer.max_depth = 5;
|
||||
@@ -2031,6 +2036,10 @@ mod tests {
|
||||
|
||||
put_partial_string(&mut wam.machine_st.heap, "abc", &wam.machine_st.atom_tbl);
|
||||
|
||||
wam.machine_st.heap.push(pstr_loc_as_cell!(0));
|
||||
|
||||
let h = wam.machine_st.heap.len() - 1;
|
||||
|
||||
{
|
||||
let printer = HCPrinter::new(
|
||||
&mut wam.machine_st.heap,
|
||||
@@ -2038,7 +2047,7 @@ mod tests {
|
||||
&mut wam.machine_st.stack,
|
||||
&wam.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
pstr_loc_as_cell!(0),
|
||||
h,
|
||||
);
|
||||
|
||||
let output = printer.print();
|
||||
@@ -2048,6 +2057,7 @@ mod tests {
|
||||
|
||||
all_cells_unmarked(&wam.machine_st.heap);
|
||||
|
||||
wam.machine_st.heap.pop();
|
||||
wam.machine_st.heap.pop();
|
||||
|
||||
wam.machine_st.heap.push(list_loc_as_cell!(2));
|
||||
@@ -2066,7 +2076,7 @@ mod tests {
|
||||
&mut wam.machine_st.stack,
|
||||
&wam.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
heap_loc_as_cell!(0),
|
||||
0,
|
||||
);
|
||||
|
||||
printer.double_quotes = true;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::atom_table::*;
|
||||
use crate::parser::ast::*;
|
||||
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
use crate::parser::ast::*;
|
||||
use crate::types::*;
|
||||
|
||||
use fxhash::FxBuildHasher;
|
||||
use indexmap::IndexMap;
|
||||
@@ -1491,34 +1491,60 @@ impl<I: Indexer> CodeOffsets<I> {
|
||||
|
||||
pub(crate) fn index_term(
|
||||
&mut self,
|
||||
optimal_arg: &Term,
|
||||
heap: &[HeapCellValue],
|
||||
optimal_arg: HeapCellValue,
|
||||
index: usize,
|
||||
clause_index_info: &mut ClauseIndexInfo,
|
||||
atom_tbl: &AtomTable,
|
||||
) {
|
||||
match optimal_arg {
|
||||
&Term::Clause(_, atom!("."), ref terms) if terms.len() == 2 => {
|
||||
read_heap_cell!(optimal_arg,
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();
|
||||
|
||||
if (name, arity) == (atom!("."), 2) {
|
||||
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
|
||||
self.index_list(index);
|
||||
} else {
|
||||
clause_index_info.opt_arg_index_key =
|
||||
OptArgIndexKey::Structure(self.optimal_index, 0, name, arity);
|
||||
|
||||
self.index_structure(name, arity, index);
|
||||
}
|
||||
}
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
debug_assert_eq!(arity, 0);
|
||||
|
||||
let overlapping_constants = self.index_constant(atom_tbl, Literal::Atom(name), index);
|
||||
|
||||
clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal(
|
||||
self.optimal_index,
|
||||
0,
|
||||
Literal::Atom(name),
|
||||
overlapping_constants,
|
||||
);
|
||||
}
|
||||
(HeapCellValueTag::Lis
|
||||
| HeapCellValueTag::CStr
|
||||
| HeapCellValueTag::PStrLoc) => {
|
||||
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
|
||||
self.index_list(index);
|
||||
}
|
||||
&Term::Cons(..) | &Term::Literal(_, Literal::String(_)) | &Term::PartialString(..) => {
|
||||
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
|
||||
self.index_list(index);
|
||||
}
|
||||
&Term::Clause(_, name, ref terms) => {
|
||||
clause_index_info.opt_arg_index_key =
|
||||
OptArgIndexKey::Structure(self.optimal_index, 0, name, terms.len());
|
||||
_ => {
|
||||
match Literal::try_from(optimal_arg) {
|
||||
Ok(lit) => {
|
||||
let overlapping_constants = self.index_constant(atom_tbl, lit, index);
|
||||
|
||||
self.index_structure(name, terms.len(), index);
|
||||
clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal(
|
||||
self.optimal_index,
|
||||
0,
|
||||
lit,
|
||||
overlapping_constants,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
&Term::Literal(_, constant) => {
|
||||
let overlapping_constants = self.index_constant(atom_tbl, constant, index);
|
||||
|
||||
clause_index_info.opt_arg_index_key =
|
||||
OptArgIndexKey::Literal(self.optimal_index, 0, constant, overlapping_constants);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn no_indices(&mut self) -> bool {
|
||||
|
||||
476
src/iterators.rs
476
src/iterators.rs
@@ -1,328 +1,224 @@
|
||||
use crate::atom_table::*;
|
||||
use crate::atom_table::AtomCell;
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
use crate::parser::ast::*;
|
||||
use crate::heap_iter::*;
|
||||
use crate::machine::heap::*;
|
||||
use crate::machine::stack::*;
|
||||
use crate::types::*;
|
||||
|
||||
use bit_set::*;
|
||||
use fxhash::FxBuildHasher;
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::VecDeque;
|
||||
use std::iter::*;
|
||||
use std::ops::Deref;
|
||||
use std::vec::Vec;
|
||||
|
||||
#[allow(clippy::borrowed_box)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum TermRef<'a> {
|
||||
AnonVar(Level),
|
||||
Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||
Literal(Level, &'a Cell<RegType>, &'a Literal),
|
||||
Clause(Level, &'a Cell<RegType>, Atom, &'a Vec<Term>),
|
||||
PartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
|
||||
CompleteString(Level, &'a Cell<RegType>, Atom),
|
||||
Var(Level, &'a Cell<VarReg>, VarPtr),
|
||||
}
|
||||
|
||||
/*
|
||||
impl<'a> TermRef<'a> {
|
||||
pub(crate) fn level(&self) -> Level {
|
||||
match self {
|
||||
TermRef::AnonVar(lvl) |
|
||||
TermRef::Cons(lvl, ..) |
|
||||
TermRef::Literal(lvl, ..) |
|
||||
TermRef::Var(lvl, ..) |
|
||||
TermRef::Clause(lvl, ..) |
|
||||
TermRef::CompleteString(lvl, ..) |
|
||||
TermRef::PartialString(lvl, ..) => *lvl,
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#[allow(clippy::borrowed_box)]
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum TermIterState<'a> {
|
||||
AnonVar(Level),
|
||||
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),
|
||||
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||
InitialPartialString(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),
|
||||
Var(Level, &'a Cell<VarReg>, VarPtr),
|
||||
}
|
||||
|
||||
impl<'a> TermIterState<'a> {
|
||||
pub(crate) fn subterm_to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> {
|
||||
match term {
|
||||
Term::AnonVar => TermIterState::AnonVar(lvl),
|
||||
Term::Clause(cell, name, subterms) => {
|
||||
TermIterState::Clause(lvl, 0, cell, *name, subterms)
|
||||
}
|
||||
Term::Cons(cell, head, tail) => {
|
||||
TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref())
|
||||
}
|
||||
Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant),
|
||||
Term::PartialString(cell, string_buf, tail) => {
|
||||
TermIterState::InitialPartialString(lvl, cell, string_buf, tail)
|
||||
}
|
||||
Term::CompleteString(cell, atom) => TermIterState::CompleteString(lvl, cell, *atom),
|
||||
Term::Var(cell, var_ptr) => TermIterState::Var(lvl, cell, var_ptr.clone()),
|
||||
}
|
||||
}
|
||||
pub(crate) trait TermIterator:
|
||||
Deref<Target = [HeapCellValue]> + Iterator<Item = HeapCellValue>
|
||||
{
|
||||
fn focus(&self) -> IterStackLoc;
|
||||
fn level(&mut self) -> Level;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct QueryIterator<'a> {
|
||||
state_stack: Vec<TermIterState<'a>>,
|
||||
pub(crate) struct TargetIterator<I: FocusedHeapIter, const SKIP_ROOT: bool> {
|
||||
shallow_terms: IndexMap<usize, BitSet<usize>, FxBuildHasher>,
|
||||
root_terms: BitSet<usize>,
|
||||
iter: I,
|
||||
arg_c: usize,
|
||||
}
|
||||
|
||||
impl<'a> QueryIterator<'a> {
|
||||
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
||||
self.state_stack
|
||||
.push(TermIterState::subterm_to_state(lvl, term));
|
||||
}
|
||||
fn record_path(
|
||||
heap: &[HeapCellValue],
|
||||
root_terms: &mut BitSet<usize>,
|
||||
mut root_loc: usize,
|
||||
) -> usize {
|
||||
loop {
|
||||
let cell = heap[root_loc];
|
||||
root_terms.insert(root_loc);
|
||||
|
||||
/*
|
||||
fn from_rule_head_clause(terms: &'a Vec<Term>) -> Self {
|
||||
let state_stack = terms
|
||||
.iter()
|
||||
.rev()
|
||||
.map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt))
|
||||
.collect();
|
||||
|
||||
QueryIterator { state_stack }
|
||||
}
|
||||
*/
|
||||
|
||||
fn from_term(term: &'a Term) -> Self {
|
||||
let state = match term {
|
||||
Term::AnonVar
|
||||
| Term::Cons(..)
|
||||
| Term::Literal(..)
|
||||
| Term::PartialString(..)
|
||||
| Term::CompleteString(..) => {
|
||||
return QueryIterator {
|
||||
state_stack: vec![],
|
||||
read_heap_cell!(cell,
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
if h == root_loc {
|
||||
break;
|
||||
} else {
|
||||
root_loc = h;
|
||||
}
|
||||
}
|
||||
Term::Clause(r, name, terms) => TermIterState::Clause(Level::Root, 0, r, *name, terms),
|
||||
Term::Var(cell, var_ptr) => TermIterState::Var(Level::Root, cell, var_ptr.clone()),
|
||||
};
|
||||
(HeapCellValueTag::Lis) => {
|
||||
root_terms.insert(root_loc);
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
if cell.is_ref() {
|
||||
root_terms.insert(cell.get_value() as usize);
|
||||
}
|
||||
|
||||
QueryIterator {
|
||||
state_stack: vec![state],
|
||||
break;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
root_loc
|
||||
}
|
||||
|
||||
fn find_root_terms(heap: &[HeapCellValue], root_loc: usize) -> (usize, BitSet<usize>) {
|
||||
let mut root_terms = BitSet::<usize>::default();
|
||||
let root_loc = record_path(heap, &mut root_terms, root_loc);
|
||||
(root_loc, root_terms)
|
||||
}
|
||||
|
||||
fn find_shallow_terms(
|
||||
heap: &[HeapCellValue],
|
||||
root_loc: usize,
|
||||
) -> IndexMap<usize, BitSet<usize>, FxBuildHasher> {
|
||||
let mut shallow_terms_map = IndexMap::with_hasher(FxBuildHasher::default());
|
||||
|
||||
let (h, arity) = read_heap_cell!(heap[root_loc],
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
(s+1, cell_as_atom_cell!(heap[s]).get_arity())
|
||||
}
|
||||
(HeapCellValueTag::Lis, l) => {
|
||||
(l, 2)
|
||||
}
|
||||
(HeapCellValueTag::Atom, (_name, arity)) => {
|
||||
(root_loc + 1, arity)
|
||||
}
|
||||
_ => {
|
||||
(root_loc, 0)
|
||||
}
|
||||
);
|
||||
|
||||
for idx in 0..arity {
|
||||
let mut shallow_terms = BitSet::default();
|
||||
record_path(heap, &mut shallow_terms, h + idx);
|
||||
shallow_terms_map.insert(idx + 1, shallow_terms);
|
||||
}
|
||||
|
||||
shallow_terms_map
|
||||
}
|
||||
|
||||
impl<I: FocusedHeapIter, const SKIP_ROOT: bool> TargetIterator<I, SKIP_ROOT> {
|
||||
fn new(iter: I, root_loc: usize, arg_c: usize) -> Self {
|
||||
let (derefed_root_loc, root_terms) = find_root_terms(&iter, root_loc);
|
||||
let shallow_terms = find_shallow_terms(&iter, derefed_root_loc);
|
||||
|
||||
Self {
|
||||
shallow_terms,
|
||||
root_terms,
|
||||
iter,
|
||||
arg_c,
|
||||
}
|
||||
}
|
||||
|
||||
fn extend_state(&mut self, lvl: Level, term: &'a QueryTerm) {
|
||||
match term {
|
||||
QueryTerm::Clause(ref cell, ClauseType::CallN(_), ref terms, _) => {
|
||||
self.state_stack
|
||||
.push(TermIterState::Clause(lvl, 1, cell, atom!("$call"), terms));
|
||||
}
|
||||
QueryTerm::Clause(ref cell, ref ct, ref terms, _) => {
|
||||
self.state_stack
|
||||
.push(TermIterState::Clause(lvl, 0, cell, ct.name(), terms));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
fn current_level(&self, arg_c_inc: usize) -> Level {
|
||||
let current_focus = self.iter.focus().value() as usize;
|
||||
|
||||
pub fn new(term: &'a QueryTerm) -> Self {
|
||||
let mut iter = QueryIterator {
|
||||
state_stack: vec![],
|
||||
};
|
||||
iter.extend_state(Level::Root, term);
|
||||
iter
|
||||
if self.root_terms.contains(current_focus) {
|
||||
return Level::Root;
|
||||
}
|
||||
|
||||
if let Some(shallow_terms) = self.shallow_terms.get(&(self.arg_c + arg_c_inc)) {
|
||||
if shallow_terms.contains(current_focus) {
|
||||
return Level::Shallow;
|
||||
}
|
||||
}
|
||||
|
||||
Level::Deep
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for QueryIterator<'a> {
|
||||
type Item = TermRef<'a>;
|
||||
impl<'a, const SKIP_ROOT: bool> TermIterator for FactIterator<'a, SKIP_ROOT> {
|
||||
fn focus(&self) -> IterStackLoc {
|
||||
self.iter.focus()
|
||||
}
|
||||
|
||||
fn level(&mut self) -> Level {
|
||||
let lvl = self.current_level(1);
|
||||
|
||||
if let Level::Shallow = lvl {
|
||||
self.arg_c += 1;
|
||||
}
|
||||
|
||||
lvl
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, const SKIP_ROOT: bool> TermIterator for QueryIterator<'a, SKIP_ROOT> {
|
||||
fn focus(&self) -> IterStackLoc {
|
||||
self.iter.focus()
|
||||
}
|
||||
|
||||
fn level(&mut self) -> Level {
|
||||
let lvl = self.current_level(0);
|
||||
|
||||
if let Level::Shallow = lvl {
|
||||
self.arg_c += 1;
|
||||
}
|
||||
|
||||
lvl
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: FocusedHeapIter, const SKIP_ROOT: bool> Iterator for TargetIterator<I, SKIP_ROOT> {
|
||||
type Item = HeapCellValue;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
while let Some(iter_state) = self.state_stack.pop() {
|
||||
match iter_state {
|
||||
TermIterState::AnonVar(lvl) => {
|
||||
return Some(TermRef::AnonVar(lvl));
|
||||
}
|
||||
TermIterState::Clause(lvl, child_num, cell, name, child_terms) => {
|
||||
if child_num == child_terms.len() {
|
||||
match name {
|
||||
atom!("$call") if lvl == Level::Root => {
|
||||
self.push_subterm(Level::Shallow, &child_terms[0]);
|
||||
}
|
||||
_ => {
|
||||
return match lvl {
|
||||
Level::Root => None,
|
||||
lvl => Some(TermRef::Clause(lvl, cell, name, child_terms)),
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
self.state_stack.push(TermIterState::Clause(
|
||||
lvl,
|
||||
child_num + 1,
|
||||
cell,
|
||||
name,
|
||||
child_terms,
|
||||
));
|
||||
loop {
|
||||
let next_term = self.iter.next();
|
||||
|
||||
self.push_subterm(lvl.child_level(), &child_terms[child_num]);
|
||||
}
|
||||
}
|
||||
TermIterState::InitialCons(lvl, cell, head, tail) => {
|
||||
self.state_stack
|
||||
.push(TermIterState::FinalCons(lvl, cell, head, tail));
|
||||
|
||||
self.push_subterm(lvl.child_level(), tail);
|
||||
self.push_subterm(lvl.child_level(), head);
|
||||
}
|
||||
TermIterState::InitialPartialString(lvl, cell, string, tail) => {
|
||||
self.state_stack
|
||||
.push(TermIterState::FinalPartialString(lvl, cell, string, tail));
|
||||
self.push_subterm(lvl.child_level(), tail);
|
||||
}
|
||||
TermIterState::FinalPartialString(lvl, cell, atom, tail) => {
|
||||
return Some(TermRef::PartialString(lvl, cell, atom, tail));
|
||||
}
|
||||
TermIterState::CompleteString(lvl, cell, atom) => {
|
||||
return Some(TermRef::CompleteString(lvl, cell, atom));
|
||||
}
|
||||
TermIterState::FinalCons(lvl, cell, head, tail) => {
|
||||
return Some(TermRef::Cons(lvl, cell, head, tail));
|
||||
}
|
||||
TermIterState::Literal(lvl, cell, constant) => {
|
||||
return Some(TermRef::Literal(lvl, cell, constant));
|
||||
}
|
||||
TermIterState::Var(lvl, cell, var_ptr) => {
|
||||
return Some(TermRef::Var(lvl, cell, var_ptr));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct FactIterator<'a> {
|
||||
state_queue: VecDeque<TermIterState<'a>>,
|
||||
iterable_root: RootIterationPolicy,
|
||||
}
|
||||
|
||||
impl<'a> FactIterator<'a> {
|
||||
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
||||
self.state_queue
|
||||
.push_back(TermIterState::subterm_to_state(lvl, term));
|
||||
}
|
||||
|
||||
pub(crate) fn from_rule_head_clause(terms: &'a [Term]) -> Self {
|
||||
let state_queue = terms
|
||||
.iter()
|
||||
.map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt))
|
||||
.collect();
|
||||
|
||||
FactIterator {
|
||||
state_queue,
|
||||
iterable_root: RootIterationPolicy::NotIterated,
|
||||
}
|
||||
}
|
||||
|
||||
fn new(term: &'a Term, iterable_root: RootIterationPolicy) -> Self {
|
||||
let states = match term {
|
||||
Term::AnonVar => {
|
||||
vec![TermIterState::AnonVar(Level::Root)]
|
||||
if next_term.is_none() {
|
||||
return None;
|
||||
}
|
||||
Term::Clause(cell, name, terms) => {
|
||||
vec![TermIterState::Clause(Level::Root, 0, cell, *name, terms)]
|
||||
}
|
||||
Term::Cons(cell, head, tail) => vec![TermIterState::InitialCons(
|
||||
Level::Root,
|
||||
cell,
|
||||
head.as_ref(),
|
||||
tail.as_ref(),
|
||||
)],
|
||||
Term::PartialString(cell, string_buf, tail) => {
|
||||
vec![TermIterState::InitialPartialString(
|
||||
Level::Root,
|
||||
cell,
|
||||
string_buf,
|
||||
tail,
|
||||
)]
|
||||
}
|
||||
Term::CompleteString(cell, atom) => {
|
||||
vec![TermIterState::CompleteString(Level::Root, cell, *atom)]
|
||||
}
|
||||
Term::Literal(cell, constant) => {
|
||||
vec![TermIterState::Literal(Level::Root, cell, constant)]
|
||||
}
|
||||
Term::Var(cell, var_ptr) => {
|
||||
vec![TermIterState::Var(Level::Root, cell, var_ptr.clone())]
|
||||
}
|
||||
};
|
||||
|
||||
FactIterator {
|
||||
state_queue: VecDeque::from(states),
|
||||
iterable_root,
|
||||
}
|
||||
}
|
||||
}
|
||||
let focus = self.iter.focus().value() as usize;
|
||||
|
||||
impl<'a> Iterator for FactIterator<'a> {
|
||||
type Item = TermRef<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
while let Some(state) = self.state_queue.pop_front() {
|
||||
match state {
|
||||
TermIterState::AnonVar(lvl) => {
|
||||
return Some(TermRef::AnonVar(lvl));
|
||||
}
|
||||
TermIterState::Clause(lvl, _, cell, name, child_terms) => {
|
||||
for child_term in child_terms {
|
||||
self.push_subterm(lvl.child_level(), child_term);
|
||||
}
|
||||
|
||||
match lvl {
|
||||
Level::Root if !self.iterable_root.iterable() => continue,
|
||||
_ => return Some(TermRef::Clause(lvl, cell, name, child_terms)),
|
||||
};
|
||||
}
|
||||
TermIterState::InitialCons(lvl, cell, head, tail) => {
|
||||
self.push_subterm(Level::Deep, head);
|
||||
self.push_subterm(Level::Deep, tail);
|
||||
|
||||
return Some(TermRef::Cons(lvl, cell, head, tail));
|
||||
}
|
||||
TermIterState::InitialPartialString(lvl, cell, string_buf, tail) => {
|
||||
self.push_subterm(Level::Deep, tail);
|
||||
return Some(TermRef::PartialString(lvl, cell, string_buf, tail));
|
||||
}
|
||||
TermIterState::CompleteString(lvl, cell, atom) => {
|
||||
return Some(TermRef::CompleteString(lvl, cell, atom));
|
||||
}
|
||||
TermIterState::Literal(lvl, cell, constant) => {
|
||||
return Some(TermRef::Literal(lvl, cell, constant))
|
||||
}
|
||||
TermIterState::Var(lvl, cell, var_ptr) => {
|
||||
return Some(TermRef::Var(lvl, cell, var_ptr));
|
||||
}
|
||||
_ => {}
|
||||
if SKIP_ROOT && self.root_terms.contains(focus) {
|
||||
continue;
|
||||
} else {
|
||||
return next_term;
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn post_order_iter(term: &'_ Term) -> QueryIterator {
|
||||
QueryIterator::from_term(term)
|
||||
impl<I: FocusedHeapIter, const SKIP_ROOT: bool> Deref for TargetIterator<I, SKIP_ROOT> {
|
||||
type Target = [HeapCellValue];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.iter.deref()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn breadth_first_iter(
|
||||
term: &'_ Term,
|
||||
iterable_root: RootIterationPolicy,
|
||||
) -> FactIterator {
|
||||
FactIterator::new(term, iterable_root)
|
||||
impl<I: FocusedHeapIter, const SKIP_ROOT: bool> FocusedHeapIter for TargetIterator<I, SKIP_ROOT> {
|
||||
fn focus(&self) -> IterStackLoc {
|
||||
self.iter.focus()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type FactIterator<'a, const SKIP_ROOT: bool> =
|
||||
TargetIterator<StackfulPreOrderHeapIter<'a, NonListElider>, SKIP_ROOT>;
|
||||
|
||||
pub(crate) fn fact_iterator<'a, const SKIP_ROOT: bool>(
|
||||
heap: &'a mut Heap,
|
||||
stack: &'a mut Stack,
|
||||
root_loc: usize,
|
||||
) -> FactIterator<'a, SKIP_ROOT> {
|
||||
// let cell = heap[root_loc];
|
||||
TargetIterator::new(stackful_preorder_iter(heap, stack, root_loc), root_loc, 0)
|
||||
}
|
||||
|
||||
pub(crate) type QueryIterator<'a, const SKIP_ROOT: bool> =
|
||||
TargetIterator<PostOrderIterator<StackfulPreOrderHeapIter<'a, NonListElider>>, SKIP_ROOT>;
|
||||
|
||||
pub(crate) fn query_iterator<'a, const SKIP_ROOT: bool>(
|
||||
heap: &'a mut Heap,
|
||||
stack: &'a mut Stack,
|
||||
root_loc: usize,
|
||||
) -> QueryIterator<'a, SKIP_ROOT> {
|
||||
// let cell = heap[root_loc];
|
||||
TargetIterator::new(stackful_post_order_iter(heap, stack, root_loc), root_loc, 1)
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
|
||||
@@ -59,7 +59,7 @@ get_attrs_var_check(Module) -->
|
||||
!,
|
||||
'$get_attr_list'(Var, Ls),
|
||||
nonvar(Ls),
|
||||
atts:'$copy_attr_list'(Ls, Module, Attr))].
|
||||
atts:'$copy_attr_list'(Ls, Module, Attr))].
|
||||
|
||||
put_attrs(Name/Arity, Module) -->
|
||||
put_attr(Name, Arity, Module),
|
||||
|
||||
@@ -1175,14 +1175,8 @@ clause(H, B) :-
|
||||
% Asserts (inserts) a new clause (rule or fact) into the current module.
|
||||
% The clause will be inserted at the beginning of the module.
|
||||
asserta(Clause0) :-
|
||||
loader:strip_module(Clause0, Module, Clause),
|
||||
asserta_(Module, Clause).
|
||||
|
||||
asserta_(Module, (Head :- Body)) :-
|
||||
!,
|
||||
'$asserta'(Module, Head, Body).
|
||||
asserta_(Module, Fact) :-
|
||||
'$asserta'(Module, Fact, true).
|
||||
loader:strip_subst_module(Clause0, user, Module, Clause),
|
||||
'$asserta'(Module, Clause).
|
||||
|
||||
:- meta_predicate assertz(:).
|
||||
|
||||
@@ -1191,14 +1185,8 @@ asserta_(Module, Fact) :-
|
||||
% Asserts (inserts) a new clause (rule or fact) into the current module.
|
||||
% The clase will be inserted at the end of the module.
|
||||
assertz(Clause0) :-
|
||||
loader:strip_module(Clause0, Module, Clause),
|
||||
assertz_(Module, Clause).
|
||||
|
||||
assertz_(Module, (Head :- Body)) :-
|
||||
!,
|
||||
'$assertz'(Module, Head, Body).
|
||||
assertz_(Module, Fact) :-
|
||||
'$assertz'(Module, Fact, true).
|
||||
loader:strip_subst_module(Clause0, user, Module, Clause),
|
||||
'$assertz'(Module, Clause).
|
||||
|
||||
|
||||
:- meta_predicate retract(:).
|
||||
|
||||
@@ -126,4 +126,3 @@ when_condition_si((A, B)) :-
|
||||
when_condition_si((A ; B)) :-
|
||||
when_condition_si(A),
|
||||
when_condition_si(B).
|
||||
|
||||
|
||||
@@ -205,6 +205,7 @@ load_loop(Stream, Evacuable) :-
|
||||
read_term(Stream, Term, [singletons(Singletons)])
|
||||
; Term = end_of_file
|
||||
),
|
||||
% write('Term: '), writeq(Term), nl,
|
||||
( Term == end_of_file ->
|
||||
close(Stream),
|
||||
'$conclude_load'(Evacuable)
|
||||
@@ -219,6 +220,7 @@ load_loop(Stream, Evacuable) :-
|
||||
|
||||
compile_term(Term, Evacuable) :-
|
||||
expand_terms_and_goals(Term, Terms),
|
||||
% write('Terms: '), writeq(Terms),nl,
|
||||
!,
|
||||
( var(Terms) ->
|
||||
instantiation_error(load/1)
|
||||
|
||||
@@ -1155,8 +1155,17 @@ impl MachineState {
|
||||
value: HeapCellValue,
|
||||
) -> Result<Number, MachineStub> {
|
||||
let stub_gen = || functor_stub(atom!("is"), 2);
|
||||
let mut iter =
|
||||
stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, value);
|
||||
|
||||
let root_loc = if value.is_ref() {
|
||||
value.get_value() as usize
|
||||
} else {
|
||||
let type_error = self.type_error(ValidType::Evaluable, value);
|
||||
return Err(self.error_form(type_error, stub_gen()));
|
||||
};
|
||||
|
||||
let mut iter = stackful_post_order_iter::<NonListElider>(
|
||||
&mut self.heap, &mut self.stack, root_loc,
|
||||
);
|
||||
|
||||
while let Some(value) = iter.next() {
|
||||
if value.get_forwarding_bit() {
|
||||
|
||||
@@ -11,8 +11,8 @@ use std::vec::IntoIter;
|
||||
pub(super) type Bindings = Vec<(usize, HeapCellValue)>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct AttrVarInitializer {
|
||||
pub(super) attr_var_queue: Vec<usize>,
|
||||
pub(crate) struct AttrVarInitializer {
|
||||
pub(crate) attr_var_queue: Vec<usize>,
|
||||
pub(super) bindings: Bindings,
|
||||
pub(super) p: usize,
|
||||
pub(super) cp: usize,
|
||||
@@ -131,9 +131,15 @@ impl MachineState {
|
||||
pub(super) fn attr_vars_of_term(&mut self, cell: HeapCellValue) -> Vec<HeapCellValue> {
|
||||
let mut seen_set = IndexSet::new();
|
||||
let mut seen_vars = vec![];
|
||||
let root_loc = if cell.is_ref() {
|
||||
cell.get_value() as usize
|
||||
} else {
|
||||
return vec![];
|
||||
};
|
||||
|
||||
let mut iter =
|
||||
stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, cell);
|
||||
let mut iter = stackful_preorder_iter::<NonListElider>(
|
||||
&mut self.heap, &mut self.stack, root_loc, // cell,
|
||||
);
|
||||
|
||||
while let Some(value) = iter.next() {
|
||||
read_heap_cell!(value,
|
||||
|
||||
@@ -11,7 +11,6 @@ use crate::machine::term_stream::*;
|
||||
use crate::machine::*;
|
||||
use crate::parser::ast::*;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::VecDeque;
|
||||
use std::mem;
|
||||
use std::ops::Range;
|
||||
@@ -1233,14 +1232,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
|
||||
fn compile_standalone_clause(
|
||||
&mut self,
|
||||
term: Term,
|
||||
term: FocusedHeap,
|
||||
settings: CodeGenSettings,
|
||||
) -> Result<StandaloneCompileResult, SessionError> {
|
||||
let mut preprocessor = Preprocessor::new(settings);
|
||||
|
||||
let clause = self.try_term_to_tl(term, &mut preprocessor)?;
|
||||
// let queue = preprocessor.parse_queue(self)?;
|
||||
|
||||
let mut cg = CodeGenerator::new(&LS::machine_st(&mut self.payload).atom_tbl, settings);
|
||||
|
||||
let clause_code = cg.compile_predicate(vec![clause])?;
|
||||
@@ -1272,7 +1269,6 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
}
|
||||
|
||||
let mut cg = CodeGenerator::new(&LS::machine_st(&mut self.payload).atom_tbl, settings);
|
||||
|
||||
let mut code = cg.compile_predicate(clauses)?;
|
||||
|
||||
if settings.is_extensible {
|
||||
@@ -1470,7 +1466,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
pub(super) fn incremental_compile_clause(
|
||||
&mut self,
|
||||
key: PredicateKey,
|
||||
clause: Term,
|
||||
clause: FocusedHeap,
|
||||
compilation_target: CompilationTarget,
|
||||
non_counted_bt: bool,
|
||||
append_or_prepend: AppendOrPrepend,
|
||||
@@ -2005,16 +2001,13 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
}
|
||||
|
||||
impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
pub(super) fn compile_clause_clauses<ClauseIter: Iterator<Item = (Term, Term)>>(
|
||||
pub(super) fn compile_clause_clauses(
|
||||
&mut self,
|
||||
key: PredicateKey,
|
||||
compilation_target: CompilationTarget,
|
||||
clause_clauses: ClauseIter,
|
||||
clause_clauses: Vec<FocusedHeap>,
|
||||
append_or_prepend: AppendOrPrepend,
|
||||
) -> Result<(), SessionError> {
|
||||
let clause_predicates = clause_clauses
|
||||
.map(|(head, body)| Term::Clause(Cell::default(), atom!("$clause"), vec![head, body]));
|
||||
|
||||
let clause_clause_compilation_target = match compilation_target {
|
||||
CompilationTarget::User => CompilationTarget::Module(atom!("builtins")),
|
||||
_ => compilation_target,
|
||||
@@ -2022,7 +2015,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
|
||||
let mut num_clause_predicates = 0;
|
||||
|
||||
for clause_term in clause_predicates {
|
||||
for clause_term in clause_clauses {
|
||||
self.incremental_compile_clause(
|
||||
(atom!("$clause"), 2),
|
||||
clause_term,
|
||||
@@ -2253,13 +2246,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
.clause_clauses
|
||||
.drain(0..std::cmp::min(predicates_len, clause_clauses_len))
|
||||
.collect();
|
||||
|
||||
let compilation_target = self.payload.predicates.compilation_target;
|
||||
|
||||
self.compile_clause_clauses(
|
||||
key,
|
||||
compilation_target,
|
||||
clauses_vec.into_iter(),
|
||||
clauses_vec,
|
||||
AppendOrPrepend::Append,
|
||||
)?;
|
||||
}
|
||||
@@ -2288,15 +2280,43 @@ impl Machine {
|
||||
|
||||
pub(crate) fn compile_standalone_clause(
|
||||
&mut self,
|
||||
term_loc: RegType,
|
||||
vars: &[Term],
|
||||
term_reg: RegType,
|
||||
vars: Vec<HeapCellValue>,
|
||||
) -> Result<(), SessionError> {
|
||||
let mut compile = || {
|
||||
let cell = self.machine_st.store(self.machine_st.deref(self.machine_st[term_reg]));
|
||||
|
||||
// append the variables of vars.
|
||||
let focus = cell.get_value() as usize;
|
||||
let header_loc = term_nth_arg(&self.machine_st.heap, focus, 0).unwrap();
|
||||
let name = term_name(&self.machine_st.heap, header_loc).unwrap();
|
||||
let old_arity = term_arity(&self.machine_st.heap, header_loc);
|
||||
|
||||
let new_header_loc = self.machine_st.heap.len();
|
||||
let new_arity = old_arity + vars.len();
|
||||
|
||||
self.machine_st.heap.push(atom_as_cell!(name, new_arity));
|
||||
|
||||
for idx in header_loc + 1 .. header_loc + 1 + old_arity {
|
||||
self.machine_st.heap.push(self.machine_st.heap[idx]);
|
||||
}
|
||||
|
||||
for var in vars {
|
||||
self.machine_st.heap.push(var);
|
||||
}
|
||||
|
||||
let value = if new_arity > 0 {
|
||||
str_loc_as_cell!(new_header_loc)
|
||||
} else {
|
||||
heap_loc_as_cell!(new_header_loc)
|
||||
};
|
||||
|
||||
let mut compile = |cell| {
|
||||
use crate::heap_iter::eager_stackful_preorder_iter;
|
||||
|
||||
let mut loader: Loader<'_, InlineLoadState<'_>> =
|
||||
Loader::new(self, InlineTermStream {});
|
||||
|
||||
let term = loader.read_term_from_heap(term_loc);
|
||||
let clause = build_rule_body(vars, term);
|
||||
let mut term = loader.copy_term_from_heap(cell);
|
||||
|
||||
let settings = CodeGenSettings {
|
||||
global_clock_tick: None,
|
||||
@@ -2304,10 +2324,16 @@ impl Machine {
|
||||
non_counted_bt: true,
|
||||
};
|
||||
|
||||
loader.compile_standalone_clause(clause, settings)
|
||||
let value = term.heap[term.focus];
|
||||
|
||||
term.var_locs = var_locs_from_iter(
|
||||
eager_stackful_preorder_iter(&mut term.heap, value),
|
||||
);
|
||||
|
||||
loader.compile_standalone_clause(term, settings)
|
||||
};
|
||||
|
||||
let StandaloneCompileResult { clause_code, .. } = compile()?;
|
||||
let StandaloneCompileResult { clause_code, .. } = compile(value)?;
|
||||
self.code.extend(clause_code);
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
use crate::atom_table::*;
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
use crate::iterators::*;
|
||||
use crate::iterators::fact_iterator;
|
||||
use crate::machine::Stack;
|
||||
use crate::machine::loader::*;
|
||||
use crate::machine::machine_errors::CompilationError;
|
||||
use crate::machine::preprocessor::*;
|
||||
use crate::parser::ast::*;
|
||||
use crate::parser::dashu::Rational;
|
||||
use crate::types::*;
|
||||
use crate::variable_records::*;
|
||||
|
||||
use dashu::Integer;
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::VecDeque;
|
||||
use std::hash::{Hash, Hasher};
|
||||
@@ -147,11 +148,21 @@ enum TraversalState {
|
||||
// where it leaves off.
|
||||
BuildFinalDisjunct(usize),
|
||||
Fail,
|
||||
GetCutPoint { var_num: usize, prev_b: bool },
|
||||
Cut { var_num: usize, is_global: bool },
|
||||
Succeed,
|
||||
GetCutPoint {
|
||||
var_num: usize,
|
||||
prev_b: bool,
|
||||
},
|
||||
Cut {
|
||||
var_num: usize,
|
||||
is_global: bool,
|
||||
},
|
||||
CutPrev(usize),
|
||||
ResetCallPolicy(CallPolicy),
|
||||
Term(Term),
|
||||
Term {
|
||||
subterm: HeapCellValue,
|
||||
term_loc: usize,
|
||||
},
|
||||
OverrideGlobalCutVar(usize),
|
||||
ResetGlobalCutVarOverride(Option<usize>),
|
||||
RemoveBranchNum, // pop the current_branch_num and from the root set.
|
||||
@@ -183,7 +194,7 @@ 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::Perm { .. } => Some(global_cut_var_num),
|
||||
VarAlloc::Temp { term_loc, .. } if term_loc.chunk_num() > 0 => {
|
||||
Some(global_cut_var_num)
|
||||
}
|
||||
@@ -196,7 +207,7 @@ impl VarData {
|
||||
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);
|
||||
VarAlloc::Perm { reg: 0, allocation: PermVarAllocation::Pending };
|
||||
|
||||
match build_stack.front_mut() {
|
||||
Some(ChunkedTerms::Branch(_)) => {
|
||||
@@ -213,8 +224,8 @@ impl VarData {
|
||||
}
|
||||
}
|
||||
|
||||
pub type ClassifyFactResult = (Term, VarData);
|
||||
pub type ClassifyRuleResult = (Term, ChunkedTermVec, VarData);
|
||||
pub type ClassifyFactResult = VarData;
|
||||
pub type ClassifyRuleResult = (ChunkedTermVec, VarData);
|
||||
|
||||
fn merge_branch_seq(branches: impl Iterator<Item = BranchInfo>) -> BranchInfo {
|
||||
let mut branch_info = BranchInfo::new(BranchNumber::default());
|
||||
@@ -255,28 +266,32 @@ impl VariableClassifier {
|
||||
}
|
||||
}
|
||||
|
||||
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_fact(
|
||||
mut self,
|
||||
term: &mut FocusedHeap,
|
||||
) -> Result<ClassifyFactResult, CompilationError> {
|
||||
let focus = term.focus;
|
||||
self.classify_head_variables(term, focus)?;
|
||||
|
||||
Ok(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,
|
||||
term: &mut FocusedHeap,
|
||||
) -> Result<ClassifyRuleResult, CompilationError> {
|
||||
self.classify_head_variables(&head)?;
|
||||
let head_loc = term.nth_arg(term.focus, 1).unwrap();
|
||||
let body_loc = term.nth_arg(term.focus, 2).unwrap();
|
||||
|
||||
self.classify_head_variables(term, head_loc)?;
|
||||
self.root_set.insert(self.current_branch_num.clone());
|
||||
|
||||
let mut query_terms = self.classify_body_variables(loader, body)?;
|
||||
let mut query_terms = self.classify_body_variables(loader, term, body_loc)?;
|
||||
|
||||
self.merge_branches();
|
||||
|
||||
@@ -288,7 +303,7 @@ impl VariableClassifier {
|
||||
|
||||
var_data.emit_initial_get_level(&mut query_terms);
|
||||
|
||||
Ok((head, query_terms, var_data))
|
||||
Ok((query_terms, var_data))
|
||||
}
|
||||
|
||||
fn merge_branches(&mut self) {
|
||||
@@ -332,22 +347,39 @@ impl VariableClassifier {
|
||||
}
|
||||
}
|
||||
|
||||
fn probe_body_term(&mut self, arg_c: usize, arity: usize, term: &Term) {
|
||||
fn probe_body_term(
|
||||
&mut self,
|
||||
arg_c: usize,
|
||||
arity: usize,
|
||||
term: &mut FocusedHeap,
|
||||
term_loc: usize,
|
||||
) {
|
||||
let classify_info = ClassifyInfo { arg_c, arity };
|
||||
|
||||
let mut lvl = Level::Shallow;
|
||||
let mut stack = Stack::uninitialized();
|
||||
let mut iter = fact_iterator::<false>(
|
||||
&mut term.heap,
|
||||
&mut stack,
|
||||
term_loc,
|
||||
);
|
||||
|
||||
// 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,
|
||||
});
|
||||
while let Some(subterm) = iter.next() {
|
||||
if !subterm.is_var() {
|
||||
lvl = Level::Deep;
|
||||
continue;
|
||||
}
|
||||
|
||||
let var_loc = subterm.get_value() as usize;
|
||||
let var_ptr = term.var_locs.read_next_var_ptr_at_key(var_loc).unwrap();
|
||||
|
||||
self.probe_body_var(VarInfo {
|
||||
var_ptr: var_ptr.clone(),
|
||||
lvl,
|
||||
classify_info,
|
||||
chunk_type: self.current_chunk_type,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,56 +433,79 @@ impl VariableClassifier {
|
||||
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),
|
||||
}
|
||||
fn classify_head_variables(
|
||||
&mut self,
|
||||
term: &mut FocusedHeap,
|
||||
head_loc: usize,
|
||||
) -> Result<(), CompilationError> {
|
||||
let arity = read_heap_cell!(term.deref_loc(head_loc),
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
cell_as_atom_cell!(term.heap[s]).get_arity()
|
||||
}
|
||||
(HeapCellValueTag::Atom) => {
|
||||
return Ok(());
|
||||
}
|
||||
_ => {
|
||||
return Err(CompilationError::InvalidRuleHead);
|
||||
}
|
||||
);
|
||||
|
||||
let mut classify_info = ClassifyInfo {
|
||||
arg_c: 1,
|
||||
arity: term.arity(),
|
||||
};
|
||||
let mut classify_info = ClassifyInfo { arg_c: 1, arity };
|
||||
|
||||
if let Term::Clause(_, _, terms) = term {
|
||||
for term in terms.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();
|
||||
if arity > 0 {
|
||||
let (_term_loc, value) = subterm_index(&term.heap, head_loc);
|
||||
let str_offset = value.get_value() as usize;
|
||||
|
||||
// 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_default();
|
||||
debug_assert_eq!(value.get_tag(), HeapCellValueTag::Str);
|
||||
|
||||
let needs_new_branch = branch_info_v.is_empty();
|
||||
for idx in str_offset + 1 ..= str_offset + arity {
|
||||
let mut lvl = Level::Shallow;
|
||||
let mut stack = Stack::uninitialized();
|
||||
let mut iter = fact_iterator::<false>(
|
||||
&mut term.heap,
|
||||
&mut stack,
|
||||
idx,
|
||||
);
|
||||
|
||||
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);
|
||||
while let Some(subterm) = iter.next() {
|
||||
if !subterm.is_var() {
|
||||
lvl = Level::Deep;
|
||||
continue;
|
||||
}
|
||||
|
||||
let h = subterm.get_value() as usize;
|
||||
let var_ptr = term.var_locs.read_next_var_ptr_at_key(h).unwrap().clone();
|
||||
|
||||
// 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_default();
|
||||
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;
|
||||
@@ -460,17 +515,40 @@ impl VariableClassifier {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn new_cut_state(&mut self) -> TraversalState {
|
||||
let (var_num, is_global) = if let Some(var_num) = self.global_cut_var_num_override {
|
||||
(var_num, false)
|
||||
} else if let Some(var_num) = self.global_cut_var_num {
|
||||
(var_num, true)
|
||||
} else {
|
||||
let var_num = self.var_num;
|
||||
|
||||
self.global_cut_var_num = Some(var_num);
|
||||
self.var_num += 1;
|
||||
|
||||
(var_num, true)
|
||||
};
|
||||
|
||||
self.probe_in_situ_var(var_num);
|
||||
|
||||
TraversalState::Cut { var_num, is_global }
|
||||
}
|
||||
|
||||
fn classify_body_variables<'a, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
term: Term,
|
||||
terms: &mut FocusedHeap,
|
||||
term_loc: usize,
|
||||
) -> Result<ChunkedTermVec, CompilationError> {
|
||||
let mut state_stack = vec![TraversalState::Term(term)];
|
||||
let mut state_stack = vec![TraversalState::Term {
|
||||
subterm: terms.heap[term_loc],
|
||||
term_loc,
|
||||
}];
|
||||
let mut build_stack = ChunkedTermVec::new();
|
||||
|
||||
self.current_chunk_type = ChunkType::Mid;
|
||||
|
||||
while let Some(traversal_st) = state_stack.pop() {
|
||||
'outer: while let Some(traversal_st) = state_stack.pop() {
|
||||
match traversal_st {
|
||||
TraversalState::AddBranchNum(branch_num) => {
|
||||
self.root_set.insert(branch_num.clone());
|
||||
@@ -544,297 +622,339 @@ impl VariableClassifier {
|
||||
TraversalState::Fail => {
|
||||
build_stack.push_chunk_term(QueryTerm::Fail);
|
||||
}
|
||||
TraversalState::Term(term) => {
|
||||
TraversalState::Succeed => {
|
||||
build_stack.push_chunk_term(QueryTerm::Succeed);
|
||||
}
|
||||
TraversalState::Term {
|
||||
mut subterm,
|
||||
mut term_loc,
|
||||
} => {
|
||||
// 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) {
|
||||
let update_chunk_data = |classifier: &mut Self, key: PredicateKey| {
|
||||
if ClauseType::is_inlined(key.0, key.1) {
|
||||
classifier.try_set_chunk_at_inlined_boundary()
|
||||
} else {
|
||||
classifier.try_set_chunk_at_call_boundary()
|
||||
}
|
||||
};
|
||||
|
||||
let mut add_chunk = |classifier: &mut Self, name: Atom, terms: Vec<Term>| {
|
||||
if update_chunk_data(classifier, name, terms.len()) {
|
||||
build_stack.add_chunk();
|
||||
}
|
||||
|
||||
for (arg_c, term) in terms.iter().enumerate() {
|
||||
classifier.probe_body_term(arg_c + 1, terms.len(), term);
|
||||
}
|
||||
|
||||
build_stack.push_chunk_term(clause_to_query_term(
|
||||
loader,
|
||||
name,
|
||||
terms,
|
||||
classifier.call_policy,
|
||||
));
|
||||
};
|
||||
|
||||
match term {
|
||||
Term::Clause(
|
||||
_,
|
||||
name @ (atom!("->") | atom!(";") | atom!(",")),
|
||||
mut terms,
|
||||
) if terms.len() == 3 => {
|
||||
if let Some(last_arg) = terms.last() {
|
||||
if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg {
|
||||
terms.pop();
|
||||
state_stack.push(TraversalState::Term(Term::Clause(
|
||||
Cell::default(),
|
||||
name,
|
||||
terms,
|
||||
)));
|
||||
} else {
|
||||
add_chunk(self, name, terms);
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
});
|
||||
macro_rules! add_chunk {
|
||||
($classifier:ident, $key:expr, $tag:expr, $term_loc:expr) => {{
|
||||
if update_chunk_data($classifier, $key) {
|
||||
build_stack.add_chunk();
|
||||
}
|
||||
|
||||
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]
|
||||
for (arg_c, term_loc) in
|
||||
($term_loc + 1 ..= $term_loc + $key.1).enumerate()
|
||||
{
|
||||
state_stack[final_disjunct_loc] =
|
||||
TraversalState::BuildFinalDisjunct(build_stack_len);
|
||||
$classifier.probe_body_term(arg_c + 1, $key.1, terms, term_loc);
|
||||
}
|
||||
|
||||
self.current_chunk_type = ChunkType::Mid;
|
||||
self.current_chunk_num += 1;
|
||||
}
|
||||
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.
|
||||
match state_stack.iter().rev().nth(1) {
|
||||
Some(&TraversalState::BuildDisjunct(preceding_len)) => {
|
||||
preceding_len + 1 == build_stack.len()
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
} 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![],
|
||||
build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term(
|
||||
loader,
|
||||
$key,
|
||||
terms.as_ref_mut($term_loc),
|
||||
HeapCellValue::build_with($tag, $term_loc as u64),
|
||||
$classifier.call_policy,
|
||||
)));
|
||||
state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
|
||||
state_stack.push(TraversalState::Fail);
|
||||
state_stack.push(TraversalState::CutPrev(self.var_num));
|
||||
state_stack.push(TraversalState::ResetGlobalCutVarOverride(
|
||||
self.global_cut_var_num_override,
|
||||
));
|
||||
state_stack.push(TraversalState::Term(not_term));
|
||||
state_stack.push(TraversalState::OverrideGlobalCutVar(self.var_num));
|
||||
state_stack.push(TraversalState::GetCutPoint {
|
||||
var_num: self.var_num,
|
||||
prev_b: false,
|
||||
});
|
||||
}};
|
||||
}
|
||||
|
||||
self.current_chunk_type = ChunkType::Mid;
|
||||
self.current_chunk_num += 1;
|
||||
|
||||
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) => {
|
||||
add_chunk(self, name, terms);
|
||||
}
|
||||
var @ Term::Var(..) => {
|
||||
if update_chunk_data(self, atom!("call"), 1) {
|
||||
macro_rules! add_qualified_chunk {
|
||||
($classifier:ident, $module_name:expr, $key:expr, $tag:expr, $term_loc:expr) => {{
|
||||
if update_chunk_data($classifier, $key) {
|
||||
build_stack.add_chunk();
|
||||
}
|
||||
|
||||
self.probe_body_term(1, 1, &var);
|
||||
for (arg_c, term_loc) in
|
||||
($term_loc + 1..$term_loc + $key.1 + 1).enumerate()
|
||||
{
|
||||
$classifier.probe_body_term(arg_c + 1, $key.1, terms, term_loc);
|
||||
}
|
||||
|
||||
build_stack.push_chunk_term(clause_to_query_term(
|
||||
loader,
|
||||
atom!("call"),
|
||||
vec![var],
|
||||
self.call_policy,
|
||||
build_stack.push_chunk_term(QueryTerm::Clause(
|
||||
qualified_clause_to_query_term(
|
||||
loader,
|
||||
$key,
|
||||
$module_name,
|
||||
terms.as_ref_mut($term_loc),
|
||||
HeapCellValue::build_with($tag, $term_loc as u64),
|
||||
$classifier.call_policy,
|
||||
),
|
||||
));
|
||||
}
|
||||
Term::Literal(_, Literal::Atom(atom!("!")) | Literal::Char('!')) => {
|
||||
let (var_num, is_global) =
|
||||
if let Some(var_num) = self.global_cut_var_num_override {
|
||||
(var_num, false)
|
||||
} else if let Some(var_num) = self.global_cut_var_num {
|
||||
(var_num, true)
|
||||
}};
|
||||
}
|
||||
|
||||
loop {
|
||||
read_heap_cell!(subterm,
|
||||
(HeapCellValueTag::Str, subterm_loc) => {
|
||||
let (name, arity) = cell_as_atom_cell!(terms.heap[subterm_loc])
|
||||
.get_name_and_arity();
|
||||
|
||||
match (name, arity) {
|
||||
(atom!("->") | atom!(";") | atom!(","), 3) => {
|
||||
if blunt_index_ptr(&mut terms.heap, (name, 2), subterm_loc) {
|
||||
subterm = terms.heap[subterm_loc];
|
||||
continue;
|
||||
}
|
||||
|
||||
add_chunk!(self, (name, 2), HeapCellValueTag::Str, subterm_loc);
|
||||
}
|
||||
(atom!(","), 2) => {
|
||||
let head_loc = terms.nth_arg(subterm_loc, 1).unwrap();
|
||||
let tail_loc = terms.nth_arg(subterm_loc, 2).unwrap();
|
||||
let head = terms.heap[head_loc];
|
||||
|
||||
let iter = unfold_by_str_locs(&mut terms.heap, tail_loc, atom!(","))
|
||||
.into_iter()
|
||||
.rev()
|
||||
.chain(std::iter::once((head, head_loc)))
|
||||
.map(|(subterm, term_loc)| {
|
||||
TraversalState::Term { subterm, term_loc }
|
||||
});
|
||||
state_stack.extend(iter);
|
||||
}
|
||||
(atom!(";"), 2) => {
|
||||
let head_loc = terms.nth_arg(subterm_loc, 1).unwrap();
|
||||
let tail_loc = terms.nth_arg(subterm_loc, 2).unwrap();
|
||||
|
||||
let head = terms.heap[head_loc];
|
||||
|
||||
let first_branch_num = self.current_branch_num.split();
|
||||
let branches: Vec<_> = std::iter::once((head, head_loc))
|
||||
.chain(
|
||||
unfold_by_str_locs(&mut terms.heap, tail_loc, 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 ((subterm, term_loc), branch_num) in iter.rev() {
|
||||
state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
|
||||
state_stack.push(TraversalState::RemoveBranchNum);
|
||||
state_stack.push(TraversalState::Term { subterm, term_loc });
|
||||
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);
|
||||
}
|
||||
|
||||
self.current_chunk_type = ChunkType::Mid;
|
||||
self.current_chunk_num += 1;
|
||||
}
|
||||
(atom!("->"), 2) => {
|
||||
let if_term_loc = terms.nth_arg(subterm_loc, 1).unwrap();
|
||||
let then_term_loc = terms.nth_arg(subterm_loc, 2).unwrap();
|
||||
|
||||
let if_term = terms.heap[if_term_loc];
|
||||
let then_term = terms.heap[then_term_loc];
|
||||
|
||||
let prev_b = if matches!(
|
||||
state_stack.last(),
|
||||
Some(TraversalState::RemoveBranchNum)
|
||||
) {
|
||||
// check if the second-to-last element
|
||||
// is a regular BuildDisjunct, as we
|
||||
// don't want to add GetPrevLevel in
|
||||
// case of a TrustMe.
|
||||
match state_stack.iter().rev().nth(1) {
|
||||
Some(&TraversalState::BuildDisjunct(preceding_len)) => {
|
||||
preceding_len + 1 == build_stack.len()
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
state_stack.push(TraversalState::Term {
|
||||
subterm: then_term,
|
||||
term_loc: then_term_loc,
|
||||
});
|
||||
state_stack.push(TraversalState::Cut {
|
||||
var_num: self.var_num,
|
||||
is_global: false,
|
||||
});
|
||||
state_stack.push(TraversalState::Term {
|
||||
subterm: if_term,
|
||||
term_loc: if_term_loc,
|
||||
});
|
||||
state_stack.push(TraversalState::GetCutPoint {
|
||||
var_num: self.var_num,
|
||||
prev_b,
|
||||
});
|
||||
|
||||
self.var_num += 1;
|
||||
}
|
||||
(atom!("\\+"), 1) => {
|
||||
let not_term_loc = terms.nth_arg(subterm_loc, 1).unwrap();
|
||||
let not_term = terms.heap[not_term_loc];
|
||||
let build_stack_len = build_stack.len();
|
||||
|
||||
build_stack.reserve_branch(2);
|
||||
|
||||
let branch_num = self.current_branch_num.split();
|
||||
let succ_branch_num = branch_num.incr_by_delta();
|
||||
|
||||
state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len));
|
||||
state_stack.push(TraversalState::Succeed);
|
||||
state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
|
||||
state_stack.push(TraversalState::RepBranchNum(succ_branch_num));
|
||||
state_stack.push(TraversalState::Fail);
|
||||
state_stack.push(TraversalState::CutPrev(self.var_num));
|
||||
state_stack.push(TraversalState::ResetGlobalCutVarOverride(
|
||||
self.global_cut_var_num_override,
|
||||
));
|
||||
state_stack.push(TraversalState::Term {
|
||||
subterm: not_term,
|
||||
term_loc: not_term_loc,
|
||||
});
|
||||
state_stack.push(TraversalState::OverrideGlobalCutVar(self.var_num));
|
||||
state_stack.push(TraversalState::GetCutPoint {
|
||||
var_num: self.var_num,
|
||||
prev_b: false,
|
||||
});
|
||||
state_stack.push(TraversalState::AddBranchNum(branch_num));
|
||||
|
||||
self.current_chunk_type = ChunkType::Mid;
|
||||
self.current_chunk_num += 1;
|
||||
|
||||
self.var_num += 1;
|
||||
}
|
||||
(atom!(":"), 2) => {
|
||||
let module_name_loc = terms.nth_arg(subterm_loc, 1).unwrap();
|
||||
let predicate_term_loc = terms.nth_arg(subterm_loc, 2).unwrap();
|
||||
|
||||
let module_name = terms.deref_loc(module_name_loc);
|
||||
let predicate_term = terms.deref_loc(predicate_term_loc);
|
||||
|
||||
read_heap_cell!(module_name,
|
||||
(HeapCellValueTag::Atom, (module_name, arity)) => {
|
||||
if arity == 0 {
|
||||
read_heap_cell!(predicate_term,
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
let key = cell_as_atom_cell!(terms.heap[s])
|
||||
.get_name_and_arity();
|
||||
|
||||
add_qualified_chunk!(
|
||||
self,
|
||||
module_name,
|
||||
key,
|
||||
HeapCellValueTag::Str,
|
||||
s
|
||||
);
|
||||
}
|
||||
(HeapCellValueTag::Atom, (predicate_name, predicate_arity)) => {
|
||||
debug_assert_eq!(predicate_arity, 0);
|
||||
let key = (predicate_name, predicate_arity);
|
||||
|
||||
add_qualified_chunk!(
|
||||
self,
|
||||
module_name,
|
||||
key,
|
||||
HeapCellValueTag::Str,
|
||||
predicate_term_loc
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
);
|
||||
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
);
|
||||
|
||||
if update_chunk_data(self, (atom!("call"), 2)) {
|
||||
build_stack.add_chunk();
|
||||
}
|
||||
|
||||
self.probe_body_term(1, 0, terms, module_name_loc);
|
||||
self.probe_body_term(2, 0, terms, predicate_term_loc);
|
||||
|
||||
let h = terms.heap.len();
|
||||
|
||||
terms.heap.push(atom_as_cell!(atom!("call"), 1));
|
||||
terms.heap.push(str_loc_as_cell!(subterm_loc));
|
||||
|
||||
build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term(
|
||||
loader,
|
||||
(atom!("call"), 1),
|
||||
terms.as_ref_mut(h),
|
||||
str_loc_as_cell!(h),
|
||||
self.call_policy,
|
||||
)));
|
||||
}
|
||||
(atom!("$call_with_inference_counting"), 1) => {
|
||||
let term_loc = terms.nth_arg(subterm_loc, 1).unwrap();
|
||||
let subterm = terms.deref_loc(term_loc);
|
||||
|
||||
state_stack.push(TraversalState::ResetCallPolicy(self.call_policy));
|
||||
state_stack.push(TraversalState::Term { subterm, term_loc });
|
||||
|
||||
self.call_policy = CallPolicy::Counted;
|
||||
}
|
||||
(name, arity) => {
|
||||
add_chunk!(self, (name, arity), HeapCellValueTag::Str, subterm_loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
debug_assert_eq!(arity, 0);
|
||||
|
||||
if name == atom!("!") {
|
||||
state_stack.push(self.new_cut_state());
|
||||
} else {
|
||||
let var_num = self.var_num;
|
||||
|
||||
self.global_cut_var_num = Some(var_num);
|
||||
self.var_num += 1;
|
||||
|
||||
(var_num, true)
|
||||
};
|
||||
|
||||
self.probe_in_situ_var(var_num);
|
||||
|
||||
state_stack.push(TraversalState::Cut { var_num, is_global });
|
||||
}
|
||||
Term::Literal(_, Literal::Atom(name)) => {
|
||||
if update_chunk_data(self, name, 0) {
|
||||
build_stack.add_chunk();
|
||||
add_chunk!(self, (name, 0), HeapCellValueTag::Var, term_loc);
|
||||
}
|
||||
}
|
||||
(HeapCellValueTag::Char, c) => {
|
||||
if c == '!' {
|
||||
state_stack.push(self.new_cut_state());
|
||||
} else {
|
||||
return Err(CompilationError::InadmissibleQueryTerm);
|
||||
}
|
||||
}
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
if h != term_loc {
|
||||
subterm = terms.heap[h];
|
||||
term_loc = h;
|
||||
continue;
|
||||
}
|
||||
|
||||
build_stack.push_chunk_term(clause_to_query_term(
|
||||
loader,
|
||||
name,
|
||||
vec![],
|
||||
self.call_policy,
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
return Err(CompilationError::InadmissibleQueryTerm);
|
||||
}
|
||||
add_chunk!(self, (atom!("call"), 1), HeapCellValueTag::Var, h);
|
||||
}
|
||||
_ => {
|
||||
return Err(CompilationError::InadmissibleQueryTerm);
|
||||
}
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -899,7 +1019,8 @@ impl BranchMap {
|
||||
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));
|
||||
let is_anon = var_info.var_ptr.is_anon();
|
||||
var_info.var_ptr.set(Var::Generated { is_anon, var_num });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2664,6 +2664,8 @@ impl Machine {
|
||||
&Instruction::CallNamed(arity, name, ref idx) => {
|
||||
let idx = idx.get();
|
||||
|
||||
// println!("calling {}/{}", name.as_str(), arity);
|
||||
|
||||
try_or_throw!(self.machine_st, self.try_call(name, arity, idx));
|
||||
|
||||
if self.machine_st.fail {
|
||||
@@ -2675,6 +2677,8 @@ impl Machine {
|
||||
&Instruction::ExecuteNamed(arity, name, ref idx) => {
|
||||
let idx = idx.get();
|
||||
|
||||
// println!("executing {}/{}", name.as_str(), arity);
|
||||
|
||||
try_or_throw!(self.machine_st, self.try_execute(name, arity, idx));
|
||||
|
||||
if self.machine_st.fail {
|
||||
@@ -2686,6 +2690,8 @@ impl Machine {
|
||||
&Instruction::DefaultCallNamed(arity, name, ref idx) => {
|
||||
let idx = idx.get();
|
||||
|
||||
// println!("calling {}/{}", name.as_str(), arity);
|
||||
|
||||
try_or_throw!(self.machine_st, self.try_call(name, arity, idx));
|
||||
|
||||
if self.machine_st.fail {
|
||||
@@ -2695,6 +2701,8 @@ impl Machine {
|
||||
&Instruction::DefaultExecuteNamed(arity, name, ref idx) => {
|
||||
let idx = idx.get();
|
||||
|
||||
// println!("executing {}/{}", name.as_str(), arity);
|
||||
|
||||
try_or_throw!(self.machine_st, self.try_execute(name, arity, idx));
|
||||
|
||||
if self.machine_st.fail {
|
||||
@@ -3511,6 +3519,15 @@ impl Machine {
|
||||
self.dynamic_module_resolution(arity - 2)
|
||||
);
|
||||
|
||||
/*
|
||||
println!(
|
||||
"(slow) calling {}:{}/{}",
|
||||
module_name.as_str(),
|
||||
key.0.as_str(),
|
||||
key.1,
|
||||
);
|
||||
*/
|
||||
|
||||
try_or_throw!(self.machine_st, self.call_clause(module_name, key));
|
||||
|
||||
if self.machine_st.fail {
|
||||
@@ -3523,6 +3540,15 @@ impl Machine {
|
||||
self.dynamic_module_resolution(arity - 2)
|
||||
);
|
||||
|
||||
/*
|
||||
println!(
|
||||
"(slow) executing {}:{}/{}",
|
||||
module_name.as_str(),
|
||||
key.0.as_str(),
|
||||
key.1,
|
||||
);
|
||||
*/
|
||||
|
||||
try_or_throw!(self.machine_st, self.execute_clause(module_name, key));
|
||||
|
||||
if self.machine_st.fail {
|
||||
|
||||
@@ -7,6 +7,9 @@ use crate::types::*;
|
||||
#[cfg(test)]
|
||||
use crate::heap_iter::{FocusedHeapIter, HeapOrStackTag, IterStackLoc};
|
||||
|
||||
#[cfg(test)]
|
||||
use std::ops::Deref;
|
||||
|
||||
pub(crate) trait UnmarkPolicy {
|
||||
fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter<Self>) -> Option<HeapCellValue>
|
||||
where
|
||||
@@ -103,6 +106,15 @@ pub(crate) struct StacklessPreOrderHeapIter<'a, UMP: UnmarkPolicy> {
|
||||
iter_state: UMP,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl<'a> Deref for StacklessPreOrderHeapIter<'a, IteratorUMP> {
|
||||
type Target = [HeapCellValue];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.heap
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl<'a> FocusedHeapIter for StacklessPreOrderHeapIter<'a, IteratorUMP> {
|
||||
#[inline]
|
||||
|
||||
@@ -436,7 +436,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
|
||||
pub(super) fn try_term_to_tl(
|
||||
&mut self,
|
||||
term: Term,
|
||||
term: FocusedHeap,
|
||||
preprocessor: &mut Preprocessor,
|
||||
) -> Result<PredicateClause, SessionError> {
|
||||
let tl = preprocessor.try_term_to_tl(self, term)?;
|
||||
@@ -1164,7 +1164,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
let mut path_buf = PathBuf::from(&*filename.as_str());
|
||||
path_buf.set_extension("pl");
|
||||
|
||||
let file = File::open(&path_buf)?;
|
||||
let file = File::open(&path_buf)
|
||||
.map_err(|err| ParserError::IO(err, ParserErrorSrc::default()))?;
|
||||
|
||||
(
|
||||
Stream::from_file_as_input(
|
||||
@@ -1245,7 +1246,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
ModuleSource::File(filename) => {
|
||||
let mut path_buf = PathBuf::from(&*filename.as_str());
|
||||
path_buf.set_extension("pl");
|
||||
let file = File::open(&path_buf)?;
|
||||
let file = File::open(&path_buf)
|
||||
.map_err(|err| ParserError::IO(err, ParserErrorSrc::default()))?;
|
||||
|
||||
(
|
||||
Stream::from_file_as_input(
|
||||
|
||||
@@ -15,7 +15,6 @@ use crate::types::*;
|
||||
|
||||
use indexmap::IndexSet;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::VecDeque;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
@@ -177,18 +176,18 @@ impl CompilationTarget {
|
||||
}
|
||||
|
||||
pub struct PredicateQueue {
|
||||
pub(super) predicates: Vec<Term>,
|
||||
pub(super) predicates: Vec<FocusedHeap>,
|
||||
pub(super) compilation_target: CompilationTarget,
|
||||
}
|
||||
|
||||
impl PredicateQueue {
|
||||
#[inline]
|
||||
pub(super) fn push(&mut self, clause: Term) {
|
||||
pub(super) fn push(&mut self, clause: FocusedHeap) {
|
||||
self.predicates.push(clause);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn first(&self) -> Option<&Term> {
|
||||
pub(crate) fn first(&self) -> Option<&FocusedHeap> {
|
||||
self.predicates.first()
|
||||
}
|
||||
|
||||
@@ -492,11 +491,23 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn read_term_from_heap(&mut self, r: RegType) -> Term {
|
||||
let machine_st = LS::machine_st(&mut self.payload);
|
||||
let cell = machine_st[r];
|
||||
pub(crate) fn copy_term_from_heap(&mut self, cell: HeapCellValue) -> FocusedHeap {
|
||||
use crate::iterators::fact_iterator;
|
||||
|
||||
machine_st.read_term_from_heap(cell)
|
||||
let mut term = FocusedHeap::empty();
|
||||
let mut stack = Stack::uninitialized();
|
||||
let machine_st = LS::machine_st(&mut self.payload);
|
||||
|
||||
term.copy_term_from_machine_heap(machine_st, cell);
|
||||
term.var_locs = var_locs_from_iter(
|
||||
fact_iterator::<false>(
|
||||
&mut term.heap,
|
||||
&mut stack,
|
||||
0,
|
||||
),
|
||||
);
|
||||
|
||||
term
|
||||
}
|
||||
|
||||
pub(crate) fn load(mut self) -> Result<LS::Evacuable, SessionError> {
|
||||
@@ -513,18 +524,17 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
let compilation_target = &load_state.compilation_target;
|
||||
let composite_op_dir = self.wam_prelude.composite_op_dir(compilation_target);
|
||||
|
||||
let term = load_state.term_stream.next(&composite_op_dir)?;
|
||||
let mut term = load_state.term_stream.next(&composite_op_dir)?;
|
||||
|
||||
if !term.is_consistent(&load_state.predicates) {
|
||||
self.compile_and_submit()?;
|
||||
}
|
||||
|
||||
let term = match term {
|
||||
Term::Clause(_, name, terms) if name == atom!(":-") && terms.len() == 1 => {
|
||||
return Ok(Some(setup_declaration(self, terms)?));
|
||||
}
|
||||
term => term,
|
||||
};
|
||||
if Some(atom!(":-")) == term.name(term.focus) && term.arity(term.focus) == 1 {
|
||||
let new_focus = term.nth_arg(term.focus, 1).unwrap();
|
||||
let term = term.as_ref_mut(new_focus);
|
||||
return Ok(Some(setup_declaration(self, term)?));
|
||||
}
|
||||
|
||||
self.payload.predicates.push(term);
|
||||
}
|
||||
@@ -1045,31 +1055,60 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
let machine_st = LS::machine_st(&mut self.payload);
|
||||
let cell = machine_st[r];
|
||||
|
||||
let export_list = machine_st.read_term_from_heap(cell);
|
||||
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 = FocusedHeapRefMut::from_cell(&mut machine_st.heap, cell);
|
||||
let export_list = setup_module_export_list(export_list)?;
|
||||
|
||||
Ok(export_list.into_iter().collect())
|
||||
}
|
||||
|
||||
fn add_clause_clause(&mut self, term: Term) -> Result<(), CompilationError> {
|
||||
match term {
|
||||
Term::Clause(_, atom!(":-"), mut terms) if terms.len() == 2 => {
|
||||
let body = terms.pop().unwrap();
|
||||
let head = terms.pop().unwrap();
|
||||
fn clause_clause(&mut self, cell: HeapCellValue) -> Result<FocusedHeap, CompilationError> {
|
||||
let machine_st = LS::machine_st(&mut self.payload);
|
||||
let mut term = FocusedHeap::empty();
|
||||
|
||||
self.payload.clause_clauses.push((head, body));
|
||||
read_heap_cell!(cell,
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
let (name, arity) = cell_as_atom_cell!(machine_st.heap[s])
|
||||
.get_name_and_arity();
|
||||
|
||||
term.copy_term_from_machine_heap(machine_st, cell);
|
||||
let focus = term.heap.len();
|
||||
|
||||
term.heap.push(str_loc_as_cell!(focus+1));
|
||||
term.heap.push(atom_as_cell!(atom!("clause"), 2));
|
||||
|
||||
match (name, arity) {
|
||||
(atom!(":-"), 2) => {
|
||||
term.heap.push(heap_loc_as_cell!(2));
|
||||
term.heap.push(heap_loc_as_cell!(3));
|
||||
}
|
||||
_ => {
|
||||
term.heap.push(heap_loc_as_cell!(0));
|
||||
term.heap.push(atom_as_cell!(atom!("true")));
|
||||
}
|
||||
}
|
||||
|
||||
term.focus = focus;
|
||||
}
|
||||
head @ Term::Literal(_, Literal::Atom(..)) | head @ Term::Clause(..) => {
|
||||
let body = Term::Literal(Cell::default(), Literal::Atom(atom!("true")));
|
||||
self.payload.clause_clauses.push((head, body));
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
if arity == 0 {
|
||||
term.heap.push(str_loc_as_cell!(1));
|
||||
term.heap.push(atom_as_cell!(atom!("clause"), 2));
|
||||
term.heap.push(atom_as_cell!(name));
|
||||
term.heap.push(atom_as_cell!(atom!("true")));
|
||||
|
||||
term.focus = 0;
|
||||
} else {
|
||||
return Err(CompilationError::InadmissibleFact);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(CompilationError::InadmissibleFact);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
Ok(())
|
||||
let value = term.heap[term.focus];
|
||||
term.var_locs = var_locs_from_iter(eager_stackful_preorder_iter(&mut term.heap, value));
|
||||
Ok(term)
|
||||
}
|
||||
|
||||
fn add_extensible_predicate_declaration(
|
||||
@@ -1287,9 +1326,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
)
|
||||
}
|
||||
|
||||
fn add_clause_clause_if_dynamic(&mut self, term: &Term) -> Result<(), SessionError> {
|
||||
if let Some(predicate_name) = ClauseInfo::name(term) {
|
||||
let arity = ClauseInfo::arity(term);
|
||||
fn add_clause_clause_if_dynamic(&mut self, value: HeapCellValue) -> Result<(), SessionError> {
|
||||
let machine_st = LS::machine_st(&mut self.payload);
|
||||
let term = FocusedHeapRefMut::from_cell(&mut machine_st.heap, value);
|
||||
|
||||
let name_opt = ClauseInfo::name(&term);
|
||||
|
||||
if let Some(predicate_name) = name_opt {
|
||||
let arity = ClauseInfo::arity(&term);
|
||||
let predicates_compilation_target = self.payload.predicates.compilation_target;
|
||||
|
||||
let is_dynamic = self
|
||||
@@ -1300,7 +1344,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
.unwrap_or(false);
|
||||
|
||||
if is_dynamic {
|
||||
self.add_clause_clause(term.clone())?;
|
||||
let clause_clause_term = self.clause_clause(value)?;
|
||||
self.payload.clause_clauses.push(clause_clause_term);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1366,108 +1411,6 @@ impl<'a> MachinePreludeView<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl MachineState {
|
||||
pub(super) fn read_term_from_heap(&mut self, term_addr: HeapCellValue) -> Term {
|
||||
let mut term_stack = vec![];
|
||||
let mut iter =
|
||||
stackful_post_order_iter::<NonListElider>(&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 = AtomTable::build_with(&self.atom_tbl, &string);
|
||||
term_stack.push(Term::CompleteString(Cell::default(), atom));
|
||||
}
|
||||
Err(cons_term) => term_stack.push(cons_term),
|
||||
}
|
||||
}
|
||||
(HeapCellValueTag::StackVar, h) => {
|
||||
term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("s_{}", h))));
|
||||
}
|
||||
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar, 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);
|
||||
term_stack.pop().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Machine {
|
||||
pub(crate) fn use_module(&mut self) -> CallResult {
|
||||
let subevacuable_addr = self
|
||||
@@ -1628,10 +1571,11 @@ impl Machine {
|
||||
}
|
||||
|
||||
pub(crate) fn add_term_expansion_clause(&mut self) -> CallResult {
|
||||
let value = self.machine_st.registers[1];
|
||||
let mut loader = self.loader_from_heap_evacuable(temp_v!(2));
|
||||
|
||||
let add_clause = || {
|
||||
let term = loader.read_term_from_heap(temp_v!(1));
|
||||
let term = loader.copy_term_from_heap(value);
|
||||
|
||||
loader.incremental_compile_clause(
|
||||
(atom!("term_expansion"), 2),
|
||||
@@ -1653,6 +1597,7 @@ impl Machine {
|
||||
.machine_st
|
||||
.store(self.machine_st.deref(self.machine_st.registers[1])));
|
||||
|
||||
let value = self.machine_st.registers[2];
|
||||
let mut loader = self.loader_from_heap_evacuable(temp_v!(3));
|
||||
|
||||
let compilation_target = match target_module_name {
|
||||
@@ -1661,21 +1606,21 @@ impl Machine {
|
||||
};
|
||||
|
||||
let add_clause = || {
|
||||
let term = loader.read_term_from_heap(temp_v!(2));
|
||||
let term = loader.copy_term_from_heap(value);
|
||||
|
||||
let indexing_arg = match term.name() {
|
||||
Some(atom!(":-")) => term.first_arg().and_then(Term::first_arg),
|
||||
Some(_) => term.first_arg(),
|
||||
let indexing_arg = match term.name(term.focus) {
|
||||
Some(atom!(":-")) => term.nth_arg(term.focus, 1).and_then(|h| term.nth_arg(h, 1)),
|
||||
Some(_) => term.nth_arg(term.focus, 1),
|
||||
None => None,
|
||||
};
|
||||
|
||||
if let Some(indexing_term) = indexing_arg {
|
||||
if let Some(indexing_name) = indexing_term.name() {
|
||||
if let Some(indexing_term_loc) = indexing_arg {
|
||||
if let Some(indexing_name) = term.name(indexing_term_loc) {
|
||||
loader
|
||||
.wam_prelude
|
||||
.indices
|
||||
.goal_expansion_indices
|
||||
.insert((indexing_name, indexing_term.arity()));
|
||||
.insert((indexing_name, term.arity(indexing_term_loc)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1981,30 +1926,24 @@ impl Machine {
|
||||
};
|
||||
|
||||
let stub_gen = || functor_stub(key.0, key.1);
|
||||
let assert_clause = self.machine_st.registers[2];
|
||||
let (name, arity) = {
|
||||
let term = FocusedHeapRefMut::from_cell(&mut self.machine_st.heap, assert_clause);
|
||||
(ClauseInfo::name(&term), ClauseInfo::arity(&term))
|
||||
};
|
||||
|
||||
let head = self.deref_register(2);
|
||||
|
||||
if head.is_var() {
|
||||
let err = self.machine_st.instantiation_error();
|
||||
return Err(self.machine_st.error_form(err, stub_gen()));
|
||||
}
|
||||
|
||||
let mut compile_assert = || {
|
||||
let mut compile_assert = |assert_clause, name, arity| {
|
||||
let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> =
|
||||
Loader::new(self, LiveTermStream::new(ListingSource::User));
|
||||
|
||||
loader.payload.compilation_target = compilation_target;
|
||||
|
||||
let head =
|
||||
LiveLoadAndMachineState::machine_st(&mut loader.payload).read_term_from_heap(head);
|
||||
|
||||
let name = if let Some(name) = head.name() {
|
||||
let name = if let Some(name) = name {
|
||||
name
|
||||
} else {
|
||||
return Err(SessionError::from(CompilationError::InvalidRuleHead));
|
||||
};
|
||||
|
||||
let arity = head.arity();
|
||||
let is_builtin = loader.wam_prelude.indices.builtin_property((name, arity));
|
||||
|
||||
let is_dynamic_predicate = loader
|
||||
@@ -2036,16 +1975,9 @@ impl Machine {
|
||||
return LiveLoadAndMachineState::evacuate(loader);
|
||||
}
|
||||
|
||||
let body = loader.read_term_from_heap(temp_v!(3));
|
||||
|
||||
let asserted_clause = Term::Clause(
|
||||
Cell::default(),
|
||||
atom!(":-"),
|
||||
vec![head.clone(), body.clone()],
|
||||
);
|
||||
|
||||
// if a new predicate was just created, make it dynamic.
|
||||
loader.add_dynamic_predicate(compilation_target, name, arity)?;
|
||||
let asserted_clause = loader.copy_term_from_heap(assert_clause);
|
||||
|
||||
loader.incremental_compile_clause(
|
||||
(name, arity),
|
||||
@@ -2055,20 +1987,22 @@ impl Machine {
|
||||
append_or_prepend,
|
||||
)?;
|
||||
|
||||
let clause_clause_term = loader.clause_clause(assert_clause)?;
|
||||
|
||||
// the global clock is incremented after each assertion.
|
||||
LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1;
|
||||
|
||||
loader.compile_clause_clauses(
|
||||
(name, arity),
|
||||
compilation_target,
|
||||
std::iter::once((head, body)),
|
||||
vec![clause_clause_term],
|
||||
append_or_prepend,
|
||||
)?;
|
||||
|
||||
LiveLoadAndMachineState::evacuate(loader)
|
||||
};
|
||||
|
||||
match compile_assert() {
|
||||
match compile_assert(assert_clause, name, arity) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(SessionError::CompilationError(
|
||||
CompilationError::InvalidRuleHead | CompilationError::InadmissibleFact,
|
||||
@@ -2474,9 +2408,12 @@ impl<'a> Loader<'a, LiveLoadAndMachineState<'a>> {
|
||||
self.payload.predicates.compilation_target = compilation_target;
|
||||
}
|
||||
|
||||
let term = self.read_term_from_heap(term_reg);
|
||||
let machine_st = LiveLoadAndMachineState::machine_st(&mut self.payload);
|
||||
let value = machine_st[term_reg];
|
||||
|
||||
self.add_clause_clause_if_dynamic(&term)?;
|
||||
self.add_clause_clause_if_dynamic(value)?;
|
||||
|
||||
let term = self.copy_term_from_heap(value);
|
||||
self.payload.term_stream.term_queue.push_back(term);
|
||||
|
||||
self.load()
|
||||
|
||||
@@ -24,7 +24,7 @@ enum ErrorProvenance {
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct MachineError {
|
||||
stub: MachineStub,
|
||||
location: Option<(usize, usize)>, // line_num, col_num
|
||||
location: Option<ParserErrorSrc>,
|
||||
from: ErrorProvenance,
|
||||
}
|
||||
|
||||
@@ -649,7 +649,7 @@ impl MachineState {
|
||||
stub[1] = err.stub[0];
|
||||
}
|
||||
|
||||
if let Some((line_num, _)) = location {
|
||||
if let Some(ParserErrorSrc { line_num, .. }) = location {
|
||||
stub.push(atom_as_cell!(atom!(":"), 2));
|
||||
stub.push(str_loc_as_cell!(h + 6 + stub_addition_len));
|
||||
stub.push(integer_as_cell!(Number::arena_from(
|
||||
@@ -741,9 +741,9 @@ impl From<ParserError> for CompilationError {
|
||||
}
|
||||
|
||||
impl CompilationError {
|
||||
pub(crate) fn line_and_col_num(&self) -> Option<(usize, usize)> {
|
||||
pub(crate) fn line_and_col_num(&self) -> Option<ParserErrorSrc> {
|
||||
match self {
|
||||
CompilationError::ParserError(err) => err.line_and_col_num(),
|
||||
CompilationError::ParserError(err) => Some(err.err_src()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -1044,13 +1044,6 @@ pub enum SessionError {
|
||||
PredicateNotMultifileOrDiscontiguous(CompilationTarget, PredicateKey),
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for SessionError {
|
||||
#[inline]
|
||||
fn from(err: std::io::Error) -> SessionError {
|
||||
SessionError::from(ParserError::from(err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ParserError> for SessionError {
|
||||
#[inline]
|
||||
fn from(err: ParserError) -> Self {
|
||||
|
||||
@@ -21,6 +21,8 @@ use std::collections::BTreeSet;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::types::*;
|
||||
// #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
// pub(crate) struct OrderedOpDirKey(pub(crate) Atom, pub(crate) Fixity);
|
||||
|
||||
// 7.2
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
@@ -212,30 +214,6 @@ impl CodeIndex {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum VarKey {
|
||||
AnonVar(usize),
|
||||
VarPtr(VarPtr),
|
||||
}
|
||||
|
||||
impl VarKey {
|
||||
#[allow(clippy::inherent_to_string)]
|
||||
#[inline]
|
||||
pub(crate) fn to_string(&self) -> String {
|
||||
match self {
|
||||
VarKey::AnonVar(h) => format!("_{}", h),
|
||||
VarKey::VarPtr(var) => var.borrow().to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn is_anon(&self) -> bool {
|
||||
matches!(self, VarKey::AnonVar(_))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type HeapVarDict = IndexMap<VarKey, HeapCellValue, FxBuildHasher>;
|
||||
|
||||
pub(crate) type GlobalVarDir = IndexMap<Atom, (Ball, Option<HeapCellValue>), FxBuildHasher>;
|
||||
|
||||
pub(crate) type StreamAliasDir = IndexMap<Atom, Stream, FxBuildHasher>;
|
||||
@@ -292,11 +270,9 @@ impl IndexStore {
|
||||
_ => self
|
||||
.get_meta_predicate_spec(key.0, key.1, &compilation_target)
|
||||
.map(|meta_specs| {
|
||||
meta_specs.iter().find(|meta_spec| {
|
||||
matches!(
|
||||
meta_spec,
|
||||
MetaSpec::Colon | MetaSpec::RequiresExpansionWithArgument(_)
|
||||
)
|
||||
meta_specs.iter().find(|meta_spec| match meta_spec {
|
||||
MetaSpec::Colon | MetaSpec::RequiresExpansionWithArgument(_) => true,
|
||||
_ => false,
|
||||
})
|
||||
})
|
||||
.map(|meta_spec_opt| meta_spec_opt.is_some())
|
||||
|
||||
@@ -71,7 +71,7 @@ pub struct MachineState {
|
||||
pub(super) e: usize,
|
||||
pub(super) num_of_args: usize,
|
||||
pub(super) cp: usize,
|
||||
pub(super) attr_var_init: AttrVarInitializer,
|
||||
pub(crate) attr_var_init: AttrVarInitializer,
|
||||
pub(super) fail: bool,
|
||||
pub heap: Heap,
|
||||
pub(super) mode: MachineMode,
|
||||
@@ -200,20 +200,21 @@ pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixn
|
||||
)
|
||||
}
|
||||
|
||||
fn push_var_eq_functors<'a>(
|
||||
fn push_var_eq_functors(
|
||||
heap: &mut Heap,
|
||||
iter: impl Iterator<Item = (&'a VarKey, &'a HeapCellValue)>,
|
||||
iter: impl Iterator<Item = (usize, VarPtr)>, // (&'a VarPtr, &'a HeapCellValue)>,
|
||||
atom_tbl: &AtomTable,
|
||||
) -> Vec<HeapCellValue> {
|
||||
let mut list_of_var_eqs = vec![];
|
||||
|
||||
for (var, binding) in iter {
|
||||
let var_atom = AtomTable::build_with(atom_tbl, &var.to_string());
|
||||
for (var_loc, var_ptr) in iter { // (var, binding) in iter {
|
||||
let var_atom = AtomTable::build_with(atom_tbl, &*var_ptr.borrow().to_string());
|
||||
let h = heap.len();
|
||||
let binding = heap[var_loc];
|
||||
|
||||
heap.push(atom_as_cell!(atom!("="), 2));
|
||||
heap.push(atom_as_cell!(var_atom));
|
||||
heap.push(*binding);
|
||||
heap.push(binding);
|
||||
|
||||
list_of_var_eqs.push(str_loc_as_cell!(h));
|
||||
}
|
||||
@@ -221,6 +222,16 @@ fn push_var_eq_functors<'a>(
|
||||
list_of_var_eqs
|
||||
}
|
||||
|
||||
|
||||
pub(crate) fn copy_and_align_iter<Iter: Iterator<Item = HeapCellValue>>(
|
||||
iter: Iter,
|
||||
boundary: i64,
|
||||
h: i64,
|
||||
) -> impl Iterator<Item = HeapCellValue> {
|
||||
let diff = boundary - h;
|
||||
iter.map(move |heap_value| heap_value - diff)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Ball {
|
||||
pub(super) boundary: usize,
|
||||
@@ -241,13 +252,7 @@ impl Ball {
|
||||
}
|
||||
|
||||
pub(super) fn copy_and_align(&self, h: usize) -> Heap {
|
||||
let diff = self.boundary as i64 - h as i64;
|
||||
|
||||
self.stub
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|heap_value| heap_value - diff)
|
||||
.collect()
|
||||
copy_and_align_iter(self.stub.iter().cloned(), self.boundary as i64, h as i64).collect()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,7 +316,7 @@ impl<'a> CopierTarget for CopyTerm<'a> {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct CopyBallTerm<'a> {
|
||||
pub(crate) struct CopyBallTerm<'a> {
|
||||
attr_var_queue: &'a mut Vec<usize>,
|
||||
stack: &'a mut Stack,
|
||||
heap: &'a mut Heap,
|
||||
@@ -320,7 +325,7 @@ pub(super) struct CopyBallTerm<'a> {
|
||||
}
|
||||
|
||||
impl<'a> CopyBallTerm<'a> {
|
||||
pub(super) fn new(
|
||||
pub(crate) fn new(
|
||||
attr_var_queue: &'a mut Vec<usize>,
|
||||
stack: &'a mut Stack,
|
||||
heap: &'a mut Heap,
|
||||
@@ -536,18 +541,19 @@ impl MachineState {
|
||||
|
||||
pub fn write_read_term_options(
|
||||
&mut self,
|
||||
mut var_list: Vec<(VarKey, HeapCellValue, usize)>,
|
||||
mut var_list: Vec<(VarPtr, HeapCellValue, usize)>,
|
||||
singleton_var_list: Vec<HeapCellValue>,
|
||||
) -> CallResult {
|
||||
var_list.sort_by(|(_, _, idx_1), (_, _, idx_2)| idx_1.cmp(idx_2));
|
||||
|
||||
let list_of_var_eqs = push_var_eq_functors(
|
||||
&mut self.heap,
|
||||
var_list.iter().filter_map(|(var_name, var, _)| {
|
||||
if var_name.is_anon() {
|
||||
var_list.iter().filter_map(|(var_ptr, var, _)| {
|
||||
if var_ptr.is_anon() {
|
||||
None
|
||||
} else {
|
||||
Some((var_name, var))
|
||||
let var_loc = var.get_value() as usize;
|
||||
Some((var_loc, var_ptr.clone()))
|
||||
}
|
||||
}),
|
||||
&self.atom_tbl,
|
||||
@@ -586,13 +592,13 @@ impl MachineState {
|
||||
Ok(unify_fn!(*self, var_names_offset, var_names_addr))
|
||||
}
|
||||
|
||||
pub fn read_term_body(&mut self, mut term_write_result: TermWriteResult) -> CallResult {
|
||||
let heap_loc = read_heap_cell!(self.heap[term_write_result.heap_loc],
|
||||
pub fn read_term_body(&mut self, term: TermWriteResult) -> CallResult {
|
||||
let heap_loc = read_heap_cell!(self.heap[term.heap_loc],
|
||||
(HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
|
||||
pstr_loc_as_cell!(term_write_result.heap_loc)
|
||||
pstr_loc_as_cell!(term.heap_loc)
|
||||
}
|
||||
_ => {
|
||||
heap_loc_as_cell!(term_write_result.heap_loc)
|
||||
heap_loc_as_cell!(term.heap_loc)
|
||||
}
|
||||
);
|
||||
|
||||
@@ -602,15 +608,15 @@ impl MachineState {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/*
|
||||
for var in term_write_result.var_dict.values_mut() {
|
||||
*var = heap_bound_deref(&self.heap, *var);
|
||||
}
|
||||
*/
|
||||
|
||||
let mut singleton_var_set: IndexMap<Ref, bool> = IndexMap::new();
|
||||
|
||||
for cell in
|
||||
stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, heap_loc)
|
||||
{
|
||||
for cell in eager_stackful_preorder_iter(&mut self.heap, heap_loc) {
|
||||
let cell = unmark_cell_bits!(cell);
|
||||
|
||||
if let Some(var) = cell.as_var() {
|
||||
@@ -624,34 +630,42 @@ impl MachineState {
|
||||
|
||||
let singleton_var_list = push_var_eq_functors(
|
||||
&mut self.heap,
|
||||
term_write_result
|
||||
.var_dict
|
||||
term.var_locs
|
||||
.iter()
|
||||
.filter(|(var_name, binding)| {
|
||||
if var_name.is_anon() {
|
||||
return false;
|
||||
.filter_map(|(var_loc, var_ptrs)| {
|
||||
let var_ptr = var_ptrs.front().unwrap();
|
||||
|
||||
if var_ptr.is_anon() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(r) = binding.as_var() {
|
||||
*singleton_var_set.get(&r).unwrap_or(&false)
|
||||
// add h to offset the term variable into its heap location.
|
||||
let r = Ref::heap_cell(var_loc);
|
||||
|
||||
if singleton_var_set.get(&r).cloned().unwrap_or(false) {
|
||||
Some((var_loc, var_ptr.clone()))
|
||||
} else {
|
||||
false
|
||||
None
|
||||
}
|
||||
}),
|
||||
&self.atom_tbl,
|
||||
);
|
||||
|
||||
/*
|
||||
for var in term_write_result.var_dict.values_mut() {
|
||||
*var = heap_bound_deref(&self.heap, *var);
|
||||
}
|
||||
*/
|
||||
|
||||
let mut var_list = Vec::with_capacity(singleton_var_set.len());
|
||||
|
||||
for (var_name, addr) in term_write_result.var_dict {
|
||||
if let Some(var) = addr.as_var() {
|
||||
if let Some(idx) = singleton_var_set.get_index_of(&var) {
|
||||
var_list.push((var_name, addr, idx));
|
||||
}
|
||||
for (var_loc, var_ptrs) in term.var_locs.iter() {
|
||||
let var_ptr = var_ptrs.front().unwrap().clone();
|
||||
let r = Ref::heap_cell(var_loc);
|
||||
let cell = self.heap[var_loc];
|
||||
|
||||
if let Some(idx) = singleton_var_set.get_index_of(&r) {
|
||||
var_list.push((var_ptr, cell, idx));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -734,8 +748,8 @@ impl MachineState {
|
||||
}
|
||||
|
||||
loop {
|
||||
match self.read(stream, &indices.op_dir) {
|
||||
Ok(term_write_result) => return self.read_term_body(term_write_result),
|
||||
match self.read_to_heap(stream, &indices.op_dir) {
|
||||
Ok(term) => return self.read_term_body(term),
|
||||
Err(err) => {
|
||||
match &err {
|
||||
CompilationError::ParserError(e) if e.is_unexpected_eof() => {
|
||||
@@ -881,13 +895,16 @@ impl MachineState {
|
||||
}
|
||||
);
|
||||
|
||||
let h = self.heap.len();
|
||||
self.heap.push(term_to_be_printed);
|
||||
|
||||
let mut printer = HCPrinter::new(
|
||||
&mut self.heap,
|
||||
Arc::clone(&self.atom_tbl),
|
||||
&mut self.stack,
|
||||
op_dir,
|
||||
PrinterOutputter::new(),
|
||||
term_to_be_printed,
|
||||
h,
|
||||
);
|
||||
|
||||
printer.ignore_ops = ignore_ops;
|
||||
|
||||
@@ -39,7 +39,7 @@ impl MockWAM {
|
||||
&mut self,
|
||||
input_stream: Stream,
|
||||
) -> Result<TermWriteResult, CompilationError> {
|
||||
self.machine_st.read(input_stream, &self.op_dir)
|
||||
self.machine_st.read_to_heap(input_stream, &self.op_dir)
|
||||
}
|
||||
|
||||
pub fn parse_and_write_parsed_term_to_heap(
|
||||
@@ -58,23 +58,24 @@ impl MockWAM {
|
||||
|
||||
print_heap_terms(self.machine_st.heap.iter(), term_write_result.heap_loc);
|
||||
|
||||
let var_names = term_write_result
|
||||
.var_locs
|
||||
.iter()
|
||||
.map(|(var_loc, var_ptrs)| {
|
||||
(self.machine_st.heap[var_loc], var_ptrs.front().unwrap().clone())
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut printer = HCPrinter::new(
|
||||
&mut self.machine_st.heap,
|
||||
Arc::clone(&self.machine_st.atom_tbl),
|
||||
&mut self.machine_st.stack,
|
||||
&self.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
heap_loc_as_cell!(term_write_result.heap_loc),
|
||||
term_write_result.heap_loc,
|
||||
);
|
||||
|
||||
printer.var_names = term_write_result
|
||||
.var_dict
|
||||
.into_iter()
|
||||
.map(|(var, cell)| match var {
|
||||
VarKey::VarPtr(var) => (cell, var.clone()),
|
||||
VarKey::AnonVar(_) => (cell, VarPtr::from(var.to_string())),
|
||||
})
|
||||
.collect();
|
||||
printer.var_names = var_names;
|
||||
|
||||
Ok(printer.print().result())
|
||||
}
|
||||
@@ -217,7 +218,7 @@ pub(crate) fn write_parsed_term_to_heap(
|
||||
input_stream: Stream,
|
||||
op_dir: &OpDir,
|
||||
) -> Result<TermWriteResult, CompilationError> {
|
||||
machine_st.read(input_stream, op_dir)
|
||||
machine_st.read_to_heap(input_stream, op_dir)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -287,14 +288,15 @@ mod tests {
|
||||
wam.heap.clear();
|
||||
|
||||
{
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
|
||||
let term_write_result_1 =
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
|
||||
|
||||
let term_write_result_2 =
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(b,b).", &op_dir).unwrap();
|
||||
|
||||
unify!(
|
||||
wam,
|
||||
str_loc_as_cell!(1),
|
||||
heap_loc_as_cell!(term_write_result_1.heap_loc),
|
||||
heap_loc_as_cell!(term_write_result_2.heap_loc)
|
||||
);
|
||||
|
||||
@@ -307,14 +309,15 @@ mod tests {
|
||||
wam.heap.clear();
|
||||
|
||||
{
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
|
||||
let term_write_result_1 =
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
|
||||
|
||||
let term_write_result_2 =
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap();
|
||||
|
||||
unify!(
|
||||
wam,
|
||||
heap_loc_as_cell!(0),
|
||||
heap_loc_as_cell!(term_write_result_1.heap_loc),
|
||||
heap_loc_as_cell!(term_write_result_2.heap_loc)
|
||||
);
|
||||
|
||||
@@ -327,14 +330,15 @@ mod tests {
|
||||
wam.heap.clear();
|
||||
|
||||
{
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
|
||||
let term_write_result_1 =
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
|
||||
|
||||
let term_write_result_2 =
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap();
|
||||
|
||||
unify!(
|
||||
wam,
|
||||
heap_loc_as_cell!(0),
|
||||
heap_loc_as_cell!(term_write_result_1.heap_loc),
|
||||
heap_loc_as_cell!(term_write_result_2.heap_loc)
|
||||
);
|
||||
|
||||
@@ -347,14 +351,15 @@ mod tests {
|
||||
wam.heap.clear();
|
||||
|
||||
{
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
|
||||
let term_write_result_1 =
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
|
||||
|
||||
let term_write_result_2 =
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),A).", &op_dir).unwrap();
|
||||
|
||||
unify!(
|
||||
wam,
|
||||
heap_loc_as_cell!(0),
|
||||
heap_loc_as_cell!(term_write_result_1.heap_loc),
|
||||
heap_loc_as_cell!(term_write_result_2.heap_loc)
|
||||
);
|
||||
|
||||
@@ -367,7 +372,8 @@ mod tests {
|
||||
wam.heap.clear();
|
||||
|
||||
{
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
|
||||
let term_write_result_1 =
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
|
||||
|
||||
let term_write_result_2 =
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap();
|
||||
@@ -376,7 +382,7 @@ mod tests {
|
||||
|
||||
unify!(
|
||||
wam,
|
||||
heap_loc_as_cell!(0),
|
||||
heap_loc_as_cell!(term_write_result_1.heap_loc),
|
||||
heap_loc_as_cell!(term_write_result_2.heap_loc)
|
||||
);
|
||||
|
||||
@@ -459,21 +465,8 @@ mod tests {
|
||||
wam.heap.push(heap_loc_as_cell!(0));
|
||||
|
||||
unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
|
||||
|
||||
assert!(!wam.fail);
|
||||
all_cells_unmarked(&wam.heap);
|
||||
wam.heap.clear();
|
||||
|
||||
{
|
||||
let term_write_result_1 =
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "X = g(X,y).", &op_dir).unwrap();
|
||||
|
||||
print_heap_terms(wam.heap.iter(), term_write_result_1.heap_loc);
|
||||
|
||||
unify!(wam, heap_loc_as_cell!(2), str_loc_as_cell!(4));
|
||||
|
||||
assert_eq!(wam.heap[2], str_loc_as_cell!(4));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -496,8 +489,8 @@ mod tests {
|
||||
|
||||
unify_with_occurs_check!(
|
||||
wam,
|
||||
str_loc_as_cell!(0),
|
||||
str_loc_as_cell!(term_write_result_2.heap_loc)
|
||||
heap_loc_as_cell!(0),
|
||||
heap_loc_as_cell!(term_write_result_2.heap_loc)
|
||||
);
|
||||
|
||||
assert!(wam.fail);
|
||||
|
||||
@@ -5,11 +5,14 @@ use crate::instructions::*;
|
||||
use crate::machine::disjuncts::*;
|
||||
use crate::machine::loader::*;
|
||||
use crate::machine::machine_errors::*;
|
||||
use crate::machine::CodeIndex;
|
||||
use crate::parser::ast::*;
|
||||
use crate::types::*;
|
||||
|
||||
use fxhash::FxBuildHasher;
|
||||
use indexmap::IndexMap;
|
||||
use indexmap::IndexSet;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::convert::TryFrom;
|
||||
pub(crate) fn to_op_decl(prec: u16, spec: OpDeclSpec, name: Atom) -> OpDecl {
|
||||
OpDecl::new(OpDesc::build_with(prec, spec), name)
|
||||
@@ -21,44 +24,30 @@ pub(crate) fn to_op_decl_spec(spec: Atom) -> Result<OpDeclSpec, CompilationError
|
||||
})
|
||||
}
|
||||
|
||||
fn setup_op_decl(mut terms: Vec<Term>, atom_tbl: &AtomTable) -> Result<OpDecl, CompilationError> {
|
||||
// should allow non-partial lists?
|
||||
let name = match terms.pop().unwrap() {
|
||||
Term::Literal(_, Literal::Atom(name)) => name,
|
||||
Term::Literal(_, Literal::Char(c)) => AtomTable::build_with(atom_tbl, &c.to_string()),
|
||||
other => {
|
||||
return Err(CompilationError::InvalidDirective(
|
||||
DirectiveError::InvalidOpDeclNameType(other),
|
||||
));
|
||||
}
|
||||
fn setup_op_decl(term: &FocusedHeapRefMut) -> Result<OpDecl, CompilationError> {
|
||||
let (focus, _cell) = subterm_index(term.heap, term.focus);
|
||||
|
||||
let name = match term.name(focus+3) {
|
||||
Some(name) => name,
|
||||
None => return Err(CompilationError::InconsistentEntry),
|
||||
};
|
||||
|
||||
let spec = match terms.pop().unwrap() {
|
||||
Term::Literal(_, Literal::Atom(name)) => name,
|
||||
other => {
|
||||
return Err(CompilationError::InvalidDirective(
|
||||
DirectiveError::InvalidOpDeclSpecDomain(other),
|
||||
))
|
||||
}
|
||||
let spec = match term.name(focus+2) {
|
||||
Some(name) => name,
|
||||
None => return Err(CompilationError::InconsistentEntry),
|
||||
};
|
||||
|
||||
let spec = to_op_decl_spec(spec)?;
|
||||
|
||||
let prec = match terms.pop().unwrap() {
|
||||
Term::Literal(_, Literal::Fixnum(bi)) => match u16::try_from(bi.get_num()) {
|
||||
Ok(n) if n <= 1200 => n,
|
||||
_ => {
|
||||
return Err(CompilationError::InvalidDirective(
|
||||
DirectiveError::InvalidOpDeclPrecDomain(bi),
|
||||
));
|
||||
let prec = read_heap_cell!(term.deref_loc(focus+1),
|
||||
(HeapCellValueTag::Fixnum, n) => {
|
||||
match u16::try_from(n.get_num()) {
|
||||
Ok(n) if n <= 1200 => n,
|
||||
_ => return Err(CompilationError::InconsistentEntry),
|
||||
}
|
||||
},
|
||||
other => {
|
||||
return Err(CompilationError::InvalidDirective(
|
||||
DirectiveError::InvalidOpDeclPrecType(other),
|
||||
));
|
||||
}
|
||||
};
|
||||
_ => {
|
||||
return Err(CompilationError::InconsistentEntry);
|
||||
}
|
||||
);
|
||||
|
||||
if name == "[]" || name == "{}" {
|
||||
return Err(CompilationError::InvalidDirective(
|
||||
@@ -81,140 +70,166 @@ fn setup_op_decl(mut terms: Vec<Term>, atom_tbl: &AtomTable) -> Result<OpDecl, C
|
||||
Ok(to_op_decl(prec, spec, name))
|
||||
}
|
||||
|
||||
fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, CompilationError> {
|
||||
match term {
|
||||
Term::Clause(_, slash, ref mut terms)
|
||||
if (*slash == atom!("/") || *slash == atom!("//")) && terms.len() == 2 =>
|
||||
{
|
||||
let arity = terms.pop().unwrap();
|
||||
let name = terms.pop().unwrap();
|
||||
fn setup_predicate_indicator(term: &FocusedHeapRefMut) -> Result<PredicateKey, CompilationError> {
|
||||
let name_opt = term.name(term.focus);
|
||||
let arity = term.arity(term.focus);
|
||||
|
||||
let arity = match arity {
|
||||
Term::Literal(_, Literal::Integer(n)) => (&*n).try_into().ok(),
|
||||
Term::Literal(_, Literal::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
|
||||
_ => None,
|
||||
}
|
||||
.ok_or(CompilationError::InvalidModuleExport)?;
|
||||
if let (Some(atom!("/") | atom!("//")), 2) = (name_opt, arity) {
|
||||
let arity_loc = term.nth_arg(term.focus, 2).unwrap();
|
||||
|
||||
let name = match name {
|
||||
Term::Literal(_, Literal::Atom(name)) => Some(name),
|
||||
_ => None,
|
||||
}
|
||||
.ok_or(CompilationError::InvalidModuleExport)?;
|
||||
|
||||
if *slash == atom!("/") {
|
||||
Ok((name, arity))
|
||||
} else {
|
||||
Ok((name, arity + 2))
|
||||
}
|
||||
let arity = match Number::try_from(term.deref_loc(arity_loc)) {
|
||||
Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
|
||||
Ok(Number::Integer(n)) => (&*n).try_into().ok(),
|
||||
_ => None,
|
||||
}
|
||||
_ => Err(CompilationError::InvalidModuleExport),
|
||||
.ok_or(CompilationError::InvalidModuleExport)?;
|
||||
|
||||
let name_loc = term.nth_arg(term.focus, 1).unwrap();
|
||||
let name = term
|
||||
.name(name_loc)
|
||||
.ok_or(CompilationError::InvalidModuleExport)?;
|
||||
|
||||
if name_opt == Some(atom!("/")) {
|
||||
Ok((name, arity))
|
||||
} else {
|
||||
Ok((name, arity + 2))
|
||||
}
|
||||
} else {
|
||||
Err(CompilationError::InvalidModuleExport)
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_module_export(
|
||||
mut term: Term,
|
||||
atom_tbl: &AtomTable,
|
||||
) -> Result<ModuleExport, CompilationError> {
|
||||
setup_predicate_indicator(&mut term)
|
||||
fn setup_module_export(term: &FocusedHeapRefMut) -> Result<ModuleExport, CompilationError> {
|
||||
setup_predicate_indicator(term)
|
||||
.map(ModuleExport::PredicateKey)
|
||||
.or_else(|_| {
|
||||
if let Term::Clause(_, name, terms) = term {
|
||||
if terms.len() == 3 && name == atom!("op") {
|
||||
Ok(ModuleExport::OpDecl(setup_op_decl(terms, atom_tbl)?))
|
||||
} else {
|
||||
Err(CompilationError::InvalidModuleDecl)
|
||||
}
|
||||
let name_opt = term.name(term.focus);
|
||||
let arity = term.arity(term.focus);
|
||||
|
||||
if let (Some(atom!("op")), 3) = (name_opt, arity) {
|
||||
Ok(ModuleExport::OpDecl(setup_op_decl(term)?))
|
||||
} else {
|
||||
Err(CompilationError::InvalidModuleDecl)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/* TODO: should be unnecessary now.
|
||||
|
||||
pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term {
|
||||
let head_term = Term::Clause(Cell::default(), atom!(""), vars.to_vec());
|
||||
let rule = vec![head_term, body_term];
|
||||
|
||||
Term::Clause(Cell::default(), atom!(":-"), rule)
|
||||
}
|
||||
*/
|
||||
|
||||
pub(super) fn setup_module_export_list(
|
||||
mut export_list: Term,
|
||||
atom_tbl: &AtomTable,
|
||||
term: FocusedHeapRefMut,
|
||||
) -> Result<Vec<ModuleExport>, CompilationError> {
|
||||
let mut exports = vec![];
|
||||
let mut focus = term.focus;
|
||||
|
||||
while let Term::Cons(_, t1, t2) = export_list {
|
||||
let module_export = setup_module_export(*t1, atom_tbl)?;
|
||||
loop {
|
||||
read_heap_cell!(term.heap[focus],
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
if h == focus {
|
||||
break;
|
||||
} else {
|
||||
focus = h;
|
||||
}
|
||||
}
|
||||
(HeapCellValueTag::Lis, l) => {
|
||||
let term = FocusedHeapRefMut {
|
||||
heap: term.heap,
|
||||
focus: l,
|
||||
};
|
||||
exports.push(setup_module_export(&term)?);
|
||||
|
||||
exports.push(module_export);
|
||||
export_list = *t2;
|
||||
focus = l + 1;
|
||||
}
|
||||
(HeapCellValueTag::Atom, (name, _arity)) => {
|
||||
if name == atom!("[]") {
|
||||
return Ok(exports);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
break;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list {
|
||||
Ok(exports)
|
||||
} else {
|
||||
Err(CompilationError::InvalidModuleDecl)
|
||||
}
|
||||
Err(CompilationError::InvalidModuleDecl)
|
||||
}
|
||||
|
||||
fn setup_module_decl(
|
||||
mut terms: Vec<Term>,
|
||||
atom_tbl: &AtomTable,
|
||||
) -> Result<ModuleDecl, CompilationError> {
|
||||
let export_list = terms.pop().unwrap();
|
||||
let name = terms.pop().unwrap();
|
||||
|
||||
let name = match name {
|
||||
Term::Literal(_, Literal::Atom(name)) => Some(name),
|
||||
_ => None,
|
||||
}
|
||||
.ok_or(CompilationError::InvalidModuleDecl)?;
|
||||
|
||||
let exports = setup_module_export_list(export_list, atom_tbl)?;
|
||||
fn setup_module_decl(term: FocusedHeapRefMut) -> Result<ModuleDecl, CompilationError> {
|
||||
let name = term
|
||||
.name(term.focus + 1)
|
||||
.ok_or(CompilationError::InvalidModuleDecl)?;
|
||||
let export_list = FocusedHeapRefMut {
|
||||
heap: term.heap,
|
||||
focus: term.focus + 2,
|
||||
};
|
||||
let exports = setup_module_export_list(export_list)?;
|
||||
|
||||
Ok(ModuleDecl { name, exports })
|
||||
}
|
||||
|
||||
fn setup_use_module_decl(mut terms: Vec<Term>) -> Result<ModuleSource, CompilationError> {
|
||||
match terms.pop().unwrap() {
|
||||
Term::Clause(_, name, mut terms) if name == atom!("library") && terms.len() == 1 => {
|
||||
match terms.pop().unwrap() {
|
||||
Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)),
|
||||
_ => Err(CompilationError::InvalidModuleDecl),
|
||||
fn setup_use_module_decl(term: &FocusedHeapRefMut) -> Result<ModuleSource, CompilationError> {
|
||||
read_heap_cell!(term.deref_loc(term.focus+1),
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
let (name, arity) = cell_as_atom_cell!(term.heap[s]).get_name_and_arity();
|
||||
|
||||
if (name, arity) == (atom!("library"), 1) {
|
||||
read_heap_cell!(term.deref_loc(s+1),
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
if arity == 0 {
|
||||
return Ok(ModuleSource::Library(name));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return Err(CompilationError::InvalidModuleDecl);
|
||||
}
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
if arity == 0 {
|
||||
Ok(ModuleSource::File(name))
|
||||
} else {
|
||||
Err(CompilationError::InvalidUseModuleDecl)
|
||||
}
|
||||
}
|
||||
Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)),
|
||||
_ => Err(CompilationError::InvalidUseModuleDecl),
|
||||
}
|
||||
_ => {
|
||||
Err(CompilationError::InvalidUseModuleDecl)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
type UseModuleExport = (ModuleSource, IndexSet<ModuleExport>);
|
||||
|
||||
fn setup_qualified_import(
|
||||
mut terms: Vec<Term>,
|
||||
atom_tbl: &AtomTable,
|
||||
) -> Result<UseModuleExport, CompilationError> {
|
||||
let mut export_list = terms.pop().unwrap();
|
||||
let module_src = match terms.pop().unwrap() {
|
||||
Term::Clause(_, name, mut terms) if name == atom!("library") && terms.len() == 1 => {
|
||||
match terms.pop().unwrap() {
|
||||
Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)),
|
||||
_ => Err(CompilationError::InvalidModuleDecl),
|
||||
}
|
||||
}
|
||||
Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)),
|
||||
_ => Err(CompilationError::InvalidUseModuleDecl),
|
||||
}?;
|
||||
|
||||
fn setup_qualified_import(term: FocusedHeapRefMut) -> Result<UseModuleExport, CompilationError> {
|
||||
let module_src = setup_use_module_decl(&term)?;
|
||||
let mut exports = IndexSet::new();
|
||||
|
||||
while let Term::Cons(_, t1, t2) = export_list {
|
||||
exports.insert(setup_module_export(*t1, atom_tbl)?);
|
||||
export_list = *t2;
|
||||
let mut focus = term.focus + 2;
|
||||
|
||||
while let HeapCellValueTag::Lis = term.heap[focus].get_tag() {
|
||||
focus = term.heap[focus].get_value() as usize;
|
||||
|
||||
let term = FocusedHeapRefMut {
|
||||
heap: term.heap,
|
||||
focus,
|
||||
};
|
||||
exports.insert(setup_module_export(&term)?);
|
||||
|
||||
focus = focus + 1;
|
||||
}
|
||||
|
||||
if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list {
|
||||
if term.heap[focus] == empty_list_as_cell!() {
|
||||
Ok((module_src, exports))
|
||||
} else {
|
||||
Err(CompilationError::InvalidModuleDecl)
|
||||
@@ -261,18 +276,20 @@ fn setup_qualified_import(
|
||||
*/
|
||||
|
||||
fn setup_meta_predicate<'a, LS: LoadState<'a>>(
|
||||
mut terms: Vec<Term>,
|
||||
term: FocusedHeapRefMut,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
) -> Result<(Atom, Atom, Vec<MetaSpec>), CompilationError> {
|
||||
fn get_name_and_meta_specs(
|
||||
name: Atom,
|
||||
terms: &mut [Term],
|
||||
) -> Result<(Atom, Vec<MetaSpec>), CompilationError> {
|
||||
fn get_meta_specs(
|
||||
term: FocusedHeapRefMut,
|
||||
arity: usize,
|
||||
) -> Result<Vec<MetaSpec>, CompilationError> {
|
||||
let mut meta_specs = vec![];
|
||||
|
||||
for meta_spec in terms.iter_mut() {
|
||||
match meta_spec {
|
||||
Term::Literal(_, Literal::Atom(meta_spec)) => {
|
||||
for meta_spec_loc in term.focus + 1..term.focus + arity + 1 {
|
||||
read_heap_cell!(term.deref_loc(meta_spec_loc),
|
||||
(HeapCellValueTag::Atom, (meta_spec, arity)) => {
|
||||
debug_assert_eq!(arity, 0);
|
||||
|
||||
let meta_spec = match meta_spec {
|
||||
atom!("+") => MetaSpec::Plus,
|
||||
atom!("-") => MetaSpec::Minus,
|
||||
@@ -283,271 +300,307 @@ fn setup_meta_predicate<'a, LS: LoadState<'a>>(
|
||||
|
||||
meta_specs.push(meta_spec);
|
||||
}
|
||||
Term::Literal(_, Literal::Fixnum(n)) => match usize::try_from(n.get_num()) {
|
||||
Ok(n) if n <= MAX_ARITY => {
|
||||
meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n));
|
||||
(HeapCellValueTag::Fixnum, n) => {
|
||||
match usize::try_from(n.get_num()) {
|
||||
Ok(n) if n <= MAX_ARITY => {
|
||||
meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n));
|
||||
}
|
||||
_ => {
|
||||
return Err(CompilationError::InvalidMetaPredicateDecl);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(CompilationError::InvalidMetaPredicateDecl);
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
return Err(CompilationError::InvalidMetaPredicateDecl);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Ok((name, meta_specs))
|
||||
Ok(meta_specs)
|
||||
}
|
||||
|
||||
match terms.pop().unwrap() {
|
||||
Term::Clause(_, name, mut terms) if name == atom!(":") && terms.len() == 2 => {
|
||||
let spec = terms.pop().unwrap();
|
||||
let module_name = terms.pop().unwrap();
|
||||
read_heap_cell!(term.deref_loc(term.focus+1),
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
let (name, arity) = cell_as_atom_cell!(term.heap[s]).get_name_and_arity();
|
||||
|
||||
match module_name {
|
||||
Term::Literal(_, Literal::Atom(module_name)) => match spec {
|
||||
Term::Clause(_, name, mut terms) => {
|
||||
let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?;
|
||||
Ok((module_name, name, meta_specs))
|
||||
}
|
||||
_ => Err(CompilationError::InvalidMetaPredicateDecl),
|
||||
},
|
||||
_ => Err(CompilationError::InvalidMetaPredicateDecl),
|
||||
match (name, arity) {
|
||||
(atom!(":"), 2) => {
|
||||
let module_name = term.heap[s+1];
|
||||
let spec = term.heap[s+2];
|
||||
|
||||
read_heap_cell!(module_name,
|
||||
(HeapCellValueTag::Atom, (module_name, arity)) => {
|
||||
if arity == 0 {
|
||||
read_heap_cell!(spec,
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
let (name, arity) = cell_as_atom_cell!(term.heap[s])
|
||||
.get_name_and_arity();
|
||||
|
||||
let term = FocusedHeapRefMut { heap: term.heap, focus: s };
|
||||
return Ok((module_name, name, get_meta_specs(term, arity)?));
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
);
|
||||
} else {
|
||||
return Err(CompilationError::InvalidMetaPredicateDecl);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
let term = FocusedHeapRefMut { heap: term.heap, focus: s };
|
||||
let module_name = loader.payload.compilation_target.module_name();
|
||||
return Ok((module_name, name, get_meta_specs(term, arity)?));
|
||||
}
|
||||
}
|
||||
|
||||
Err(CompilationError::InvalidMetaPredicateDecl)
|
||||
}
|
||||
Term::Clause(_, name, mut terms) => {
|
||||
let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?;
|
||||
Ok((
|
||||
loader.payload.compilation_target.module_name(),
|
||||
name,
|
||||
meta_specs,
|
||||
))
|
||||
_ => {
|
||||
Err(CompilationError::InvalidMetaPredicateDecl)
|
||||
}
|
||||
_ => Err(CompilationError::InvalidMetaPredicateDecl),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
|
||||
loader: &mut Loader<'a, LS>,
|
||||
mut terms: Vec<Term>,
|
||||
term: FocusedHeapRefMut,
|
||||
) -> Result<Declaration, CompilationError> {
|
||||
let term = terms.pop().unwrap();
|
||||
let mut focus = term.focus;
|
||||
|
||||
match term {
|
||||
Term::Clause(_, name, mut terms) => match (name, terms.len()) {
|
||||
(atom!("dynamic"), 1) => {
|
||||
let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
|
||||
Ok(Declaration::Dynamic(name, arity))
|
||||
}
|
||||
(atom!("module"), 2) => {
|
||||
let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl;
|
||||
Ok(Declaration::Module(setup_module_decl(terms, atom_tbl)?))
|
||||
}
|
||||
(atom!("op"), 3) => {
|
||||
let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl;
|
||||
Ok(Declaration::Op(setup_op_decl(terms, atom_tbl)?))
|
||||
}
|
||||
(atom!("non_counted_backtracking"), 1) => {
|
||||
let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
|
||||
Ok(Declaration::NonCountedBacktracking(name, arity))
|
||||
}
|
||||
(atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)),
|
||||
(atom!("use_module"), 2) => {
|
||||
let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl;
|
||||
let (name, exports) = setup_qualified_import(terms, atom_tbl)?;
|
||||
loop {
|
||||
read_heap_cell!(term.heap[focus],
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
let term = FocusedHeapRefMut { heap: term.heap, focus };
|
||||
|
||||
Ok(Declaration::UseQualifiedModule(name, exports))
|
||||
return match (name, arity) {
|
||||
(atom!("dynamic"), 1) => {
|
||||
let (name, arity) = setup_predicate_indicator(&term)?;
|
||||
Ok(Declaration::Dynamic(name, arity))
|
||||
}
|
||||
(atom!("module"), 2) => {
|
||||
Ok(Declaration::Module(setup_module_decl(term)?))
|
||||
}
|
||||
(atom!("op"), 3) => {
|
||||
Ok(Declaration::Op(setup_op_decl(&term)?))
|
||||
}
|
||||
(atom!("non_counted_backtracking"), 1) => {
|
||||
let focus = term.nth_arg(term.focus, 1).unwrap();
|
||||
let (name, arity) = setup_predicate_indicator(&FocusedHeapRefMut { heap: term.heap, focus })?;
|
||||
Ok(Declaration::NonCountedBacktracking(name, arity))
|
||||
}
|
||||
(atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(&term)?)),
|
||||
(atom!("use_module"), 2) => {
|
||||
let (name, exports) = setup_qualified_import(term)?;
|
||||
|
||||
Ok(Declaration::UseQualifiedModule(name, exports))
|
||||
}
|
||||
(atom!("meta_predicate"), 1) => {
|
||||
let (module_name, name, meta_specs) = setup_meta_predicate(term, loader)?;
|
||||
Ok(Declaration::MetaPredicate(module_name, name, meta_specs))
|
||||
}
|
||||
_ => Err(CompilationError::InvalidDirective(
|
||||
DirectiveError::InvalidDirective(name, arity)
|
||||
))
|
||||
};
|
||||
}
|
||||
(atom!("meta_predicate"), 1) => {
|
||||
let (module_name, name, meta_specs) = setup_meta_predicate(terms, loader)?;
|
||||
Ok(Declaration::MetaPredicate(module_name, name, meta_specs))
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
focus = s;
|
||||
}
|
||||
_ => Err(CompilationError::InvalidDirective(
|
||||
DirectiveError::InvalidDirective(name, terms.len()),
|
||||
)),
|
||||
},
|
||||
other => Err(CompilationError::InvalidDirective(
|
||||
DirectiveError::ExpectedDirective(other),
|
||||
)),
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
if focus != h {
|
||||
focus = h;
|
||||
} else {
|
||||
return Err(CompilationError::InvalidDirective(
|
||||
DirectiveError::ExpectedDirective(heap_loc_as_cell!(h)),
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(CompilationError::InvalidDirective(
|
||||
DirectiveError::ExpectedDirective(term.heap[focus])
|
||||
));
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
|
||||
loader: &mut Loader<'a, LS>,
|
||||
module_name: Atom,
|
||||
terms: Vec<Term>,
|
||||
arity: usize,
|
||||
term: &FocusedHeapRefMut,
|
||||
meta_specs: Vec<MetaSpec>,
|
||||
) -> Vec<Term> {
|
||||
let mut arg_terms = Vec::with_capacity(terms.len());
|
||||
) -> IndexMap<usize, CodeIndex, FxBuildHasher> {
|
||||
let mut index_ptrs = IndexMap::with_hasher(FxBuildHasher::default());
|
||||
|
||||
for (term, meta_spec) in terms.into_iter().zip(meta_specs.iter()) {
|
||||
for (subterm_loc, meta_spec) in (term.focus + 1..term.focus + arity + 1).zip(meta_specs) {
|
||||
if let MetaSpec::RequiresExpansionWithArgument(supp_args) = meta_spec {
|
||||
if let Some(name) = term.name() {
|
||||
if let Some(name) = term.name(subterm_loc) {
|
||||
if name == atom!("$call") {
|
||||
arg_terms.push(term);
|
||||
continue;
|
||||
}
|
||||
|
||||
let arity = term.arity();
|
||||
let arity = term.arity(subterm_loc);
|
||||
|
||||
struct QualifiedNameInfo {
|
||||
module_name: Atom,
|
||||
name: Atom,
|
||||
qualified_term_loc: usize,
|
||||
}
|
||||
|
||||
fn get_qualified_name(
|
||||
module_term: &Term,
|
||||
qualified_term: &Term,
|
||||
) -> Option<(Atom, Atom)> {
|
||||
if let Term::Literal(_, Literal::Atom(module_name)) = module_term {
|
||||
if let Some(name) = qualified_term.name() {
|
||||
return Some((*module_name, name));
|
||||
term: &FocusedHeapRefMut,
|
||||
module_term_loc: usize,
|
||||
qualified_term_loc: usize,
|
||||
) -> Option<QualifiedNameInfo> {
|
||||
let (module_term_loc, _) = subterm_index(term.heap, module_term_loc);
|
||||
let (qualified_term_loc, _) = subterm_index(term.heap, qualified_term_loc);
|
||||
|
||||
read_heap_cell!(term.heap[module_term_loc],
|
||||
(HeapCellValueTag::Atom, (module_name, arity)) => {
|
||||
if arity == 0 {
|
||||
if let Some(name) = term.name(qualified_term_loc) {
|
||||
return Some(QualifiedNameInfo {
|
||||
module_name,
|
||||
name,
|
||||
qualified_term_loc,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
);
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn identity_fn(_module_name: Atom, term: Term) -> Term {
|
||||
term
|
||||
}
|
||||
let (subterm_loc, _) = subterm_index(term.heap, subterm_loc);
|
||||
|
||||
fn tag_with_module_name(module_name: Atom, term: Term) -> Term {
|
||||
Term::Clause(
|
||||
Cell::default(),
|
||||
atom!(":"),
|
||||
vec![
|
||||
Term::Literal(Cell::default(), Literal::Atom(module_name)),
|
||||
term,
|
||||
],
|
||||
)
|
||||
}
|
||||
let subterm_arity = term.arity(subterm_loc);
|
||||
let subterm_name_opt = term.name(subterm_loc);
|
||||
|
||||
let process_term: fn(Atom, Term) -> Term;
|
||||
let (module_name, key, term_loc) =
|
||||
if subterm_name_opt == Some(atom!(":")) && subterm_arity == 2 {
|
||||
debug_assert_eq!(term.heap[subterm_loc].get_tag(), HeapCellValueTag::Atom);
|
||||
|
||||
let (module_name, key, term) = match term {
|
||||
Term::Clause(cell, atom!(":"), mut terms) if terms.len() == 2 => {
|
||||
if let Some((module_name, name)) = get_qualified_name(&terms[0], &terms[1])
|
||||
{
|
||||
process_term = tag_with_module_name;
|
||||
(
|
||||
match get_qualified_name(term, subterm_loc + 1, subterm_loc + 2) {
|
||||
Some(QualifiedNameInfo {
|
||||
module_name,
|
||||
(name, terms[1].arity() + supp_args),
|
||||
terms.pop().unwrap(),
|
||||
)
|
||||
} else {
|
||||
arg_terms.push(Term::Clause(cell, atom!(":"), terms));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
term => {
|
||||
process_term = identity_fn;
|
||||
(module_name, (name, arity + supp_args), term)
|
||||
}
|
||||
};
|
||||
|
||||
let term = match term {
|
||||
Term::Clause(cell, name, mut terms) => {
|
||||
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
|
||||
arg_terms
|
||||
.push(process_term(module_name, Term::Clause(cell, name, terms)));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
let idx = loader.get_or_insert_qualified_code_index(module_name, key);
|
||||
|
||||
terms.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx)));
|
||||
process_term(module_name, Term::Clause(cell, name, terms))
|
||||
}
|
||||
Term::Literal(cell, Literal::Atom(name)) => {
|
||||
let idx = loader.get_or_insert_qualified_code_index(module_name, key);
|
||||
|
||||
process_term(
|
||||
module_name,
|
||||
Term::Clause(
|
||||
cell,
|
||||
name,
|
||||
vec![Term::Literal(Cell::default(), Literal::CodeIndex(idx))],
|
||||
qualified_term_loc,
|
||||
}) => (
|
||||
module_name,
|
||||
(name, term.arity(qualified_term_loc) + supp_args),
|
||||
qualified_term_loc,
|
||||
),
|
||||
)
|
||||
}
|
||||
term => term,
|
||||
};
|
||||
None => {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
(module_name, (name, arity + supp_args), subterm_loc)
|
||||
};
|
||||
|
||||
arg_terms.push(term);
|
||||
continue;
|
||||
if let Some(index_ptr) = fetch_index_ptr(term.heap, key.1, term_loc) {
|
||||
index_ptrs.insert(term_loc, index_ptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
index_ptrs.insert(
|
||||
term_loc,
|
||||
loader.get_or_insert_qualified_code_index(module_name, key),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
arg_terms.push(term);
|
||||
}
|
||||
|
||||
arg_terms
|
||||
index_ptrs
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>(
|
||||
loader: &mut Loader<'a, LS>,
|
||||
name: Atom,
|
||||
mut terms: Vec<Term>,
|
||||
key: PredicateKey,
|
||||
terms: FocusedHeapRefMut,
|
||||
term: HeapCellValue,
|
||||
call_policy: CallPolicy,
|
||||
) -> QueryTerm {
|
||||
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
|
||||
// supplementary code vector indices are unnecessary for
|
||||
// root-level clauses.
|
||||
terms.pop();
|
||||
}
|
||||
) -> QueryClause {
|
||||
// supplementary code vector indices are unnecessary for
|
||||
// root-level clauses.
|
||||
blunt_index_ptr(terms.heap, key, terms.focus);
|
||||
|
||||
let mut ct = loader.get_clause_type(name, terms.len());
|
||||
let mut ct = loader.get_clause_type(key.0, key.1);
|
||||
|
||||
if let ClauseType::Named(arity, name, idx) = ct {
|
||||
if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() {
|
||||
let module_name = loader.payload.compilation_target.module_name();
|
||||
let terms = build_meta_predicate_clause(loader, module_name, terms, meta_specs);
|
||||
let code_indices =
|
||||
build_meta_predicate_clause(loader, module_name, arity, &terms, meta_specs);
|
||||
|
||||
return QueryTerm::Clause(
|
||||
Cell::default(),
|
||||
ClauseType::Named(arity, name, idx),
|
||||
terms,
|
||||
return QueryClause {
|
||||
ct: ClauseType::Named(key.1, key.0, idx),
|
||||
arity,
|
||||
term,
|
||||
code_indices,
|
||||
call_policy,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
ct = ClauseType::Named(arity, name, idx);
|
||||
ct = ClauseType::Named(key.1, key.0, idx);
|
||||
}
|
||||
|
||||
QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
|
||||
QueryClause {
|
||||
ct,
|
||||
arity: key.1,
|
||||
term,
|
||||
code_indices: IndexMap::with_hasher(FxBuildHasher::default()),
|
||||
call_policy,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
|
||||
loader: &mut Loader<'a, LS>,
|
||||
key: PredicateKey,
|
||||
module_name: Atom,
|
||||
name: Atom,
|
||||
mut terms: Vec<Term>,
|
||||
terms: FocusedHeapRefMut,
|
||||
term: HeapCellValue,
|
||||
call_policy: CallPolicy,
|
||||
) -> QueryTerm {
|
||||
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
|
||||
// supplementary code vector indices are unnecessary for
|
||||
// root-level clauses.
|
||||
terms.pop();
|
||||
}
|
||||
) -> QueryClause {
|
||||
// supplementary code vector indices are unnecessary for
|
||||
// root-level clauses.
|
||||
blunt_index_ptr(terms.heap, key, terms.focus);
|
||||
|
||||
let mut ct = loader.get_qualified_clause_type(module_name, name, terms.len());
|
||||
let mut ct = loader.get_qualified_clause_type(module_name, key.0, key.1);
|
||||
|
||||
if let ClauseType::Named(arity, name, idx) = ct {
|
||||
if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() {
|
||||
let terms = build_meta_predicate_clause(loader, module_name, terms, meta_specs);
|
||||
let code_indices =
|
||||
build_meta_predicate_clause(loader, module_name, arity, &terms, meta_specs);
|
||||
|
||||
return QueryTerm::Clause(
|
||||
Cell::default(),
|
||||
ClauseType::Named(arity, name, idx),
|
||||
terms,
|
||||
return QueryClause {
|
||||
ct: ClauseType::Named(key.1, key.0, idx),
|
||||
arity,
|
||||
term,
|
||||
code_indices,
|
||||
call_policy,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
ct = ClauseType::Named(arity, name, idx);
|
||||
ct = ClauseType::Named(key.1, key.0, idx);
|
||||
}
|
||||
|
||||
QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
|
||||
QueryClause {
|
||||
ct,
|
||||
arity: key.1,
|
||||
term,
|
||||
code_indices: IndexMap::with_hasher(FxBuildHasher::default()),
|
||||
call_policy,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -560,69 +613,50 @@ impl Preprocessor {
|
||||
Preprocessor { settings }
|
||||
}
|
||||
|
||||
fn setup_fact(&mut self, term: Term) -> Result<(Fact, VarData), CompilationError> {
|
||||
match term {
|
||||
Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => {
|
||||
let classifier = VariableClassifier::new(self.settings.default_call_policy());
|
||||
pub fn setup_fact(
|
||||
&mut self,
|
||||
mut term: FocusedHeap,
|
||||
) -> Result<(Fact, VarData), CompilationError> {
|
||||
if term.name(term.focus).is_some() {
|
||||
let classifier = VariableClassifier::new(self.settings.default_call_policy());
|
||||
let var_data = classifier.classify_fact(&mut term)?;
|
||||
|
||||
let (head, var_data) = classifier.classify_fact(term)?;
|
||||
Ok((Fact { head }, var_data))
|
||||
}
|
||||
_ => Err(CompilationError::InadmissibleFact),
|
||||
Ok((Fact { term }, var_data))
|
||||
} else {
|
||||
Err(CompilationError::InadmissibleFact)
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_rule<'a, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
head: Term,
|
||||
body: Term,
|
||||
mut term: FocusedHeap,
|
||||
) -> Result<(Rule, VarData), CompilationError> {
|
||||
let classifier = VariableClassifier::new(self.settings.default_call_policy());
|
||||
let (clauses, var_data) = classifier.classify_rule(loader, &mut term)?;
|
||||
let head_loc = term.nth_arg(term.focus, 1).unwrap();
|
||||
|
||||
let (head, clauses, var_data) = classifier.classify_rule(loader, head, body)?;
|
||||
|
||||
match head {
|
||||
Term::Clause(_, name, terms) => Ok((
|
||||
Rule {
|
||||
head: (name, terms),
|
||||
clauses,
|
||||
},
|
||||
var_data,
|
||||
)),
|
||||
Term::Literal(_, Literal::Atom(name)) => Ok((
|
||||
Rule {
|
||||
head: (name, vec![]),
|
||||
clauses,
|
||||
},
|
||||
var_data,
|
||||
)),
|
||||
_ => Err(CompilationError::InvalidRuleHead),
|
||||
if term.name(head_loc).is_some() {
|
||||
Ok((Rule { term, clauses }, var_data))
|
||||
} else {
|
||||
Err(CompilationError::InvalidRuleHead)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
term: Term,
|
||||
term: FocusedHeap,
|
||||
) -> Result<TopLevel, CompilationError> {
|
||||
match term {
|
||||
Term::Clause(r, name, mut terms) => {
|
||||
let is_rule = name == atom!(":-") && terms.len() == 2;
|
||||
let name = term.name(term.focus);
|
||||
let arity = term.arity(term.focus);
|
||||
|
||||
if is_rule {
|
||||
let tail = terms.pop().unwrap();
|
||||
let head = terms.pop().unwrap();
|
||||
|
||||
let (rule, var_data) = self.setup_rule(loader, head, tail)?;
|
||||
Ok(TopLevel::Rule(rule, var_data))
|
||||
} else {
|
||||
let term = Term::Clause(r, name, terms);
|
||||
let (fact, var_data) = self.setup_fact(term)?;
|
||||
Ok(TopLevel::Fact(fact, var_data))
|
||||
}
|
||||
match (name, arity) {
|
||||
(Some(atom!(":-")), 2) => {
|
||||
let (rule, var_data) = self.setup_rule(loader, term)?;
|
||||
Ok(TopLevel::Rule(rule, var_data))
|
||||
}
|
||||
term => {
|
||||
_ => {
|
||||
let (fact, var_data) = self.setup_fact(term)?;
|
||||
Ok(TopLevel::Fact(fact, var_data))
|
||||
}
|
||||
|
||||
@@ -24,12 +24,7 @@ pub(crate) struct RawBlock<T: RawBlockTraits> {
|
||||
|
||||
impl<T: RawBlockTraits> RawBlock<T> {
|
||||
pub(crate) fn new() -> Self {
|
||||
let mut block = RawBlock {
|
||||
size: 0,
|
||||
base: ptr::null(),
|
||||
top: ptr::null(),
|
||||
_marker: PhantomData,
|
||||
};
|
||||
let mut block = Self::uninitialized();
|
||||
|
||||
unsafe {
|
||||
block.grow();
|
||||
@@ -38,6 +33,15 @@ impl<T: RawBlockTraits> RawBlock<T> {
|
||||
block
|
||||
}
|
||||
|
||||
pub(crate) fn uninitialized() -> Self {
|
||||
Self {
|
||||
size: 0,
|
||||
base: ptr::null(),
|
||||
top: ptr::null(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn init_at_size(&mut self, cap: usize) {
|
||||
let layout = alloc::Layout::from_size_align_unchecked(cap, T::align());
|
||||
|
||||
|
||||
@@ -168,6 +168,13 @@ impl Stack {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn uninitialized() -> Self {
|
||||
Stack {
|
||||
buf: RawBlock::empty_block(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn alloc(&mut self, frame_size: usize) -> *mut u8 {
|
||||
loop {
|
||||
|
||||
@@ -1880,7 +1880,7 @@ impl MachineState {
|
||||
) -> Result<Stream, ParserError> {
|
||||
match stream.peek_char() {
|
||||
None => Ok(stream), // empty stream is handled gracefully by Lexer::eof
|
||||
Some(Err(e)) => Err(ParserError::IO(e)),
|
||||
Some(Err(e)) => Err(ParserError::IO(e, ParserErrorSrc::default())),
|
||||
Some(Ok(c)) => {
|
||||
if c == '\u{feff}' {
|
||||
// skip UTF-8 BOM
|
||||
|
||||
@@ -28,7 +28,7 @@ use crate::machine::stack::*;
|
||||
use crate::machine::streams::*;
|
||||
use crate::machine::{get_structure_index, Machine, VERIFY_ATTR_INTERRUPT_LOC};
|
||||
use crate::parser::char_reader::*;
|
||||
use crate::parser::dashu::Integer;
|
||||
use crate::parser::dashu::{Integer, Rational};
|
||||
use crate::read::*;
|
||||
use crate::types::*;
|
||||
use rand::rngs::StdRng;
|
||||
@@ -824,25 +824,30 @@ impl MachineState {
|
||||
) {
|
||||
let mut seen_set = IndexSet::new();
|
||||
|
||||
{
|
||||
let mut iter =
|
||||
stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, term);
|
||||
let outcome = if term.is_ref() {
|
||||
{
|
||||
let mut iter = stackful_post_order_iter::<NonListElider>(
|
||||
&mut self.heap, &mut self.stack, term.get_value() as usize,
|
||||
);
|
||||
|
||||
while let Some(value) = iter.next() {
|
||||
if iter.parent_stack_len() >= max_depth {
|
||||
iter.pop_stack();
|
||||
continue;
|
||||
}
|
||||
while let Some(value) = iter.next() {
|
||||
if iter.parent_stack_len() >= max_depth {
|
||||
iter.pop_stack();
|
||||
continue;
|
||||
}
|
||||
|
||||
let value = unmark_cell_bits!(value);
|
||||
let value = unmark_cell_bits!(value);
|
||||
|
||||
if value.is_var() {
|
||||
seen_set.insert(value);
|
||||
if value.is_var() {
|
||||
seen_set.insert(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let outcome = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, seen_set.into_iter(),));
|
||||
heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, seen_set.into_iter()))
|
||||
} else {
|
||||
empty_list_as_cell!()
|
||||
};
|
||||
|
||||
unify_fn!(*self, list_of_vars, outcome);
|
||||
}
|
||||
@@ -942,36 +947,51 @@ impl MachineState {
|
||||
tokens.reverse();
|
||||
|
||||
match parser.read_term(&op_dir, Tokens::Provided(tokens)) {
|
||||
Err(err) => {
|
||||
let err = self.syntax_error(err);
|
||||
return Err(self.error_form(err, stub_gen()));
|
||||
}
|
||||
Ok(Term::Literal(_, Literal::Rational(n))) => {
|
||||
self.unify_rational(n, nx);
|
||||
}
|
||||
Ok(Term::Literal(_, Literal::Float(n))) => {
|
||||
self.unify_f64(n.as_ptr(), nx);
|
||||
}
|
||||
Ok(Term::Literal(_, Literal::Integer(n))) => {
|
||||
self.unify_big_int(n, nx);
|
||||
}
|
||||
Ok(Term::Literal(_, Literal::Fixnum(n))) => {
|
||||
self.unify_fixnum(n, nx);
|
||||
}
|
||||
_ => {
|
||||
let err = ParserError::ParseBigInt(0, 0);
|
||||
let err = self.syntax_error(err);
|
||||
Ok(term) => {
|
||||
let mut error_gen = || {
|
||||
let e = ParserError::ParseBigInt(ParserErrorSrc::default());
|
||||
let e = self.syntax_error(e);
|
||||
|
||||
return Err(self.error_form(err, stub_gen()));
|
||||
return Err(self.error_form(e, stub_gen()));
|
||||
};
|
||||
|
||||
read_heap_cell!(term.heap[term.focus],
|
||||
(HeapCellValueTag::Cons, c) => {
|
||||
match_untyped_arena_ptr!(c,
|
||||
(ArenaHeaderTag::Rational, n) => {
|
||||
self.unify_rational(n, nx);
|
||||
}
|
||||
(ArenaHeaderTag::Integer, n) => {
|
||||
self.unify_big_int(n, nx);
|
||||
}
|
||||
_ => {
|
||||
return error_gen();
|
||||
}
|
||||
)
|
||||
}
|
||||
(HeapCellValueTag::F64, n) => {
|
||||
self.unify_f64(n, nx);
|
||||
}
|
||||
(HeapCellValueTag::Fixnum, n) => {
|
||||
self.unify_fixnum(n, nx);
|
||||
}
|
||||
_ => {
|
||||
return error_gen();
|
||||
}
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
let e = self.syntax_error(e);
|
||||
return Err(self.error_form(e, stub_gen()));
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
Ok(c) => {
|
||||
let (line_num, col_num) = (lexer.line_num, lexer.col_num);
|
||||
let err_src = lexer.loc_to_err_src();
|
||||
|
||||
let err = ParserError::UnexpectedChar(c, line_num, col_num);
|
||||
let err = ParserError::UnexpectedChar(c, err_src);
|
||||
let err = self.syntax_error(err);
|
||||
|
||||
return Err(self.error_form(err, stub_gen()));
|
||||
@@ -1440,6 +1460,8 @@ impl Machine {
|
||||
}
|
||||
};
|
||||
|
||||
// println!("(fast) calling {}/{}", name.as_str(), arity);
|
||||
|
||||
if let Some(code_index) = index_cell {
|
||||
if !code_index.is_undefined() {
|
||||
load_registers(&mut self.machine_st, goal, goal_arity);
|
||||
@@ -1599,12 +1621,12 @@ impl Machine {
|
||||
|
||||
let vars: Vec<_> = vars
|
||||
.union(&result.supp_vars) // difference + union does not cancel.
|
||||
.map(|v| Term::Var(Cell::default(), VarPtr::from(format!("_{}", v.get_value()))))
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
let helper_clause_loc = self.code.len();
|
||||
|
||||
match self.compile_standalone_clause(temp_v!(1), &vars) {
|
||||
match self.compile_standalone_clause(temp_v!(1), vars) {
|
||||
Err(e) => {
|
||||
let err = self.machine_st.session_error(e);
|
||||
let stub = functor_stub(atom!("call"), result.key.1);
|
||||
@@ -3572,7 +3594,9 @@ impl Machine {
|
||||
}
|
||||
Some(Err(e)) => {
|
||||
let stub = functor_stub(atom!("$get_n_chars"), 3);
|
||||
let err = self.machine_st.session_error(SessionError::from(e));
|
||||
let err = self.machine_st.session_error(SessionError::from(
|
||||
ParserError::IO(e, ParserErrorSrc::default()),
|
||||
));
|
||||
|
||||
return Err(self.machine_st.error_form(err, stub));
|
||||
}
|
||||
@@ -6266,10 +6290,10 @@ impl Machine {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn read_term_and_write_to_heap(
|
||||
fn read_term_from_atom(
|
||||
&mut self,
|
||||
atom_or_string: AtomOrString,
|
||||
) -> Result<Option<TermWriteResult>, MachineStub> {
|
||||
) -> Result<Option<FocusedHeap>, MachineStub> {
|
||||
let string = match atom_or_string {
|
||||
AtomOrString::Atom(atom!("[]")) => "".to_owned(),
|
||||
_ => atom_or_string.into(),
|
||||
@@ -6279,15 +6303,12 @@ impl Machine {
|
||||
let mut parser = Parser::new(chars, &mut self.machine_st);
|
||||
let op_dir = CompositeOpDir::new(&self.indices.op_dir, None);
|
||||
|
||||
let term_write_result = parser
|
||||
let term = parser
|
||||
.read_term(&op_dir, Tokens::Default)
|
||||
.map_err(|err| error_after_read_term(err, 0, &parser))
|
||||
.and_then(|term| {
|
||||
write_term_to_heap(&term, &mut self.machine_st.heap, &self.machine_st.atom_tbl)
|
||||
});
|
||||
.map_err(|e| error_after_read_term(e, 0));
|
||||
|
||||
match term_write_result {
|
||||
Ok(term_write_result) => Ok(Some(term_write_result)),
|
||||
match term {
|
||||
Ok(term) => Ok(Some(term)),
|
||||
Err(CompilationError::ParserError(e)) if e.is_unexpected_eof() => {
|
||||
let value = self.machine_st.registers[2];
|
||||
self.machine_st.unify_atom(atom!("end_of_file"), value);
|
||||
@@ -6305,42 +6326,50 @@ impl Machine {
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn read_from_chars(&mut self) -> CallResult {
|
||||
if let Some(atom_or_string) = self
|
||||
let atom_or_string = self
|
||||
.machine_st
|
||||
.value_to_str_like(self.machine_st.registers[1])
|
||||
{
|
||||
if let Some(term_write_result) = self.read_term_and_write_to_heap(atom_or_string)? {
|
||||
let result = heap_loc_as_cell!(term_write_result.heap_loc);
|
||||
let var = self.deref_register(2).as_var().unwrap();
|
||||
.unwrap();
|
||||
|
||||
self.machine_st.bind(var, result);
|
||||
}
|
||||
if let Some(mut term) = self.read_term_from_atom(atom_or_string)? {
|
||||
let heap_len = self.machine_st.heap.len();
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
unreachable!()
|
||||
self.machine_st.heap.extend(
|
||||
copy_and_align_iter(term.heap.drain(..), 0, heap_len as i64),
|
||||
);
|
||||
|
||||
let result = heap_loc_as_cell!(heap_len + term.focus);
|
||||
let var = self.deref_register(2).as_var().unwrap();
|
||||
|
||||
self.machine_st.bind(var, result);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn read_term_from_chars(&mut self) -> CallResult {
|
||||
if let Some(atom_or_string) = self
|
||||
let atom_or_string = self
|
||||
.machine_st
|
||||
.value_to_str_like(self.machine_st.registers[1])
|
||||
{
|
||||
if let Some(term_write_result) = self.read_term_and_write_to_heap(atom_or_string)? {
|
||||
self.machine_st.read_term_body(term_write_result)
|
||||
} else {
|
||||
if !self.machine_st.fail {
|
||||
// wrote end_of_file term in this case.
|
||||
self.machine_st.write_read_term_options(vec![], vec![])?;
|
||||
}
|
||||
.unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
let string = match atom_or_string {
|
||||
AtomOrString::Atom(atom!("[]")) => "".to_owned(),
|
||||
_ => atom_or_string.into(),
|
||||
};
|
||||
|
||||
let chars = CharReader::new(ByteStream::from_string(string));
|
||||
let term_write_result = self.machine_st.read(chars, &self.indices.op_dir)
|
||||
.map(|(term, _)| term.to_machine_heap(&mut self.machine_st))
|
||||
.map_err(|e| {
|
||||
let e = self.machine_st.session_error(SessionError::from(e));
|
||||
let stub = functor_stub(atom!("read_term_from_chars"), 3);
|
||||
|
||||
self.machine_st.error_form(e, stub)
|
||||
})?;
|
||||
|
||||
self.machine_st.read_term_body(term_write_result)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -8095,8 +8124,13 @@ impl Machine {
|
||||
|
||||
match devour_whitespace(&mut parser) {
|
||||
Ok(false) => {
|
||||
// not at EOF.
|
||||
// not at EOF ...
|
||||
stream.add_lines_read(parser.lines_read());
|
||||
|
||||
// ... unless we are.
|
||||
if stream.at_end_of_stream() {
|
||||
self.machine_st.fail = true;
|
||||
}
|
||||
}
|
||||
Ok(true) => {
|
||||
stream.add_lines_read(parser.lines_read());
|
||||
|
||||
@@ -20,11 +20,11 @@ pub struct LoadStatePayload<TS> {
|
||||
pub(super) module_op_exports: ModuleOpExports,
|
||||
pub(super) non_counted_bt_preds: IndexSet<PredicateKey, FxBuildHasher>,
|
||||
pub(super) predicates: PredicateQueue,
|
||||
pub(super) clause_clauses: Vec<(Term, Term)>,
|
||||
pub(super) clause_clauses: Vec<FocusedHeap>,
|
||||
}
|
||||
|
||||
pub trait TermStream: Sized {
|
||||
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError>;
|
||||
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<FocusedHeap, CompilationError>;
|
||||
fn eof(&mut self) -> Result<bool, CompilationError>;
|
||||
fn listing_src(&self) -> &ListingSource;
|
||||
}
|
||||
@@ -52,7 +52,7 @@ impl<'a> BootstrappingTermStream<'a> {
|
||||
|
||||
impl<'a> TermStream for BootstrappingTermStream<'a> {
|
||||
#[inline]
|
||||
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError> {
|
||||
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<FocusedHeap, CompilationError> {
|
||||
self.parser.reset();
|
||||
self.parser
|
||||
.read_term(op_dir, Tokens::Default)
|
||||
@@ -72,7 +72,7 @@ impl<'a> TermStream for BootstrappingTermStream<'a> {
|
||||
}
|
||||
|
||||
pub struct LiveTermStream {
|
||||
pub(super) term_queue: VecDeque<Term>,
|
||||
pub(super) term_queue: VecDeque<FocusedHeap>,
|
||||
pub(super) listing_src: ListingSource,
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ impl<TS> LoadStatePayload<TS> {
|
||||
|
||||
impl TermStream for LiveTermStream {
|
||||
#[inline]
|
||||
fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
|
||||
fn next(&mut self, _: &CompositeOpDir) -> Result<FocusedHeap, CompilationError> {
|
||||
Ok(self.term_queue.pop_front().unwrap())
|
||||
}
|
||||
|
||||
@@ -126,8 +126,8 @@ impl TermStream for LiveTermStream {
|
||||
pub struct InlineTermStream {}
|
||||
|
||||
impl TermStream for InlineTermStream {
|
||||
fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
|
||||
Err(CompilationError::from(ParserError::unexpected_eof()))
|
||||
fn next(&mut self, _: &CompositeOpDir) -> Result<FocusedHeap, CompilationError> {
|
||||
Err(CompilationError::from(ParserError::unexpected_eof(ParserErrorSrc::default())))
|
||||
}
|
||||
|
||||
fn eof(&mut self) -> Result<bool, CompilationError> {
|
||||
|
||||
@@ -705,13 +705,16 @@ fn bind_with_occurs_check<U: Unifier>(unifier: &mut U, r: Ref, value: HeapCellVa
|
||||
|
||||
let mut occurs_triggered = false;
|
||||
|
||||
if !value.is_constant() {
|
||||
let machine_st: &mut MachineState = unifier.deref_mut();
|
||||
let machine_st: &mut MachineState = unifier.deref_mut();
|
||||
let value = machine_st.store(MachineState::deref(machine_st, value));
|
||||
|
||||
if value.is_ref() && !value.is_stack_var() {
|
||||
let root_loc = value.get_value() as usize;
|
||||
|
||||
for cell in stackful_preorder_iter::<NonListElider>(
|
||||
&mut machine_st.heap,
|
||||
&mut machine_st.stack,
|
||||
value,
|
||||
root_loc, // value,
|
||||
) {
|
||||
let cell = unmark_cell_bits!(cell);
|
||||
|
||||
|
||||
@@ -346,6 +346,11 @@ macro_rules! read_heap_cell_pat_body {
|
||||
#[allow(unused_braces)]
|
||||
$code
|
||||
}};
|
||||
($cell:ident, Atom, (_, $arity:ident), $code:expr) => {{
|
||||
let $arity = cell_as_atom_cell!($cell).get_arity();
|
||||
#[allow(unused_braces)]
|
||||
$code
|
||||
}};
|
||||
($cell:ident, PStr, $atom:ident, $code:expr) => {{
|
||||
let $atom = cell_as_atom!($cell);
|
||||
#[allow(unused_braces)]
|
||||
|
||||
@@ -2,15 +2,19 @@
|
||||
|
||||
use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::forms::PredicateKey;
|
||||
use crate::machine::copier::*;
|
||||
use crate::machine::heap::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::parser::char_reader::*;
|
||||
use crate::types::HeapCellValueTag;
|
||||
use crate::machine::machine_state::*;
|
||||
use crate::types::*;
|
||||
|
||||
use std::cell::{Cell, Ref, RefCell, RefMut};
|
||||
use std::cell::{Ref, RefCell, RefMut};
|
||||
use std::collections::VecDeque;
|
||||
use std::fmt;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::io::{Error as IOError, ErrorKind};
|
||||
use std::ops::{Deref, Neg};
|
||||
use std::ops::{Deref, Neg, RangeBounds};
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::vec::Vec;
|
||||
@@ -426,35 +430,42 @@ pub enum ArithmeticError {
|
||||
UninstantiatedVar,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
pub struct ParserErrorSrc {
|
||||
pub col_num: usize,
|
||||
pub line_num: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ParserError {
|
||||
BackQuotedString(usize, usize),
|
||||
IO(IOError),
|
||||
IncompleteReduction(usize, usize),
|
||||
InfiniteFloat(usize, usize),
|
||||
InvalidSingleQuotedCharacter(char),
|
||||
LexicalError(lexical::Error),
|
||||
MissingQuote(usize, usize),
|
||||
NonPrologChar(usize, usize),
|
||||
ParseBigInt(usize, usize),
|
||||
UnexpectedChar(char, usize, usize),
|
||||
BackQuotedString(ParserErrorSrc),
|
||||
IO(IOError, ParserErrorSrc),
|
||||
IncompleteReduction(ParserErrorSrc),
|
||||
InfiniteFloat(ParserErrorSrc),
|
||||
InvalidSingleQuotedCharacter(char, ParserErrorSrc),
|
||||
LexicalError(lexical::Error, ParserErrorSrc),
|
||||
MissingQuote(ParserErrorSrc),
|
||||
NonPrologChar(ParserErrorSrc),
|
||||
ParseBigInt(ParserErrorSrc),
|
||||
UnexpectedChar(char, ParserErrorSrc),
|
||||
// UnexpectedEOF,
|
||||
Utf8Error(usize, usize),
|
||||
Utf8Error(ParserErrorSrc),
|
||||
}
|
||||
|
||||
impl ParserError {
|
||||
pub fn line_and_col_num(&self) -> Option<(usize, usize)> {
|
||||
pub fn err_src(&self) -> ParserErrorSrc {
|
||||
match self {
|
||||
&ParserError::BackQuotedString(line_num, col_num)
|
||||
| &ParserError::IncompleteReduction(line_num, col_num)
|
||||
| &ParserError::InfiniteFloat(line_num, col_num)
|
||||
| &ParserError::MissingQuote(line_num, col_num)
|
||||
| &ParserError::NonPrologChar(line_num, col_num)
|
||||
| &ParserError::ParseBigInt(line_num, col_num)
|
||||
| &ParserError::UnexpectedChar(_, line_num, col_num)
|
||||
| &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)),
|
||||
_ => None,
|
||||
&ParserError::BackQuotedString(err_src)
|
||||
| &ParserError::IO(_, err_src)
|
||||
| &ParserError::IncompleteReduction(err_src)
|
||||
| &ParserError::InfiniteFloat(err_src)
|
||||
| &ParserError::InvalidSingleQuotedCharacter(_, err_src)
|
||||
| &ParserError::LexicalError(_, err_src)
|
||||
| &ParserError::MissingQuote(err_src)
|
||||
| &ParserError::NonPrologChar(err_src)
|
||||
| &ParserError::ParseBigInt(err_src)
|
||||
| &ParserError::UnexpectedChar(_, err_src)
|
||||
| &ParserError::Utf8Error(err_src) => err_src,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,14 +479,14 @@ impl ParserError {
|
||||
ParserError::InfiniteFloat(..) => {
|
||||
atom!("infinite_float")
|
||||
}
|
||||
ParserError::IO(e) if e.kind() == ErrorKind::UnexpectedEof => {
|
||||
ParserError::IO(e, _) if e.kind() == ErrorKind::UnexpectedEof => {
|
||||
atom!("unexpected_end_of_file")
|
||||
}
|
||||
ParserError::IO(e) if e.kind() == ErrorKind::InvalidData => {
|
||||
ParserError::IO(e, _) if e.kind() == ErrorKind::InvalidData => {
|
||||
atom!("invalid_data")
|
||||
}
|
||||
ParserError::IO(_) => atom!("input_output_error"),
|
||||
ParserError::LexicalError(_) => atom!("lexical_error"),
|
||||
ParserError::IO(..) => atom!("input_output_error"),
|
||||
ParserError::LexicalError(..) => atom!("lexical_error"),
|
||||
ParserError::MissingQuote(..) => atom!("missing_quote"),
|
||||
ParserError::NonPrologChar(..) => atom!("non_prolog_character"),
|
||||
ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"),
|
||||
@@ -485,23 +496,23 @@ impl ParserError {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn unexpected_eof() -> Self {
|
||||
ParserError::IO(std::io::Error::from(ErrorKind::UnexpectedEof))
|
||||
pub fn unexpected_eof(err_src: ParserErrorSrc) -> Self {
|
||||
ParserError::IO(std::io::Error::from(ErrorKind::UnexpectedEof), err_src)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_unexpected_eof(&self) -> bool {
|
||||
if let ParserError::IO(e) = self {
|
||||
if let ParserError::IO(e, _) = self {
|
||||
e.kind() == ErrorKind::UnexpectedEof
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl From<lexical::Error> for ParserError {
|
||||
fn from(e: lexical::Error) -> ParserError {
|
||||
ParserError::LexicalError(e)
|
||||
fn from((e, err_src): (lexical::Error, ParserErrorSrc)) -> ParserError {
|
||||
ParserError::LexicalError(e, err_src)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -520,7 +531,7 @@ impl From<&IOError> for ParserError {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct CompositeOpDir<'a, 'b> {
|
||||
pub primary_op_dir: Option<&'b OpDir>,
|
||||
@@ -694,6 +705,14 @@ impl Deref for VarPtr {
|
||||
}
|
||||
|
||||
impl VarPtr {
|
||||
#[inline]
|
||||
pub(crate) fn is_anon(&self) -> bool {
|
||||
match *self.borrow() {
|
||||
Var::Anon | Var::Generated { is_anon: true, .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn borrow(&self) -> Ref<'_, Var> {
|
||||
self.0.borrow()
|
||||
@@ -706,7 +725,7 @@ impl VarPtr {
|
||||
|
||||
pub(crate) fn to_var_num(&self) -> Option<usize> {
|
||||
match *self.borrow() {
|
||||
Var::Generated(var_num) => Some(var_num),
|
||||
Var::Generated { var_num, .. } => Some(var_num),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -740,7 +759,8 @@ impl From<&str> for VarPtr {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Var {
|
||||
Generated(usize),
|
||||
Anon,
|
||||
Generated { is_anon: bool, var_num: usize },
|
||||
InSitu(usize),
|
||||
Named(String),
|
||||
}
|
||||
@@ -764,12 +784,34 @@ impl Var {
|
||||
#[inline(always)]
|
||||
pub fn to_string(&self) -> String {
|
||||
match self {
|
||||
Var::InSitu(n) | Var::Generated(n) => format!("_{}", n),
|
||||
Var::Anon => "_".to_owned(),
|
||||
Var::InSitu(var_num) | Var::Generated { var_num, .. } => format!("_{}", var_num),
|
||||
Var::Named(value) => value.to_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn subterm_index(heap: &[HeapCellValue], subterm_loc: usize) -> (usize, HeapCellValue) {
|
||||
let subterm = heap[subterm_loc];
|
||||
|
||||
if subterm.is_ref() {
|
||||
let subterm = heap_bound_deref(heap, subterm);
|
||||
let subterm_loc = subterm.get_value() as usize;
|
||||
let subterm = heap_bound_store(heap, subterm);
|
||||
|
||||
let subterm_loc = if subterm.is_ref() {
|
||||
subterm.get_value() as usize
|
||||
} else {
|
||||
subterm_loc
|
||||
};
|
||||
|
||||
(subterm_loc, subterm)
|
||||
} else {
|
||||
(subterm_loc, subterm)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Term {
|
||||
AnonVar,
|
||||
@@ -836,3 +878,441 @@ pub fn unfold_by_str(mut term: Term, s: Atom) -> Vec<Term> {
|
||||
terms.push(term);
|
||||
terms
|
||||
}
|
||||
*/
|
||||
|
||||
pub(crate) fn fetch_index_ptr(
|
||||
heap: &[HeapCellValue],
|
||||
arity: usize,
|
||||
term_loc: usize,
|
||||
) -> Option<CodeIndex> {
|
||||
if term_loc + arity + 1 >= heap.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
read_heap_cell!(heap[term_loc + arity + 1],
|
||||
(HeapCellValueTag::Cons, c) => {
|
||||
match_untyped_arena_ptr!(c,
|
||||
(ArenaHeaderTag::IndexPtr, ptr) => {
|
||||
return Some(CodeIndex::from(ptr));
|
||||
}
|
||||
_ => {}
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
);
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) fn blunt_index_ptr(
|
||||
heap: &mut [HeapCellValue],
|
||||
key: PredicateKey,
|
||||
term_loc: usize,
|
||||
) -> bool {
|
||||
if fetch_index_ptr(heap, key.1, term_loc).is_some() {
|
||||
heap[term_loc] = atom_as_cell!(key.0, key.1);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn unfold_by_str_once(
|
||||
heap: &mut [HeapCellValue],
|
||||
start_term: HeapCellValue,
|
||||
atom: Atom,
|
||||
) -> Option<usize> {
|
||||
let start_term = heap_bound_store(
|
||||
heap,
|
||||
heap_bound_deref(heap, start_term),
|
||||
);
|
||||
|
||||
if let HeapCellValueTag::Str = start_term.get_tag() {
|
||||
let s = start_term.get_value() as usize;
|
||||
|
||||
let (s_atom, s_arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();
|
||||
blunt_index_ptr(heap, (s_atom, s_arity), s);
|
||||
|
||||
if (s_atom, s_arity) == (atom, 2) {
|
||||
return Some(s+1);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn unfold_by_str(
|
||||
heap: &mut [HeapCellValue],
|
||||
mut start_term: HeapCellValue,
|
||||
atom: Atom,
|
||||
) -> Vec<HeapCellValue> {
|
||||
let mut terms = vec![];
|
||||
start_term = heap_bound_store(heap, heap_bound_deref(heap, start_term));
|
||||
|
||||
while let Some(fst_loc) = unfold_by_str_once(heap, start_term, atom) {
|
||||
let (_, snd) = subterm_index(heap, fst_loc + 1);
|
||||
let (_, fst) = subterm_index(heap, fst_loc);
|
||||
terms.push(fst);
|
||||
start_term = snd;
|
||||
}
|
||||
|
||||
terms
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn unfold_by_str_locs(
|
||||
heap: &mut [HeapCellValue],
|
||||
mut term_loc: usize,
|
||||
atom: Atom,
|
||||
) -> Vec<(HeapCellValue, usize)> {
|
||||
let mut terms = vec![];
|
||||
let mut current_term = heap_bound_store(
|
||||
heap,
|
||||
heap_bound_deref(heap, heap[term_loc]),
|
||||
);
|
||||
|
||||
while let Some(fst_loc) = unfold_by_str_once(heap, current_term, atom) {
|
||||
(term_loc, current_term) = subterm_index(heap, fst_loc + 1);
|
||||
let (fst_loc, fst) = subterm_index(heap, fst_loc);
|
||||
terms.push((fst, fst_loc));
|
||||
}
|
||||
|
||||
terms.push((current_term, term_loc));
|
||||
terms
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn unfold_by_str_locs(
|
||||
heap: &mut [HeapCellValue],
|
||||
mut term_loc: usize,
|
||||
atom: Atom,
|
||||
) -> Vec<(HeapCellValue, usize)> {
|
||||
let mut terms = vec![];
|
||||
let mut current_term = heap[term_loc];
|
||||
|
||||
while let Some(fst_loc) = unfold_by_str_once(heap, current_term, atom) {
|
||||
term_loc = fst_loc+1;
|
||||
current_term = heap[term_loc];
|
||||
let fst = heap[fst_loc];
|
||||
terms.push((fst, fst_loc));
|
||||
}
|
||||
|
||||
terms.push((current_term, term_loc));
|
||||
terms
|
||||
}
|
||||
|
||||
pub fn term_name(heap: &[HeapCellValue], mut term_loc: usize) -> Option<Atom> {
|
||||
loop {
|
||||
read_heap_cell!(heap[term_loc],
|
||||
(HeapCellValueTag::Atom, (name, _arity)) => {
|
||||
return Some(name);
|
||||
}
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
term_loc = s;
|
||||
}
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
if h != term_loc {
|
||||
term_loc = h;
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn term_arity(heap: &[HeapCellValue], mut term_loc: usize) -> usize {
|
||||
loop {
|
||||
read_heap_cell!(heap[term_loc],
|
||||
(HeapCellValueTag::Atom, (_name, arity)) => {
|
||||
return arity;
|
||||
}
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
term_loc = s;
|
||||
}
|
||||
(HeapCellValueTag::Lis) => {
|
||||
return 2;
|
||||
}
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
if h != term_loc {
|
||||
term_loc = h;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return 0;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn var_locs_from_iter<I: Iterator<Item = HeapCellValue>>(iter: I) -> VarLocs {
|
||||
let mut occurrence_set: IndexMap<HeapCellValue, usize, FxBuildHasher> =
|
||||
IndexMap::with_hasher(FxBuildHasher::default());
|
||||
|
||||
for term in iter {
|
||||
if term.is_var() {
|
||||
let var_count = occurrence_set.entry(term).or_insert(0);
|
||||
*var_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
VarLocs(
|
||||
occurrence_set
|
||||
.into_iter()
|
||||
.map(|(var, count)| {
|
||||
let key = var.get_value() as usize;
|
||||
let queue = if count > 1 {
|
||||
(0 .. count).map(|_| VarPtr::from(format!("_{}", key))).collect()
|
||||
} else {
|
||||
(0 .. count).map(|_| VarPtr::from(Var::Anon)).collect()
|
||||
};
|
||||
|
||||
(key, queue)
|
||||
})
|
||||
.collect()
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn term_deref(heap: &[HeapCellValue], mut term_loc: usize) -> HeapCellValue {
|
||||
loop {
|
||||
read_heap_cell!(heap[term_loc],
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
if h != term_loc {
|
||||
term_loc = h;
|
||||
} else {
|
||||
return heap[h];
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return heap[term_loc];
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn term_nth_arg(heap: &[HeapCellValue], mut term_loc: usize, n: usize) -> Option<usize> {
|
||||
loop {
|
||||
read_heap_cell!(heap[term_loc],
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
return if cell_as_atom_cell!(heap[s]).get_arity() >= n {
|
||||
Some(s+n)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
}
|
||||
(HeapCellValueTag::Atom, (_name, arity)) => {
|
||||
return if arity >= n {
|
||||
Some(term_loc + n)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
}
|
||||
(HeapCellValueTag::Lis, l) => {
|
||||
return if 1 <= n && n <= 2 {
|
||||
Some(l+n-1)
|
||||
} else if n == 0 {
|
||||
Some(term_loc)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
}
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
if h != term_loc {
|
||||
term_loc = h;
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub type VarNamesToLocs = IndexMap<String, HeapCellValue, FxBuildHasher>;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct VarLocs(IndexMap<usize, VecDeque<VarPtr>, FxBuildHasher>);
|
||||
|
||||
impl VarLocs {
|
||||
pub fn get(&self, key: usize) -> Option<&VarPtr> {
|
||||
self.0.get(&key)
|
||||
.and_then(|queue| {
|
||||
queue.front()
|
||||
})
|
||||
}
|
||||
|
||||
// if a queue of VarPtr's is stored at location key, pop the front
|
||||
// if it exists and pass it along to wrapper, returning a value of
|
||||
// type R. A return value of None indicates that the key doesn't
|
||||
// exist (the map containing a key necessarily means its queue
|
||||
// value is non-empty).
|
||||
fn rotate_latest_mut<R>(
|
||||
&mut self,
|
||||
key: usize,
|
||||
wrapper: impl FnOnce(&VarPtr) -> R,
|
||||
) -> Option<R> {
|
||||
self.0.get_mut(&key)
|
||||
.and_then(move |queue| {
|
||||
if let Some(var_ptr) = queue.pop_front() {
|
||||
let result = wrapper(&var_ptr);
|
||||
queue.push_back(var_ptr);
|
||||
Some(result)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn peek_next_var_ptr_at_key(&self, key: usize) -> Option<&VarPtr> {
|
||||
self.0.get(&key).and_then(|queue| queue.front())
|
||||
}
|
||||
|
||||
pub fn read_next_var_ptr_at_key(&mut self, key: usize) -> Option<VarPtr> {
|
||||
self.rotate_latest_mut(key, VarPtr::clone)
|
||||
}
|
||||
|
||||
pub fn push_at_key(&mut self, key: usize, var_ptr: VarPtr) {
|
||||
let entry = self.0.entry(key).or_default();
|
||||
entry.push_back(var_ptr);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn iter(&self) -> impl Iterator<Item = (usize, &VecDeque<VarPtr>)> {
|
||||
self.0.iter().map(|(&k, v)| (k, v))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn drain<R>(&mut self, range: R) -> indexmap::map::Drain<usize, VecDeque<VarPtr>>
|
||||
where R: RangeBounds<usize>
|
||||
{
|
||||
self.0.drain(range)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn insert(&mut self, key: usize, var_ptrs: VecDeque<VarPtr>) {
|
||||
self.0.insert(key, var_ptrs);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FocusedHeap {
|
||||
pub heap: Vec<HeapCellValue>,
|
||||
pub focus: usize,
|
||||
pub var_locs: VarLocs,
|
||||
}
|
||||
|
||||
impl FocusedHeap {
|
||||
pub fn empty() -> Self {
|
||||
Self {
|
||||
heap: vec![],
|
||||
focus: 0,
|
||||
var_locs: VarLocs::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn copy_term_from_machine_heap(
|
||||
&mut self,
|
||||
machine_st: &mut MachineState,
|
||||
cell: HeapCellValue,
|
||||
) {
|
||||
let hb = machine_st.heap.len();
|
||||
|
||||
copy_term(
|
||||
CopyBallTerm::new(
|
||||
&mut machine_st.attr_var_init.attr_var_queue,
|
||||
&mut machine_st.stack,
|
||||
&mut machine_st.heap,
|
||||
&mut self.heap,
|
||||
),
|
||||
cell,
|
||||
AttrVarPolicy::DeepCopy,
|
||||
);
|
||||
|
||||
for cell in self.heap.iter_mut() {
|
||||
*cell = *cell - hb;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_ref_mut(&mut self, focus: usize) -> FocusedHeapRefMut {
|
||||
FocusedHeapRefMut {
|
||||
heap: &mut self.heap,
|
||||
focus,
|
||||
// var_locs: &self.var_locs,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deref_loc(&self, term_loc: usize) -> HeapCellValue {
|
||||
use crate::machine::heap::*;
|
||||
|
||||
let cell = self.heap[term_loc];
|
||||
heap_bound_store(&self.heap, heap_bound_deref(&self.heap, cell))
|
||||
}
|
||||
|
||||
pub fn name(&self, term_loc: usize) -> Option<Atom> {
|
||||
term_name(&self.heap, term_loc)
|
||||
}
|
||||
|
||||
pub fn arity(&self, term_loc: usize) -> usize {
|
||||
term_arity(&self.heap, term_loc)
|
||||
}
|
||||
|
||||
pub fn nth_arg(&self, term_loc: usize, n: usize) -> Option<usize> {
|
||||
term_nth_arg(&self.heap, term_loc, n)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FocusedHeapRefMut<'a> {
|
||||
pub heap: &'a mut Vec<HeapCellValue>,
|
||||
pub focus: usize,
|
||||
}
|
||||
|
||||
impl<'a> FocusedHeapRefMut<'a> {
|
||||
pub fn name(&self, term_loc: usize) -> Option<Atom> {
|
||||
term_name(&self.heap, term_loc)
|
||||
}
|
||||
|
||||
pub fn arity(&self, term_loc: usize) -> usize {
|
||||
term_arity(&self.heap, term_loc)
|
||||
}
|
||||
|
||||
pub fn deref_loc(&self, term_loc: usize) -> HeapCellValue {
|
||||
use crate::machine::heap::*;
|
||||
|
||||
let cell = self.heap[term_loc];
|
||||
heap_bound_store(&self.heap, heap_bound_deref(&self.heap, cell))
|
||||
}
|
||||
|
||||
pub fn nth_arg(&self, term_loc: usize, n: usize) -> Option<usize> {
|
||||
term_nth_arg(self.heap, term_loc, n)
|
||||
}
|
||||
|
||||
pub fn from_cell(heap: &'a mut Vec<HeapCellValue>, cell: HeapCellValue) -> Self {
|
||||
let focus = read_heap_cell!(cell,
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
h
|
||||
}
|
||||
_ => {
|
||||
let h = heap.len();
|
||||
heap.push(cell);
|
||||
|
||||
h
|
||||
}
|
||||
);
|
||||
|
||||
Self { heap, focus }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use crate::arena::F64Ptr;
|
||||
use crate::arena::TypedArenaPtr;
|
||||
use lexical::{FromLexicalLossy, parse_lossy};
|
||||
|
||||
use crate::arena::ArenaAllocated;
|
||||
use crate::atom_table::*;
|
||||
pub use crate::machine::machine_state::*;
|
||||
use crate::parser::ast::*;
|
||||
@@ -130,17 +133,22 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
||||
pub fn lookahead_char(&mut self) -> Result<char, ParserError> {
|
||||
match self.reader.peek_char() {
|
||||
Some(Ok(c)) => Ok(c),
|
||||
_ => Err(ParserError::unexpected_eof()),
|
||||
_ => Err(ParserError::unexpected_eof(self.loc_to_err_src())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_char(&mut self) -> Result<char, ParserError> {
|
||||
match self.reader.read_char() {
|
||||
Some(Ok(c)) => Ok(c),
|
||||
_ => Err(ParserError::unexpected_eof()),
|
||||
_ => Err(ParserError::unexpected_eof(self.loc_to_err_src())),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn loc_to_err_src(&self) -> ParserErrorSrc {
|
||||
ParserErrorSrc { line_num: self.line_num, col_num: self.col_num }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn return_char(&mut self, c: char) {
|
||||
self.reader.put_back_char(c);
|
||||
@@ -212,10 +220,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
||||
|
||||
match comment_loop() {
|
||||
Err(e) if e.is_unexpected_eof() => {
|
||||
return Err(ParserError::IncompleteReduction(
|
||||
self.line_num,
|
||||
self.col_num,
|
||||
));
|
||||
return Err(ParserError::IncompleteReduction(self.loc_to_err_src()));
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
@@ -227,7 +232,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
||||
self.skip_char(c);
|
||||
Ok(true)
|
||||
} else {
|
||||
Err(ParserError::NonPrologChar(self.line_num, self.col_num))
|
||||
Err(ParserError::NonPrologChar(self.loc_to_err_src()))
|
||||
}
|
||||
} else {
|
||||
self.return_char('/');
|
||||
@@ -244,7 +249,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
||||
|
||||
if !back_quote_char!(c2) {
|
||||
self.return_char(c);
|
||||
Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
|
||||
Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()))
|
||||
} else {
|
||||
self.skip_char(c2);
|
||||
Ok(c2)
|
||||
@@ -269,7 +274,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
||||
Ok(None)
|
||||
} else {
|
||||
self.return_char(c);
|
||||
Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
|
||||
Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()))
|
||||
}
|
||||
} else {
|
||||
self.get_back_quoted_char().map(Some)
|
||||
@@ -291,10 +296,10 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
||||
self.skip_char(c);
|
||||
Ok(token)
|
||||
} else {
|
||||
Err(ParserError::MissingQuote(self.line_num, self.col_num))
|
||||
Err(ParserError::MissingQuote(self.loc_to_err_src()))
|
||||
}
|
||||
} else {
|
||||
Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
|
||||
Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +330,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
||||
|
||||
if !single_quote_char!(c2) {
|
||||
self.return_char(c);
|
||||
Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
|
||||
Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()))
|
||||
} else {
|
||||
self.skip_char(c2);
|
||||
Ok(c2)
|
||||
@@ -366,7 +371,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
||||
|
||||
if !double_quote_char!(c2) {
|
||||
self.return_char(c);
|
||||
Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
|
||||
Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()))
|
||||
} else {
|
||||
self.skip_char(c2);
|
||||
Ok(c2)
|
||||
@@ -390,7 +395,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
||||
't' => '\t',
|
||||
'n' => '\n',
|
||||
'r' => '\r',
|
||||
c => return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)),
|
||||
c => return Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())),
|
||||
};
|
||||
|
||||
self.skip_char(c);
|
||||
@@ -408,10 +413,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
||||
if hexadecimal_digit_char!(c) {
|
||||
self.escape_sequence_to_char(|c| hexadecimal_digit_char!(c), 16)
|
||||
} else {
|
||||
Err(ParserError::IncompleteReduction(
|
||||
self.line_num,
|
||||
self.col_num,
|
||||
))
|
||||
Err(ParserError::IncompleteReduction(self.loc_to_err_src()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,17 +439,14 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
||||
if backslash_char!(c) {
|
||||
self.skip_char(c);
|
||||
u32::from_str_radix(&token, radix).map_or_else(
|
||||
|_| Err(ParserError::ParseBigInt(self.line_num, self.col_num)),
|
||||
|_| Err(ParserError::ParseBigInt(self.loc_to_err_src())),
|
||||
|n| {
|
||||
char::try_from(n)
|
||||
.map_err(|_| ParserError::Utf8Error(self.line_num, self.col_num))
|
||||
.map_err(|_| ParserError::Utf8Error(self.loc_to_err_src()))
|
||||
},
|
||||
)
|
||||
} else {
|
||||
Err(ParserError::IncompleteReduction(
|
||||
self.line_num,
|
||||
self.col_num,
|
||||
))
|
||||
Err(ParserError::IncompleteReduction(self.loc_to_err_src()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,7 +458,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
||||
Ok(c)
|
||||
} else {
|
||||
if !backslash_char!(c) {
|
||||
return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num));
|
||||
return Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()));
|
||||
}
|
||||
|
||||
self.skip_char(c);
|
||||
@@ -490,7 +489,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
||||
self.skip_char(c);
|
||||
Ok(token)
|
||||
} else {
|
||||
Err(ParserError::MissingQuote(self.line_num, self.col_num))
|
||||
Err(ParserError::MissingQuote(self.loc_to_err_src()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,7 +514,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
||||
.map(NumberToken::Number)
|
||||
} else {
|
||||
self.return_char(start);
|
||||
Err(ParserError::ParseBigInt(self.line_num, self.col_num))
|
||||
Err(ParserError::ParseBigInt(self.loc_to_err_src()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,7 +539,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
||||
.map(NumberToken::Number)
|
||||
} else {
|
||||
self.return_char(start);
|
||||
Err(ParserError::ParseBigInt(self.line_num, self.col_num))
|
||||
Err(ParserError::ParseBigInt(self.loc_to_err_src()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -565,7 +564,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
||||
.map(NumberToken::Number)
|
||||
} else {
|
||||
self.return_char(start);
|
||||
Err(ParserError::ParseBigInt(self.line_num, self.col_num))
|
||||
Err(ParserError::ParseBigInt(self.loc_to_err_src()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -636,11 +635,11 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(ParserError::InvalidSingleQuotedCharacter(c));
|
||||
return Err(ParserError::InvalidSingleQuotedCharacter(c, self.loc_to_err_src()));
|
||||
}
|
||||
} else {
|
||||
match self.get_back_quoted_string() {
|
||||
Ok(_) => return Err(ParserError::BackQuotedString(self.line_num, self.col_num)),
|
||||
Ok(_) => return Err(ParserError::BackQuotedString(self.loc_to_err_src())),
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
@@ -655,10 +654,17 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
||||
}
|
||||
}
|
||||
|
||||
fn vacate_with_float(&mut self, mut token: String) -> Result<Number, ParserError> {
|
||||
fn parse_lossy_wrapper<T: FromLexicalLossy>(&self, token: String) -> Result<T, ParserError> {
|
||||
match parse_lossy::<T, _>(token.as_bytes()) {
|
||||
Ok(n) => Ok(n),
|
||||
Err(e) => return Err(ParserError::LexicalError(e, self.loc_to_err_src())),
|
||||
}
|
||||
}
|
||||
|
||||
fn vacate_with_float(&mut self, mut token: String) -> Result<Token, ParserError> {
|
||||
self.return_char(token.pop().unwrap());
|
||||
let n = parse_float_lossy(&token)?;
|
||||
Ok(Number::Float(float_alloc!(n, self.machine_st.arena)))
|
||||
let n = self.parse_lossy_wrapper::<f64>(token)?;
|
||||
Ok(Token::Literal(Literal::from(float_alloc!(n, self.machine_st.arena))))
|
||||
}
|
||||
|
||||
fn skip_underscore_in_number(&mut self) -> Result<char, ParserError> {
|
||||
@@ -672,7 +678,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
||||
if decimal_digit_char!(c) {
|
||||
Ok(c)
|
||||
} else {
|
||||
Err(ParserError::ParseBigInt(self.line_num, self.col_num))
|
||||
Err(ParserError::ParseBigInt(self.loc_to_err_src()))
|
||||
}
|
||||
} else {
|
||||
Ok(c)
|
||||
@@ -1038,7 +1044,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
||||
}
|
||||
|
||||
if c == '\u{0}' {
|
||||
return Err(ParserError::unexpected_eof());
|
||||
return Err(ParserError::unexpected_eof(self.loc_to_err_src()));
|
||||
}
|
||||
|
||||
self.name_token(c)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,7 +19,7 @@ pub struct RawBlock<T: RawBlockTraits> {
|
||||
|
||||
impl<T: RawBlockTraits> RawBlock<T> {
|
||||
#[inline]
|
||||
fn empty_block() -> Self {
|
||||
pub(crate) fn empty_block() -> Self {
|
||||
RawBlock {
|
||||
base: ptr::null(),
|
||||
top: ptr::null(),
|
||||
|
||||
272
src/read.rs
272
src/read.rs
@@ -2,19 +2,12 @@ use crate::parser::ast::*;
|
||||
use crate::parser::parser::*;
|
||||
|
||||
use crate::atom_table::*;
|
||||
use crate::forms::*;
|
||||
use crate::iterators::*;
|
||||
use crate::machine::heap::*;
|
||||
use crate::machine::machine_errors::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::machine::machine_state::MachineState;
|
||||
use crate::machine::machine_state::{MachineState, copy_and_align_iter};
|
||||
use crate::machine::streams::*;
|
||||
use crate::parser::char_reader::*;
|
||||
#[cfg(feature = "repl")]
|
||||
use crate::repl_helper::Helper;
|
||||
use crate::types::*;
|
||||
|
||||
use fxhash::FxBuildHasher;
|
||||
|
||||
#[cfg(feature = "repl")]
|
||||
use rustyline::error::ReadlineError;
|
||||
@@ -23,14 +16,11 @@ use rustyline::history::DefaultHistory;
|
||||
#[cfg(feature = "repl")]
|
||||
use rustyline::{Config, Editor};
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::io::{Cursor, Read};
|
||||
#[cfg(feature = "repl")]
|
||||
use std::io::{Error, ErrorKind};
|
||||
use std::sync::Arc;
|
||||
|
||||
type SubtermDeque = VecDeque<(usize, usize)>;
|
||||
|
||||
pub(crate) fn devour_whitespace<R: CharRead>(
|
||||
parser: &mut Parser<'_, R>,
|
||||
) -> Result<bool, ParserError> {
|
||||
@@ -41,46 +31,72 @@ pub(crate) fn devour_whitespace<R: CharRead>(
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn error_after_read_term<R>(
|
||||
pub(crate) fn error_after_read_term(
|
||||
err: ParserError,
|
||||
prior_num_lines_read: usize,
|
||||
parser: &Parser<R>,
|
||||
) -> CompilationError {
|
||||
if err.is_unexpected_eof() {
|
||||
let line_num = parser.lexer.line_num;
|
||||
let col_num = parser.lexer.col_num;
|
||||
let ParserErrorSrc { line_num, col_num } = err.err_src();
|
||||
|
||||
// rough overlap with errors 8.14.1.3 k) & l) of the ISO standard here
|
||||
if !(line_num == prior_num_lines_read && col_num == 0) {
|
||||
return CompilationError::from(ParserError::IncompleteReduction(line_num, col_num));
|
||||
return CompilationError::from(ParserError::IncompleteReduction(err.err_src()));
|
||||
}
|
||||
}
|
||||
|
||||
CompilationError::from(err)
|
||||
}
|
||||
|
||||
impl FocusedHeap {
|
||||
pub fn to_machine_heap(mut self, machine_st: &mut MachineState) -> TermWriteResult {
|
||||
let heap_len = machine_st.heap.len();
|
||||
machine_st.heap.extend(copy_and_align_iter(self.heap.drain(..), 0, heap_len as i64));
|
||||
|
||||
let mut var_locs = VarLocs::default();
|
||||
|
||||
for (var_loc, var_ptrs) in self.var_locs.drain(..) {
|
||||
var_locs.insert(var_loc + heap_len, var_ptrs);
|
||||
}
|
||||
|
||||
TermWriteResult {
|
||||
heap_loc: self.focus + heap_len,
|
||||
var_locs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MachineState {
|
||||
pub(crate) fn read(
|
||||
pub(crate) fn read<R: CharRead>(
|
||||
&mut self,
|
||||
inner: R,
|
||||
op_dir: &OpDir,
|
||||
) -> Result<(FocusedHeap, usize), ParserError> {
|
||||
let mut parser = Parser::new(inner, self);
|
||||
let op_dir = CompositeOpDir::new(op_dir, None);
|
||||
|
||||
let term_result = parser.read_term(&op_dir, Tokens::Default);
|
||||
let lines_read = parser.lines_read();
|
||||
|
||||
term_result.map(|term| (term, lines_read))
|
||||
}
|
||||
|
||||
pub(crate) fn read_to_heap(
|
||||
&mut self,
|
||||
mut inner: Stream,
|
||||
op_dir: &OpDir,
|
||||
) -> Result<TermWriteResult, CompilationError> {
|
||||
let (term, num_lines_read) = {
|
||||
let prior_num_lines_read = inner.lines_read();
|
||||
let mut parser = Parser::new(inner, self);
|
||||
let op_dir = CompositeOpDir::new(op_dir, None);
|
||||
|
||||
parser.add_lines_read(prior_num_lines_read);
|
||||
|
||||
let term = parser
|
||||
.read_term(&op_dir, Tokens::Default)
|
||||
.map_err(|err| error_after_read_term(err, prior_num_lines_read, &parser))?; // CompilationError::from
|
||||
|
||||
(term, parser.lines_read() - prior_num_lines_read)
|
||||
let prior_num_lines_read = inner.lines_read();
|
||||
let term = match self.read(inner, op_dir) {
|
||||
Ok((term, num_lines_read)) => {
|
||||
inner.add_lines_read(num_lines_read);
|
||||
term
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(error_after_read_term(e, prior_num_lines_read));
|
||||
}
|
||||
};
|
||||
|
||||
inner.add_lines_read(num_lines_read);
|
||||
write_term_to_heap(&term, &mut self.heap, &self.atom_tbl)
|
||||
Ok(term.to_machine_heap(self))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +295,6 @@ impl CharRead for ReadlineStream {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn consume(&mut self, nread: usize) {
|
||||
self.pending_input.consume(nread);
|
||||
@@ -291,199 +306,8 @@ impl CharRead for ReadlineStream {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn write_term_to_heap(
|
||||
term: &Term,
|
||||
heap: &mut Heap,
|
||||
atom_tbl: &AtomTable,
|
||||
) -> Result<TermWriteResult, CompilationError> {
|
||||
let term_writer = TermWriter::new(heap, atom_tbl);
|
||||
term_writer.write_term_to_heap(term)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct TermWriter<'a, 'b> {
|
||||
heap: &'a mut Heap,
|
||||
atom_tbl: &'b AtomTable,
|
||||
queue: SubtermDeque,
|
||||
var_dict: HeapVarDict,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TermWriteResult {
|
||||
pub heap_loc: usize,
|
||||
pub var_dict: HeapVarDict,
|
||||
}
|
||||
|
||||
impl<'a, 'b> TermWriter<'a, 'b> {
|
||||
#[inline]
|
||||
fn new(heap: &'a mut Heap, atom_tbl: &'b AtomTable) -> Self {
|
||||
TermWriter {
|
||||
heap,
|
||||
atom_tbl,
|
||||
queue: SubtermDeque::new(),
|
||||
var_dict: HeapVarDict::with_hasher(FxBuildHasher::default()),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn modify_head_of_queue(&mut self, term: &TermRef, h: usize) {
|
||||
if let Some((arity, site_h)) = self.queue.pop_front() {
|
||||
self.heap[site_h] = self.term_as_addr(term, h);
|
||||
|
||||
if arity > 1 {
|
||||
self.queue.push_front((arity - 1, site_h + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn push_stub_addr(&mut self) {
|
||||
let h = self.heap.len();
|
||||
self.heap.push(heap_loc_as_cell!(h));
|
||||
}
|
||||
|
||||
fn term_as_addr(&mut self, term: &TermRef, h: usize) -> HeapCellValue {
|
||||
match term {
|
||||
&TermRef::Cons(..) => list_loc_as_cell!(h),
|
||||
&TermRef::AnonVar(_) | &TermRef::Var(..) => heap_loc_as_cell!(h),
|
||||
TermRef::CompleteString(_, _, src) => {
|
||||
if src.as_str().is_empty() {
|
||||
empty_list_as_cell!()
|
||||
} else if self.heap[h].get_tag() == HeapCellValueTag::CStr {
|
||||
heap_loc_as_cell!(h)
|
||||
} else {
|
||||
pstr_loc_as_cell!(h)
|
||||
}
|
||||
}
|
||||
&TermRef::PartialString(..) => pstr_loc_as_cell!(h),
|
||||
&TermRef::Literal(_, _, literal) => HeapCellValue::from(*literal),
|
||||
&TermRef::Clause(_, _, _, subterms) if subterms.is_empty() => heap_loc_as_cell!(h),
|
||||
&TermRef::Clause(..) => str_loc_as_cell!(h),
|
||||
}
|
||||
}
|
||||
|
||||
fn write_term_to_heap(mut self, term: &Term) -> Result<TermWriteResult, CompilationError> {
|
||||
let heap_loc = self.heap.len();
|
||||
|
||||
for term in breadth_first_iter(term, RootIterationPolicy::Iterated) {
|
||||
let h = self.heap.len();
|
||||
|
||||
match &term {
|
||||
&TermRef::Cons(Level::Root, ..) => {
|
||||
self.queue.push_back((2, h + 1));
|
||||
self.heap.push(list_loc_as_cell!(h + 1));
|
||||
|
||||
self.push_stub_addr();
|
||||
self.push_stub_addr();
|
||||
|
||||
continue;
|
||||
}
|
||||
&TermRef::Cons(..) => {
|
||||
self.queue.push_back((2, h));
|
||||
|
||||
self.push_stub_addr();
|
||||
self.push_stub_addr();
|
||||
}
|
||||
&TermRef::Clause(Level::Root, _, name, subterms) => {
|
||||
if subterms.len() > MAX_ARITY {
|
||||
return Err(CompilationError::ExceededMaxArity);
|
||||
}
|
||||
|
||||
self.heap.push(if subterms.is_empty() {
|
||||
heap_loc_as_cell!(heap_loc + 1)
|
||||
} else {
|
||||
str_loc_as_cell!(heap_loc + 1)
|
||||
});
|
||||
|
||||
self.queue.push_back((subterms.len(), h + 2));
|
||||
let named = atom_as_cell!(name, subterms.len());
|
||||
|
||||
self.heap.push(named);
|
||||
|
||||
for _ in 0..subterms.len() {
|
||||
self.push_stub_addr();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
&TermRef::Clause(_, _, name, subterms) => {
|
||||
self.queue.push_back((subterms.len(), h + 1));
|
||||
let named = atom_as_cell!(name, subterms.len());
|
||||
|
||||
self.heap.push(named);
|
||||
|
||||
for _ in 0..subterms.len() {
|
||||
self.push_stub_addr();
|
||||
}
|
||||
}
|
||||
&TermRef::AnonVar(Level::Root) | TermRef::Literal(Level::Root, ..) => {
|
||||
let addr = self.term_as_addr(&term, h);
|
||||
self.heap.push(addr);
|
||||
}
|
||||
&TermRef::Var(Level::Root, _, ref var_ptr) => {
|
||||
let addr = self.term_as_addr(&term, h);
|
||||
self.var_dict.insert(VarKey::VarPtr(var_ptr.clone()), addr);
|
||||
self.heap.push(addr);
|
||||
}
|
||||
&TermRef::AnonVar(_) => {
|
||||
if let Some((arity, site_h)) = self.queue.pop_front() {
|
||||
self.var_dict
|
||||
.insert(VarKey::AnonVar(h), heap_loc_as_cell!(site_h));
|
||||
|
||||
if arity > 1 {
|
||||
self.queue.push_front((arity - 1, site_h + 1));
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
TermRef::CompleteString(_, _, src) => {
|
||||
let src = src.as_str().to_owned();
|
||||
put_complete_string(self.heap, &src, self.atom_tbl);
|
||||
}
|
||||
&TermRef::PartialString(lvl, _, src, _) => {
|
||||
if let Level::Root = lvl {
|
||||
// Var tags can't refer directly to partial strings,
|
||||
// so a PStrLoc cell must be pushed.
|
||||
self.heap.push(pstr_loc_as_cell!(heap_loc + 1));
|
||||
}
|
||||
|
||||
allocate_pstr(self.heap, src.as_str(), self.atom_tbl);
|
||||
|
||||
let h = self.heap.len();
|
||||
self.queue.push_back((1, h - 1));
|
||||
|
||||
if let Level::Root = lvl {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
TermRef::Var(.., var) => {
|
||||
if let Some((arity, site_h)) = self.queue.pop_front() {
|
||||
let var_key = VarKey::VarPtr(var.clone());
|
||||
|
||||
if let Some(addr) = self.var_dict.get(&var_key).cloned() {
|
||||
self.heap[site_h] = addr;
|
||||
} else {
|
||||
self.var_dict.insert(var_key, heap_loc_as_cell!(site_h));
|
||||
}
|
||||
|
||||
if arity > 1 {
|
||||
self.queue.push_front((arity - 1, site_h + 1));
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
self.modify_head_of_queue(&term, h);
|
||||
}
|
||||
|
||||
Ok(TermWriteResult {
|
||||
heap_loc,
|
||||
var_dict: self.var_dict,
|
||||
})
|
||||
}
|
||||
pub var_locs: VarLocs,
|
||||
}
|
||||
|
||||
@@ -3,17 +3,12 @@ use crate::parser::ast::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
use crate::iterators::*;
|
||||
use crate::types::*;
|
||||
|
||||
pub(crate) struct FactInstruction;
|
||||
pub(crate) struct QueryInstruction;
|
||||
|
||||
pub(crate) trait CompilationTarget<'a> {
|
||||
type Iterator: Iterator<Item = TermRef<'a>>;
|
||||
|
||||
fn iter(term: &'a Term) -> Self::Iterator;
|
||||
|
||||
fn to_constant(lvl: Level, literal: Literal, r: RegType) -> Instruction;
|
||||
fn to_list(lvl: Level, r: RegType) -> Instruction;
|
||||
fn to_structure(lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction;
|
||||
@@ -41,12 +36,6 @@ pub(crate) trait CompilationTarget<'a> {
|
||||
}
|
||||
|
||||
impl<'a> CompilationTarget<'a> for FactInstruction {
|
||||
type Iterator = FactIterator<'a>;
|
||||
|
||||
fn iter(term: &'a Term) -> Self::Iterator {
|
||||
breadth_first_iter(term, RootIterationPolicy::NotIterated)
|
||||
}
|
||||
|
||||
fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
|
||||
Instruction::GetConstant(lvl, HeapCellValue::from(constant), reg)
|
||||
}
|
||||
@@ -115,12 +104,6 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
|
||||
}
|
||||
|
||||
impl<'a> CompilationTarget<'a> for QueryInstruction {
|
||||
type Iterator = QueryIterator<'a>;
|
||||
|
||||
fn iter(term: &'a Term) -> Self::Iterator {
|
||||
post_order_iter(term)
|
||||
}
|
||||
|
||||
fn to_structure(_lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction {
|
||||
Instruction::PutStructure(name, arity, r)
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ test_queries_on_builtins :-
|
||||
\+ float([1,2,_]),
|
||||
\+ (X is 3 rdiv 4, float(X)),
|
||||
\+ \+ (X is 3 rdiv 4, rational(X)),
|
||||
\+ rational(3),
|
||||
rational(3),
|
||||
\+ rational(f(_)),
|
||||
\+ rational("sdfa"),
|
||||
\+ rational(atom),
|
||||
|
||||
@@ -87,7 +87,7 @@ pub enum VarAlloc {
|
||||
safety: VarSafetyStatus,
|
||||
to_perm_var_num: Option<usize>,
|
||||
},
|
||||
Perm(usize, PermVarAllocation), // stack offset, allocation info
|
||||
Perm { reg: usize, allocation: PermVarAllocation }, // stack offset, allocation info
|
||||
}
|
||||
|
||||
impl VarAlloc {
|
||||
@@ -95,14 +95,14 @@ impl VarAlloc {
|
||||
pub(crate) fn as_reg_type(&self) -> RegType {
|
||||
match *self {
|
||||
VarAlloc::Temp { temp_reg, .. } => RegType::Temp(temp_reg),
|
||||
VarAlloc::Perm(r, _) => RegType::Perm(r),
|
||||
VarAlloc::Perm { reg, .. } => RegType::Perm(reg),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn set_register(&mut self, reg_num: usize) {
|
||||
match self {
|
||||
VarAlloc::Perm(ref mut p, _) => *p = reg_num,
|
||||
VarAlloc::Perm { ref mut reg, .. } => *reg = reg_num,
|
||||
VarAlloc::Temp {
|
||||
ref mut temp_reg, ..
|
||||
} => *temp_reg = reg_num,
|
||||
@@ -151,7 +151,7 @@ pub struct VariableRecord {
|
||||
impl Default for VariableRecord {
|
||||
fn default() -> Self {
|
||||
VariableRecord {
|
||||
allocation: VarAlloc::Perm(0, PermVarAllocation::Pending),
|
||||
allocation: VarAlloc::Perm { reg: 0, allocation: PermVarAllocation::Pending },
|
||||
num_occurrences: 0,
|
||||
running_count: 0,
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ fn hello_world() {
|
||||
fn syntax_error() {
|
||||
load_module_test(
|
||||
"tests-pl/syntax_error.pl",
|
||||
" error(syntax_error(incomplete_reduction),read_term/3:6).\n",
|
||||
" error(syntax_error(incomplete_reduction),read_term/3:3).\n",
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user