840 lines
25 KiB
Rust
840 lines
25 KiB
Rust
use crate::arena::*;
|
|
use crate::atom_table::*;
|
|
use crate::forms::*;
|
|
use crate::heap_iter::*;
|
|
use crate::heap_print::*;
|
|
use crate::machine::Machine;
|
|
use crate::machine::attributed_variables::*;
|
|
use crate::machine::copier::*;
|
|
use crate::machine::heap::*;
|
|
use crate::machine::machine_errors::*;
|
|
use crate::machine::machine_indices::*;
|
|
use crate::machine::stack::*;
|
|
use crate::machine::streams::*;
|
|
use crate::parser::ast::*;
|
|
use crate::types::*;
|
|
|
|
use crate::parser::rug::Integer;
|
|
|
|
use indexmap::IndexMap;
|
|
|
|
use std::convert::TryFrom;
|
|
use std::fmt;
|
|
use std::ops::{Index, IndexMut};
|
|
use std::rc::Rc;
|
|
|
|
pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1];
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub(super) enum MachineMode {
|
|
Read,
|
|
Write,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub(super) enum HeapPtr {
|
|
HeapCell(usize),
|
|
PStrChar(usize, usize),
|
|
PStrLocation(usize, usize),
|
|
}
|
|
|
|
impl Default for HeapPtr {
|
|
fn default() -> Self {
|
|
HeapPtr::HeapCell(0)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum FirstOrNext {
|
|
First,
|
|
Next,
|
|
}
|
|
|
|
pub struct MachineState {
|
|
pub atom_tbl: AtomTable,
|
|
pub arena: Arena,
|
|
pub(super) pdl: Vec<HeapCellValue>,
|
|
pub(super) s: HeapPtr,
|
|
pub(super) s_offset: usize,
|
|
pub(super) p: usize,
|
|
pub(super) oip: u32, // first internal code ptr
|
|
pub(super) iip : u32, // second internal code ptr
|
|
pub(super) b: usize,
|
|
pub(super) b0: usize,
|
|
pub(super) e: usize,
|
|
pub(super) num_of_args: usize,
|
|
pub(super) cp: usize,
|
|
pub(super) attr_var_init: AttrVarInitializer,
|
|
pub(super) fail: bool,
|
|
pub heap: Heap,
|
|
pub(super) mode: MachineMode,
|
|
pub(crate) stack: Stack,
|
|
pub(super) registers: Registers,
|
|
pub(super) trail: Vec<TrailEntry>,
|
|
pub(super) tr: usize,
|
|
pub(super) hb: usize,
|
|
pub(super) block: usize, // an offset into the OR stack.
|
|
pub(super) ball: Ball,
|
|
pub(super) lifted_heap: Heap,
|
|
pub(super) interms: Vec<Number>, // intermediate numbers.
|
|
// locations of cleaners, cut points, the previous block. for setup_call_cleanup.
|
|
pub(super) cont_pts: Vec<(HeapCellValue, usize, usize)>,
|
|
pub(super) cwil: CWIL,
|
|
pub(crate) flags: MachineFlags,
|
|
pub(crate) cc: usize,
|
|
pub(crate) global_clock: usize,
|
|
pub(crate) dynamic_mode: FirstOrNext,
|
|
pub(crate) unify_fn: fn(&mut MachineState),
|
|
pub(crate) bind_fn: fn(&mut MachineState, Ref, HeapCellValue),
|
|
pub(crate) run_cleaners_fn: fn(&mut Machine) -> bool,
|
|
pub(crate) increment_call_count_fn: fn(&mut MachineState) -> CallResult,
|
|
}
|
|
|
|
impl fmt::Debug for MachineState {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
f.debug_struct("MachineState")
|
|
.field("atom_tbl", &self.atom_tbl)
|
|
.field("arena", &self.arena)
|
|
.field("s", &self.s)
|
|
.field("p", &self.p)
|
|
.field("b", &self.b)
|
|
.field("b0", &self.b0)
|
|
.field("e", &self.e)
|
|
.field("num_of_args", &self.num_of_args)
|
|
.field("cp", &self.cp)
|
|
.field("attr_var_init", &self.attr_var_init)
|
|
.field("fail", &self.fail)
|
|
.field("heap", &self.heap)
|
|
.field("mode", &self.mode)
|
|
.field("stack", &self.stack)
|
|
.field("registers", &self.registers)
|
|
.field("trail", &self.trail)
|
|
.field("tr", &self.tr)
|
|
.field("hb", &self.hb)
|
|
.field("block", &self.block)
|
|
.field("ball", &self.ball)
|
|
.field("lifted_heap", &self.lifted_heap)
|
|
.field("interms", &self.interms)
|
|
.field("flags", &self.flags)
|
|
.field("cc", &self.cc)
|
|
.field("global_clock", &self.global_clock)
|
|
.field("dynamic_mode", &self.dynamic_mode)
|
|
.field(
|
|
"unify_fn",
|
|
if self.unify_fn as usize == MachineState::unify as usize {
|
|
&"MachineState::unify"
|
|
} else if self.unify_fn as usize == MachineState::unify_with_occurs_check as usize {
|
|
&"MachineState::unify_with_occurs_check"
|
|
} else {
|
|
&"MachineState::unify_with_occurs_check_with_error"
|
|
},
|
|
)
|
|
.field(
|
|
"bind_fn",
|
|
if self.bind_fn as usize == MachineState::bind as usize {
|
|
&"MachineState::bind"
|
|
} else if self.bind_fn as usize
|
|
== MachineState::bind_with_occurs_check_wrapper as usize
|
|
{
|
|
&"MachineState::bind_with_occurs_check"
|
|
} else {
|
|
&"MachineState::bind_with_occurs_check_with_error_wrapper"
|
|
},
|
|
)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
impl Index<RegType> for MachineState {
|
|
type Output = HeapCellValue;
|
|
|
|
#[inline(always)]
|
|
fn index(&self, reg: RegType) -> &Self::Output {
|
|
match reg {
|
|
RegType::Temp(temp) => &self.registers[temp],
|
|
RegType::Perm(perm) => {
|
|
let e = self.e;
|
|
&self.stack[stack_loc!(AndFrame, e, perm)]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl IndexMut<RegType> for MachineState {
|
|
#[inline(always)]
|
|
fn index_mut(&mut self, reg: RegType) -> &mut Self::Output {
|
|
match reg {
|
|
RegType::Temp(temp) => &mut self.registers[temp],
|
|
RegType::Perm(perm) => {
|
|
let e = self.e;
|
|
&mut self.stack[stack_loc!(AndFrame, e, perm)]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub type CallResult = Result<(), Vec<HeapCellValue>>;
|
|
|
|
#[inline(always)]
|
|
pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixnum) {
|
|
read_heap_cell!(heap[index],
|
|
(HeapCellValueTag::PStr | HeapCellValueTag::CStr) => {
|
|
(index, Fixnum::build_with(0))
|
|
}
|
|
(HeapCellValueTag::PStrOffset, h) => {
|
|
(h, cell_as_fixnum!(heap[index+1]))
|
|
}
|
|
_ => {
|
|
unreachable!()
|
|
}
|
|
)
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Ball {
|
|
pub(super) boundary: usize,
|
|
pub(super) stub: Heap,
|
|
}
|
|
|
|
impl Ball {
|
|
pub(super) fn new() -> Self {
|
|
Ball {
|
|
boundary: 0,
|
|
stub: Heap::new(),
|
|
}
|
|
}
|
|
|
|
pub(super) fn reset(&mut self) {
|
|
self.boundary = 0;
|
|
self.stub.clear();
|
|
}
|
|
|
|
pub(super) fn copy_and_align(&self, h: usize) -> Heap {
|
|
let diff = self.boundary as i64 - h as i64;
|
|
|
|
self.stub.iter().cloned().map(|heap_value| {
|
|
heap_value - diff
|
|
}).collect()
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub(super) struct CopyTerm<'a> {
|
|
state: &'a mut MachineState,
|
|
}
|
|
|
|
impl<'a> CopyTerm<'a> {
|
|
pub(super) fn new(state: &'a mut MachineState) -> Self {
|
|
CopyTerm { state }
|
|
}
|
|
}
|
|
|
|
impl<'a> Index<usize> for CopyTerm<'a> {
|
|
type Output = HeapCellValue;
|
|
|
|
#[inline(always)]
|
|
fn index(&self, index: usize) -> &Self::Output {
|
|
&self.state.heap[index]
|
|
}
|
|
}
|
|
|
|
impl<'a> IndexMut<usize> for CopyTerm<'a> {
|
|
#[inline(always)]
|
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
|
&mut self.state.heap[index]
|
|
}
|
|
}
|
|
|
|
impl<'a> CopierTarget for CopyTerm<'a> {
|
|
#[inline(always)]
|
|
fn threshold(&self) -> usize {
|
|
self.state.heap.len()
|
|
}
|
|
|
|
#[inline(always)]
|
|
fn push(&mut self, hcv: HeapCellValue) {
|
|
self.state.heap.push(hcv);
|
|
}
|
|
|
|
#[inline(always)]
|
|
fn store(&self, value: HeapCellValue) -> HeapCellValue {
|
|
self.state.store(value)
|
|
}
|
|
|
|
#[inline(always)]
|
|
fn deref(&self, value: HeapCellValue) -> HeapCellValue {
|
|
self.state.deref(value)
|
|
}
|
|
|
|
#[inline(always)]
|
|
fn stack(&mut self) -> &mut Stack {
|
|
&mut self.state.stack
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub(super) struct CopyBallTerm<'a> {
|
|
stack: &'a mut Stack,
|
|
heap: &'a mut Heap,
|
|
heap_boundary: usize,
|
|
stub: &'a mut Heap,
|
|
}
|
|
|
|
impl<'a> CopyBallTerm<'a> {
|
|
pub(super) fn new(stack: &'a mut Stack, heap: &'a mut Heap, stub: &'a mut Heap) -> Self {
|
|
let hb = heap.len();
|
|
|
|
CopyBallTerm {
|
|
stack,
|
|
heap,
|
|
heap_boundary: hb,
|
|
stub,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> Index<usize> for CopyBallTerm<'a> {
|
|
type Output = HeapCellValue;
|
|
|
|
fn index(&self, index: usize) -> &Self::Output {
|
|
if index < self.heap_boundary {
|
|
&self.heap[index]
|
|
} else {
|
|
let index = index - self.heap_boundary;
|
|
&self.stub[index]
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> IndexMut<usize> for CopyBallTerm<'a> {
|
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
|
if index < self.heap_boundary {
|
|
&mut self.heap[index]
|
|
} else {
|
|
let index = index - self.heap_boundary;
|
|
&mut self.stub[index]
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> CopierTarget for CopyBallTerm<'a> {
|
|
fn threshold(&self) -> usize {
|
|
self.heap_boundary + self.stub.len()
|
|
}
|
|
|
|
fn push(&mut self, value: HeapCellValue) {
|
|
self.stub.push(value);
|
|
}
|
|
|
|
fn store(&self, value: HeapCellValue) -> HeapCellValue {
|
|
read_heap_cell!(value,
|
|
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
|
|
if h < self.heap_boundary {
|
|
self.heap[h]
|
|
} else {
|
|
let index = h - self.heap_boundary;
|
|
self.stub[index]
|
|
}
|
|
}
|
|
(HeapCellValueTag::StackVar, s) => {
|
|
self.stack[s]
|
|
}
|
|
_ => {
|
|
value
|
|
}
|
|
)
|
|
}
|
|
|
|
fn deref(&self, mut addr: HeapCellValue) -> HeapCellValue {
|
|
loop {
|
|
let value = self.store(addr);
|
|
|
|
if value.is_var() && value != addr {
|
|
addr = value;
|
|
continue;
|
|
}
|
|
|
|
return addr;
|
|
}
|
|
}
|
|
|
|
fn stack(&mut self) -> &mut Stack {
|
|
self.stack
|
|
}
|
|
}
|
|
|
|
impl MachineState {
|
|
pub(crate) fn backtrack(&mut self) {
|
|
let b = self.b;
|
|
let or_frame = self.stack.index_or_frame(b);
|
|
|
|
self.b0 = or_frame.prelude.b0;
|
|
self.p = or_frame.prelude.bp;
|
|
|
|
self.oip = or_frame.prelude.boip;
|
|
self.iip = or_frame.prelude.biip;
|
|
|
|
self.pdl.clear();
|
|
self.fail = false;
|
|
}
|
|
|
|
pub(crate) fn increment_call_count(&mut self) -> CallResult {
|
|
if self.cwil.inference_limit_exceeded || self.ball.stub.len() > 0 {
|
|
return Ok(());
|
|
}
|
|
|
|
if let Some(&(ref limit, bp)) = self.cwil.limits.last() {
|
|
if self.cwil.count == *limit {
|
|
self.cwil.inference_limit_exceeded = true;
|
|
|
|
return Err(
|
|
functor!(atom!("inference_limit_exceeded"), [fixnum(bp)])
|
|
);
|
|
} else {
|
|
self.cwil.count += 1;
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
pub(super) fn try_char_list(&mut self, addrs: Vec<HeapCellValue>) -> Result<String, MachineError> {
|
|
let mut chars = String::new();
|
|
|
|
for addr in addrs {
|
|
let addr = self.store(self.deref(addr));
|
|
|
|
read_heap_cell!(addr,
|
|
(HeapCellValueTag::Char, c) => {
|
|
chars.push(c);
|
|
continue;
|
|
}
|
|
(HeapCellValueTag::Atom, (name, arity)) => {
|
|
if arity == 0 {
|
|
if let Some(c) = name.as_char() {
|
|
chars.push(c);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
_ => {
|
|
}
|
|
);
|
|
|
|
return Err(self.type_error(ValidType::Character, addr));
|
|
}
|
|
|
|
Ok(chars)
|
|
}
|
|
|
|
pub(super) fn throw_undefined_error(&mut self, name: Atom, arity: usize) -> MachineStub {
|
|
let stub = functor_stub(name, arity);
|
|
let err = self.existence_error(ExistenceError::Procedure(name, arity));
|
|
|
|
self.error_form(err, stub)
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(super) fn call_at_index(&mut self, arity: usize, p: usize) {
|
|
self.cp = self.p + 1;
|
|
self.p = p;
|
|
self.oip = 0;
|
|
self.iip = 0;
|
|
self.num_of_args = arity;
|
|
self.b0 = self.b;
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(super) fn execute_at_index(&mut self, arity: usize, p: usize) {
|
|
self.p = p;
|
|
self.oip = 0;
|
|
self.iip = 0;
|
|
self.num_of_args = arity;
|
|
self.b0 = self.b;
|
|
}
|
|
|
|
pub fn read_term(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult {
|
|
fn push_var_eq_functors<'a>(
|
|
heap: &mut Heap,
|
|
iter: impl Iterator<Item = (&'a Rc<String>, &'a HeapCellValue)>,
|
|
atom_tbl: &mut AtomTable,
|
|
) -> Vec<HeapCellValue> {
|
|
let mut list_of_var_eqs = vec![];
|
|
|
|
for (var, binding) in iter {
|
|
let var_atom = atom_tbl.build_with(&var);
|
|
let h = heap.len();
|
|
|
|
heap.push(atom_as_cell!(atom!("="), 2));
|
|
heap.push(atom_as_cell!(var_atom));
|
|
heap.push(*binding);
|
|
|
|
list_of_var_eqs.push(str_loc_as_cell!(h));
|
|
}
|
|
|
|
list_of_var_eqs
|
|
}
|
|
|
|
self.check_stream_properties(
|
|
stream,
|
|
StreamType::Text,
|
|
Some(self.registers[2]),
|
|
atom!("read_term"),
|
|
3,
|
|
)?;
|
|
|
|
if stream.past_end_of_stream() {
|
|
if EOFAction::Reset != stream.options().eof_action() {
|
|
return Ok(());
|
|
} else if self.fail {
|
|
return Ok(());
|
|
}
|
|
}
|
|
|
|
loop {
|
|
match self.read(stream, &indices.op_dir) {
|
|
Ok(term_write_result) => {
|
|
let term = self.registers[2];
|
|
unify_fn!(*self, heap_loc_as_cell!(term_write_result.heap_loc), term);
|
|
let term = heap_loc_as_cell!(term_write_result.heap_loc);
|
|
|
|
if self.fail {
|
|
return Ok(());
|
|
}
|
|
|
|
let mut singleton_var_set: IndexMap<Ref, bool> = IndexMap::new();
|
|
|
|
for addr in stackful_preorder_iter(&mut self.heap, term) {
|
|
let addr = unmark_cell_bits!(addr);
|
|
|
|
if let Some(var) = addr.as_var() {
|
|
if !singleton_var_set.contains_key(&var) {
|
|
singleton_var_set.insert(var, true);
|
|
} else {
|
|
singleton_var_set.insert(var, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
let singleton_var_list = push_var_eq_functors(
|
|
&mut self.heap,
|
|
term_write_result.var_dict.iter().filter(|(_, binding)| {
|
|
if let Some(r) = binding.as_var() {
|
|
*singleton_var_set.get(&r).unwrap_or(&false)
|
|
} else {
|
|
false
|
|
}
|
|
}),
|
|
&mut self.atom_tbl,
|
|
);
|
|
|
|
let mut var_list = Vec::with_capacity(singleton_var_set.len());
|
|
|
|
for (var_name, addr) in term_write_result.var_dict {
|
|
if let Some(var) = addr.as_var() {
|
|
let idx = singleton_var_set.get_index_of(&var).unwrap();
|
|
var_list.push((var_name, addr, idx));
|
|
}
|
|
}
|
|
|
|
var_list.sort_by(|(_,_,idx_1),(_,_,idx_2)| idx_1.cmp(idx_2));
|
|
|
|
let list_of_var_eqs = push_var_eq_functors(
|
|
&mut self.heap,
|
|
var_list.iter().map(|(var_name, var,_)| (var_name,var)),
|
|
&mut self.atom_tbl,
|
|
);
|
|
|
|
let singleton_addr = self.registers[3];
|
|
let singletons_offset = heap_loc_as_cell!(
|
|
iter_to_heap_list(&mut self.heap, singleton_var_list.into_iter())
|
|
);
|
|
|
|
unify_fn!(*self, singletons_offset, singleton_addr);
|
|
|
|
if self.fail {
|
|
return Ok(());
|
|
}
|
|
|
|
let vars_addr = self.registers[4];
|
|
let vars_offset = heap_loc_as_cell!(
|
|
iter_to_heap_list(&mut self.heap, var_list.into_iter().map(|(_,cell,_)| cell))
|
|
);
|
|
|
|
unify_fn!(*self, vars_offset, vars_addr);
|
|
|
|
if self.fail {
|
|
return Ok(());
|
|
}
|
|
|
|
let var_names_addr = self.registers[5];
|
|
let var_names_offset = heap_loc_as_cell!(
|
|
iter_to_heap_list(&mut self.heap, list_of_var_eqs.into_iter())
|
|
);
|
|
|
|
return Ok(unify_fn!(*self, var_names_offset, var_names_addr));
|
|
}
|
|
Err(err) => {
|
|
if let ParserError::UnexpectedEOF = err {
|
|
self.eof_action(
|
|
self.registers[2],
|
|
stream,
|
|
atom!("read_term"),
|
|
3,
|
|
)?;
|
|
|
|
if stream.options().eof_action() == EOFAction::Reset {
|
|
if self.fail == false {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return Ok(());
|
|
}
|
|
|
|
let stub = functor_stub(atom!("read_term"), 3);
|
|
let err = self.syntax_error(err);
|
|
|
|
return Err(self.error_form(err, stub));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(crate) fn write_term<'a>(
|
|
&'a mut self,
|
|
op_dir: &'a OpDir,
|
|
) -> Result<Option<HCPrinter<'a, PrinterOutputter>>, MachineStub> {
|
|
let ignore_ops = self.store(self.deref(self.registers[3]));
|
|
let numbervars = self.store(self.deref(self.registers[4]));
|
|
let quoted = self.store(self.deref(self.registers[5]));
|
|
let max_depth = self.store(self.deref(self.registers[7]));
|
|
|
|
let term_to_be_printed = self.store(self.deref(self.registers[2]));
|
|
let stub_gen = || functor_stub(atom!("write_term"), 2);
|
|
|
|
let printer = match self.try_from_list(self.registers[6], stub_gen) {
|
|
Ok(addrs) => {
|
|
let mut var_names: IndexMap<HeapCellValue, Rc<String>> = IndexMap::new();
|
|
|
|
for addr in addrs {
|
|
read_heap_cell!(addr,
|
|
(HeapCellValueTag::Str, s) => {
|
|
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
|
.get_name_and_arity();
|
|
|
|
if name == atom!("=") && arity == 2 {
|
|
let atom = self.store(self.deref(self.heap[s+1]));
|
|
let var = self.store(self.deref(self.heap[s+2]));
|
|
|
|
if var_names.contains_key(&var) {
|
|
continue;
|
|
}
|
|
|
|
var_names.insert(var, Rc::new(cell_as_atom!(atom).as_str().to_owned()));
|
|
}
|
|
}
|
|
_ => {
|
|
}
|
|
);
|
|
}
|
|
|
|
let mut printer = HCPrinter::new(
|
|
&mut self.heap,
|
|
&mut self.arena,
|
|
op_dir,
|
|
PrinterOutputter::new(),
|
|
term_to_be_printed,
|
|
);
|
|
|
|
if let HeapCellValueTag::Atom = ignore_ops.get_tag() {
|
|
let name = cell_as_atom!(ignore_ops);
|
|
printer.ignore_ops = name == atom!("true");
|
|
} else {
|
|
unreachable!();
|
|
}
|
|
|
|
if let HeapCellValueTag::Atom = numbervars.get_tag() {
|
|
let name = cell_as_atom!(numbervars);
|
|
printer.numbervars = name == atom!("true");
|
|
} else {
|
|
unreachable!();
|
|
}
|
|
|
|
if let HeapCellValueTag::Atom = quoted.get_tag() {
|
|
let name = cell_as_atom!(quoted);
|
|
printer.quoted = name == atom!("true");
|
|
} else {
|
|
unreachable!();
|
|
}
|
|
|
|
match Number::try_from(max_depth) {
|
|
Ok(Number::Fixnum(n)) => {
|
|
if let Ok(n) = usize::try_from(n.get_num()) {
|
|
printer.max_depth = n;
|
|
} else {
|
|
self.fail = true;
|
|
return Ok(None);
|
|
}
|
|
}
|
|
Ok(Number::Integer(n)) => {
|
|
if let Some(n) = n.to_usize() {
|
|
printer.max_depth = n;
|
|
} else {
|
|
self.fail = true;
|
|
return Ok(None);
|
|
}
|
|
}
|
|
_ => {
|
|
unreachable!();
|
|
}
|
|
}
|
|
|
|
printer.var_names = var_names;
|
|
|
|
printer
|
|
}
|
|
Err(err) => {
|
|
return Err(err);
|
|
}
|
|
};
|
|
|
|
Ok(Some(printer))
|
|
}
|
|
|
|
pub(super) fn read_predicate_key(&self, name: HeapCellValue, arity: HeapCellValue) -> (Atom, usize) {
|
|
let name = cell_as_atom!(self.store(self.deref(name)));
|
|
let arity = cell_as_fixnum!(self.store(self.deref(arity)));
|
|
|
|
(name, usize::try_from(arity.get_num()).unwrap())
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(super) fn cut_body(&mut self, value: HeapCellValue) {
|
|
let b = self.b;
|
|
|
|
read_heap_cell!(value,
|
|
(HeapCellValueTag::Fixnum, b0) => {
|
|
let b0 = b0.get_num() as usize;
|
|
|
|
if b > b0 {
|
|
self.b = b0;
|
|
}
|
|
}
|
|
_ => {
|
|
self.fail = true;
|
|
}
|
|
);
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(super) fn try_me_else(&mut self, offset: usize) {
|
|
let n = self.num_of_args;
|
|
let b = self.stack.allocate_or_frame(n);
|
|
let or_frame = self.stack.index_or_frame_mut(b);
|
|
|
|
or_frame.prelude.univ_prelude.num_cells = n;
|
|
or_frame.prelude.e = self.e;
|
|
or_frame.prelude.cp = self.cp;
|
|
or_frame.prelude.b = self.b;
|
|
or_frame.prelude.bp = self.p + offset;
|
|
or_frame.prelude.boip = 0;
|
|
or_frame.prelude.biip = 0;
|
|
or_frame.prelude.tr = self.tr;
|
|
or_frame.prelude.h = self.heap.len();
|
|
or_frame.prelude.b0 = self.b0;
|
|
|
|
self.b = b;
|
|
|
|
for i in 0..n {
|
|
or_frame[i] = self.registers[i+1];
|
|
}
|
|
|
|
self.hb = self.heap.len();
|
|
self.p += 1;
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(super) fn indexed_try(&mut self, offset: usize) {
|
|
let n = self.num_of_args;
|
|
let b = self.stack.allocate_or_frame(n);
|
|
let or_frame = self.stack.index_or_frame_mut(b);
|
|
|
|
or_frame.prelude.univ_prelude.num_cells = n;
|
|
or_frame.prelude.e = self.e;
|
|
or_frame.prelude.cp = self.cp;
|
|
or_frame.prelude.b = self.b;
|
|
or_frame.prelude.bp = self.p; // + 1; in self.iip now!
|
|
or_frame.prelude.boip = self.oip;
|
|
or_frame.prelude.biip = self.iip + 1;
|
|
or_frame.prelude.tr = self.tr;
|
|
or_frame.prelude.h = self.heap.len();
|
|
or_frame.prelude.b0 = self.b0;
|
|
|
|
self.b = b;
|
|
|
|
for i in 0..n {
|
|
or_frame[i] = self.registers[i+1];
|
|
}
|
|
|
|
self.hb = self.heap.len();
|
|
self.p = self.p + offset;
|
|
|
|
self.oip = 0;
|
|
self.iip = 0;
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub(crate) struct CWIL {
|
|
count: Integer,
|
|
limits: Vec<(Integer, usize)>,
|
|
inference_limit_exceeded: bool,
|
|
}
|
|
|
|
impl CWIL {
|
|
pub(crate) fn new() -> Self {
|
|
CWIL {
|
|
count: Integer::from(0),
|
|
limits: vec![],
|
|
inference_limit_exceeded: false,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn add_limit(&mut self, limit: usize, b: usize) -> &Integer {
|
|
let mut limit = Integer::from(limit);
|
|
limit += &self.count;
|
|
|
|
match self.limits.last() {
|
|
Some((ref inner_limit, _)) if *inner_limit <= limit => {}
|
|
_ => self.limits.push((limit, b)),
|
|
};
|
|
|
|
&self.count
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn remove_limit(&mut self, b: usize) -> &Integer {
|
|
if let Some((_, bp)) = self.limits.last() {
|
|
if bp == &b {
|
|
self.limits.pop();
|
|
}
|
|
}
|
|
|
|
&self.count
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn reset(&mut self) {
|
|
self.count = Integer::from(0);
|
|
self.limits.clear();
|
|
self.inference_limit_exceeded = false;
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn is_empty(&self) -> bool {
|
|
self.limits.is_empty()
|
|
}
|
|
}
|