use new heap term representation

This commit is contained in:
Mark Thom
2021-11-14 13:39:56 -07:00
parent d0b74a95f4
commit 0404c3bd94
72 changed files with 26285 additions and 17019 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,15 @@
use crate::heap_iter::*;
use crate::machine::*;
use prolog_parser::temp_v;
use crate::parser::ast::*;
use crate::temp_v;
use crate::types::*;
use indexmap::IndexSet;
use std::cmp::Ordering;
use std::vec::IntoIter;
pub(super) type Bindings = Vec<(usize, Addr)>;
pub(super) type Bindings = Vec<(usize, HeapCellValue)>;
#[derive(Debug)]
pub(super) struct AttrVarInitializer {
@@ -37,7 +39,7 @@ impl AttrVarInitializer {
}
impl MachineState {
pub(super) fn push_attr_var_binding(&mut self, h: usize, addr: Addr) {
pub(super) fn push_attr_var_binding(&mut self, h: usize, addr: HeapCellValue) {
if self.attr_var_init.bindings.is_empty() {
self.attr_var_init.instigating_p = self.p.local();
@@ -53,28 +55,24 @@ impl MachineState {
self.attr_var_init.bindings.push((h, addr));
}
fn populate_var_and_value_lists(&mut self) -> (Addr, Addr) {
fn populate_var_and_value_lists(&mut self) -> (HeapCellValue, HeapCellValue) {
let iter = self
.attr_var_init
.bindings
.iter()
.map(|(ref h, _)| HeapCellValue::Addr(Addr::AttrVar(*h)));
.map(|(ref h, _)| attr_var_as_cell!(*h));
let var_list_addr = Addr::HeapCell(self.heap.to_list(iter));
let var_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter));
let iter = self
.attr_var_init
.bindings
.drain(0..)
.map(|(_, addr)| HeapCellValue::Addr(addr));
let iter = self.attr_var_init.bindings.drain(0..).map(|(_, ref v)| *v);
let value_list_addr = Addr::HeapCell(self.heap.to_list(iter));
let value_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter));
(var_list_addr, value_list_addr)
}
fn verify_attributes(&mut self) {
for (h, _) in &self.attr_var_init.bindings {
self.heap[*h] = HeapCellValue::Addr(Addr::AttrVar(*h));
self.heap[*h] = attr_var_as_cell!(*h);
}
let (var_list_addr, value_list_addr) = self.populate_var_and_value_lists();
@@ -83,19 +81,26 @@ impl MachineState {
self[temp_v!(2)] = value_list_addr;
}
pub(super) fn gather_attr_vars_created_since(&self, b: usize) -> IntoIter<Addr> {
pub(super) fn gather_attr_vars_created_since(&mut self, b: usize) -> IntoIter<HeapCellValue> {
let mut attr_vars: Vec<_> = self.attr_var_init.attr_var_queue[b..]
.iter()
.filter_map(|h| match self.store(self.deref(Addr::HeapCell(*h))) {
Addr::AttrVar(h) => Some(Addr::AttrVar(h)),
_ => None,
.filter_map(|h| {
read_heap_cell!(self.store(self.deref(heap_loc_as_cell!(*h))), //Addr::HeapCell(*h))) {
(HeapCellValueTag::AttrVar, h) => {
Some(attr_var_as_cell!(h))
}
_ => {
None
}
)
})
.collect();
attr_vars
.sort_unstable_by(|a1, a2| self.compare_term_test(a1, a2).unwrap_or(Ordering::Less));
attr_vars.sort_unstable_by(|a1, a2| {
compare_term_test!(self, *a1, *a2).unwrap_or(Ordering::Less)
});
self.term_dedup(&mut attr_vars);
attr_vars.dedup();
attr_vars.into_iter()
}
@@ -109,8 +114,10 @@ impl MachineState {
self.stack.index_and_frame_mut(e)[i] = self[RegType::Temp(i)];
}
self.stack.index_and_frame_mut(e)[self.num_of_args + 1] = Addr::CutPoint(self.b0);
self.stack.index_and_frame_mut(e)[self.num_of_args + 2] = Addr::Usize(self.num_of_args);
self.stack.index_and_frame_mut(e)[self.num_of_args + 1] =
fixnum_as_cell!(Fixnum::build_with(self.b0 as i64));
self.stack.index_and_frame_mut(e)[self.num_of_args + 2] =
fixnum_as_cell!(Fixnum::build_with(self.num_of_args as i64));
self.verify_attributes();
@@ -119,33 +126,51 @@ impl MachineState {
self.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
}
pub(super) fn attr_vars_of_term(&self, addr: Addr) -> Vec<Addr> {
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 mut iter = self.acyclic_pre_order_iter(addr);
let mut iter = stackful_preorder_iter(&mut self.heap, cell);
while let Some(addr) = iter.next() {
if let HeapCellValue::Addr(Addr::AttrVar(h)) = self.heap.index_addr(&addr).as_ref() {
if seen_set.contains(h) {
continue;
while let Some(value) = iter.next() {
read_heap_cell!(value,
(HeapCellValueTag::AttrVar, h) => {
if seen_set.contains(&h) {
continue;
}
seen_vars.push(value);
seen_set.insert(h);
let mut l = h + 1;
// let mut list_elements = vec![];
// let iter_stack_len = iter.stack_len();
loop {
read_heap_cell!(iter.heap[l],
(HeapCellValueTag::Lis) => {
iter.push_stack(l);
// l = elem + 1;
break;
}
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
if h == l {
break;
} else {
l = h;
}
}
_ => {
break;
}
)
}
// iter.stack_slice_from(iter_stack_len ..).reverse();
}
seen_vars.push(addr);
seen_set.insert(*h);
let mut l = h + 1;
let mut list_elements = vec![];
while let Addr::Lis(elem) = self.store(self.deref(Addr::HeapCell(l))) {
list_elements.push(self.heap[elem].as_addr(elem));
l = elem + 1;
_ => {
}
for element in list_elements.into_iter().rev() {
iter.stack().push(element);
}
}
);
}
seen_vars

View File

@@ -3,7 +3,7 @@ use crate::instructions::*;
use crate::machine::machine_indices::*;
#[derive(Debug)]
pub(crate) struct CodeRepo {
pub struct CodeRepo {
pub(super) code: Code,
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,6 @@
use crate::machine::machine_indices::*;
use crate::atom_table::*;
use crate::machine::stack::*;
use crate::types::*;
use std::mem;
use std::ops::IndexMut;
@@ -7,20 +8,24 @@ use std::ops::IndexMut;
type Trail = Vec<(Ref, HeapCellValue)>;
#[derive(Debug, Clone, Copy)]
pub(crate) enum AttrVarPolicy {
pub enum AttrVarPolicy {
DeepCopy,
StripAttributes,
}
pub(crate) trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
fn deref(&self, val: Addr) -> Addr;
fn push(&mut self, val: HeapCellValue);
pub trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
fn store(&self, value: HeapCellValue) -> HeapCellValue;
fn deref(&self, value: HeapCellValue) -> HeapCellValue;
fn push(&mut self, value: HeapCellValue);
fn stack(&mut self) -> &mut Stack;
fn store(&self, val: Addr) -> Addr;
fn threshold(&self) -> usize;
}
pub(crate) fn copy_term<T: CopierTarget>(target: T, addr: Addr, attr_var_policy: AttrVarPolicy) {
pub(crate) fn copy_term<T: CopierTarget>(
target: T,
addr: HeapCellValue,
attr_var_policy: AttrVarPolicy,
) {
let mut copy_term_state = CopyTermState::new(target, attr_var_policy);
copy_term_state.copy_term_impl(addr);
}
@@ -47,50 +52,51 @@ impl<T: CopierTarget> CopyTermState<T> {
#[inline]
fn value_at_scan(&mut self) -> &mut HeapCellValue {
let scan = self.scan;
&mut self.target[scan]
&mut self.target[self.scan]
}
fn trail_list_cell(&mut self, addr: usize, threshold: usize) {
let trail_item = mem::replace(
&mut self.target[addr],
HeapCellValue::Addr(Addr::Lis(threshold)),
);
self.trail.push((Ref::HeapCell(addr), trail_item));
let trail_item = mem::replace(&mut self.target[addr], list_loc_as_cell!(threshold));
self.trail.push((Ref::heap_cell(addr), trail_item));
}
fn copy_list(&mut self, addr: usize) {
for offset in 0..2 {
if let Addr::Lis(h) = self.target[addr + offset].as_addr(addr + offset) {
if h >= self.old_h {
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(h));
self.scan += 1;
read_heap_cell!(self.target[addr + offset],
(HeapCellValueTag::Lis, h) => {
if h >= self.old_h {
*self.value_at_scan() = list_loc_as_cell!(h);
self.scan += 1;
return;
return;
}
}
}
_ => {
}
)
}
let threshold = self.target.threshold();
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(threshold));
*self.value_at_scan() = list_loc_as_cell!(threshold);
for i in 0..2 {
let hcv = self.target[addr + i].context_free_clone();
let hcv = self.target[addr + i];
self.target.push(hcv);
}
let cdr = self
.target
.store(self.target.deref(Addr::HeapCell(addr + 1)));
.store(self.target.deref(heap_loc_as_cell!(addr + 1)));
if !cdr.is_ref() {
if !cdr.is_var() {
self.trail_list_cell(addr + 1, threshold);
} else {
let car = self.target.store(self.target.deref(Addr::HeapCell(addr)));
let car = self
.target
.store(self.target.deref(heap_loc_as_cell!(addr)));
if !car.is_ref() {
if !car.is_var() {
self.trail_list_cell(addr, threshold);
}
}
@@ -98,187 +104,208 @@ impl<T: CopierTarget> CopyTermState<T> {
self.scan += 1;
}
fn copy_partial_string(&mut self, addr: usize, n: usize) {
if let &HeapCellValue::Addr(Addr::PStrLocation(h, _)) = &self.target[addr] {
if h >= self.old_h {
*self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(h, n));
self.scan += 1;
fn copy_partial_string(&mut self, scan_tag: HeapCellValueTag, pstr_loc: usize) {
read_heap_cell!(self.target[pstr_loc],
(HeapCellValueTag::PStrLoc, h) => {
if h >= self.old_h {
*self.value_at_scan() = match scan_tag {
HeapCellValueTag::PStrLoc => {
pstr_loc_as_cell!(h)
}
tag => {
debug_assert!(tag == HeapCellValueTag::PStrOffset);
pstr_offset_as_cell!(h)
}
};
return;
self.scan += 1;
return;
}
}
}
_ => {}
);
let threshold = self.target.threshold();
*self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(threshold, n));
*self.value_at_scan() = pstr_loc_as_cell!(threshold);
self.scan += 1;
let (pstr, has_tail) = match &self.target[addr] {
&HeapCellValue::PartialString(ref pstr, has_tail) => {
(pstr.clone_from_offset(0), has_tail)
}
_ => {
unreachable!()
}
};
self.target.push(self.target[pstr_loc]);
self.target
.push(HeapCellValue::PartialString(pstr, has_tail));
let replacement = pstr_loc_as_cell!(threshold);
let trail_item = mem::replace(&mut self.target[pstr_loc], replacement);
let replacement = HeapCellValue::Addr(Addr::PStrLocation(threshold, n));
let trail_item = mem::replace(&mut self.target[addr], replacement);
self.trail.push((Ref::HeapCell(addr), trail_item));
if has_tail {
let tail_addr = self.target[addr + 1].as_addr(addr + 1);
self.target.push(HeapCellValue::Addr(tail_addr));
}
self.trail.push((Ref::heap_cell(pstr_loc), trail_item));
self.target.push(self.target[pstr_loc + 1]);
}
fn reinstantiate_var(&mut self, addr: Addr, frontier: usize) {
match addr {
Addr::HeapCell(h) => {
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier));
self.target[h] = HeapCellValue::Addr(Addr::HeapCell(frontier));
fn reinstantiate_var(&mut self, addr: HeapCellValue, frontier: usize) {
read_heap_cell!(addr,
(HeapCellValueTag::Var, h) => {
self.target[frontier] = heap_loc_as_cell!(frontier);
self.target[h] = heap_loc_as_cell!(frontier);
self.trail
.push((Ref::HeapCell(h), HeapCellValue::Addr(Addr::HeapCell(h))));
self.trail.push((Ref::heap_cell(h), heap_loc_as_cell!(h)));
}
Addr::StackCell(fr, sc) => {
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier));
self.target.stack().index_and_frame_mut(fr)[sc] = Addr::HeapCell(frontier);
(HeapCellValueTag::StackVar, s) => {
self.target[frontier] = heap_loc_as_cell!(frontier);
self.target.stack()[s] = heap_loc_as_cell!(frontier);
self.trail.push((
Ref::StackCell(fr, sc),
HeapCellValue::Addr(Addr::StackCell(fr, sc)),
));
self.trail.push((Ref::stack_cell(s), stack_loc_as_cell!(s)));
}
Addr::AttrVar(h) => {
(HeapCellValueTag::AttrVar, h) => {
let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
self.target.threshold()
} else {
frontier
};
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(threshold));
self.target[h] = HeapCellValue::Addr(Addr::HeapCell(threshold));
self.target[frontier] = heap_loc_as_cell!(threshold);
self.target[h] = heap_loc_as_cell!(threshold);
self.trail
.push((Ref::AttrVar(h), HeapCellValue::Addr(Addr::AttrVar(h))));
self.trail.push((Ref::attr_var(h), attr_var_as_cell!(h)));
if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
self.target
.push(HeapCellValue::Addr(Addr::AttrVar(threshold)));
.push(attr_var_as_cell!(threshold));
let list_val = self.target[h + 1].context_free_clone();
let list_val = self.target[h + 1];
self.target.push(list_val);
}
}
_ => {
unreachable!()
}
);
}
fn copy_var(&mut self, addr: HeapCellValue) {
let rd = self.target.deref(addr);
let ra = self.target.store(rd);
read_heap_cell!(ra,
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
if h >= self.old_h {
*self.value_at_scan() = rd;
self.scan += 1;
return;
}
}
_ => {}
);
if addr == ra {
self.reinstantiate_var(addr, self.scan);
self.scan += 1;
} else {
*self.value_at_scan() = ra;
// self.copy_compound(rd, ra);
}
}
fn copy_var(&mut self, addr: Addr) {
let rd = self.target.store(self.target.deref(addr));
/*
fn copy_compound(&mut self, rd: HeapCellValue, ra: HeapCellValue) {
let h = rd.get_value();
let trail_item = self.target[h];
let threshold = self.target.threshold();
match rd {
Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => {
*self.value_at_scan() = HeapCellValue::Addr(rd);
self.scan += 1;
self.trail.push((Ref::heap_cell(h), trail_item));
self.target[self.scan].set_value(threshold);
read_heap_cell!(ra,
(HeapCellValueTag::Atom, (_name, arity)) => {
self.target.push(ra);
for i in 0..arity {
self.target.push(self.target[h + 1 + i]);
}
self.target[h] = str_loc_as_cell!(self.scan + 1);
}
_ if addr == rd => {
self.reinstantiate_var(addr, self.scan);
self.scan += 1;
(HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
self.target.push(ra);
self.target.push(self.target[h + 1]);
self.target[h] = pstr_loc_as_cell!(self.scan + 1);
}
(HeapCellValueTag::CStr, cstr_atom) => {
self.target[h] = atom_as_cstr_cell!(cstr_atom);
}
(HeapCellValueTag::Str, s) => {
self.copy_structure(s);
return;
}
_ => {
*self.value_at_scan() = HeapCellValue::Addr(rd);
*self.value_at_scan() = rd;
self.trail.pop();
return;
}
}
);
self.scan += 1;
}
*/
fn copy_structure(&mut self, addr: usize) {
match self.target[addr].context_free_clone() {
HeapCellValue::NamedStr(arity, name, fixity) => {
read_heap_cell!(self.target[addr],
(HeapCellValueTag::Atom, (name, arity)) => {
let threshold = self.target.threshold();
*self.value_at_scan() = HeapCellValue::Addr(Addr::Str(threshold));
*self.value_at_scan() = str_loc_as_cell!(threshold);
let trail_item = mem::replace(
&mut self.target[addr],
HeapCellValue::Addr(Addr::Str(threshold)),
str_loc_as_cell!(threshold),
);
self.trail.push((Ref::HeapCell(addr), trail_item));
self.target
.push(HeapCellValue::NamedStr(arity, name, fixity));
self.trail.push((Ref::heap_cell(addr), trail_item));
self.target.push(atom_as_cell!(name, arity));
for i in 0..arity {
let hcv = self.target[addr + 1 + i].context_free_clone();
let hcv = self.target[addr + 1 + i];
self.target.push(hcv);
}
}
HeapCellValue::Addr(Addr::Str(addr)) => {
*self.value_at_scan() = HeapCellValue::Addr(Addr::Str(addr))
(HeapCellValueTag::Str, h) => {
*self.value_at_scan() = str_loc_as_cell!(h);
}
_ => {
unreachable!()
}
}
);
self.scan += 1;
}
fn copy_term_impl(&mut self, addr: Addr) {
fn copy_term_impl(&mut self, addr: HeapCellValue) {
self.scan = self.target.threshold();
self.target.push(HeapCellValue::Addr(addr));
self.target.push(addr);
while self.scan < self.target.threshold() {
match self.value_at_scan() {
&mut HeapCellValue::Addr(addr) => match addr {
Addr::Con(h) => {
let addr = self.target[h].as_addr(h);
let addr = *self.value_at_scan();
if addr == Addr::Con(h) {
*self.value_at_scan() = self.target[h].context_free_clone();
} else {
*self.value_at_scan() = HeapCellValue::Addr(addr);
}
}
Addr::Lis(h) => {
if h >= self.old_h {
self.scan += 1;
} else {
self.copy_list(h);
}
}
addr @ Addr::AttrVar(_)
| addr @ Addr::HeapCell(_)
| addr @ Addr::StackCell(..) => {
self.copy_var(addr);
}
Addr::Str(addr) => {
self.copy_structure(addr);
}
Addr::PStrLocation(addr, n) => {
self.copy_partial_string(addr, n);
}
Addr::Stream(h) => {
*self.value_at_scan() = self.target[h].context_free_clone();
}
_ => {
read_heap_cell!(addr,
(HeapCellValueTag::Lis, h) => {
if h >= self.old_h {
self.scan += 1;
} else {
self.copy_list(h);
}
},
}
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var) => {
self.copy_var(addr);
}
(HeapCellValueTag::Str, h) => {
self.copy_structure(h);
}
(HeapCellValueTag::PStrLoc | HeapCellValueTag::PStrOffset, pstr_loc) => {
self.copy_partial_string(addr.get_tag(), pstr_loc);
}
_ => {
self.scan += 1;
}
}
);
}
self.unwind_trail();
@@ -286,12 +313,117 @@ impl<T: CopierTarget> CopyTermState<T> {
fn unwind_trail(&mut self) {
for (r, value) in self.trail.drain(0..) {
match r {
Ref::AttrVar(h) | Ref::HeapCell(h) => self.target[h] = value,
Ref::StackCell(fr, sc) => {
self.target.stack().index_and_frame_mut(fr)[sc] = value.as_addr(0)
}
let index = r.get_value() as usize;
match r.get_tag() {
RefTag::AttrVar | RefTag::HeapCell => self.target[index] = value,
RefTag::StackCell => self.target.stack()[index] = value,
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::machine::mock_wam::*;
#[test]
fn copier_tests() {
let mut wam = MockWAM::new();
let f_atom = atom!("f");
let a_atom = atom!("a");
let b_atom = atom!("b");
wam.machine_st.heap
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 2));
assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom));
assert_eq!(wam.machine_st.heap[2], atom_as_cell!(b_atom));
{
let wam = TermCopyingMockWAM { wam: &mut wam };
copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy);
}
// check that the original heap state is still intact.
assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 2));
assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom));
assert_eq!(wam.machine_st.heap[2], atom_as_cell!(b_atom));
assert_eq!(wam.machine_st.heap[3], str_loc_as_cell!(4));
assert_eq!(wam.machine_st.heap[4], atom_as_cell!(f_atom, 2));
assert_eq!(wam.machine_st.heap[5], atom_as_cell!(a_atom));
assert_eq!(wam.machine_st.heap[6], atom_as_cell!(b_atom));
wam.machine_st.heap.clear();
let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl);
let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
wam.machine_st.heap.pop();
wam.machine_st.heap.push(pstr_loc_as_cell!(2));
let pstr_second_var_cell = put_partial_string(&mut wam.machine_st.heap, "def", &mut 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.pop();
wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1));
wam.machine_st.heap.push(pstr_offset_as_cell!(0));
wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0i64)));
{
let wam = TermCopyingMockWAM { wam: &mut wam };
copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy);
}
print_heap_terms(wam.machine_st.heap[6..].iter(), 6);
assert_eq!(wam.machine_st.heap[0], pstr_cell);
assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(2));
assert_eq!(wam.machine_st.heap[2], pstr_second_cell);
assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(4));
assert_eq!(wam.machine_st.heap[4], pstr_offset_as_cell!(0));
assert_eq!(wam.machine_st.heap[5], fixnum_as_cell!(Fixnum::build_with(0i64)));
assert_eq!(wam.machine_st.heap[7], pstr_cell);
assert_eq!(wam.machine_st.heap[8], pstr_loc_as_cell!(9));
assert_eq!(wam.machine_st.heap[9], pstr_second_cell);
assert_eq!(wam.machine_st.heap[10], pstr_loc_as_cell!(11));
assert_eq!(wam.machine_st.heap[11], pstr_offset_as_cell!(7));
assert_eq!(wam.machine_st.heap[12], fixnum_as_cell!(Fixnum::build_with(0i64)));
wam.machine_st.heap.clear();
wam.machine_st.heap.extend(functor!(
f_atom,
[
atom(a_atom),
atom(b_atom),
atom(a_atom),
cell(str_loc_as_cell!(0))
]
));
{
let wam = TermCopyingMockWAM { wam: &mut wam };
copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy);
}
assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 4));
assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom));
assert_eq!(wam.machine_st.heap[2], atom_as_cell!(b_atom));
assert_eq!(wam.machine_st.heap[3], atom_as_cell!(a_atom));
assert_eq!(wam.machine_st.heap[4], str_loc_as_cell!(0));
assert_eq!(wam.machine_st.heap[5], str_loc_as_cell!(6));
assert_eq!(wam.machine_st.heap[6], atom_as_cell!(f_atom, 4));
assert_eq!(wam.machine_st.heap[7], atom_as_cell!(a_atom));
assert_eq!(wam.machine_st.heap[8], atom_as_cell!(b_atom));
assert_eq!(wam.machine_st.heap[9], atom_as_cell!(a_atom));
assert_eq!(wam.machine_st.heap[10], str_loc_as_cell!(6));
}
}

1101
src/machine/gc.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,140 +1,282 @@
use core::marker::PhantomData;
use prolog_parser::ast::Constant;
use crate::arena::*;
use crate::atom_table::*;
use crate::forms::*;
use crate::machine::machine_indices::*;
use crate::machine::partial_string::*;
use crate::machine::raw_block::*;
use crate::parser::ast::*;
use crate::types::*;
use ordered_float::OrderedFloat;
use rug::{Integer, Rational};
use std::convert::TryFrom;
use std::mem;
use std::ops::{Index, IndexMut};
use std::ptr;
#[derive(Debug)]
pub(crate) struct StandardHeapTraits {}
pub(crate) type Heap = Vec<HeapCellValue>;
impl RawBlockTraits for StandardHeapTraits {
impl From<Literal> for HeapCellValue {
#[inline]
fn init_size() -> usize {
256 * mem::size_of::<HeapCellValue>()
}
#[inline]
fn align() -> usize {
mem::align_of::<HeapCellValue>()
}
}
#[derive(Debug)]
pub(crate) struct HeapTemplate<T: RawBlockTraits> {
buf: RawBlock<T>,
_marker: PhantomData<HeapCellValue>,
}
pub(crate) type Heap = HeapTemplate<StandardHeapTraits>;
impl<T: RawBlockTraits> Drop for HeapTemplate<T> {
fn drop(&mut self) {
self.clear();
self.buf.deallocate();
}
}
#[derive(Debug)]
pub(crate) struct HeapIntoIter<T: RawBlockTraits> {
offset: usize,
buf: RawBlock<T>,
}
impl<T: RawBlockTraits> Drop for HeapIntoIter<T> {
fn drop(&mut self) {
let mut heap = HeapTemplate {
buf: self.buf.take(),
_marker: PhantomData,
};
heap.truncate(self.offset / mem::size_of::<HeapCellValue>());
heap.buf.deallocate();
}
}
impl<T: RawBlockTraits> Iterator for HeapIntoIter<T> {
type Item = HeapCellValue;
fn next(&mut self) -> Option<Self::Item> {
let ptr = self.buf.base as usize + self.offset;
self.offset += mem::size_of::<HeapCellValue>();
if ptr < self.buf.top as usize {
unsafe { Some(ptr::read(ptr as *const HeapCellValue)) }
} else {
None
fn from(literal: Literal) -> Self {
match literal {
Literal::Atom(name) => atom_as_cell!(name),
Literal::Char(c) => char_as_cell!(c),
Literal::Fixnum(n) => fixnum_as_cell!(n),
Literal::Integer(bigint_ptr) => {
typed_arena_ptr_as_cell!(bigint_ptr)
}
Literal::Rational(bigint_ptr) => {
typed_arena_ptr_as_cell!(bigint_ptr)
}
Literal::Float(f) => HeapCellValue::from(f),
Literal::String(s) => {
if s == atom!("") {
empty_list_as_cell!()
} else {
string_as_cstr_cell!(s)
}
}
}
}
}
#[derive(Debug)]
pub(crate) struct HeapIter<'a, T: RawBlockTraits> {
offset: usize,
buf: &'a RawBlock<T>,
}
impl TryFrom<HeapCellValue> for Literal {
type Error = ();
impl<'a, T: RawBlockTraits> HeapIter<'a, T> {
pub(crate) fn new(buf: &'a RawBlock<T>, offset: usize) -> Self {
HeapIter { buf, offset }
fn try_from(value: HeapCellValue) -> Result<Literal, ()> {
read_heap_cell!(value,
(HeapCellValueTag::Atom, (name, arity)) => {
if arity == 0 {
Ok(Literal::Atom(name))
} else {
Err(())
}
}
(HeapCellValueTag::Char, c) => {
Ok(Literal::Char(c))
}
(HeapCellValueTag::Fixnum, n) => {
Ok(Literal::Fixnum(n))
}
(HeapCellValueTag::F64, f) => {
Ok(Literal::Float(f))
}
(HeapCellValueTag::Cons, cons_ptr) => {
match_untyped_arena_ptr!(cons_ptr,
(ArenaHeaderTag::Integer, n) => {
Ok(Literal::Integer(n))
}
(ArenaHeaderTag::Rational, n) => {
Ok(Literal::Rational(n))
}
_ => {
Err(())
}
)
}
(HeapCellValueTag::CStr, cstr_atom) => {
Ok(Literal::String(cstr_atom))
}
_ => {
Err(())
}
)
}
}
impl<'a, T: RawBlockTraits> Iterator for HeapIter<'a, T> {
type Item = &'a HeapCellValue;
// sometimes we need to dereference variables that are found only in
// the heap without access to the full WAM (e.g., while detecting
// cycles in terms), and which therefore may only point other cells in
// the heap (thanks to the design of the WAM).
pub fn heap_bound_deref(heap: &[HeapCellValue], mut value: HeapCellValue) -> HeapCellValue {
loop {
let new_value = read_heap_cell!(value,
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
heap[h]
}
_ => {
value
}
);
fn next(&mut self) -> Option<Self::Item> {
let ptr = self.buf.base as usize + self.offset;
self.offset += mem::size_of::<HeapCellValue>();
if ptr < self.buf.top as usize {
unsafe { Some(&*(ptr as *const _)) }
} else {
None
if new_value != value && new_value.is_var() {
value = new_value;
continue;
}
return value;
}
}
pub fn heap_bound_store(heap: &[HeapCellValue], value: HeapCellValue) -> HeapCellValue {
read_heap_cell!(value,
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
heap[h]
}
_ => {
value
}
)
}
#[allow(dead_code)]
pub(crate) fn print_heap_terms<'a, I: Iterator<Item = &'a HeapCellValue>>(heap: I, h: usize) {
pub fn print_heap_terms<'a, I: Iterator<Item = &'a HeapCellValue>>(heap: I, h: usize) {
for (index, term) in heap.enumerate() {
println!("{} : {}", h + index, term);
println!("{} : {:?}", h + index, term);
}
}
#[derive(Debug)]
pub(crate) struct HeapIterMut<'a, T: RawBlockTraits> {
offset: usize,
buf: &'a mut RawBlock<T>,
}
#[inline]
pub(crate) fn put_complete_string(
heap: &mut Heap,
s: &str,
atom_tbl: &mut AtomTable,
) -> HeapCellValue {
match allocate_pstr(heap, s, atom_tbl) {
Some(h) => {
heap.pop(); // pop the trailing variable cell from the heap planted by allocate_pstr.
impl<'a, T: RawBlockTraits> HeapIterMut<'a, T> {
pub(crate) fn new(buf: &'a mut RawBlock<T>, offset: usize) -> Self {
HeapIterMut { buf, offset }
}
}
impl<'a, T: RawBlockTraits> Iterator for HeapIterMut<'a, T> {
type Item = &'a mut HeapCellValue;
fn next(&mut self) -> Option<Self::Item> {
let ptr = self.buf.base as usize + self.offset;
self.offset += mem::size_of::<HeapCellValue>();
if ptr < self.buf.top as usize {
unsafe { Some(&mut *(ptr as *mut _)) }
} else {
None
if heap.len() == h + 1 {
let pstr_atom = cell_as_atom!(heap[h]);
heap[h] = atom_as_cstr_cell!(pstr_atom);
heap_loc_as_cell!(h)
} else {
heap.push(empty_list_as_cell!());
pstr_loc_as_cell!(h)
}
}
None => {
empty_list_as_cell!()
}
}
}
#[inline]
pub(crate) fn put_partial_string(
heap: &mut Heap,
s: &str,
atom_tbl: &mut AtomTable,
) -> HeapCellValue {
match allocate_pstr(heap, s, atom_tbl) {
Some(h) => {
pstr_loc_as_cell!(h)
}
None => {
empty_list_as_cell!()
}
}
}
#[inline]
pub(crate) fn allocate_pstr(
heap: &mut Heap,
mut src: &str,
atom_tbl: &mut AtomTable,
) -> Option<usize> {
let orig_h = heap.len();
loop {
if src == "" {
return if orig_h == heap.len() {
None
} else {
let tail_h = heap.len() - 1;
heap[tail_h] = heap_loc_as_cell!(tail_h);
Some(orig_h)
};
}
let h = heap.len();
let (pstr, rest_src) = match PartialString::new(src, atom_tbl) {
Some(tuple) => tuple,
None => {
if src.len() > '\u{0}'.len_utf8() {
src = &src['\u{0}'.len_utf8()..];
continue;
} else if orig_h == h {
return None;
} else {
heap[h - 1] = heap_loc_as_cell!(h - 1);
return Some(orig_h);
}
}
};
heap.push(string_as_pstr_cell!(pstr));
if rest_src != "" {
heap.push(pstr_loc_as_cell!(h + 2));
src = rest_src;
} else {
heap.push(heap_loc_as_cell!(h + 1));
return Some(orig_h);
}
}
}
pub fn filtered_iter_to_heap_list<SrcT: Into<HeapCellValue>>(
heap: &mut Heap,
values: impl Iterator<Item = SrcT>,
filter_fn: impl Fn(&Heap, HeapCellValue) -> bool,
) -> usize {
let head_addr = heap.len();
let mut h = head_addr;
for value in values {
let value = value.into();
if filter_fn(heap, value) {
heap.push(list_loc_as_cell!(h + 1));
heap.push(value);
h += 2;
}
}
heap.push(empty_list_as_cell!());
head_addr
}
#[inline(always)]
pub fn iter_to_heap_list<Iter, SrcT>(heap: &mut Heap, values: Iter) -> usize
where
Iter: Iterator<Item = SrcT>,
SrcT: Into<HeapCellValue>,
{
filtered_iter_to_heap_list(heap, values, |_, _| true)
}
pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option<LocalCodePtr> {
let extract_integer = |s: usize| -> Option<usize> {
match Number::try_from(heap[s]) {
Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
Ok(Number::Integer(n)) => n.to_usize(),
_ => None,
}
};
read_heap_cell!(addr,
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();
if name == atom!("dir_entry") && arity == 1 {
extract_integer(s+1).map(LocalCodePtr::DirEntry)
} else {
panic!(
"to_local_code_ptr crashed with p.i. {}/{}",
name.as_str(),
arity,
);
}
}
_ => {
None
}
)
}
/*
impl<T: RawBlockTraits> HeapTemplate<T> {
#[inline]
pub(crate) fn new() -> Self {
@@ -144,67 +286,40 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
}
}
#[inline]
pub(crate) fn clone(&self, h: usize) -> HeapCellValue {
match &self[h] {
&HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr),
&HeapCellValue::Atom(ref name, ref op) => HeapCellValue::Atom(name.clone(), op.clone()),
&HeapCellValue::DBRef(ref db_ref) => HeapCellValue::DBRef(db_ref.clone()),
&HeapCellValue::Integer(ref n) => HeapCellValue::Integer(n.clone()),
&HeapCellValue::LoadStatePayload(_) => HeapCellValue::Addr(Addr::LoadStatePayload(h)),
&HeapCellValue::NamedStr(arity, ref name, ref op) => {
HeapCellValue::NamedStr(arity, name.clone(), op.clone())
}
&HeapCellValue::PartialString(..) => HeapCellValue::Addr(Addr::PStrLocation(h, 0)),
&HeapCellValue::Rational(ref r) => HeapCellValue::Rational(r.clone()),
&HeapCellValue::Stream(_) => HeapCellValue::Addr(Addr::Stream(h)),
&HeapCellValue::TcpListener(_) => HeapCellValue::Addr(Addr::TcpListener(h)),
}
}
#[inline]
pub(crate) fn put_complete_string(&mut self, s: &str) -> Addr {
if s.is_empty() {
return Addr::EmptyList;
}
let addr = self.allocate_pstr(s);
self.pop();
let h = self.h();
match &mut self[h - 1] {
&mut HeapCellValue::PartialString(_, ref mut has_tail) => {
*has_tail = false;
}
_ => {
unreachable!()
}
}
addr
}
#[inline]
pub(crate) fn put_constant(&mut self, c: Constant) -> Addr {
match c {
Constant::Atom(name, op) => Addr::Con(self.push(HeapCellValue::Atom(name, op))),
Constant::Char(c) => Addr::Char(c),
Constant::EmptyList => Addr::EmptyList,
Constant::Fixnum(n) => Addr::Fixnum(n),
Constant::Integer(n) => Addr::Con(self.push(HeapCellValue::Integer(n))),
Constant::Rational(r) => Addr::Con(self.push(HeapCellValue::Rational(r))),
Constant::Float(f) => Addr::Float(f),
Constant::String(s) => {
if s.is_empty() {
Addr::EmptyList
} else {
self.put_complete_string(&s)
/*
// TODO: move this to the WAM, then remove the temporary (and by
// then, unnecessary and impossible) "arena" argument. OR, remove
// this thing totally! if we can. by that I mean, just convert a
// little to a HeapCellValue. don't bother writing to the
// heap at all. Each of these data is either already inlinable in a
// HeapCellValue or a pointer to an GC'ed location in memory.
#[inline]
pub(crate) fn put_literal(&mut self, literal: Literal) -> HeapCellValue {
match literal {
Literal::Atom(name) => atom_as_cell!(name),
Literal::Char(c) => char_as_cell!(c),
Literal::EmptyList => empty_list_as_cell!(),
Literal::Fixnum(n) => fixnum_as_cell!(n),
Literal::Integer(bigint_ptr) => {
let h = self.push(typed_arena_ptr_as_cell!(bigint_ptr));
self[h]
}
Literal::Rational(bigint_ptr) => {
let h = self.push(typed_arena_ptr_as_cell!(bigint_ptr));
self[h]
}
Literal::Float(f) => typed_arena_ptr_as_cell!(f),
Literal::String(s) => {
if s.as_str().is_empty() {
empty_list_as_cell!()
} else {
// TODO: how do we know where the tail is located?? well, there is no tail. separate tag?
untyped_arena_ptr_as_cell!(s) // self.put_complete_string(arena, &s)
}
} // Literal::Usize(n) => Addr::Usize(n),
}
Constant::Usize(n) => Addr::Usize(n),
}
}
*/
#[inline]
pub(crate) fn is_empty(&self) -> bool {
@@ -225,14 +340,14 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
let h = self.h();
unsafe {
let new_top = self.buf.new_block(mem::size_of::<HeapCellValue>());
ptr::write(self.buf.top as *mut _, val);
self.buf.top = new_top;
let new_ptr = self.buf.alloc(mem::size_of::<HeapCellValue>());
ptr::write(new_ptr as *mut _, val);
}
h
}
/*
#[inline]
pub(crate) fn atom_at(&self, h: usize) -> bool {
if let HeapCellValue::Atom(..) = &self[h] {
@@ -265,76 +380,17 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
val @ HeapCellValue::TcpListener(..) => Addr::TcpListener(self.push(val)),
}
}
#[inline]
pub(crate) fn allocate_pstr(&mut self, src: &str) -> Addr {
self.write_pstr(src).unwrap_or_else(|| Addr::EmptyList)
}
#[inline]
fn write_pstr(&mut self, mut src: &str) -> Option<Addr> {
let orig_h = self.h();
loop {
if src == "" {
return if orig_h == self.h() {
None
} else {
let tail_h = self.h() - 1;
self[tail_h] = HeapCellValue::Addr(Addr::HeapCell(tail_h));
Some(Addr::PStrLocation(orig_h, 0))
};
}
let h = self.h();
let (pstr, rest_src) = match PartialString::new(src) {
Some(tuple) => tuple,
None => {
if src.len() > '\u{0}'.len_utf8() {
src = &src['\u{0}'.len_utf8()..];
continue;
} else if orig_h == h {
return None;
} else {
self[h - 1] = HeapCellValue::Addr(Addr::HeapCell(h - 1));
return Some(Addr::PStrLocation(orig_h, 0));
}
}
};
self.push(HeapCellValue::PartialString(pstr, true));
if rest_src != "" {
self.push(HeapCellValue::Addr(Addr::PStrLocation(h + 2, 0)));
src = rest_src;
} else {
self.push(HeapCellValue::Addr(Addr::HeapCell(h + 1)));
return Some(Addr::PStrLocation(orig_h, 0));
}
}
}
*/
#[inline]
pub(crate) fn truncate(&mut self, h: usize) {
let new_top = h * mem::size_of::<HeapCellValue>() + self.buf.base as usize;
let mut h = new_top;
unsafe {
while h as *const _ < self.buf.top {
let val = h as *mut HeapCellValue;
ptr::drop_in_place(val);
h += mem::size_of::<HeapCellValue>();
}
}
self.buf.top = new_top as *const _;
let new_ptr = self.buf.top as usize - h * mem::size_of::<HeapCellValue>();
self.buf.ptr = new_ptr as *mut _;
}
#[inline]
pub(crate) fn h(&self) -> usize {
(self.buf.top as usize - self.buf.base as usize) / mem::size_of::<HeapCellValue>()
(self.buf.top as usize - self.buf.ptr as usize) / mem::size_of::<HeapCellValue>()
}
pub(crate) fn append(&mut self, vals: Vec<HeapCellValue>) {
@@ -350,84 +406,7 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
}
}
pub(crate) fn to_list<Iter, SrcT>(&mut self, values: Iter) -> usize
where
Iter: Iterator<Item = SrcT>,
SrcT: Into<HeapCellValue>,
{
let head_addr = self.h();
let mut h = head_addr;
for value in values.map(|v| v.into()) {
self.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
self.push(value);
h += 2;
}
self.push(HeapCellValue::Addr(Addr::EmptyList));
head_addr
}
/* Create an iterator starting from the passed offset. */
pub(crate) fn iter_from<'a>(&'a self, offset: usize) -> HeapIter<'a, T> {
HeapIter::new(&self.buf, offset * mem::size_of::<HeapCellValue>())
}
pub(crate) fn iter_mut_from<'a>(&'a mut self, offset: usize) -> HeapIterMut<'a, T> {
HeapIterMut::new(&mut self.buf, offset * mem::size_of::<HeapCellValue>())
}
pub(crate) fn into_iter(mut self) -> HeapIntoIter<T> {
HeapIntoIter {
buf: self.buf.take(),
offset: 0,
}
}
pub(crate) fn extend<Iter: Iterator<Item = HeapCellValue>>(&mut self, iter: Iter) {
for hcv in iter {
self.push(hcv);
}
}
pub(crate) fn to_local_code_ptr(&self, addr: &Addr) -> Option<LocalCodePtr> {
let extract_integer = |s: usize| -> Option<usize> {
match &self[s] {
&HeapCellValue::Addr(Addr::Fixnum(n)) => usize::try_from(n).ok(),
&HeapCellValue::Integer(ref n) => n.to_usize(),
_ => None,
}
};
match addr {
Addr::Str(s) => {
match &self[*s] {
HeapCellValue::NamedStr(arity, ref name, _) => {
match (name.as_str(), *arity) {
("dir_entry", 1) => extract_integer(s + 1).map(LocalCodePtr::DirEntry),
/*
("top_level", 2) => {
if let Some(chunk_num) = extract_integer(s+1) {
if let Some(p) = extract_integer(s+2) {
return Some(LocalCodePtr::TopLevel(chunk_num, p));
}
}
None
}
*/
_ => None,
}
}
_ => unreachable!(),
}
}
_ => None,
}
}
/* TODO: get rid of this!!
#[inline]
pub(crate) fn index_addr<'a>(&'a self, addr: &Addr) -> RefOrOwned<'a, HeapCellValue> {
match addr {
@@ -437,6 +416,20 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
addr => RefOrOwned::Owned(HeapCellValue::Addr(*addr)),
}
}
*/
}
impl<T: RawBlockTraits> Index<u64> for HeapTemplate<T> {
type Output = HeapCellValue;
#[inline]
fn index(&self, index: u64) -> &Self::Output {
unsafe {
let ptr =
self.buf.top as usize - (index as usize + 1) * mem::size_of::<HeapCellValue>();
&*(ptr as *const HeapCellValue)
}
}
}
impl<T: RawBlockTraits> Index<usize> for HeapTemplate<T> {
@@ -445,7 +438,7 @@ impl<T: RawBlockTraits> Index<usize> for HeapTemplate<T> {
#[inline]
fn index(&self, index: usize) -> &Self::Output {
unsafe {
let ptr = self.buf.base as usize + index * mem::size_of::<HeapCellValue>();
let ptr = self.buf.top as usize - (index + 1) * mem::size_of::<HeapCellValue>();
&*(ptr as *const HeapCellValue)
}
}
@@ -455,8 +448,9 @@ impl<T: RawBlockTraits> IndexMut<usize> for HeapTemplate<T> {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
unsafe {
let ptr = self.buf.base as usize + index * mem::size_of::<HeapCellValue>();
let ptr = self.buf.top as usize - (index + 1) * mem::size_of::<HeapCellValue>();
&mut *(ptr as *mut HeapCellValue)
}
}
}
*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,53 +1,43 @@
use prolog_parser::ast::*;
use prolog_parser::clause_name;
use crate::parser::ast::*;
use crate::arena::*;
use crate::atom_table::*;
use crate::clause_types::*;
use crate::fixtures::*;
use crate::forms::*;
use crate::instructions::*;
use crate::machine::code_repo::CodeRepo;
use crate::machine::heap::*;
use crate::machine::loader::*;
use crate::machine::machine_errors::MachineStub;
use crate::machine::machine_state::*;
use crate::machine::partial_string::*;
use crate::machine::raw_block::RawBlockTraits;
use crate::machine::streams::Stream;
use crate::machine::term_stream::LoadStatePayload;
use crate::machine::CompilationTarget;
use crate::rug::{Integer, Rational};
use ordered_float::OrderedFloat;
use indexmap::IndexMap;
use std::cell::Cell;
use std::cmp::Ordering;
use std::collections::{BTreeMap, BTreeSet};
use std::convert::TryFrom;
use std::collections::BTreeSet;
use std::fmt;
// use std::mem;
use std::net::TcpListener;
use std::ops::{Add, AddAssign, Deref, Sub, SubAssign};
use std::rc::Rc;
use crate::types::*;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct OrderedOpDirKey(pub(crate) ClauseName, pub(crate) Fixity);
pub(crate) struct OrderedOpDirKey(pub(crate) Atom, pub(crate) Fixity);
pub(crate) type OssifiedOpDir = BTreeMap<OrderedOpDirKey, (usize, Specifier)>;
pub(crate) type OssifiedOpDir = IndexMap<(Atom, Fixity), (usize, Specifier)>;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub(crate) enum DBRef {
NamedPred(ClauseName, usize, Option<SharedOpDesc>),
Op(
usize,
Specifier,
ClauseName,
Rc<OssifiedOpDir>,
SharedOpDesc,
),
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DBRef {
NamedPred(Atom, usize),
Op(Atom, Fixity, TypedArenaPtr<OssifiedOpDir>),
}
// 7.2
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) enum TermOrderCategory {
pub enum TermOrderCategory {
Variable,
FloatingPoint,
Integer,
@@ -55,43 +45,95 @@ pub(crate) enum TermOrderCategory {
Compound,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) enum Addr {
AttrVar(usize),
Char(char),
Con(usize),
CutPoint(usize),
EmptyList,
Fixnum(isize),
Float(OrderedFloat<f64>),
Lis(usize),
LoadStatePayload(usize),
HeapCell(usize),
PStrLocation(usize, usize), // location of pstr in heap, offset into string in bytes.
StackCell(usize, usize),
Str(usize),
Stream(usize),
TcpListener(usize),
Usize(usize),
}
// the position-dependent heap template:
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, PartialOrd)]
pub(crate) enum Ref {
AttrVar(usize),
HeapCell(usize),
StackCell(usize, usize),
}
/*
read_heap_cell!(
(HeapCellValueTag::AttrVar, n) => {
}
(HeapCellValueTag::Lis, n) => {
}
(HeapCellValueTag::Var, n) => {
}
(HeapCellValueTag::Str, n) => {
}
(HeapCellValueTag::PStrOffset, n) => {
}
_ => {
}
)
*/
impl Ref {
pub(crate) fn as_addr(self) -> Addr {
match self {
Ref::AttrVar(h) => Addr::AttrVar(h),
Ref::HeapCell(h) => Addr::HeapCell(h),
Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc),
}
impl PartialEq<Ref> for HeapCellValue {
fn eq(&self, r: &Ref) -> bool {
self.as_var() == Some(*r)
}
}
impl PartialOrd<Ref> for HeapCellValue {
fn partial_cmp(&self, r: &Ref) -> Option<Ordering> {
read_heap_cell!(*self,
(HeapCellValueTag::StackVar, s1) => {
match r.get_tag() {
RefTag::StackCell => {
let s2 = r.get_value() as usize;
s1.partial_cmp(&s2)
}
_ => Some(Ordering::Greater),
}
}
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h1) => {
match r.get_tag() {
RefTag::StackCell => Some(Ordering::Less),
_ => {
let h2 = r.get_value() as usize;
h1.partial_cmp(&h2)
}
}
}
_ => {
None
}
)
}
}
/*
impl HeapCellValue {
#[inline]
pub fn as_constant_index(self, machine_st: &MachineState) -> Option<Literal> {
read_heap_cell!(self,
(HeapCellValueTag::Char, c) => Some(Literal::Char(c)),
(HeapCellValueTag::Atom, (name, arity)) => {
if arity == 0 {
Some(Literal::Atom(name))
} else {
None
}
}
(HeapCellValueTag::Fixnum, n) => {
Some(Literal::Fixnum(n))
}
(HeapCellValueTag::F64, f) => {
Some(Literal::Float(f))
}
(HeapCellValueTag::Cons, ptr) => {
match_untyped_arena_ptr!(ptr,
(ArenaHeaderTag::Integer, n) => {
Some(Literal::Integer(n))
}
(ArenaHeaderTag::Rational, r) => {
Some(Literal::Rational(r))
}
_ => {
None
}
)
}
)
}
}
*/
/*
impl Ord for Ref {
fn cmp(&self, other: &Ref) -> Ordering {
match (self, other) {
@@ -114,31 +156,6 @@ impl PartialEq<Ref> for Addr {
}
}
// for use crate::in MachineState::bind.
impl PartialOrd<Ref> for Addr {
fn partial_cmp(&self, r: &Ref) -> Option<Ordering> {
match self {
&Addr::StackCell(fr, sc) => match *r {
Ref::AttrVar(_) | Ref::HeapCell(_) => Some(Ordering::Greater),
Ref::StackCell(fr1, sc1) => {
if fr1 < fr || (fr1 == fr && sc1 < sc) {
Some(Ordering::Greater)
} else if fr1 == fr && sc1 == sc {
Some(Ordering::Equal)
} else {
Some(Ordering::Less)
}
}
},
&Addr::HeapCell(h) | &Addr::AttrVar(h) => match r {
Ref::StackCell(..) => Some(Ordering::Less),
Ref::AttrVar(h1) | Ref::HeapCell(h1) => h.partial_cmp(h1),
},
_ => None,
}
}
}
impl Addr {
#[inline]
pub(crate) fn is_heap_bound(&self) -> bool {
@@ -171,57 +188,6 @@ impl Addr {
}
}
pub(super) fn order_category(&self, heap: &Heap) -> Option<TermOrderCategory> {
match Number::try_from((*self, heap)) {
Ok(Number::Integer(_)) | Ok(Number::Fixnum(_)) | Ok(Number::Rational(_)) => {
Some(TermOrderCategory::Integer)
}
Ok(Number::Float(_)) => Some(TermOrderCategory::FloatingPoint),
_ => match self {
Addr::HeapCell(_) | Addr::AttrVar(_) | Addr::StackCell(..) => {
Some(TermOrderCategory::Variable)
}
Addr::Float(_) => Some(TermOrderCategory::FloatingPoint),
&Addr::Con(h) => match &heap[h] {
HeapCellValue::Atom(..) => Some(TermOrderCategory::Atom),
HeapCellValue::DBRef(_) => None,
_ => {
unreachable!()
}
},
Addr::Char(_) | Addr::EmptyList => Some(TermOrderCategory::Atom),
Addr::Fixnum(_) | Addr::Usize(_) => Some(TermOrderCategory::Integer),
Addr::Lis(_) | Addr::PStrLocation(..) | Addr::Str(_) => {
Some(TermOrderCategory::Compound)
}
Addr::CutPoint(_)
| Addr::LoadStatePayload(_)
| Addr::Stream(_)
| Addr::TcpListener(_) => None,
},
}
}
pub(crate) fn as_constant_index(&self, machine_st: &MachineState) -> Option<Constant> {
match self {
&Addr::Char(c) => Some(Constant::Char(c)),
&Addr::Con(h) => match &machine_st.heap[h] {
&HeapCellValue::Atom(ref name, _) if name.is_char() => {
Some(Constant::Char(name.as_str().chars().next().unwrap()))
}
&HeapCellValue::Atom(ref name, _) => Some(Constant::Atom(name.clone(), None)),
&HeapCellValue::Integer(ref n) => Some(Constant::Integer(n.clone())),
&HeapCellValue::Rational(ref n) => Some(Constant::Rational(n.clone())),
_ => None,
},
&Addr::EmptyList => Some(Constant::EmptyList),
&Addr::Fixnum(n) => Some(Constant::Fixnum(n)),
&Addr::Float(f) => Some(Constant::Float(f)),
&Addr::Usize(n) => Some(Constant::Usize(n)),
_ => None,
}
}
pub(crate) fn is_protected(&self, e: usize) -> bool {
match self {
&Addr::StackCell(addr, _) if addr >= e => false,
@@ -230,61 +196,6 @@ impl Addr {
}
}
impl Add<usize> for Addr {
type Output = Addr;
fn add(self, rhs: usize) -> Self::Output {
match self {
Addr::Stream(h) => Addr::Stream(h + rhs),
Addr::Con(h) => Addr::Con(h + rhs),
Addr::Lis(a) => Addr::Lis(a + rhs),
Addr::AttrVar(h) => Addr::AttrVar(h + rhs),
Addr::HeapCell(h) => Addr::HeapCell(h + rhs),
Addr::Str(s) => Addr::Str(s + rhs),
Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs, n),
_ => self,
}
}
}
impl Sub<i64> for Addr {
type Output = Addr;
fn sub(self, rhs: i64) -> Self::Output {
if rhs < 0 {
match self {
Addr::Stream(h) => Addr::Stream(h + rhs.abs() as usize),
Addr::Con(h) => Addr::Con(h + rhs.abs() as usize),
Addr::Lis(a) => Addr::Lis(a + rhs.abs() as usize),
Addr::AttrVar(h) => Addr::AttrVar(h + rhs.abs() as usize),
Addr::HeapCell(h) => Addr::HeapCell(h + rhs.abs() as usize),
Addr::Str(s) => Addr::Str(s + rhs.abs() as usize),
Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs.abs() as usize, n),
_ => self,
}
} else {
self.sub(rhs as usize)
}
}
}
impl Sub<usize> for Addr {
type Output = Addr;
fn sub(self, rhs: usize) -> Self::Output {
match self {
Addr::Stream(h) => Addr::Stream(h - rhs),
Addr::Con(h) => Addr::Con(h - rhs),
Addr::Lis(a) => Addr::Lis(a - rhs),
Addr::AttrVar(h) => Addr::AttrVar(h - rhs),
Addr::HeapCell(h) => Addr::HeapCell(h - rhs),
Addr::Str(s) => Addr::Str(s - rhs),
Addr::PStrLocation(h, n) => Addr::PStrLocation(h - rhs, n),
_ => self,
}
}
}
impl SubAssign<usize> for Addr {
fn sub_assign(&mut self, rhs: usize) {
*self = self.clone() - rhs;
@@ -305,72 +216,9 @@ impl From<Ref> for TrailRef {
TrailRef::Ref(r)
}
}
#[derive(Debug)]
pub(crate) enum HeapCellValue {
Addr(Addr),
Atom(ClauseName, Option<SharedOpDesc>),
DBRef(DBRef),
Integer(Rc<Integer>),
LoadStatePayload(Box<LoadStatePayload>),
NamedStr(usize, ClauseName, Option<SharedOpDesc>), // arity, name, precedence/Specifier if it has one.
Rational(Rc<Rational>),
PartialString(PartialString, bool), // the partial string, a bool indicating whether it came from a Constant.
Stream(Stream),
TcpListener(TcpListener),
}
impl HeapCellValue {
#[inline]
pub(crate) fn as_addr(&self, focus: usize) -> Addr {
match self {
HeapCellValue::Addr(ref a) => *a,
HeapCellValue::Atom(..)
| HeapCellValue::DBRef(..)
| HeapCellValue::Integer(..)
| HeapCellValue::Rational(..) => Addr::Con(focus),
HeapCellValue::LoadStatePayload(_) => Addr::LoadStatePayload(focus),
HeapCellValue::NamedStr(_, _, _) => Addr::Str(focus),
HeapCellValue::PartialString(..) => Addr::PStrLocation(focus, 0),
HeapCellValue::Stream(_) => Addr::Stream(focus),
HeapCellValue::TcpListener(_) => Addr::TcpListener(focus),
}
}
#[inline]
pub(crate) fn context_free_clone(&self) -> HeapCellValue {
match self {
&HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr),
&HeapCellValue::Atom(ref name, ref op) => HeapCellValue::Atom(name.clone(), op.clone()),
&HeapCellValue::DBRef(ref db_ref) => HeapCellValue::DBRef(db_ref.clone()),
&HeapCellValue::Integer(ref n) => HeapCellValue::Integer(n.clone()),
&HeapCellValue::LoadStatePayload(_) => {
HeapCellValue::Atom(clause_name!("$live_term_stream"), None)
}
&HeapCellValue::NamedStr(arity, ref name, ref op) => {
HeapCellValue::NamedStr(arity, name.clone(), op.clone())
}
&HeapCellValue::Rational(ref r) => HeapCellValue::Rational(r.clone()),
&HeapCellValue::PartialString(ref pstr, has_tail) => {
HeapCellValue::PartialString(pstr.clone(), has_tail)
}
&HeapCellValue::Stream(ref stream) => HeapCellValue::Stream(stream.clone()),
&HeapCellValue::TcpListener(_) => {
HeapCellValue::Atom(clause_name!("$tcp_listener"), None)
}
}
}
}
impl From<Addr> for HeapCellValue {
#[inline]
fn from(value: Addr) -> HeapCellValue {
HeapCellValue::Addr(value)
}
}
*/
#[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub(crate) enum IndexPtr {
pub enum IndexPtr {
DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined.
DynamicIndex(usize),
Index(usize),
@@ -378,7 +226,7 @@ pub(crate) enum IndexPtr {
}
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub(crate) struct CodeIndex(pub(crate) Rc<Cell<IndexPtr>>);
pub struct CodeIndex(pub(crate) Rc<Cell<IndexPtr>>);
impl Deref for CodeIndex {
type Target = Cell<IndexPtr>;
@@ -419,7 +267,7 @@ impl Default for CodeIndex {
}
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
pub(crate) enum REPLCodePtr {
pub enum REPLCodePtr {
AddDiscontiguousPredicate,
AddDynamicPredicate,
AddMultifilePredicate,
@@ -456,12 +304,11 @@ pub(crate) enum REPLCodePtr {
AddNonCountedBacktracking,
}
#[derive(Debug, Clone, PartialEq)]
pub(crate) enum CodePtr {
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum CodePtr {
BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call.
CallN(usize, LocalCodePtr, bool), // arity, local, last call.
Local(LocalCodePtr),
// DynamicTransaction(DynamicTransactionType, LocalCodePtr), // the type of transaction, the return pointer.
REPL(REPLCodePtr, LocalCodePtr), // the REPL code, the return pointer.
VerifyAttrInterrupt(usize), // location of the verify attribute interrupt code in the CodeDir.
}
@@ -488,7 +335,7 @@ impl CodePtr {
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub(crate) enum LocalCodePtr {
pub enum LocalCodePtr {
DirEntry(usize), // offset
Halt,
IndexingBuf(usize, usize, usize), // DirEntry offset, first internal offset, second internal offset
@@ -496,7 +343,7 @@ pub(crate) enum LocalCodePtr {
}
impl LocalCodePtr {
pub(crate) fn assign_if_local(&mut self, cp: CodePtr) {
pub fn assign_if_local(&mut self, cp: CodePtr) {
match cp {
CodePtr::Local(local) => *self = local,
_ => {}
@@ -504,7 +351,7 @@ impl LocalCodePtr {
}
#[inline]
pub(crate) fn abs_loc(&self) -> usize {
pub fn abs_loc(&self) -> usize {
match self {
LocalCodePtr::DirEntry(ref p) => *p,
LocalCodePtr::IndexingBuf(ref p, ..) => *p,
@@ -528,33 +375,21 @@ impl LocalCodePtr {
false
}
pub(crate) fn as_functor<T: RawBlockTraits>(&self, heap: &mut HeapTemplate<T>) -> Addr {
let addr = Addr::HeapCell(heap.h());
pub(crate) fn as_functor(&self) -> MachineStub {
match self {
LocalCodePtr::DirEntry(p) => {
heap.append(functor!("dir_entry", [integer(*p)]));
functor!(atom!("dir_entry"), [fixnum(*p)])
}
LocalCodePtr::Halt => {
heap.append(functor!("halt"));
functor!(atom!("halt"))
}
/*
LocalCodePtr::TopLevel(chunk_num, offset) => {
heap.append(functor!(
"top_level",
[integer(*chunk_num), integer(*offset)]
));
}
*/
LocalCodePtr::IndexingBuf(p, o, i) => {
heap.append(functor!(
"indexed_buf",
[integer(*p), integer(*o), integer(*i)]
));
functor!(
atom!("indexed_buf"),
[fixnum(*p), fixnum(*o), fixnum(*i)]
)
}
}
addr
}
}
@@ -614,9 +449,8 @@ impl AddAssign<usize> for LocalCodePtr {
#[inline]
fn add_assign(&mut self, rhs: usize) {
match self {
&mut LocalCodePtr::DirEntry(ref mut p) /* |
&mut LocalCodePtr::TopLevel(_, ref mut p) */ => *p += rhs,
&mut LocalCodePtr::IndexingBuf(_, _, ref mut i) => *i += rhs,
&mut LocalCodePtr::DirEntry(ref mut i)
| &mut LocalCodePtr::IndexingBuf(_, _, ref mut i) => *i += rhs,
&mut LocalCodePtr::Halt => unreachable!(),
}
}
@@ -627,11 +461,7 @@ impl Add<usize> for CodePtr {
fn add(self, rhs: usize) -> Self::Output {
match self {
p @ CodePtr::REPL(..) | p @ CodePtr::VerifyAttrInterrupt(_) => {
// |
// p @ CodePtr::DynamicTransaction(..) => {
p
}
p @ CodePtr::REPL(..) | p @ CodePtr::VerifyAttrInterrupt(_) => p,
CodePtr::Local(local) => CodePtr::Local(local + rhs),
CodePtr::BuiltInClause(_, local) | CodePtr::CallN(_, local, _) => {
CodePtr::Local(local + rhs)
@@ -660,12 +490,12 @@ impl SubAssign<usize> for CodePtr {
}
}
pub(crate) type HeapVarDict = IndexMap<Rc<Var>, Addr>;
pub(crate) type AllocVarDict = IndexMap<Rc<Var>, VarData>;
pub(crate) type HeapVarDict = IndexMap<Rc<String>, HeapCellValue>;
pub(crate) type AllocVarDict = IndexMap<Rc<String>, VarData>;
pub(crate) type GlobalVarDir = IndexMap<ClauseName, (Ball, Option<Addr>)>;
pub(crate) type GlobalVarDir = IndexMap<Atom, (Ball, Option<HeapCellValue>)>;
pub(crate) type StreamAliasDir = IndexMap<ClauseName, Stream>;
pub(crate) type StreamAliasDir = IndexMap<Atom, Stream>;
pub(crate) type StreamDir = BTreeSet<Stream>;
pub(crate) type MetaPredicateDir = IndexMap<PredicateKey, Vec<MetaSpec>>;
@@ -676,7 +506,7 @@ pub(crate) type LocalExtensiblePredicates =
IndexMap<(CompilationTarget, PredicateKey), LocalPredicateSkeleton>;
#[derive(Debug)]
pub(crate) struct IndexStore {
pub struct IndexStore {
pub(super) code_dir: CodeDir,
pub(super) extensible_predicates: ExtensiblePredicates,
pub(super) local_extensible_predicates: LocalExtensiblePredicates,
@@ -688,31 +518,21 @@ pub(crate) struct IndexStore {
pub(super) stream_aliases: StreamAliasDir,
}
impl Default for IndexStore {
#[inline]
fn default() -> Self {
index_store!(CodeDir::new(), default_op_dir(), ModuleDir::new())
}
}
impl IndexStore {
pub(crate) fn get_predicate_skeleton_mut(
&mut self,
compilation_target: &CompilationTarget,
key: &PredicateKey,
) -> Option<&mut PredicateSkeleton> {
match (key.0.as_str(), key.1) {
// ("term_expansion", 2) => self.extensible_predicates.get_mut(key),
_ => match compilation_target {
CompilationTarget::User => self.extensible_predicates.get_mut(key),
CompilationTarget::Module(ref module_name) => {
if let Some(module) = self.modules.get_mut(module_name) {
module.extensible_predicates.get_mut(key)
} else {
None
}
match compilation_target {
CompilationTarget::User => self.extensible_predicates.get_mut(key),
CompilationTarget::Module(ref module_name) => {
if let Some(module) = self.modules.get_mut(module_name) {
module.extensible_predicates.get_mut(key)
} else {
None
}
},
}
}
}
@@ -737,7 +557,7 @@ impl IndexStore {
&mut self,
mut src_compilation_target: CompilationTarget,
local_compilation_target: CompilationTarget,
listing_src_file_name: Option<ClauseName>,
listing_src_file_name: Option<Atom>,
key: PredicateKey,
) -> Option<&mut LocalPredicateSkeleton> {
if let Some(filename) = listing_src_file_name {
@@ -748,8 +568,8 @@ impl IndexStore {
CompilationTarget::User => self
.local_extensible_predicates
.get_mut(&(local_compilation_target, key)),
CompilationTarget::Module(ref module_name) => {
if let Some(module) = self.modules.get_mut(module_name) {
CompilationTarget::Module(module_name) => {
if let Some(module) = self.modules.get_mut(&module_name) {
module
.local_extensible_predicates
.get_mut(&(local_compilation_target, key))
@@ -764,7 +584,7 @@ impl IndexStore {
&self,
mut src_compilation_target: CompilationTarget,
local_compilation_target: CompilationTarget,
listing_src_file_name: Option<ClauseName>,
listing_src_file_name: Option<Atom>,
key: PredicateKey,
) -> Option<&LocalPredicateSkeleton> {
if let Some(filename) = listing_src_file_name {
@@ -775,8 +595,8 @@ impl IndexStore {
CompilationTarget::User => self
.local_extensible_predicates
.get(&(local_compilation_target, key)),
CompilationTarget::Module(ref module_name) => {
if let Some(module) = self.modules.get(module_name) {
CompilationTarget::Module(module_name) => {
if let Some(module) = self.modules.get(&module_name) {
module
.local_extensible_predicates
.get(&(local_compilation_target, key))
@@ -806,35 +626,30 @@ impl IndexStore {
pub(crate) fn get_predicate_code_index(
&self,
name: ClauseName,
name: Atom,
arity: usize,
module: ClauseName,
op_spec: Option<SharedOpDesc>,
module: Atom,
) -> Option<CodeIndex> {
if module.as_str() == "user" {
match ClauseType::from(name, arity, op_spec) {
if module == atom!("user") {
match ClauseType::from(name, arity) {
ClauseType::Named(name, arity, _) => self.code_dir.get(&(name, arity)).cloned(),
ClauseType::Op(name, spec, ..) => self.code_dir.get(&(name, spec.arity())).cloned(),
_ => None,
}
} else {
self.modules.get(&module).and_then(|module| {
match ClauseType::from(name, arity, op_spec) {
self.modules
.get(&module)
.and_then(|module| match ClauseType::from(name, arity) {
ClauseType::Named(name, arity, _) => {
module.code_dir.get(&(name, arity)).cloned()
}
ClauseType::Op(name, spec, ..) => {
module.code_dir.get(&(name, spec.arity())).cloned()
}
_ => None,
}
})
})
}
}
pub(crate) fn get_meta_predicate_spec(
&self,
name: ClauseName,
name: Atom,
arity: usize,
compilation_target: &CompilationTarget,
) -> Option<&Vec<MetaSpec>> {
@@ -850,9 +665,13 @@ impl IndexStore {
}
}
pub(crate) fn is_dynamic_predicate(&self, module_name: ClauseName, key: PredicateKey) -> bool {
match module_name.as_str() {
"user" => self
pub(crate) fn is_dynamic_predicate(
&self,
module_name: Atom,
key: PredicateKey,
) -> bool {
match module_name {
atom!("user") => self
.extensible_predicates
.get(&key)
.map(|skeleton| skeleton.core.is_dynamic)
@@ -870,19 +689,19 @@ impl IndexStore {
#[inline]
pub(super) fn new() -> Self {
IndexStore::default()
index_store!(CodeDir::new(), default_op_dir(), ModuleDir::new())
}
pub(super) fn get_cleaner_sites(&self) -> (usize, usize) {
let r_w_h = clause_name!("run_cleaners_with_handling");
let r_wo_h = clause_name!("run_cleaners_without_handling");
let iso_ext = clause_name!("iso_ext");
let r_w_h = atom!("run_cleaners_with_handling");
let r_wo_h = atom!("run_cleaners_without_handling");
let iso_ext = atom!("iso_ext");
let r_w_h = self
.get_predicate_code_index(r_w_h, 0, iso_ext.clone(), None)
.get_predicate_code_index(r_w_h, 0, iso_ext)
.and_then(|item| item.local());
let r_wo_h = self
.get_predicate_code_index(r_wo_h, 1, iso_ext, None)
.get_predicate_code_index(r_wo_h, 1, iso_ext)
.and_then(|item| item.local());
if let Some(r_w_h) = r_w_h {
@@ -895,7 +714,7 @@ impl IndexStore {
}
}
pub(crate) type CodeDir = BTreeMap<PredicateKey, CodeIndex>;
pub(crate) type CodeDir = IndexMap<PredicateKey, CodeIndex>;
pub(crate) enum RefOrOwned<'a, T: 'a> {
Borrowed(&'a T),
@@ -918,14 +737,4 @@ impl<'a, T> RefOrOwned<'a, T> {
&RefOrOwned::Owned(ref r) => r,
}
}
pub(crate) fn to_owned(self) -> T
where
T: Clone,
{
match self {
RefOrOwned::Borrowed(item) => item.clone(),
RefOrOwned::Owned(item) => item,
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

766
src/machine/mock_wam.rs Normal file
View File

@@ -0,0 +1,766 @@
pub use crate::arena::*;
pub use crate::atom_table::*;
use crate::heap_print::*;
pub use crate::machine::heap::*;
pub use crate::machine::Machine;
pub use crate::machine::machine_state::*;
pub use crate::machine::stack::*;
pub use crate::machine::streams::*;
pub use crate::macros::*;
pub use crate::parser::ast::*;
use crate::read::*;
pub use crate::types::*;
#[cfg(test)]
use crate::machine::copier::CopierTarget;
#[cfg(test)]
use std::ops::{Deref, DerefMut, Index, IndexMut};
// a mini-WAM for test purposes.
pub struct MockWAM {
pub machine_st: MachineState,
pub op_dir: OpDir,
pub flags: MachineFlags,
}
impl MockWAM {
pub fn new() -> Self {
let op_dir = default_op_dir();
Self {
machine_st: MachineState::new(),
op_dir,
flags: MachineFlags::default(),
}
}
pub fn write_parsed_term_to_heap(
&mut self,
input_stream: Stream,
) -> Result<TermWriteResult, ParserError> {
self.machine_st.read(input_stream, &self.op_dir)
}
pub fn parse_and_write_parsed_term_to_heap(
&mut self,
term_string: &'static str,
) -> Result<TermWriteResult, ParserError> {
let stream = Stream::from_static_string(term_string, &mut self.machine_st.arena);
self.write_parsed_term_to_heap(stream)
}
pub fn parse_and_print_term(
&mut self,
term_string: &'static str,
) -> Result<String, ParserError> {
let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?;
print_heap_terms(self.machine_st.heap.iter(), term_write_result.heap_loc);
let mut printer = HCPrinter::new(
&mut self.machine_st.heap,
&mut self.machine_st.arena,
&self.op_dir,
PrinterOutputter::new(),
heap_loc_as_cell!(term_write_result.heap_loc),
);
printer.var_names = term_write_result
.var_dict
.into_iter()
.map(|(var, cell)| (cell, var))
.collect();
Ok(printer.print().result())
}
}
#[cfg(test)]
pub struct TermCopyingMockWAM<'a> {
pub wam: &'a mut MockWAM,
}
#[cfg(test)]
impl<'a> Index<usize> for TermCopyingMockWAM<'a> {
type Output = HeapCellValue;
fn index(&self, index: usize) -> &HeapCellValue {
&self.wam.machine_st.heap[index]
}
}
#[cfg(test)]
impl<'a> IndexMut<usize> for TermCopyingMockWAM<'a> {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut HeapCellValue {
&mut self.wam.machine_st.heap[index]
}
}
#[cfg(test)]
impl<'a> Deref for TermCopyingMockWAM<'a> {
type Target = MockWAM;
fn deref(&self) -> &Self::Target {
&self.wam
}
}
#[cfg(test)]
impl<'a> DerefMut for TermCopyingMockWAM<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.wam
}
}
#[cfg(test)]
impl<'a> CopierTarget for TermCopyingMockWAM<'a> {
fn store(&self, val: HeapCellValue) -> HeapCellValue {
read_heap_cell!(val,
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
self.wam.machine_st.heap[h]
}
(HeapCellValueTag::StackVar, s) => {
self.wam.machine_st.stack[s]
}
_ => {
val
}
)
}
fn deref(&self, mut val: HeapCellValue) -> HeapCellValue {
loop {
let value = self.store(val);
if value.is_var() && value != val {
val = value;
continue;
}
return val;
}
}
fn push(&mut self, val: HeapCellValue) {
self.wam.machine_st.heap.push(val);
}
fn stack(&mut self) -> &mut Stack {
&mut self.wam.machine_st.stack
}
fn threshold(&self) -> usize {
self.wam.machine_st.heap.len()
}
}
#[cfg(test)]
pub fn all_cells_marked_and_unforwarded(heap: &[HeapCellValue]) {
for (idx, cell) in heap.iter().enumerate() {
assert_eq!(
cell.get_mark_bit(),
true,
"cell {:?} at index {} is not marked",
cell,
idx
);
assert!(
cell.get_forwarding_bit() != Some(true),
"cell {:?} at index {} is forwarded",
cell,
idx
);
}
}
#[cfg(test)]
pub fn all_cells_unmarked(heap: &Heap) {
for (idx, cell) in heap.iter().enumerate() {
assert!(
!cell.get_mark_bit(),
"cell {:?} at index {} is still marked",
cell,
idx
);
assert!(
cell.get_forwarding_bit() != Some(true),
"cell {:?} at index {} is still forwarded",
cell,
idx
);
}
}
#[cfg(test)]
pub(crate) fn write_parsed_term_to_heap(
machine_st: &mut MachineState,
input_stream: Stream,
op_dir: &OpDir,
) -> Result<TermWriteResult, ParserError> {
machine_st.read(input_stream, op_dir)
}
#[cfg(test)]
pub(crate) fn parse_and_write_parsed_term_to_heap(
machine_st: &mut MachineState,
term_string: &'static str,
op_dir: &OpDir,
) -> Result<TermWriteResult, ParserError> {
let stream = Stream::from_static_string(term_string, &mut machine_st.arena);
write_parsed_term_to_heap(machine_st, stream, op_dir)
}
impl Machine {
pub fn test_load_file(&mut self, file: &str) -> Vec<u8> {
use std::io::Read;
let old_output = std::mem::replace(
&mut self.user_output,
Stream::from_owned_string("".to_owned(), &mut self.machine_st.arena),
);
let stream = Stream::from_owned_string(
std::fs::read_to_string(AsRef::<std::path::Path>::as_ref(file)).unwrap(),
&mut self.machine_st.arena,
);
self.load_file(file.into(), stream);
let output = self.user_output.bytes().map(|b| b.unwrap()).collect();
self.user_output = old_output;
output
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unify_tests() {
let mut wam = MachineState::new();
let mut op_dir = default_op_dir();
op_dir.insert(
(atom!("+"), Fixity::In),
OpDesc::build_with(500, YFX as u8),
);
op_dir.insert(
(atom!("-"), Fixity::In),
OpDesc::build_with(500, YFX as u8),
);
op_dir.insert(
(atom!("*"), Fixity::In),
OpDesc::build_with(500, YFX as u8),
);
op_dir.insert(
(atom!("/"), Fixity::In),
OpDesc::build_with(400, YFX as u8),
);
op_dir.insert(
(atom!("="), Fixity::In),
OpDesc::build_with(700, XFX as u8),
);
{
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,a).", &op_dir).unwrap();
unify!(
wam,
str_loc_as_cell!(0),
str_loc_as_cell!(term_write_result_2.heap_loc)
);
assert!(wam.fail);
}
all_cells_unmarked(&wam.heap);
wam.fail = false;
wam.heap.clear();
{
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_2.heap_loc)
);
assert!(!wam.fail);
}
all_cells_unmarked(&wam.heap);
wam.fail = false;
wam.heap.clear();
{
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_2.heap_loc)
);
assert!(!wam.fail);
}
all_cells_unmarked(&wam.heap);
wam.fail = false;
wam.heap.clear();
{
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_2.heap_loc)
);
assert!(!wam.fail);
}
all_cells_unmarked(&wam.heap);
wam.fail = false;
wam.heap.clear();
{
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_2.heap_loc)
);
assert!(!wam.fail);
}
all_cells_unmarked(&wam.heap);
wam.fail = false;
wam.heap.clear();
{
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();
all_cells_unmarked(&wam.heap);
unify!(
wam,
heap_loc_as_cell!(0),
heap_loc_as_cell!(term_write_result_2.heap_loc)
);
assert!(!wam.fail);
}
all_cells_unmarked(&wam.heap);
wam.heap.clear();
wam.heap.push(pstr_as_cell!(atom!("this is a string")));
wam.heap.push(heap_loc_as_cell!(1));
wam.heap.push(pstr_as_cell!(atom!("this is a string")));
wam.heap.push(pstr_loc_as_cell!(4));
wam.heap.push(pstr_offset_as_cell!(0));
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(6)));
unify!(wam, pstr_loc_as_cell!(0), pstr_loc_as_cell!(2));
assert!(!wam.fail);
assert_eq!(wam.heap[1], pstr_loc_as_cell!(4));
all_cells_unmarked(&wam.heap);
wam.heap.clear();
wam.heap.push(list_loc_as_cell!(1));
wam.heap.push(atom_as_cell!(atom!("a")));
wam.heap.push(list_loc_as_cell!(3));
wam.heap.push(atom_as_cell!(atom!("b")));
wam.heap.push(heap_loc_as_cell!(0));
wam.heap.push(list_loc_as_cell!(6));
wam.heap.push(atom_as_cell!(atom!("a")));
wam.heap.push(list_loc_as_cell!(8));
wam.heap.push(atom_as_cell!(atom!("b")));
wam.heap.push(heap_loc_as_cell!(5));
unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
assert!(!wam.fail);
all_cells_unmarked(&wam.heap);
wam.heap.clear();
wam.heap.push(list_loc_as_cell!(1));
wam.heap.push(atom_as_cell!(atom!("a")));
wam.heap.push(list_loc_as_cell!(3));
wam.heap.push(atom_as_cell!(atom!("b")));
wam.heap.push(heap_loc_as_cell!(0));
wam.heap.push(list_loc_as_cell!(6));
wam.heap.push(atom_as_cell!(atom!("a")));
wam.heap.push(list_loc_as_cell!(8));
wam.heap.push(atom_as_cell!(atom!("c")));
wam.heap.push(heap_loc_as_cell!(5));
unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
assert!(wam.fail);
wam.fail = false;
all_cells_unmarked(&wam.heap);
wam.heap.clear();
wam.heap.push(list_loc_as_cell!(1));
wam.heap.push(atom_as_cell!(atom!("a")));
wam.heap.push(list_loc_as_cell!(3));
wam.heap.push(atom_as_cell!(atom!("b")));
wam.heap.push(heap_loc_as_cell!(5));
wam.heap.push(list_loc_as_cell!(6));
wam.heap.push(atom_as_cell!(atom!("a")));
wam.heap.push(list_loc_as_cell!(8));
wam.heap.push(atom_as_cell!(atom!("b")));
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]
fn test_unify_with_occurs_check() {
let mut wam = MachineState::new();
let mut op_dir = default_op_dir();
op_dir.insert(
(atom!("+"), Fixity::In),
OpDesc::build_with(500, YFX as u8),
);
op_dir.insert(
(atom!("-"), Fixity::In),
OpDesc::build_with(500, YFX as u8),
);
op_dir.insert(
(atom!("*"), Fixity::In),
OpDesc::build_with(400, YFX as u8),
);
op_dir.insert(
(atom!("/"), Fixity::In),
OpDesc::build_with(400, YFX as u8),
);
{
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();
all_cells_unmarked(&wam.heap);
unify_with_occurs_check!(
wam,
str_loc_as_cell!(0),
str_loc_as_cell!(term_write_result_2.heap_loc)
);
assert!(wam.fail);
}
}
#[test]
fn test_term_compare() {
use ordered_float::OrderedFloat;
use std::cmp::Ordering;
let mut wam = MachineState::new();
wam.heap.push(heap_loc_as_cell!(0));
wam.heap.push(heap_loc_as_cell!(1));
assert_eq!(
compare_term_test!(wam, wam.heap[0], wam.heap[1]),
Some(Ordering::Less)
);
assert_eq!(
compare_term_test!(wam, wam.heap[1], wam.heap[0]),
Some(Ordering::Greater)
);
assert_eq!(
compare_term_test!(wam, wam.heap[0], wam.heap[0]),
Some(Ordering::Equal)
);
assert_eq!(
compare_term_test!(wam, wam.heap[1], wam.heap[1]),
Some(Ordering::Equal)
);
assert_eq!(
compare_term_test!(
wam,
atom_as_cell!(atom!("atom")),
atom_as_cstr_cell!(atom!("string"))
),
Some(Ordering::Less)
);
assert_eq!(
compare_term_test!(
wam,
atom_as_cell!(atom!("atom")),
atom_as_cell!(atom!("atom"))
),
Some(Ordering::Equal)
);
assert_eq!(
compare_term_test!(
wam,
atom_as_cell!(atom!("atom")),
atom_as_cell!(atom!("aaa"))
),
Some(Ordering::Greater)
);
assert_eq!(
compare_term_test!(
wam,
fixnum_as_cell!(Fixnum::build_with(6)),
heap_loc_as_cell!(1)
),
Some(Ordering::Greater)
);
wam.heap.clear();
wam.heap.push(atom_as_cell!(atom!("f"), 1));
wam.heap.push(heap_loc_as_cell!(1));
assert_eq!(
compare_term_test!(
wam,
heap_loc_as_cell!(0),
heap_loc_as_cell!(0)
),
Some(Ordering::Equal)
);
assert_eq!(
compare_term_test!(
wam,
heap_loc_as_cell!(0),
atom_as_cell!(atom!("a"))
),
Some(Ordering::Greater)
);
wam.heap.clear();
// [1,2,3]
wam.heap.push(list_loc_as_cell!(1));
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1)));
wam.heap.push(list_loc_as_cell!(3));
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2)));
wam.heap.push(list_loc_as_cell!(5));
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(3)));
wam.heap.push(empty_list_as_cell!());
// [1,2]
wam.heap.push(list_loc_as_cell!(8));
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1)));
wam.heap.push(list_loc_as_cell!(10));
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2)));
wam.heap.push(empty_list_as_cell!());
assert_eq!(
compare_term_test!(
wam,
heap_loc_as_cell!(7),
heap_loc_as_cell!(7)
),
Some(Ordering::Equal)
);
assert_eq!(
compare_term_test!(
wam,
heap_loc_as_cell!(0),
heap_loc_as_cell!(7)
),
Some(Ordering::Greater)
);
assert_eq!(
compare_term_test!(
wam,
empty_list_as_cell!(),
heap_loc_as_cell!(7)
),
Some(Ordering::Less)
);
assert_eq!(
compare_term_test!(
wam,
empty_list_as_cell!(),
fixnum_as_cell!(Fixnum::build_with(1))
),
Some(Ordering::Greater)
);
assert_eq!(
compare_term_test!(
wam,
empty_list_as_cell!(),
atom_as_cstr_cell!(atom!("string"))
),
Some(Ordering::Less)
);
assert_eq!(
compare_term_test!(
wam,
empty_list_as_cell!(),
atom_as_cell!(atom!("atom"))
),
Some(Ordering::Less)
);
assert_eq!(
compare_term_test!(
wam,
atom_as_cell!(atom!("atom")),
empty_list_as_cell!()
),
Some(Ordering::Greater)
);
let one_p_one = typed_arena_ptr_as_cell!(
arena_alloc!(OrderedFloat(1.1), &mut wam.arena)
);
assert_eq!(
compare_term_test!(
wam,
one_p_one,
fixnum_as_cell!(Fixnum::build_with(1))
),
Some(Ordering::Less)
);
assert_eq!(
compare_term_test!(
wam,
fixnum_as_cell!(Fixnum::build_with(1)),
one_p_one
),
Some(Ordering::Greater)
);
}
#[test]
fn is_cyclic_term_tests() {
let mut wam = MachineState::new();
assert!(!wam.is_cyclic_term(atom_as_cell!(atom!("f"))));
assert!(!wam.is_cyclic_term(fixnum_as_cell!(Fixnum::build_with(555))));
wam.heap.push(heap_loc_as_cell!(0));
assert!(!wam.is_cyclic_term(heap_loc_as_cell!(0)));
all_cells_unmarked(&wam.heap);
wam.heap.clear();
wam.heap.extend(functor!(atom!("f"), [atom(atom!("a")), atom(atom!("b"))]));
assert!(!wam.is_cyclic_term(str_loc_as_cell!(0)));
all_cells_unmarked(&wam.heap);
assert!(!wam.is_cyclic_term(heap_loc_as_cell!(1)));
all_cells_unmarked(&wam.heap);
assert!(!wam.is_cyclic_term(heap_loc_as_cell!(2)));
all_cells_unmarked(&wam.heap);
wam.heap[2] = str_loc_as_cell!(0);
print_heap_terms(wam.heap.iter(), 0);
assert!(wam.is_cyclic_term(str_loc_as_cell!(0)));
all_cells_unmarked(&wam.heap);
wam.heap[2] = atom_as_cell!(atom!("b"));
wam.heap[1] = str_loc_as_cell!(0);
assert!(wam.is_cyclic_term(str_loc_as_cell!(0)));
all_cells_unmarked(&wam.heap);
assert!(wam.is_cyclic_term(heap_loc_as_cell!(1)));
all_cells_unmarked(&wam.heap);
wam.heap.clear();
wam.heap.push(pstr_as_cell!(atom!("a string")));
wam.heap.push(empty_list_as_cell!());
assert!(!wam.is_cyclic_term(heap_loc_as_cell!(0)));
}
}

View File

@@ -1,67 +1,70 @@
use prolog_parser::ast::*;
use prolog_parser::tabled_rc::*;
use prolog_parser::{clause_name, temp_v};
pub mod arithmetic_ops;
pub mod attributed_variables;
pub mod code_repo;
pub mod code_walker;
#[macro_use]
pub mod loader;
pub mod compile;
pub mod copier;
pub mod gc;
pub mod heap;
pub mod load_state;
pub mod machine_errors;
pub mod machine_indices;
pub mod machine_state;
pub mod machine_state_impl;
pub mod mock_wam;
pub mod partial_string;
pub mod preprocessor;
pub mod stack;
pub mod streams;
pub mod system_calls;
pub mod term_stream;
use lazy_static::lazy_static;
use crate::clause_types::*;
use crate::atom_table::*;
use crate::forms::*;
use crate::instructions::*;
use crate::machine::loader::*;
use crate::machine::term_stream::{LiveTermStream, LoadStatePayload, TermStream};
use crate::read::*;
mod attributed_variables;
pub(super) mod code_repo;
pub(crate) mod code_walker;
#[macro_use]
pub(crate) mod loader;
mod compile;
mod copier;
pub(crate) mod heap;
mod load_state;
pub(crate) mod machine_errors;
pub(crate) mod machine_indices;
pub(super) mod machine_state;
pub(crate) mod partial_string;
mod preprocessor;
mod raw_block;
mod stack;
pub(crate) mod streams;
mod term_stream;
#[macro_use]
mod arithmetic_ops;
#[macro_use]
mod machine_state_impl;
mod system_calls;
use crate::machine::code_repo::*;
use crate::machine::compile::*;
use crate::machine::heap::*;
use crate::machine::loader::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::*;
pub use crate::machine::streams::Stream;
use crate::machine::streams::*;
use crate::types::*;
use indexmap::IndexMap;
//use std::convert::TryFrom;
use prolog_parser::ast::ClauseName;
use std::fs::File;
use std::mem;
use lazy_static::lazy_static;
use std::env;
use std::path::PathBuf;
use std::sync::atomic::AtomicBool;
lazy_static! {
pub static ref INTERRUPT: AtomicBool = AtomicBool::new(false);
}
#[derive(Debug)]
pub struct Machine {
pub(super) machine_st: MachineState,
pub(super) inner_heap: Heap,
pub(super) policies: MachinePolicies,
pub(super) indices: IndexStore,
pub(super) code_repo: CodeRepo,
pub(super) user_input: Stream,
pub(super) user_output: Stream,
pub(super) user_error: Stream,
pub(super) load_contexts: Vec<LoadContext>,
}
#[derive(Debug)]
pub(crate) struct MachinePolicies {
call_policy: Box<dyn CallPolicy>,
cut_policy: Box<dyn CutPolicy>,
}
lazy_static! {
pub static ref INTERRUPT: AtomicBool = AtomicBool::new(false);
}
impl MachinePolicies {
#[inline]
fn new() -> Self {
@@ -80,10 +83,10 @@ impl Default for MachinePolicies {
}
#[derive(Debug)]
pub(super) struct LoadContext {
pub struct LoadContext {
pub(super) path: PathBuf,
pub(super) stream: Stream,
pub(super) module: ClauseName,
pub(super) module: Atom,
}
impl LoadContext {
@@ -100,32 +103,49 @@ impl LoadContext {
LoadContext {
path: path_buf,
stream,
module: clause_name!("user"),
module: atom!("user"),
}
}
}
#[derive(Debug)]
pub struct Machine {
pub(super) machine_st: MachineState,
pub(super) policies: MachinePolicies,
pub(super) indices: IndexStore,
pub(super) code_repo: CodeRepo,
pub(super) user_input: Stream,
pub(super) user_output: Stream,
pub(super) user_error: Stream,
pub(super) load_contexts: Vec<LoadContext>,
}
#[inline]
fn current_dir() -> PathBuf {
std::env::current_dir().unwrap_or(PathBuf::from("./"))
env::current_dir().unwrap_or(PathBuf::from("./"))
}
include!(concat!(env!("OUT_DIR"), "/libraries.rs"));
pub struct MachinePreludeView<'a> {
pub indices: &'a mut IndexStore,
pub code_repo: &'a mut CodeRepo,
pub load_contexts: &'a mut Vec<LoadContext>,
}
impl Machine {
fn run_module_predicate(&mut self, module_name: ClauseName, key: PredicateKey) {
#[inline]
pub fn prelude_view_and_machine_st(&mut self) -> (MachinePreludeView, &mut MachineState) {
(
MachinePreludeView {
indices: &mut self.indices,
code_repo: &mut self.code_repo,
load_contexts: &mut self.load_contexts,
},
&mut self.machine_st
)
}
pub fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) {
let err = self.machine_st.session_error(err);
let stub = functor_stub(key.0, key.1);
let err = self.machine_st.error_form(err, stub);
self.machine_st.throw_exception(err);
return;
}
}
impl Machine {
fn run_module_predicate(&mut self, module_name: Atom, key: PredicateKey) {
if let Some(module) = self.indices.modules.get(&module_name) {
if let Some(ref code_index) = module.code_dir.get(&key) {
let p = code_index.local().unwrap();
@@ -140,27 +160,29 @@ impl Machine {
unreachable!();
}
pub fn load_file(&mut self, path: String, stream: Stream) {
self.machine_st[temp_v!(1)] =
Addr::Stream(self.machine_st.heap.push(HeapCellValue::Stream(stream)));
pub fn load_file(&mut self, path: &str, stream: Stream) {
self.machine_st.registers[1] = stream_as_cell!(stream);
self.machine_st.registers[2] = atom_as_cell!(
self.machine_st.atom_tbl.build_with(path)
);
self.machine_st[temp_v!(2)] = Addr::Con(self.machine_st.heap.push(HeapCellValue::Atom(
clause_name!(path, self.machine_st.atom_tbl),
None,
)));
self.run_module_predicate(clause_name!("loader"), (clause_name!("file_load"), 2));
self.run_module_predicate(atom!("loader"), (atom!("file_load"), 2));
}
fn load_top_level(&mut self) {
let mut path_buf = current_dir();
path_buf.push("toplevel.pl");
let path = path_buf.to_str().unwrap().to_string();
path_buf.push("src/toplevel.pl");
self.load_file(path, Stream::from(include_str!("../toplevel.pl")));
let path = path_buf.to_str().unwrap();
let toplevel_stream = Stream::from_static_string(
include_str!("../toplevel.pl"),
&mut self.machine_st.arena,
);
if let Some(toplevel) = self.indices.modules.get(&clause_name!("$toplevel")) {
self.load_file(path, toplevel_stream);
if let Some(toplevel) = self.indices.modules.get(&atom!("$toplevel")) {
load_module(
&mut self.indices.code_dir,
&mut self.indices.op_dir,
@@ -178,9 +200,15 @@ impl Machine {
path_buf.push("machine/attributed_variables.pl");
bootstrapping_compile(
Stream::from(include_str!("attributed_variables.pl")),
Stream::from_static_string(
include_str!("attributed_variables.pl"),
&mut self.machine_st.arena,
),
self,
ListingSource::from_file_and_path(clause_name!("attributed_variables"), path_buf),
ListingSource::from_file_and_path(
atom!("attributed_variables"),
path_buf,
),
)
.unwrap();
@@ -188,44 +216,49 @@ impl Machine {
path_buf.push("machine/project_attributes.pl");
bootstrapping_compile(
Stream::from(include_str!("project_attributes.pl")),
Stream::from_static_string(
include_str!("project_attributes.pl"),
&mut self.machine_st.arena,
),
self,
ListingSource::from_file_and_path(clause_name!("project_attributes"), path_buf),
ListingSource::from_file_and_path(atom!("project_attributes"), path_buf),
)
.unwrap();
if let Some(module) = self.indices.modules.get(&clause_name!("$atts")) {
if let Some(code_index) = module.code_dir.get(&(clause_name!("driver"), 2)) {
if let Some(module) = self.indices.modules.get(&atom!("$atts")) {
if let Some(code_index) = module.code_dir.get(&(atom!("driver"), 2)) {
self.machine_st.attr_var_init.verify_attrs_loc = code_index.local().unwrap();
}
}
}
pub fn run_top_level(&mut self) {
use std::env;
let mut arg_pstrs = vec![];
for arg in env::args() {
arg_pstrs.push(self.machine_st.heap.put_complete_string(&arg));
arg_pstrs.push(put_complete_string(
&mut self.machine_st.heap,
&arg,
&mut self.machine_st.atom_tbl,
));
}
let list_addr = Addr::HeapCell(self.machine_st.heap.to_list(arg_pstrs.into_iter()));
self.machine_st.registers[1] = heap_loc_as_cell!(
iter_to_heap_list(&mut self.machine_st.heap, arg_pstrs.into_iter())
);
self.machine_st[temp_v!(1)] = list_addr;
self.run_module_predicate(clause_name!("$toplevel"), (clause_name!("$repl"), 1));
self.run_module_predicate(atom!("$toplevel"), (atom!("$repl"), 1));
}
pub(crate) fn configure_modules(&mut self) {
fn update_call_n_indices(loader: &Module, target_code_dir: &mut CodeDir) {
for arity in 1..66 {
let key = (clause_name!("call"), arity);
let key = (atom!("call"), arity);
match loader.code_dir.get(&key) {
Some(src_code_index) => {
let target_code_index = target_code_dir
.entry(key.clone())
.entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined));
target_code_index.set(src_code_index.get());
@@ -237,15 +270,15 @@ impl Machine {
}
}
if let Some(loader) = self.indices.modules.swap_remove(&clause_name!("loader")) {
if let Some(builtins) = self.indices.modules.get_mut(&clause_name!("builtins")) {
if let Some(loader) = self.indices.modules.swap_remove(&atom!("loader")) {
if let Some(builtins) = self.indices.modules.get_mut(&atom!("builtins")) {
// Import loader's exports into the builtins module so they will be
// implicitly included in every further module.
load_module(
&mut builtins.code_dir,
&mut builtins.op_dir,
&mut builtins.meta_predicates,
&CompilationTarget::Module(clause_name!("builtins")),
&CompilationTarget::Module(atom!("builtins")),
&loader,
);
@@ -257,7 +290,7 @@ impl Machine {
builtins
.module_decl
.exports
.push(ModuleExport::PredicateKey((clause_name!("call"), arity)));
.push(ModuleExport::PredicateKey((atom!("call"), arity)));
}
}
@@ -267,17 +300,24 @@ impl Machine {
update_call_n_indices(&loader, &mut self.indices.code_dir);
self.indices.modules.insert(clause_name!("loader"), loader);
self.indices.modules.insert(atom!("loader"), loader);
} else {
unreachable!()
}
}
pub fn new(user_input: Stream, user_output: Stream, user_error: Stream) -> Self {
pub fn new() -> Self {
use ref_thread_local::RefThreadLocal;
let mut machine_st = MachineState::new();
let user_input = Stream::stdin(&mut machine_st.arena);
let user_output = Stream::stdout(&mut machine_st.arena);
let user_error = Stream::stderr(&mut machine_st.arena);
let mut wam = Machine {
machine_st: MachineState::new(),
machine_st,
inner_heap: Heap::new(),
policies: MachinePolicies::new(),
indices: IndexStore::new(),
code_repo: CodeRepo::new(),
@@ -293,23 +333,29 @@ impl Machine {
lib_path.push("lib");
bootstrapping_compile(
Stream::from(LIBRARIES.borrow()["ops_and_meta_predicates"]),
Stream::from_static_string(
LIBRARIES.borrow()["ops_and_meta_predicates"],
&mut wam.machine_st.arena,
),
&mut wam,
ListingSource::from_file_and_path(
clause_name!("ops_and_meta_predicates.pl"),
atom!("ops_and_meta_predicates.pl"),
lib_path.clone(),
),
)
.unwrap();
bootstrapping_compile(
Stream::from(LIBRARIES.borrow()["builtins"]),
Stream::from_static_string(
LIBRARIES.borrow()["builtins"],
&mut wam.machine_st.arena,
),
&mut wam,
ListingSource::from_file_and_path(clause_name!("builtins.pl"), lib_path.clone()),
ListingSource::from_file_and_path(atom!("builtins.pl"), lib_path.clone()),
)
.unwrap();
if let Some(builtins) = wam.indices.modules.get(&clause_name!("builtins")) {
if let Some(builtins) = wam.indices.modules.get(&atom!("builtins")) {
load_module(
&mut wam.indices.code_dir,
&mut wam.indices.op_dir,
@@ -324,15 +370,15 @@ impl Machine {
lib_path.pop(); // remove the "lib" at the end
bootstrapping_compile(
Stream::from(include_str!("../loader.pl")),
Stream::from_static_string(include_str!("../loader.pl"), &mut wam.machine_st.arena),
&mut wam,
ListingSource::from_file_and_path(clause_name!("loader.pl"), lib_path.clone()),
ListingSource::from_file_and_path(atom!("loader.pl"), lib_path.clone()),
)
.unwrap();
wam.configure_modules();
if let Some(loader) = wam.indices.modules.get(&clause_name!("loader")) {
if let Some(loader) = wam.indices.modules.get(&atom!("loader")) {
load_module(
&mut wam.indices.code_dir,
&mut wam.indices.op_dir,
@@ -352,38 +398,21 @@ impl Machine {
}
pub(crate) fn configure_streams(&mut self) {
self.user_input.options_mut().alias = Some(clause_name!("user_input"));
self.user_input.options_mut().set_alias_to_atom_opt(Some(atom!("user_input")));
self.indices
.stream_aliases
.insert(clause_name!("user_input"), self.user_input.clone());
.insert(atom!("user_input"), self.user_input);
self.indices.streams.insert(self.user_input.clone());
self.indices.streams.insert(self.user_input);
self.user_output.options_mut().alias = Some(clause_name!("user_output"));
self.user_output.options_mut().set_alias_to_atom_opt(Some(atom!("user_output")));
self.indices
.stream_aliases
.insert(clause_name!("user_output"), self.user_output.clone());
.insert(atom!("user_output"), self.user_output);
self.user_error.options_mut().alias = Some(clause_name!("user_error"));
self.indices
.stream_aliases
.insert(clause_name!("user_error"), self.user_error.clone());
self.indices.streams.insert(self.user_output.clone());
}
fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) {
let h = self.machine_st.heap.h();
let err = MachineError::session_error(h, err);
let stub = MachineError::functor_stub(key.0, key.1);
let err = self.machine_st.error_form(err, stub);
self.machine_st.throw_exception(err);
return;
self.indices.streams.insert(self.user_output);
}
fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) {
@@ -604,13 +633,14 @@ impl MachineState {
self.b0 = self.stack.index_or_frame(b).prelude.b0;
self.p = CodePtr::Local(self.stack.index_or_frame(b).prelude.bp);
self.pdl.clear();
self.fail = false;
}
fn check_machine_index(&mut self, code_repo: &CodeRepo) -> bool {
match self.p {
CodePtr::Local(LocalCodePtr::DirEntry(p))
| CodePtr::Local(LocalCodePtr::IndexingBuf(p, ..))
CodePtr::Local(LocalCodePtr::DirEntry(p)) |
CodePtr::Local(LocalCodePtr::IndexingBuf(p, ..))
if p < code_repo.code.len() => {}
CodePtr::Local(LocalCodePtr::Halt) | CodePtr::REPL(..) => {
return false;
@@ -690,7 +720,9 @@ impl MachineState {
self.p = CodePtr::Local(self.attr_var_init.cp);
let instigating_p = CodePtr::Local(self.attr_var_init.instigating_p);
let instigating_instr = code_repo.lookup_instr(false, &instigating_p).unwrap();
let instigating_instr = code_repo
.lookup_instr(false, &instigating_p)
.unwrap();
if !instigating_instr.as_ref().is_head_instr() {
let cp = self.p.local();

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,10 @@
use prolog_parser::ast::*;
use prolog_parser::tabled_rc::*;
use prolog_parser::{atom, clause_name, rc_atom};
use crate::atom_table::*;
use crate::clause_types::*;
use crate::forms::*;
use crate::iterators::*;
use crate::machine::load_state::*;
use crate::machine::loader::*;
use crate::machine::machine_errors::*;
use crate::machine::*;
use crate::parser::ast::*;
use indexmap::IndexSet;
@@ -30,89 +28,81 @@ pub(crate) enum CutContext {
HasCutVariable,
}
pub(crate) fn fold_by_str<I>(terms: I, mut term: Term, sym: ClauseName) -> Term
pub(crate) fn fold_by_str<I>(terms: I, mut term: Term, sym: Atom) -> Term
where
I: DoubleEndedIterator<Item = Term>,
{
for prec in terms.rev() {
term = Term::Clause(
Cell::default(),
sym.clone(),
vec![Box::new(prec), Box::new(term)],
None,
);
term = Term::Clause(Cell::default(), sym, vec![prec, term]);
}
term
}
pub(crate) fn to_op_decl(
prec: usize,
spec: &str,
name: ClauseName,
prec: u16,
spec: Atom,
name: Atom,
) -> Result<OpDecl, CompilationError> {
match spec {
"xfx" => Ok(OpDecl::new(prec, XFX, name)),
"xfy" => Ok(OpDecl::new(prec, XFY, name)),
"yfx" => Ok(OpDecl::new(prec, YFX, name)),
"fx" => Ok(OpDecl::new(prec, FX, name)),
"fy" => Ok(OpDecl::new(prec, FY, name)),
"xf" => Ok(OpDecl::new(prec, XF, name)),
"yf" => Ok(OpDecl::new(prec, YF, name)),
atom!("xfx") => Ok(OpDecl::new(OpDesc::build_with(prec, XFX as u8), name)),
atom!("xfy") => Ok(OpDecl::new(OpDesc::build_with(prec, XFY as u8), name)),
atom!("yfx") => Ok(OpDecl::new(OpDesc::build_with(prec, YFX as u8), name)),
atom!("fx") => Ok(OpDecl::new(OpDesc::build_with(prec, FX as u8), name)),
atom!("fy") => Ok(OpDecl::new(OpDesc::build_with(prec, FY as u8), name)),
atom!("xf") => Ok(OpDecl::new(OpDesc::build_with(prec, XF as u8), name)),
atom!("yf") => Ok(OpDecl::new(OpDesc::build_with(prec, YF as u8), name)),
_ => Err(CompilationError::InconsistentEntry),
}
}
fn setup_op_decl(
mut terms: Vec<Box<Term>>,
atom_tbl: TabledData<Atom>,
mut terms: Vec<Term>,
atom_tbl: &mut AtomTable,
) -> Result<OpDecl, CompilationError> {
let name = match *terms.pop().unwrap() {
Term::Constant(_, Constant::Atom(name, _)) => name,
Term::Constant(_, Constant::Char(c)) => clause_name!(c.to_string(), atom_tbl),
let name = match terms.pop().unwrap() {
Term::Literal(_, Literal::Atom(name)) => name,
Term::Literal(_, Literal::Char(c)) => atom_tbl.build_with(&c.to_string()),
_ => return Err(CompilationError::InconsistentEntry),
};
let spec = match *terms.pop().unwrap() {
Term::Constant(_, Constant::Atom(name, _)) => name,
Term::Constant(_, Constant::Char(c)) => clause_name!(c.to_string(), atom_tbl),
let spec = match terms.pop().unwrap() {
Term::Literal(_, Literal::Atom(name)) => name,
Term::Literal(_, Literal::Char(c)) => atom_tbl.build_with(&c.to_string()),
_ => return Err(CompilationError::InconsistentEntry),
};
let prec = match *terms.pop().unwrap() {
Term::Constant(_, Constant::Fixnum(bi)) => match usize::try_from(bi) {
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::InconsistentEntry),
},
_ => return Err(CompilationError::InconsistentEntry),
};
to_op_decl(prec, spec.as_str(), name)
to_op_decl(prec, spec, name)
}
fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, CompilationError> {
match term {
Term::Clause(_, ref slash, ref mut terms, Some(_))
if (slash.as_str() == "/" || slash.as_str() == "//") && terms.len() == 2 =>
Term::Clause(_, slash, ref mut terms)
if (*slash == atom!("/") || *slash == atom!("//")) && terms.len() == 2 =>
{
let arity = *terms.pop().unwrap();
let name = *terms.pop().unwrap();
let arity = terms.pop().unwrap();
let name = terms.pop().unwrap();
let arity = arity
.into_constant()
.and_then(|c| match c {
Constant::Integer(n) => n.to_usize(),
Constant::Fixnum(n) => usize::try_from(n).ok(),
_ => None,
})
.ok_or(CompilationError::InvalidModuleExport)?;
let arity = match arity {
Term::Literal(_, Literal::Integer(n)) => n.to_usize(),
Term::Literal(_, Literal::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
_ => None,
}.ok_or(CompilationError::InvalidModuleExport)?;
let name = name
.into_constant()
.and_then(|c| c.to_atom())
.ok_or(CompilationError::InvalidModuleExport)?;
let name = match name {
Term::Literal(_, Literal::Atom(name)) => Some(name),
_ => None,
}.ok_or(CompilationError::InvalidModuleExport)?;
if slash.as_str() == "/" {
if *slash == atom!("/") {
Ok((name, arity))
} else {
Ok((name, arity + 2))
@@ -148,13 +138,13 @@ fn setup_scoped_predicate_indicator(term: &mut Term) -> Result<ScopedPredicateKe
fn setup_module_export(
mut term: Term,
atom_tbl: TabledData<Atom>,
atom_tbl: &mut AtomTable,
) -> Result<ModuleExport, CompilationError> {
setup_predicate_indicator(&mut term)
.map(ModuleExport::PredicateKey)
.or_else(|_| {
if let Term::Clause(_, name, terms, _) = term {
if terms.len() == 3 && name.as_str() == "op" {
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)
@@ -167,18 +157,18 @@ fn setup_module_export(
pub(super) fn setup_module_export_list(
mut export_list: Term,
atom_tbl: TabledData<Atom>,
atom_tbl: &mut AtomTable,
) -> Result<Vec<ModuleExport>, CompilationError> {
let mut exports = vec![];
while let Term::Cons(_, t1, t2) = export_list {
let module_export = setup_module_export(*t1, atom_tbl.clone())?;
let module_export = setup_module_export(*t1, atom_tbl)?;
exports.push(module_export);
export_list = *t2;
}
if let Term::Constant(_, Constant::EmptyList) = export_list {
if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list {
Ok(exports)
} else {
Err(CompilationError::InvalidModuleDecl)
@@ -186,35 +176,33 @@ pub(super) fn setup_module_export_list(
}
fn setup_module_decl(
mut terms: Vec<Box<Term>>,
atom_tbl: TabledData<Atom>,
mut terms: Vec<Term>,
atom_tbl: &mut AtomTable,
) -> Result<ModuleDecl, CompilationError> {
let export_list = *terms.pop().unwrap();
let name = terms
.pop()
.unwrap()
.into_constant()
.and_then(|c| c.to_atom())
.ok_or(CompilationError::InvalidModuleDecl)?;
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)?;
Ok(ModuleDecl { name, exports })
}
fn setup_use_module_decl(mut terms: Vec<Box<Term>>) -> Result<ModuleSource, CompilationError> {
match *terms.pop().unwrap() {
Term::Clause(_, ref name, ref mut terms, None)
if name.as_str() == "library" && terms.len() == 1 =>
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 =>
{
terms
.pop()
.unwrap()
.into_constant()
.and_then(|c| c.to_atom())
.map(|c| ModuleSource::Library(c))
.ok_or(CompilationError::InvalidUseModuleDecl)
match terms.pop().unwrap() {
Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)),
_ => Err(CompilationError::InvalidModuleDecl),
}
}
Term::Constant(_, Constant::Atom(ref name, _)) => Ok(ModuleSource::File(name.clone())),
Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)),
_ => Err(CompilationError::InvalidUseModuleDecl),
}
}
@@ -224,10 +212,10 @@ fn setup_double_quotes(mut terms: Vec<Box<Term>>) -> Result<DoubleQuotes, Compil
let dbl_quotes = *terms.pop().unwrap();
match terms[0].as_ref() {
Term::Constant(_, Constant::Atom(ref name, _))
Term::Literal(_, Literal::Atom(ref name, _))
if name.as_str() == "double_quotes" => {
match dbl_quotes {
Term::Constant(_, Constant::Atom(name, _)) => {
Term::Literal(_, Literal::Atom(name, _)) => {
match name.as_str() {
"atom" => Ok(DoubleQuotes::Atom),
"chars" => Ok(DoubleQuotes::Chars),
@@ -250,34 +238,31 @@ fn setup_double_quotes(mut terms: Vec<Box<Term>>) -> Result<DoubleQuotes, Compil
type UseModuleExport = (ModuleSource, IndexSet<ModuleExport>);
fn setup_qualified_import(
mut terms: Vec<Box<Term>>,
atom_tbl: TabledData<Atom>,
mut terms: Vec<Term>,
atom_tbl: &mut AtomTable,
) -> Result<UseModuleExport, CompilationError> {
let mut export_list = *terms.pop().unwrap();
let module_src = match *terms.pop().unwrap() {
Term::Clause(_, ref name, ref mut terms, None)
if name.as_str() == "library" && terms.len() == 1 =>
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 =>
{
terms
.pop()
.unwrap()
.into_constant()
.and_then(|c| c.to_atom())
.map(|c| ModuleSource::Library(c))
.ok_or(CompilationError::InvalidUseModuleDecl)
match terms.pop().unwrap() {
Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)),
_ => Err(CompilationError::InvalidModuleDecl),
}
}
Term::Constant(_, Constant::Atom(ref name, _)) => Ok(ModuleSource::File(name.clone())),
Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)),
_ => Err(CompilationError::InvalidUseModuleDecl),
}?;
let mut exports = IndexSet::new();
while let Term::Cons(_, t1, t2) = export_list {
exports.insert(setup_module_export(*t1, atom_tbl.clone())?);
exports.insert(setup_module_export(*t1, atom_tbl)?);
export_list = *t2;
}
if let Term::Constant(_, Constant::EmptyList) = export_list {
if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list {
Ok((module_src, exports))
} else {
Err(CompilationError::InvalidModuleDecl)
@@ -322,29 +307,29 @@ fn setup_qualified_import(
* -
* ?
*/
fn setup_meta_predicate<'a>(
mut terms: Vec<Box<Term>>,
load_state: &LoadState<'a>,
) -> Result<(ClauseName, ClauseName, Vec<MetaSpec>), CompilationError> {
fn setup_meta_predicate<'a, LS: LoadState<'a>>(
mut terms: Vec<Term>,
loader: &mut Loader<'a, LS>,
) -> Result<(Atom, Atom, Vec<MetaSpec>), CompilationError> {
fn get_name_and_meta_specs(
name: ClauseName,
terms: &mut [Box<Term>],
) -> Result<(ClauseName, Vec<MetaSpec>), CompilationError> {
name: Atom,
terms: &mut [Term],
) -> Result<(Atom, Vec<MetaSpec>), CompilationError> {
let mut meta_specs = vec![];
for meta_spec in terms.into_iter() {
match &**meta_spec {
Term::Constant(_, Constant::Atom(meta_spec, _)) => {
let meta_spec = match meta_spec.as_str() {
"+" => MetaSpec::Plus,
"-" => MetaSpec::Minus,
"?" => MetaSpec::Either,
match meta_spec {
Term::Literal(_, Literal::Atom(meta_spec)) => {
let meta_spec = match meta_spec {
atom!("+") => MetaSpec::Plus,
atom!("-") => MetaSpec::Minus,
atom!("?") => MetaSpec::Either,
_ => return Err(CompilationError::InvalidMetaPredicateDecl),
};
meta_specs.push(meta_spec);
}
Term::Constant(_, Constant::Fixnum(n)) => match usize::try_from(*n) {
Term::Literal(_, Literal::Fixnum(n)) => match usize::try_from(n.get_num()) {
Ok(n) if n <= MAX_ARITY => {
meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n));
}
@@ -361,16 +346,15 @@ fn setup_meta_predicate<'a>(
Ok((name, meta_specs))
}
match *terms.pop().unwrap() {
Term::Clause(_, name, mut terms, _) if name.as_str() == ":" && terms.len() == 2 => {
let spec = *terms.pop().unwrap();
let module_name = *terms.pop().unwrap();
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();
match module_name {
Term::Constant(_, Constant::Atom(module_name, _)) => match spec {
Term::Clause(_, name, mut terms, _) => {
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),
@@ -378,10 +362,10 @@ fn setup_meta_predicate<'a>(
_ => Err(CompilationError::InvalidMetaPredicateDecl),
}
}
Term::Clause(_, name, mut terms, _) => {
Term::Clause(_, name, mut terms) => {
let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?;
Ok((
load_state.compilation_target.module_name(),
loader.payload.compilation_target.module_name(),
name,
meta_specs,
))
@@ -420,11 +404,11 @@ fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, CompilationEr
}
}
fn mark_cut_variables_as(terms: &mut Vec<Term>, name: ClauseName) {
fn mark_cut_variables_as(terms: &mut Vec<Term>, name: Atom) {
for term in terms.iter_mut() {
match term {
&mut Term::Constant(_, Constant::Atom(ref mut var, _)) if var.as_str() == "!" => {
*var = name.clone()
&mut Term::Literal(_, Literal::Atom(ref mut var)) if *var == atom!("!") => {
*var = name;
}
_ => {}
}
@@ -433,12 +417,12 @@ fn mark_cut_variables_as(terms: &mut Vec<Term>, name: ClauseName) {
fn mark_cut_variable(term: &mut Term) -> bool {
let cut_var_found = match term {
&mut Term::Constant(_, Constant::Atom(ref var, _)) if var.as_str() == "!" => true,
&mut Term::Literal(_, Literal::Atom(ref var)) if *var == atom!("!") => true,
_ => false,
};
if cut_var_found {
*term = Term::Var(Cell::default(), rc_atom!("!"));
*term = Term::Var(Cell::default(), Rc::new(String::from("!")));
true
} else {
false
@@ -463,21 +447,21 @@ fn check_for_internal_if_then(terms: &mut Vec<Term>) {
return;
}
if let Some(Term::Clause(_, ref name, ref subterms, _)) = terms.last() {
if name.as_str() != "->" || subterms.len() != 2 {
if let Some(Term::Clause(_, name, ref subterms)) = terms.last() {
if *name != atom!("->") || subterms.len() != 2 {
return;
}
} else {
return;
}
if let Some(Term::Clause(_, _, mut subterms, _)) = terms.pop() {
let mut conq_terms = VecDeque::from(unfold_by_str(*subterms.pop().unwrap(), ","));
let mut pre_cut_terms = VecDeque::from(unfold_by_str(*subterms.pop().unwrap(), ","));
if let Some(Term::Clause(_, _, mut subterms)) = terms.pop() {
let mut conq_terms = VecDeque::from(unfold_by_str(subterms.pop().unwrap(), atom!(",")));
let mut pre_cut_terms = VecDeque::from(unfold_by_str(subterms.pop().unwrap(), atom!(",")));
conq_terms.push_front(Term::Constant(
conq_terms.push_front(Term::Literal(
Cell::default(),
Constant::Atom(clause_name!("blocked_!"), None),
Literal::Atom(atom!("blocked_!")),
));
while let Some(term) = pre_cut_terms.pop_back() {
@@ -489,37 +473,44 @@ fn check_for_internal_if_then(terms: &mut Vec<Term>) {
terms.push(fold_by_str(
conq_terms.into_iter(),
tail_term,
clause_name!(","),
atom!(","),
));
}
}
pub(super) fn setup_declaration<'a>(
load_state: &LoadState<'a>,
mut terms: Vec<Box<Term>>,
pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>,
mut terms: Vec<Term>,
) -> Result<Declaration, CompilationError> {
let term = *terms.pop().unwrap();
let atom_tbl = load_state.wam.machine_st.atom_tbl.clone();
let term = terms.pop().unwrap();
match term {
Term::Clause(_, name, mut terms, _) => match (name.as_str(), terms.len()) {
("dynamic", 1) => {
let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?;
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))
}
("module", 2) => Ok(Declaration::Module(setup_module_decl(terms, atom_tbl)?)),
("op", 3) => Ok(Declaration::Op(setup_op_decl(terms, atom_tbl)?)),
("non_counted_backtracking", 1) => {
let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?;
(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))
}
("use_module", 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)),
("use_module", 2) => {
(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)?;
Ok(Declaration::UseQualifiedModule(name, exports))
}
("meta_predicate", 1) => {
let (module_name, name, meta_specs) = setup_meta_predicate(terms, load_state)?;
(atom!("meta_predicate"), 1) => {
let (module_name, name, meta_specs) = setup_meta_predicate(terms, loader)?;
Ok(Declaration::MetaPredicate(module_name, name, meta_specs))
}
_ => Err(CompilationError::InconsistentEntry),
@@ -529,43 +520,43 @@ pub(super) fn setup_declaration<'a>(
}
#[inline]
fn clause_to_query_term<'a>(
load_state: &mut LoadState<'a>,
name: ClauseName,
terms: Vec<Box<Term>>,
fixity: Option<SharedOpDesc>,
fn clause_to_query_term<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>,
name: Atom,
terms: Vec<Term>,
) -> QueryTerm {
let ct = load_state.get_clause_type(name, terms.len(), fixity);
let ct = loader.get_clause_type(name, terms.len());
QueryTerm::Clause(Cell::default(), ct, terms, false)
}
#[inline]
fn qualified_clause_to_query_term<'a>(
load_state: &mut LoadState<'a>,
module_name: ClauseName,
name: ClauseName,
terms: Vec<Box<Term>>,
fixity: Option<SharedOpDesc>,
fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>,
module_name: Atom,
name: Atom,
terms: Vec<Term>,
) -> QueryTerm {
let ct = load_state.get_qualified_clause_type(module_name, name, terms.len(), fixity);
let ct = loader.get_qualified_clause_type(module_name, name, terms.len());
QueryTerm::Clause(Cell::default(), ct, terms, false)
}
#[derive(Debug)]
pub(crate) struct Preprocessor {
flags: MachineFlags,
queue: VecDeque<VecDeque<Term>>,
}
impl Preprocessor {
pub(super) fn new() -> Self {
pub(super) fn new(flags: MachineFlags) -> Self {
Preprocessor {
flags,
queue: VecDeque::new(),
}
}
fn setup_fact(&mut self, term: Term) -> Result<Term, CompilationError> {
match term {
Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => Ok(term),
Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => Ok(term),
_ => Err(CompilationError::InadmissibleFact),
}
}
@@ -579,20 +570,17 @@ impl Preprocessor {
}
}
vars.insert(rc_atom!("!"));
vars.insert(Rc::new(String::from("!")));
vars.into_iter()
.map(|v| Term::Var(Cell::default(), v))
.collect()
}
fn fabricate_rule_body(&self, vars: &Vec<Term>, body_term: Term) -> Term {
let vars_of_head = vars.iter().cloned().map(Box::new).collect();
let head_term = Term::Clause(Cell::default(), clause_name!(""), vars_of_head, None);
let head_term = Term::Clause(Cell::default(), atom!(""), vars.clone());
let rule = vec![head_term, body_term];
let rule = vec![Box::new(head_term), Box::new(body_term)];
let turnstile = clause_name!(":-");
Term::Clause(Cell::default(), turnstile, rule, None)
Term::Clause(Cell::default(), atom!(":-"), rule)
}
// the terms form the body of the rule. We create a head, by
@@ -609,16 +597,16 @@ impl Preprocessor {
fn fabricate_disjunct(&self, body_term: Term) -> (JumpStub, VecDeque<Term>) {
let vars = self.compute_head(&body_term);
let results = unfold_by_str(body_term, ";")
let results = unfold_by_str(body_term, atom!(";"))
.into_iter()
.map(|term| {
let mut subterms = unfold_by_str(term, ",");
let mut subterms = unfold_by_str(term, atom!(","));
mark_cut_variables(&mut subterms);
check_for_internal_if_then(&mut subterms);
let term = subterms.pop().unwrap();
let clause = fold_by_str(subterms.into_iter(), term, clause_name!(","));
let clause = fold_by_str(subterms.into_iter(), term, atom!(","));
self.fabricate_rule_body(&vars, clause)
})
@@ -628,80 +616,78 @@ impl Preprocessor {
}
fn fabricate_if_then(&self, prec: Term, conq: Term) -> (JumpStub, VecDeque<Term>) {
let mut prec_seq = unfold_by_str(prec, ",");
let comma_sym = clause_name!(",");
let cut_sym = atom!("!");
let mut prec_seq = unfold_by_str(prec, atom!(","));
let comma_sym = atom!(",");
let cut_sym = Literal::Atom(atom!("!"));
prec_seq.push(Term::Constant(Cell::default(), cut_sym));
prec_seq.push(Term::Literal(Cell::default(), cut_sym));
mark_cut_variables_as(&mut prec_seq, clause_name!("blocked_!"));
mark_cut_variables_as(&mut prec_seq, atom!("blocked_!"));
let mut conq_seq = unfold_by_str(conq, ",");
let mut conq_seq = unfold_by_str(conq, atom!(","));
mark_cut_variables(&mut conq_seq);
prec_seq.extend(conq_seq.into_iter());
let back_term = Box::new(prec_seq.pop().unwrap());
let front_term = Box::new(prec_seq.pop().unwrap());
let back_term = prec_seq.pop().unwrap();
let front_term = prec_seq.pop().unwrap();
let body_term = Term::Clause(
Cell::default(),
comma_sym.clone(),
comma_sym,
vec![front_term, back_term],
None,
);
self.fabricate_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym))
}
fn to_query_term<'a>(
fn to_query_term<'a, LS: LoadState<'a>>(
&mut self,
load_state: &mut LoadState<'a>,
loader: &mut Loader<'a, LS>,
term: Term,
) -> Result<QueryTerm, CompilationError> {
match term {
Term::Constant(_, Constant::Atom(name, fixity)) => {
if name.as_str() == "!" || name.as_str() == "blocked_!" {
Term::Literal(_, Literal::Atom(name)) => {
if name == atom!("!") || name == atom!("blocked_!") {
Ok(QueryTerm::BlockedCut)
} else {
Ok(clause_to_query_term(load_state, name, vec![], fixity))
Ok(clause_to_query_term(loader, name, vec![]))
}
}
Term::Constant(_, Constant::Char('!')) => Ok(QueryTerm::BlockedCut),
Term::Literal(_, Literal::Char('!')) => Ok(QueryTerm::BlockedCut),
Term::Var(_, ref v) if v.as_str() == "!" => {
Ok(QueryTerm::UnblockedCut(Cell::default()))
}
Term::Clause(r, name, mut terms, fixity) => match (name.as_str(), terms.len()) {
(";", 2) => {
let term = Term::Clause(r, name.clone(), terms, fixity);
Term::Clause(r, name, mut terms) => match (name, terms.len()) {
(atom!(";"), 2) => {
let term = Term::Clause(r, name, terms);
let (stub, clauses) = self.fabricate_disjunct(term);
self.queue.push_back(clauses);
Ok(QueryTerm::Jump(stub))
}
("->", 2) => {
let conq = *terms.pop().unwrap();
let prec = *terms.pop().unwrap();
(atom!("->"), 2) => {
let conq = terms.pop().unwrap();
let prec = terms.pop().unwrap();
let (stub, clauses) = self.fabricate_if_then(prec, conq);
self.queue.push_back(clauses);
Ok(QueryTerm::Jump(stub))
}
("\\+", 1) => {
terms.push(Box::new(Term::Constant(
(atom!("\\+"), 1) => {
terms.push(Term::Literal(
Cell::default(),
Constant::Atom(clause_name!("$fail"), None),
)));
Literal::Atom(atom!("$fail")),
));
let conq =
Term::Constant(Cell::default(), Constant::Atom(clause_name!("true"), None));
let conq = Term::Literal(Cell::default(), Literal::Atom(atom!("true")));
let prec = Term::Clause(Cell::default(), clause_name!("->"), terms, None);
let terms = vec![Box::new(prec), Box::new(conq)];
let prec = Term::Clause(Cell::default(), atom!("->"), terms);
let terms = vec![prec, conq];
let term = Term::Clause(Cell::default(), clause_name!(";"), terms, None);
let term = Term::Clause(Cell::default(), atom!(";"), terms);
let (stub, clauses) = self.fabricate_disjunct(term);
debug_assert!(clauses.len() > 0);
@@ -709,104 +695,102 @@ impl Preprocessor {
Ok(QueryTerm::Jump(stub))
}
("$get_level", 1) => {
if let Term::Var(_, ref var) = *terms[0] {
(atom!("$get_level"), 1) => {
if let Term::Var(_, ref var) = &terms[0] {
Ok(QueryTerm::GetLevelAndUnify(Cell::default(), var.clone()))
} else {
Err(CompilationError::InadmissibleQueryTerm)
}
}
(":", 2) => {
let predicate_name = *terms.pop().unwrap();
let module_name = *terms.pop().unwrap();
(atom!(":"), 2) => {
let predicate_name = terms.pop().unwrap();
let module_name = terms.pop().unwrap();
match (module_name, predicate_name) {
(
Term::Constant(_, Constant::Atom(module_name, _)),
Term::Constant(_, Constant::Atom(predicate_name, fixity)),
Term::Literal(_, Literal::Atom(module_name)),
Term::Literal(_, Literal::Atom(predicate_name)),
) => Ok(qualified_clause_to_query_term(
load_state,
loader,
module_name,
predicate_name,
vec![],
fixity,
)),
(
Term::Constant(_, Constant::Atom(module_name, _)),
Term::Clause(_, name, terms, fixity),
Term::Literal(_, Literal::Atom(module_name)),
Term::Clause(_, name, terms),
) => Ok(qualified_clause_to_query_term(
load_state,
loader,
module_name,
name,
terms,
fixity,
)),
(module_name, predicate_name) => {
terms.push(Box::new(module_name));
terms.push(Box::new(predicate_name));
terms.push(module_name);
terms.push(predicate_name);
Ok(clause_to_query_term(load_state, name, terms, fixity))
Ok(clause_to_query_term(loader, name, terms))
}
}
}
_ => Ok(clause_to_query_term(load_state, name, terms, fixity)),
_ => Ok(clause_to_query_term(loader, name, terms)),
},
Term::Var(..) => Ok(QueryTerm::Clause(
Cell::default(),
ClauseType::CallN,
vec![Box::new(term)],
vec![term],
false,
)),
_ => Err(CompilationError::InadmissibleQueryTerm),
}
}
fn pre_query_term<'a>(
fn pre_query_term<'a, LS: LoadState<'a>>(
&mut self,
load_state: &mut LoadState<'a>,
loader: &mut Loader<'a, LS>,
term: Term,
) -> Result<QueryTerm, CompilationError> {
match term {
Term::Clause(r, name, mut subterms, fixity) => {
if subterms.len() == 1 && name.as_str() == "$call_with_default_policy" {
self.to_query_term(load_state, *subterms.pop().unwrap())
Term::Clause(r, name, mut subterms) => {
if subterms.len() == 1 && name == atom!("$call_with_default_policy") {
self.to_query_term(loader, subterms.pop().unwrap())
.map(|mut query_term| {
query_term.set_default_caller();
query_term
})
} else {
let clause = Term::Clause(r, name, subterms, fixity);
self.to_query_term(load_state, clause)
let clause = Term::Clause(r, name, subterms);
self.to_query_term(loader, clause)
}
}
_ => self.to_query_term(load_state, term),
_ => self.to_query_term(loader, term),
}
}
fn setup_query<'a>(
fn setup_query<'a, LS: LoadState<'a>>(
&mut self,
load_state: &mut LoadState<'a>,
terms: Vec<Box<Term>>,
loader: &mut Loader<'a, LS>,
terms: Vec<Term>,
cut_context: CutContext,
) -> Result<Vec<QueryTerm>, CompilationError> {
let mut query_terms = vec![];
let mut work_queue = VecDeque::from(terms);
while let Some(term) = work_queue.pop_front() {
let mut term = *term;
let mut term = term;
if let Term::Clause(cell, name, terms, op_spec) = term {
if name.as_str() == "," && terms.len() == 2 {
let term = Term::Clause(cell, name, terms, op_spec);
let mut subterms = unfold_by_str(term, ",");
if let Term::Clause(cell, name, terms) = term {
if name == atom!(",") && terms.len() == 2 {
let term = Term::Clause(cell, name, terms);
let mut subterms = unfold_by_str(term, atom!(","));
while let Some(subterm) = subterms.pop() {
work_queue.push_front(Box::new(subterm));
work_queue.push_front(subterm);
}
continue;
} else {
term = Term::Clause(cell, name, terms, op_spec);
term = Term::Clause(cell, name, terms);
}
}
@@ -814,30 +798,30 @@ impl Preprocessor {
mark_cut_variable(&mut term);
}
query_terms.push(self.pre_query_term(load_state, term)?);
query_terms.push(self.pre_query_term(loader, term)?);
}
Ok(query_terms)
}
fn setup_rule<'a>(
fn setup_rule<'a, LS: LoadState<'a>>(
&mut self,
load_state: &mut LoadState<'a>,
mut terms: Vec<Box<Term>>,
loader: &mut Loader<'a, LS>,
mut terms: Vec<Term>,
cut_context: CutContext,
) -> Result<Rule, CompilationError> {
let post_head_terms: Vec<_> = terms.drain(1..).collect();
let mut query_terms = self.setup_query(load_state, post_head_terms, cut_context)?;
let mut query_terms = self.setup_query(loader, post_head_terms, cut_context)?;
let clauses = query_terms.drain(1..).collect();
let qt = query_terms.pop().unwrap();
match *terms.pop().unwrap() {
Term::Clause(_, name, terms, _) => Ok(Rule {
match terms.pop().unwrap() {
Term::Clause(_, name, terms) => Ok(Rule {
head: (name, terms, qt),
clauses,
}),
Term::Constant(_, Constant::Atom(name, _)) => Ok(Rule {
Term::Literal(_, Literal::Atom(name)) => Ok(Rule {
head: (name, vec![], qt),
clauses,
}),
@@ -845,37 +829,37 @@ impl Preprocessor {
}
}
fn try_term_to_query<'a>(
fn try_term_to_query<'a, LS: LoadState<'a>>(
&mut self,
load_state: &mut LoadState<'a>,
terms: Vec<Box<Term>>,
loader: &mut Loader<'a, LS>,
terms: Vec<Term>,
cut_context: CutContext,
) -> Result<TopLevel, CompilationError> {
Ok(TopLevel::Query(self.setup_query(
load_state,
loader,
terms,
cut_context,
)?))
}
pub(super) fn try_term_to_tl<'a>(
pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>(
&mut self,
load_state: &mut LoadState<'a>,
loader: &mut Loader<'a, LS>,
term: Term,
cut_context: CutContext,
) -> Result<TopLevel, CompilationError> {
match term {
Term::Clause(r, name, terms, fixity) => {
if name.as_str() == "?-" {
self.try_term_to_query(load_state, terms, cut_context)
} else if name.as_str() == ":-" && terms.len() == 2 {
Term::Clause(r, name, terms) => {
if name == atom!("?-") {
self.try_term_to_query(loader, terms, cut_context)
} else if name == atom!(":-") && terms.len() == 2 {
Ok(TopLevel::Rule(self.setup_rule(
load_state,
loader,
terms,
cut_context,
)?))
} else {
let term = Term::Clause(r, name, terms, fixity);
let term = Term::Clause(r, name, terms);
Ok(TopLevel::Fact(self.setup_fact(term)?))
}
}
@@ -883,30 +867,30 @@ impl Preprocessor {
}
}
fn try_terms_to_tls<'a, I: IntoIterator<Item = Term>>(
fn try_terms_to_tls<'a, I: IntoIterator<Item = Term>, LS: LoadState<'a>>(
&mut self,
load_state: &mut LoadState<'a>,
loader: &mut Loader<'a, LS>,
terms: I,
cut_context: CutContext,
) -> Result<VecDeque<TopLevel>, CompilationError> {
let mut results = VecDeque::new();
for term in terms.into_iter() {
results.push_back(self.try_term_to_tl(load_state, term, cut_context)?);
results.push_back(self.try_term_to_tl(loader, term, cut_context)?);
}
Ok(results)
}
pub(super) fn parse_queue<'a>(
pub(super) fn parse_queue<'a, LS: LoadState<'a>>(
&mut self,
load_state: &mut LoadState<'a>,
loader: &mut Loader<'a, LS>,
) -> Result<VecDeque<TopLevel>, CompilationError> {
let mut queue = VecDeque::new();
while let Some(terms) = self.queue.pop_front() {
let clauses = merge_clauses(&mut self.try_terms_to_tls(
load_state,
loader,
terms,
CutContext::HasCutVariable,
)?)?;

View File

@@ -1,16 +1,15 @@
use core::marker::PhantomData;
use crate::types::*;
use crate::machine::machine_indices::*;
use crate::machine::raw_block::*;
use crate::raw_block::*;
use std::mem;
use std::ops::{Index, IndexMut};
use std::ptr;
#[derive(Debug)]
struct StackTraits {}
impl RawBlockTraits for StackTraits {
impl RawBlockTraits for Stack {
#[inline]
fn init_size() -> usize {
10 * 1024 * 1024
@@ -18,31 +17,23 @@ impl RawBlockTraits for StackTraits {
#[inline]
fn align() -> usize {
mem::align_of::<Addr>()
}
#[inline]
fn base_offset(base: *const u8) -> *const u8 {
unsafe { base.offset(Self::align() as isize) }
mem::align_of::<HeapCellValue>()
}
}
const fn prelude_size<Prelude>() -> usize {
let size = mem::size_of::<Prelude>();
let align = mem::align_of::<Addr>();
(size & !(align - 1)) + align
#[inline(always)]
pub const fn prelude_size<Prelude>() -> usize {
mem::size_of::<Prelude>()
}
#[derive(Debug)]
pub(crate) struct Stack {
buf: RawBlock<StackTraits>,
_marker: PhantomData<Addr>,
pub struct Stack {
buf: RawBlock<Stack>,
_marker: PhantomData<HeapCellValue>,
}
impl Drop for Stack {
fn drop(&mut self) {
self.drop_in_place();
self.buf.deallocate();
}
}
@@ -57,7 +48,7 @@ pub(crate) struct AndFramePrelude {
pub(crate) univ_prelude: FramePrelude,
pub(crate) e: usize,
pub(crate) cp: LocalCodePtr,
pub(crate) interrupt_cp: LocalCodePtr,
pub(crate) interrupt_cp: LocalCodePtr, // TODO: get rid of it!
}
#[derive(Debug)]
@@ -67,22 +58,22 @@ pub(crate) struct AndFrame {
impl AndFrame {
pub(crate) fn size_of(num_cells: usize) -> usize {
prelude_size::<AndFramePrelude>() + num_cells * mem::size_of::<Addr>()
prelude_size::<AndFramePrelude>() + num_cells * mem::size_of::<HeapCellValue>()
}
}
impl Index<usize> for AndFrame {
type Output = Addr;
type Output = HeapCellValue;
fn index(&self, index: usize) -> &Self::Output {
let prelude_offset = prelude_size::<AndFramePrelude>();
let index_offset = (index - 1) * mem::size_of::<Addr>();
let index_offset = (index - 1) * mem::size_of::<HeapCellValue>();
unsafe {
let ptr = mem::transmute::<&AndFrame, *const u8>(self);
let ptr = ptr as usize + prelude_offset + index_offset;
&*(ptr as *const Addr)
&*(ptr as *const HeapCellValue)
}
}
}
@@ -90,13 +81,35 @@ impl Index<usize> for AndFrame {
impl IndexMut<usize> for AndFrame {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
let prelude_offset = prelude_size::<AndFramePrelude>();
let index_offset = (index - 1) * mem::size_of::<Addr>();
let index_offset = (index - 1) * mem::size_of::<HeapCellValue>();
unsafe {
let ptr = mem::transmute::<&mut AndFrame, *const u8>(self);
let ptr = ptr as usize + prelude_offset + index_offset;
&mut *(ptr as *mut Addr)
&mut *(ptr as *mut HeapCellValue)
}
}
}
impl Index<usize> for Stack {
type Output = HeapCellValue;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
unsafe {
let ptr = self.buf.base as usize + index;
&*(ptr as *const HeapCellValue)
}
}
}
impl IndexMut<usize> for Stack {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
unsafe {
let ptr = self.buf.base as usize + index;
&mut *(ptr as *mut HeapCellValue)
}
}
}
@@ -119,18 +132,18 @@ pub(crate) struct OrFrame {
}
impl Index<usize> for OrFrame {
type Output = Addr;
type Output = HeapCellValue;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
let prelude_offset = prelude_size::<OrFramePrelude>();
let index_offset = index * mem::size_of::<Addr>();
let index_offset = index * mem::size_of::<HeapCellValue>();
unsafe {
let ptr = mem::transmute::<&OrFrame, *const u8>(self);
let ptr = ptr as usize + prelude_offset + index_offset;
&*(ptr as *const Addr)
&*(ptr as *const HeapCellValue)
}
}
}
@@ -139,20 +152,20 @@ impl IndexMut<usize> for OrFrame {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
let prelude_offset = prelude_size::<OrFramePrelude>();
let index_offset = index * mem::size_of::<Addr>();
let index_offset = index * mem::size_of::<HeapCellValue>();
unsafe {
let ptr = mem::transmute::<&mut OrFrame, *const u8>(self);
let ptr = ptr as usize + prelude_offset + index_offset;
&mut *(ptr as *mut Addr)
&mut *(ptr as *mut HeapCellValue)
}
}
}
impl OrFrame {
pub(crate) fn size_of(num_cells: usize) -> usize {
prelude_size::<OrFramePrelude>() + num_cells * mem::size_of::<Addr>()
prelude_size::<OrFramePrelude>() + num_cells * mem::size_of::<HeapCellValue>()
}
}
@@ -164,26 +177,39 @@ impl Stack {
}
}
#[inline(always)]
unsafe fn alloc(&mut self, frame_size: usize) -> *mut u8 {
loop {
let ptr = self.buf.alloc(frame_size);
if ptr.is_null() {
self.buf.grow();
} else {
return ptr;
}
}
}
pub(crate) fn allocate_and_frame(&mut self, num_cells: usize) -> usize {
let frame_size = AndFrame::size_of(num_cells);
unsafe {
let new_top = self.buf.new_block(frame_size);
let e = self.buf.top as usize - self.buf.base as usize;
let e = self.buf.ptr as usize - self.buf.base as usize;
let new_ptr = self.alloc(frame_size);
let mut offset = prelude_size::<AndFramePrelude>();
for idx in 0..num_cells {
let offset = prelude_size::<AndFramePrelude>() + idx * mem::size_of::<Addr>();
ptr::write(
(self.buf.top as usize + offset) as *mut Addr,
Addr::StackCell(e, idx + 1),
(new_ptr as usize + offset) as *mut HeapCellValue,
stack_loc_as_cell!(AndFrame, e, idx + 1),
);
offset += mem::size_of::<HeapCellValue>();
}
let and_frame = &mut *(self.buf.top as *mut AndFrame);
let and_frame = &mut *(new_ptr as *mut AndFrame);
and_frame.prelude.univ_prelude.num_cells = num_cells;
self.buf.top = new_top;
e
}
}
@@ -192,27 +218,27 @@ impl Stack {
let frame_size = OrFrame::size_of(num_cells);
unsafe {
let new_top = self.buf.new_block(frame_size);
let b = self.buf.top as usize - self.buf.base as usize;
let b = self.buf.ptr as usize - self.buf.base as usize;
let new_ptr = self.alloc(frame_size);
let mut offset = prelude_size::<OrFramePrelude>();
for idx in 0..num_cells {
let offset = prelude_size::<OrFramePrelude>() + idx * mem::size_of::<Addr>();
ptr::write(
(self.buf.top as usize + offset) as *mut Addr,
Addr::StackCell(b, idx),
(new_ptr as usize + offset) as *mut HeapCellValue,
stack_loc_as_cell!(OrFrame, b, idx),
);
offset += mem::size_of::<HeapCellValue>();
}
let or_frame = &mut *(self.buf.top as *mut OrFrame);
let or_frame = &mut *(new_ptr as *mut OrFrame);
or_frame.prelude.univ_prelude.num_cells = num_cells;
self.buf.top = new_top;
b
}
}
#[inline]
#[inline(always)]
pub(crate) fn index_and_frame(&self, e: usize) -> &AndFrame {
unsafe {
let ptr = self.buf.base as usize + e;
@@ -220,7 +246,7 @@ impl Stack {
}
}
#[inline]
#[inline(always)]
pub(crate) fn index_and_frame_mut(&mut self, e: usize) -> &mut AndFrame {
unsafe {
let ptr = self.buf.base as usize + e;
@@ -228,7 +254,7 @@ impl Stack {
}
}
#[inline]
#[inline(always)]
pub(crate) fn index_or_frame(&self, b: usize) -> &OrFrame {
unsafe {
let ptr = self.buf.base as usize + b;
@@ -236,7 +262,7 @@ impl Stack {
}
}
#[inline]
#[inline(always)]
pub(crate) fn index_or_frame_mut(&mut self, b: usize) -> &mut OrFrame {
unsafe {
let ptr = self.buf.base as usize + b;
@@ -244,31 +270,65 @@ impl Stack {
}
}
#[inline]
#[inline(always)]
pub(crate) fn truncate(&mut self, b: usize) {
if b == 0 {
self.inner_truncate(mem::align_of::<Addr>());
} else {
self.inner_truncate(b);
let base = self.buf.base as usize + b;
if base < self.buf.ptr as usize {
self.buf.ptr = base as *mut _;
}
}
#[inline]
fn inner_truncate(&mut self, b: usize) {
let base = b + self.buf.base as usize;
if base < self.buf.top as usize {
self.buf.top = base as *const _;
}
}
pub(crate) fn drop_in_place(&mut self) {
self.truncate(mem::align_of::<Addr>());
debug_assert!(if self.buf.top.is_null() {
self.buf.top == self.buf.base
} else {
self.buf.top as usize == self.buf.base as usize + mem::align_of::<Addr>()
});
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::machine::mock_wam::*;
#[test]
fn stack_tests() {
let mut wam = MockWAM::new();
let e = wam.machine_st.stack.allocate_and_frame(10); // create an AND frame!
let and_frame = wam.machine_st.stack.index_and_frame_mut(e);
assert_eq!(
e,
0// 10 * mem::size_of::<HeapCellValue>() + prelude_size::<AndFrame>()
);
assert_eq!(and_frame.prelude.univ_prelude.num_cells, 10);
for idx in 0..10 {
assert_eq!(and_frame[idx + 1], stack_loc_as_cell!(AndFrame, e, idx + 1));
}
and_frame[5] = empty_list_as_cell!();
assert_eq!(and_frame[5], empty_list_as_cell!());
let b = wam.machine_st.stack.allocate_or_frame(5);
let or_frame = wam.machine_st.stack.index_or_frame_mut(b);
for idx in 0..5 {
assert_eq!(or_frame[idx], stack_loc_as_cell!(OrFrame, b, idx));
}
let next_e = wam.machine_st.stack.allocate_and_frame(9); // create an AND frame!
let and_frame = wam.machine_st.stack.index_and_frame_mut(next_e);
for idx in 0..9 {
assert_eq!(and_frame[idx + 1], stack_loc_as_cell!(AndFrame, next_e, idx + 1));
}
let and_frame = wam.machine_st.stack.index_and_frame(e);
assert_eq!(and_frame[5], empty_list_as_cell!());
assert_eq!(
wam.machine_st.stack[stack_loc!(AndFrame, e, 5)],
empty_list_as_cell!()
);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,48 +1,53 @@
use prolog_parser::ast::*;
use prolog_parser::parser::*;
use crate::machine::machine_errors::CompilationError;
use crate::forms::*;
use crate::machine::*;
use crate::machine::load_state::*;
use crate::machine::loader::*;
use crate::machine::machine_errors::*;
use crate::parser::ast::*;
use crate::parser::parser::*;
use crate::predicate_queue;
use indexmap::IndexSet;
use std::collections::VecDeque;
use std::fmt;
pub(crate) trait TermStream: Sized {
type Evacuable;
pub struct LoadStatePayload<TS> {
pub term_stream: TS,
pub(super) compilation_target: CompilationTarget,
pub(super) retraction_info: RetractionInfo,
pub(super) module_op_exports: ModuleOpExports,
pub(super) non_counted_bt_preds: IndexSet<PredicateKey>,
pub(super) predicates: PredicateQueue,
pub(super) clause_clauses: Vec<(Term, Term)>,
}
pub trait TermStream: Sized {
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError>;
fn eof(&mut self) -> Result<bool, CompilationError>;
fn listing_src(&self) -> &ListingSource;
fn evacuate<'a>(loader: Loader<'a, Self>) -> Result<Self::Evacuable, SessionError>;
}
#[derive(Debug)]
pub(super) struct BootstrappingTermStream<'a> {
pub struct BootstrappingTermStream<'a> {
listing_src: ListingSource,
parser: Parser<'a, Stream>,
pub(super) parser: Parser<'a, Stream>,
}
impl<'a> BootstrappingTermStream<'a> {
#[inline]
pub(super) fn from_prolog_stream(
stream: &'a mut PrologStream,
atom_tbl: TabledData<Atom>,
flags: MachineFlags,
pub(super) fn from_char_reader(
stream: Stream,
machine_st: &'a mut MachineState,
listing_src: ListingSource,
) -> Self {
let parser = Parser::new(stream, atom_tbl, flags);
Self {
parser,
listing_src,
}
let parser = Parser::new(stream, machine_st);
Self { parser, listing_src }
}
}
impl<'a> TermStream for BootstrappingTermStream<'a> {
type Evacuable = CompilationTarget;
#[inline]
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError> {
self.parser.reset();
@@ -61,24 +66,9 @@ impl<'a> TermStream for BootstrappingTermStream<'a> {
fn listing_src(&self) -> &ListingSource {
&self.listing_src
}
fn evacuate(mut loader: Loader<Self>) -> Result<Self::Evacuable, SessionError> {
if !loader.predicates.is_empty() {
loader.compile_and_submit()?;
}
loader
.load_state
.retraction_info
.reset(loader.load_state.wam.code_repo.code.len());
loader.load_state.remove_module_op_exports();
Ok(loader.load_state.compilation_target.take())
}
}
pub(crate) struct LiveTermStream {
pub struct LiveTermStream {
pub(super) term_queue: VecDeque<Term>,
pub(super) listing_src: ListingSource,
}
@@ -93,28 +83,18 @@ impl LiveTermStream {
}
}
pub(crate) struct LoadStatePayload {
pub(super) term_stream: LiveTermStream,
pub(super) compilation_target: CompilationTarget,
pub(super) retraction_info: RetractionInfo,
pub(super) module_op_exports: Vec<(OpDecl, Option<(usize, Specifier)>)>,
pub(super) non_counted_bt_preds: IndexSet<PredicateKey>,
pub(super) predicates: PredicateQueue,
pub(super) clause_clauses: Vec<(Term, Term)>,
}
impl fmt::Debug for LoadStatePayload {
impl<TS> fmt::Debug for LoadStatePayload<TS> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "LoadStatePayload")
}
}
impl LoadStatePayload {
pub(super) fn new(wam: &Machine) -> Self {
impl<TS> LoadStatePayload<TS> {
pub(super) fn new(code_repo_len: usize, term_stream: TS) -> Self {
Self {
term_stream: LiveTermStream::new(ListingSource::User),
term_stream,
compilation_target: CompilationTarget::default(),
retraction_info: RetractionInfo::new(wam.code_repo.code.len()),
retraction_info: RetractionInfo::new(code_repo_len),
module_op_exports: vec![],
non_counted_bt_preds: IndexSet::new(),
predicates: predicate_queue![],
@@ -124,8 +104,6 @@ impl LoadStatePayload {
}
impl TermStream for LiveTermStream {
type Evacuable = LoadStatePayload;
#[inline]
fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
Ok(self.term_queue.pop_front().unwrap())
@@ -140,9 +118,4 @@ impl TermStream for LiveTermStream {
fn listing_src(&self) -> &ListingSource {
&self.listing_src
}
#[inline]
fn evacuate(loader: Loader<Self>) -> Result<LoadStatePayload, SessionError> {
Ok(loader.to_load_state_payload())
}
}