Files
scryer-prolog/src/prolog/machine/machine_state.rs
2018-01-19 19:39:46 -07:00

1931 lines
66 KiB
Rust

use prolog::and_stack::*;
use prolog::ast::*;
use prolog::builtins::*;
use prolog::copier::*;
use prolog::heap_iter::*;
use prolog::heap_print::*;
use prolog::num::{Integer, ToPrimitive, Zero};
use prolog::num::bigint::{BigInt, BigUint};
use prolog::num::rational::Ratio;
use prolog::or_stack::*;
use prolog::tabled_rc::*;
use std::cmp::max;
use std::ops::{Index, IndexMut};
use std::rc::Rc;
struct DuplicateTerm<'a> {
state: &'a mut MachineState
}
impl<'a> DuplicateTerm<'a> {
fn new(state: &'a mut MachineState) -> Self {
DuplicateTerm { state: state }
}
}
impl<'a> Index<usize> for DuplicateTerm<'a> {
type Output = HeapCellValue;
fn index(&self, index: usize) -> &Self::Output {
&self.state.heap[index]
}
}
impl<'a> IndexMut<usize> for DuplicateTerm<'a> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.state.heap[index]
}
}
// the ordinary, heap term copier, used by duplicate_term.
impl<'a> CopierTarget for DuplicateTerm<'a> {
fn source(&self) -> usize {
self.state.heap.h
}
fn threshold(&self) -> usize {
self.state.heap.h
}
fn push(&mut self, hcv: HeapCellValue) {
self.state.heap.push(hcv);
}
fn store(&self, a: Addr) -> Addr {
self.state.store(a)
}
fn deref(&self, a: Addr) -> Addr {
self.state.deref(a)
}
fn stack(&mut self) -> &mut AndStack {
&mut self.state.and_stack
}
}
struct DuplicateBallTerm<'a> {
state: &'a mut MachineState,
heap_boundary: usize
}
impl<'a> DuplicateBallTerm<'a> {
fn new(state: &'a mut MachineState) -> Self {
let hb = state.heap.len();
DuplicateBallTerm { state: state, heap_boundary: hb }
}
}
impl<'a> Index<usize> for DuplicateBallTerm<'a> {
type Output = HeapCellValue;
fn index(&self, index: usize) -> &Self::Output {
if index < self.heap_boundary {
&self.state.heap[index]
} else {
let index = index - self.heap_boundary;
&self.state.ball.1[index]
}
}
}
impl<'a> IndexMut<usize> for DuplicateBallTerm<'a> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
if index < self.heap_boundary {
&mut self.state.heap[index]
} else {
let index = index - self.heap_boundary;
&mut self.state.ball.1[index]
}
}
}
// the ordinary, heap term copier, used by duplicate_term.
impl<'a> CopierTarget for DuplicateBallTerm<'a> {
fn source(&self) -> usize {
self.heap_boundary
}
fn threshold(&self) -> usize {
self.heap_boundary + self.state.ball.1.len()
}
fn push(&mut self, hcv: HeapCellValue) {
self.state.ball.1.push(hcv);
}
fn store(&self, a: Addr) -> Addr {
self.state.store(a)
}
fn deref(&self, a: Addr) -> Addr {
self.state.deref(a)
}
fn stack(&mut self) -> &mut AndStack {
&mut self.state.and_stack
}
}
impl Index<RegType> for MachineState {
type Output = Addr;
fn index(&self, reg: RegType) -> &Self::Output {
match reg {
RegType::Temp(temp) => &self.registers[temp],
RegType::Perm(perm) => {
let e = self.e;
&self.and_stack[e][perm]
}
}
}
}
impl IndexMut<RegType> for MachineState {
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.and_stack[e][perm]
}
}
}
}
macro_rules! try_or_fail {
($s:ident, $e:expr) => {{
match $e {
Ok(val) => val,
Err(msg) => {
$s.throw_exception(msg);
return;
}
}
}}
}
#[derive(Clone, Copy)]
pub(super) enum MachineMode {
Read,
Write
}
pub struct MachineState {
pub(super) atom_tbl: TabledData<Atom>,
pub(super) s: usize,
pub(super) p: CodePtr,
pub(super) b: usize,
pub(super) b0: usize,
pub(super) e: usize,
pub(super) num_of_args: usize,
pub(super) cp: CodePtr,
pub(super) fail: bool,
pub(crate) heap: Heap,
pub(super) mode: MachineMode,
pub(crate) and_stack: AndStack,
pub(super) or_stack: OrStack,
pub(super) registers: Registers,
pub(super) trail: Vec<Ref>,
pub(super) tr: usize,
pub(super) hb: usize,
pub(super) block: usize, // an offset into the OR stack.
pub(super) ball: (usize, Vec<HeapCellValue>), // heap boundary, and a term copy
pub(super) interms: Vec<Number> // intermediate numbers.
}
impl MachineState {
pub(super) fn new(atom_tbl: TabledData<Atom>) -> MachineState {
MachineState { atom_tbl,
s: 0,
p: CodePtr::default(),
b: 0,
b0: 0,
e: 0,
num_of_args: 0,
cp: CodePtr::default(),
fail: false,
heap: Heap::with_capacity(256),
mode: MachineMode::Write,
and_stack: AndStack::new(),
or_stack: OrStack::new(),
registers: vec![Addr::HeapCell(0); 64],
trail: Vec::new(),
tr: 0,
hb: 0,
block: 0,
ball: (0, Vec::new()),
interms: vec![Number::default(); 256],
}
}
fn next_global_index(&self) -> usize {
max(if self.and_stack.len() > 0 { self.and_stack[self.e].global_index } else { 0 },
if self.b > 0 { self.or_stack[self.b - 1].global_index } else { 0 }) + 1
}
pub(crate) fn store(&self, a: Addr) -> Addr {
match a {
Addr::HeapCell(r) => self.heap[r].as_addr(r),
Addr::StackCell(fr, sc) => self.and_stack[fr][sc].clone(),
addr => addr
}
}
pub(crate) fn deref(&self, mut a: Addr) -> Addr {
loop {
let value = self.store(a.clone());
if value.is_ref() && value != a {
a = value;
continue;
}
return a;
};
}
fn bind(&mut self, r1: Ref, a2: Addr) {
let t2 = self.store(a2);
match r1 {
Ref::StackCell(fr, sc) =>
self.and_stack[fr][sc] = t2,
Ref::HeapCell(hc) =>
self.heap[hc] = HeapCellValue::Addr(t2)
};
self.trail(r1);
}
fn print_var<Fmt, Outputter>(&self, r: Ref, fmt: Fmt, output: Outputter) -> Outputter
where Fmt: HeapCellValueFormatter, Outputter: HeapCellValueOutputter
{
let iter = HeapCellPreOrderIterator::new(&self, r);
let printer = HeapCellPrinter::new(iter, fmt, output);
printer.print()
}
pub(super) fn print_term<Fmt, Outputter>(&self, addr: &Addr, fmt: Fmt, mut output: Outputter)
-> Outputter
where Fmt: HeapCellValueFormatter, Outputter: HeapCellValueOutputter
{
match addr {
&Addr::Con(ref c) => {
output.append(format!("{}", c).as_str());
output
},
&Addr::Lis(h) | &Addr::HeapCell(h) | &Addr::Str(h) =>
self.print_var(Ref::HeapCell(h), fmt, output),
&Addr::StackCell(fr, sc) =>
self.print_var(Ref::StackCell(fr, sc), fmt, output)
}
}
fn unify(&mut self, a1: Addr, a2: Addr) {
let mut pdl = vec![a1, a2];
self.fail = false;
while !(pdl.is_empty() || self.fail) {
let d1 = self.deref(pdl.pop().unwrap());
let d2 = self.deref(pdl.pop().unwrap());
if d1 != d2 {
match (self.store(d1.clone()), self.store(d2.clone())) {
(Addr::HeapCell(hc), _) =>
self.bind(Ref::HeapCell(hc), d2),
(_, Addr::HeapCell(hc)) =>
self.bind(Ref::HeapCell(hc), d1),
(Addr::StackCell(fr, sc), _) =>
self.bind(Ref::StackCell(fr, sc), d2),
(_, Addr::StackCell(fr, sc)) =>
self.bind(Ref::StackCell(fr, sc), d1),
(Addr::Lis(a1), Addr::Lis(a2)) => {
pdl.push(Addr::HeapCell(a1));
pdl.push(Addr::HeapCell(a2));
pdl.push(Addr::HeapCell(a1 + 1));
pdl.push(Addr::HeapCell(a2 + 1));
},
(Addr::Con(c1), Addr::Con(c2)) => {
if c1 != c2 {
self.fail = true;
}
},
(Addr::Str(a1), Addr::Str(a2)) => {
let r1 = &self.heap[a1];
let r2 = &self.heap[a2];
if let &HeapCellValue::NamedStr(n1, ref f1, _) = r1 {
if let &HeapCellValue::NamedStr(n2, ref f2, _) = r2 {
if n1 == n2 && *f1 == *f2 {
for i in 1 .. n1 + 1 {
pdl.push(Addr::HeapCell(a1 + i));
pdl.push(Addr::HeapCell(a2 + i));
}
continue;
}
}
}
self.fail = true;
},
_ => self.fail = true
};
}
}
}
fn trail(&mut self, r: Ref) {
match r {
Ref::HeapCell(hc) => {
if hc < self.hb {
self.trail.push(r);
self.tr += 1;
}
},
Ref::StackCell(fr, _) => {
let fr_gi = self.and_stack[fr].global_index;
let b_gi = if !self.or_stack.is_empty() {
if self.b > 0 {
let b = self.b - 1;
self.or_stack[b].global_index
} else {
0
}
} else {
0
};
if fr_gi < b_gi {
self.trail.push(r);
self.tr += 1;
}
}
}
}
fn unwind_trail(&mut self, a1: usize, a2: usize) {
for i in a1 .. a2 {
match self.trail[i] {
Ref::HeapCell(r) =>
self.heap[r] = HeapCellValue::Addr(Addr::HeapCell(r)),
Ref::StackCell(fr, sc) =>
self.and_stack[fr][sc] = Addr::StackCell(fr, sc)
}
}
}
fn tidy_trail(&mut self) {
if self.b == 0 {
return;
}
let b = self.b - 1;
let mut i = self.or_stack[b].tr;
while i < self.tr {
let tr_i = self.trail[i];
let hb = self.hb;
match tr_i {
Ref::HeapCell(tr_i) =>
if tr_i < hb { //|| ((h < tr_i) && tr_i < b) {
i += 1;
} else {
let tr = self.tr;
let val = self.trail[tr - 1];
self.trail[i] = val;
},
Ref::StackCell(fr, _) => {
let b = self.b - 1;
let fr_gi = self.and_stack[fr].global_index;
let b_gi = if !self.or_stack.is_empty() {
self.or_stack[b].global_index
} else {
0
};
if fr_gi < b_gi {
i += 1;
} else {
let tr = self.tr;
let val = self.trail[tr - 1];
self.trail[i] = val;
}
}
};
}
}
fn write_constant_to_var(&mut self, addr: Addr, c: Constant) {
let addr = self.deref(addr);
match self.store(addr) {
Addr::HeapCell(hc) => {
self.heap[hc] = HeapCellValue::Addr(Addr::Con(c.clone()));
self.trail(Ref::HeapCell(hc));
},
Addr::StackCell(fr, sc) => {
self.and_stack[fr][sc] = Addr::Con(c.clone());
self.trail(Ref::StackCell(fr, sc));
},
Addr::Con(c1) => {
if c1 != c {
self.fail = true;
}
},
_ => self.fail = true
};
}
fn get_number(&self, at: &ArithmeticTerm) -> Result<Number, Vec<HeapCellValue>> {
match at {
&ArithmeticTerm::Reg(r) => {
let addr = self[r].clone();
let item = self.store(self.deref(addr));
match item {
Addr::Con(Constant::Number(n)) => Ok(n),
_ => {
let atom_tbl = self.atom_tbl.clone();
Err(functor!(self.atom_tbl,
"instantiation_error",
1,
[heap_atom!("(is)/2", atom_tbl)]))
}
}
},
&ArithmeticTerm::Interm(i) => Ok(self.interms[i-1].clone()),
&ArithmeticTerm::Number(ref n) => Ok(n.clone()),
}
}
fn get_rational(&self, at: &ArithmeticTerm) -> Result<Rc<Ratio<BigInt>>, Vec<HeapCellValue>> {
let n = self.get_number(at)?;
match n {
Number::Rational(r) => Ok(r),
Number::Float(fl) =>
if let Some(r) = Ratio::from_float(fl.into_inner()) {
Ok(Rc::new(r))
} else {
Err(functor!(self.atom_tbl,
"instantiation_error",
1,
[heap_atom!("(is)/2", self.atom_tbl)]))
},
Number::Integer(bi) =>
Ok(Rc::new(Ratio::from_integer((*bi).clone())))
}
}
fn signed_bitwise_op<Op>(&self, n1: &BigInt, n2: &BigInt, f: Op) -> Rc<BigInt>
where Op: FnOnce(&BigUint, &BigUint) -> BigUint
{
let n1_b = n1.to_signed_bytes_le();
let n2_b = n2.to_signed_bytes_le();
let u_n1 = BigUint::from_bytes_le(&n1_b);
let u_n2 = BigUint::from_bytes_le(&n2_b);
Rc::new(BigInt::from_signed_bytes_le(&f(&u_n1, &u_n2).to_bytes_le()))
}
fn arith_eval_by_metacall(&self, r: RegType) -> Result<Number, Vec<HeapCellValue>>
{
let instantiation_err = functor!(self.atom_tbl.clone(), "instantiation_error", 1,
[heap_atom!("(is)/2", self.atom_tbl.clone())]);
let a = self[r].clone();
if let &Addr::Con(Constant::Number(ref n)) = &a {
return Ok(n.clone());
}
let r = match a {
Addr::Str(h) | Addr::HeapCell(h) => Ok(Ref::HeapCell(h)),
Addr::StackCell(fr, sc) => Ok(Ref::StackCell(fr, sc)),
_ => Err(instantiation_err.clone())
}?;
let mut interms: Vec<Number> = Vec::with_capacity(64);
for heap_val in self.post_order_iter(r) {
match heap_val {
HeapCellValue::NamedStr(2, name, Some(Fixity::In)) => {
let a2 = interms.pop().unwrap();
let a1 = interms.pop().unwrap();
match name.as_str() {
"+" => interms.push(a1 + a2),
"-" => interms.push(a1 - a2),
"*" => interms.push(a1 * a2),
"rdiv" =>
match NumberPair::from(a1, a2) {
NumberPair::Rational(r1, r2) =>
interms.push(Number::Rational(self.rdiv(r1, r2)?)),
_ =>
return Err(instantiation_err)
},
"//" => interms.push(Number::Integer(self.idiv(a1, a2)?)),
"div" => interms.push(Number::Integer(self.fidiv(a1, a2)?)),
">>" => interms.push(Number::Integer(self.shr(a1, a2)?)),
"<<" => interms.push(Number::Integer(self.shl(a1, a2)?)),
"/\\" => interms.push(Number::Integer(self.and(a1, a2)?)),
"\\/" => interms.push(Number::Integer(self.or(a1, a2)?)),
"xor" => interms.push(Number::Integer(self.xor(a1, a2)?)),
"mod" => interms.push(Number::Integer(self.modulus(a1, a2)?)),
"rem" => interms.push(Number::Integer(self.remainder(a1, a2)?)),
_ => return Err(instantiation_err)
}
},
HeapCellValue::NamedStr(1, name, Some(Fixity::Pre)) => {
let a1 = interms.pop().unwrap();
match name.as_str() {
"-" => interms.push(- a1),
_ => return Err(instantiation_err)
}
},
HeapCellValue::Addr(Addr::Con(Constant::Number(n))) =>
interms.push(n),
_ =>
return Err(instantiation_err)
}
};
Ok(interms.pop().unwrap())
}
fn rdiv(&self, r1: Rc<Ratio<BigInt>>, r2: Rc<Ratio<BigInt>>)
-> Result<Rc<Ratio<BigInt>>, Vec<HeapCellValue>>
{
if *r2 == Ratio::zero() {
Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1,
[heap_atom!("zero_divisor", self.atom_tbl.clone())]))
} else {
Ok(Rc::new(&*r1 / &*r2))
}
}
fn fidiv(&self, n1: Number, n2: Number) -> Result<Rc<BigInt>, Vec<HeapCellValue>>
{
match (n1, n2) {
(Number::Integer(n1), Number::Integer(n2)) =>
if *n2 == BigInt::zero() {
Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1,
[heap_atom!("zero_divisor", self.atom_tbl.clone())]))
} else {
Ok(Rc::new(n1.div_floor(&n2)))
},
_ => Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1,
[heap_atom!("expected_integer_args", self.atom_tbl.clone())]))
}
}
fn idiv(&self, n1: Number, n2: Number) -> Result<Rc<BigInt>, Vec<HeapCellValue>>
{
match (n1, n2) {
(Number::Integer(n1), Number::Integer(n2)) =>
if *n2 == BigInt::zero() {
Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1,
[heap_atom!("zero_divisor", self.atom_tbl.clone())]))
} else {
Ok(Rc::new(&*n1 / &*n2))
},
_ =>
Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1,
[heap_atom!("expected_integer_args", self.atom_tbl.clone())]))
}
}
fn div(&self, n1: Number, n2: Number) -> Result<Number, Vec<HeapCellValue>>
{
if n2.is_zero() {
Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1,
[heap_atom!("zero_divisor", self.atom_tbl.clone())]))
} else {
Ok(n1 / n2)
}
}
fn shr(&self, n1: Number, n2: Number) -> Result<Rc<BigInt>, Vec<HeapCellValue>>
{
match (n1, n2) {
(Number::Integer(n1), Number::Integer(n2)) =>
match n2.to_usize() {
Some(n2) => Ok(Rc::new(&*n1 >> n2)),
_ => Ok(Rc::new(&*n1 >> usize::max_value()))
},
_ =>
Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1,
[heap_atom!("expected_integer_args", self.atom_tbl.clone())]))
}
}
fn shl(&self, n1: Number, n2: Number) -> Result<Rc<BigInt>, Vec<HeapCellValue>>
{
match (n1, n2) {
(Number::Integer(n1), Number::Integer(n2)) =>
match n2.to_usize() {
Some(n2) => Ok(Rc::new(&*n1 << n2)),
_ => Ok(Rc::new(&*n1 << usize::max_value()))
},
_ =>
Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1,
[heap_atom!("expected_integer_args", self.atom_tbl.clone())]))
}
}
fn xor(&self, n1: Number, n2: Number) -> Result<Rc<BigInt>, Vec<HeapCellValue>>
{
match (n1, n2) {
(Number::Integer(n1), Number::Integer(n2)) =>
Ok(self.signed_bitwise_op(&*n1, &*n2, |u_n1, u_n2| u_n1 ^ u_n2)),
_ =>
Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1,
[heap_atom!("expected_integer_args", self.atom_tbl.clone())]))
}
}
fn and(&self, n1: Number, n2: Number) -> Result<Rc<BigInt>, Vec<HeapCellValue>>
{
match (n1, n2) {
(Number::Integer(n1), Number::Integer(n2)) =>
Ok(self.signed_bitwise_op(&*n1, &*n2, |u_n1, u_n2| u_n1 & u_n2)),
_ =>
Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1,
[heap_atom!("expected_integer_args", self.atom_tbl.clone())]))
}
}
fn modulus(&self, n1: Number, n2: Number) -> Result<Rc<BigInt>, Vec<HeapCellValue>>
{
match (n1, n2) {
(Number::Integer(n1), Number::Integer(n2)) =>
if *n2 == BigInt::zero() {
Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1,
[heap_atom!("zero_divisor", self.atom_tbl.clone())]))
} else {
Ok(Rc::new(n1.mod_floor(&n2)))
},
_ =>
Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1,
[heap_atom!("expected_integer_args", self.atom_tbl.clone())]))
}
}
fn remainder(&self, n1: Number, n2: Number) -> Result<Rc<BigInt>, Vec<HeapCellValue>>
{
match (n1, n2) {
(Number::Integer(n1), Number::Integer(n2)) =>
if *n2 == BigInt::zero() {
Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1,
[heap_atom!("zero_divisor", self.atom_tbl.clone())]))
} else {
Ok(Rc::new(&*n1 % &*n2))
},
_ =>
Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1,
[heap_atom!("expected_integer_args", self.atom_tbl.clone())]))
}
}
fn or(&self, n1: Number, n2: Number) -> Result<Rc<BigInt>, Vec<HeapCellValue>>
{
match (n1, n2) {
(Number::Integer(n1), Number::Integer(n2)) =>
Ok(self.signed_bitwise_op(&*n1, &*n2, |u_n1, u_n2| u_n1 & u_n2)),
_ =>
Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1,
[heap_atom!("expected_integer_args", self.atom_tbl.clone())]))
}
}
pub(super) fn execute_arith_instr(&mut self, instr: &ArithmeticInstruction) {
match instr {
&ArithmeticInstruction::Add(ref a1, ref a2, t) => {
let n1 = try_or_fail!(self, self.get_number(a1));
let n2 = try_or_fail!(self, self.get_number(a2));
self.interms[t - 1] = n1 + n2;
self.p += 1;
},
&ArithmeticInstruction::Sub(ref a1, ref a2, t) => {
let n1 = try_or_fail!(self, self.get_number(a1));
let n2 = try_or_fail!(self, self.get_number(a2));
self.interms[t - 1] = n1 - n2;
self.p += 1;
},
&ArithmeticInstruction::Mul(ref a1, ref a2, t) => {
let n1 = try_or_fail!(self, self.get_number(a1));
let n2 = try_or_fail!(self, self.get_number(a2));
self.interms[t - 1] = n1 * n2;
self.p += 1;
},
&ArithmeticInstruction::RDiv(ref a1, ref a2, t) => {
let r1 = try_or_fail!(self, self.get_rational(a1));
let r2 = try_or_fail!(self, self.get_rational(a2));
self.interms[t - 1] = Number::Rational(try_or_fail!(self, self.rdiv(r1, r2)));
self.p += 1;
},
&ArithmeticInstruction::FIDiv(ref a1, ref a2, t) => {
let n1 = try_or_fail!(self, self.get_number(a1));
let n2 = try_or_fail!(self, self.get_number(a2));
self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.fidiv(n1, n2)));
self.p += 1;
},
&ArithmeticInstruction::IDiv(ref a1, ref a2, t) => {
let n1 = try_or_fail!(self, self.get_number(a1));
let n2 = try_or_fail!(self, self.get_number(a2));
self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.idiv(n1, n2)));
self.p += 1;
},
&ArithmeticInstruction::Neg(ref a1, t) => {
let n1 = try_or_fail!(self, self.get_number(a1));
self.interms[t - 1] = - n1;
self.p += 1;
},
&ArithmeticInstruction::Div(ref a1, ref a2, t) => {
let n1 = try_or_fail!(self, self.get_number(a1));
let n2 = try_or_fail!(self, self.get_number(a2));
self.interms[t - 1] = try_or_fail!(self, self.div(n1, n2));
self.p += 1;
},
&ArithmeticInstruction::Shr(ref a1, ref a2, t) => {
let n1 = try_or_fail!(self, self.get_number(a1));
let n2 = try_or_fail!(self, self.get_number(a2));
self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.shr(n1, n2)));
self.p += 1;
},
&ArithmeticInstruction::Shl(ref a1, ref a2, t) => {
let n1 = try_or_fail!(self, self.get_number(a1));
let n2 = try_or_fail!(self, self.get_number(a2));
self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.shl(n1, n2)));
self.p += 1;
},
&ArithmeticInstruction::Xor(ref a1, ref a2, t) => {
let n1 = try_or_fail!(self, self.get_number(a1));
let n2 = try_or_fail!(self, self.get_number(a2));
self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.xor(n1, n2)));
self.p += 1;
},
&ArithmeticInstruction::And(ref a1, ref a2, t) => {
let n1 = try_or_fail!(self, self.get_number(a1));
let n2 = try_or_fail!(self, self.get_number(a2));
self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.and(n1, n2)));
self.p += 1;
},
&ArithmeticInstruction::Or(ref a1, ref a2, t) => {
let n1 = try_or_fail!(self, self.get_number(a1));
let n2 = try_or_fail!(self, self.get_number(a2));
self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.or(n1, n2)));
self.p += 1;
},
&ArithmeticInstruction::Mod(ref a1, ref a2, t) => {
let n1 = try_or_fail!(self, self.get_number(a1));
let n2 = try_or_fail!(self, self.get_number(a2));
self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.modulus(n1, n2)));
self.p += 1;
},
&ArithmeticInstruction::Rem(ref a1, ref a2, t) => {
let n1 = try_or_fail!(self, self.get_number(a1));
let n2 = try_or_fail!(self, self.get_number(a2));
self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.remainder(n1, n2)));
self.p += 1;
}
};
}
pub(super) fn execute_fact_instr(&mut self, instr: &FactInstruction) {
match instr {
&FactInstruction::GetConstant(_, ref c, reg) => {
let addr = self[reg].clone();
self.write_constant_to_var(addr, c.clone());
},
&FactInstruction::GetList(_, reg) => {
let addr = self.deref(self[reg].clone());
match self.store(addr.clone()) {
Addr::HeapCell(hc) => {
let h = self.heap.h;
self.heap.push(HeapCellValue::Addr(Addr::Lis(h+1)));
self.bind(Ref::HeapCell(hc), Addr::HeapCell(h));
self.mode = MachineMode::Write;
},
Addr::StackCell(fr, sc) => {
let h = self.heap.h;
self.heap.push(HeapCellValue::Addr(Addr::Lis(h+1)));
self.bind(Ref::StackCell(fr, sc), Addr::HeapCell(h));
self.mode = MachineMode::Write;
},
Addr::Lis(a) => {
self.s = a;
self.mode = MachineMode::Read;
},
_ => self.fail = true
};
},
&FactInstruction::GetStructure(_, ref name, arity, reg, fixity) => {
let addr = self.deref(self[reg].clone());
match self.store(addr.clone()) {
Addr::Str(a) => {
let result = &self.heap[a];
if let &HeapCellValue::NamedStr(narity, ref str, _) = result {
if narity == arity && *name == *str {
self.s = a + 1;
self.mode = MachineMode::Read;
} else {
self.fail = true;
}
}
},
Addr::HeapCell(_) | Addr::StackCell(_, _) => {
let h = self.heap.h;
self.heap.push(HeapCellValue::Addr(Addr::Str(h + 1)));
self.heap.push(HeapCellValue::NamedStr(arity, name.clone(), fixity));
self.bind(addr.as_var().unwrap(), Addr::HeapCell(h));
self.mode = MachineMode::Write;
},
_ => self.fail = true
};
},
&FactInstruction::GetVariable(norm, arg) =>
self[norm] = self.registers[arg].clone(),
&FactInstruction::GetValue(norm, arg) => {
let norm_addr = self[norm].clone();
let reg_addr = self.registers[arg].clone();
self.unify(norm_addr, reg_addr);
},
&FactInstruction::UnifyConstant(ref c) => {
match self.mode {
MachineMode::Read => {
let addr = Addr::HeapCell(self.s);
self.write_constant_to_var(addr, c.clone());
},
MachineMode::Write => {
self.heap.push(HeapCellValue::Addr(Addr::Con(c.clone())));
}
};
self.s += 1;
},
&FactInstruction::UnifyVariable(reg) => {
match self.mode {
MachineMode::Read =>
self[reg] = self.heap[self.s].as_addr(self.s),
MachineMode::Write => {
let h = self.heap.h;
self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
self[reg] = Addr::HeapCell(h);
}
};
self.s += 1;
},
&FactInstruction::UnifyLocalValue(reg) => {
let s = self.s;
match self.mode {
MachineMode::Read => {
let reg_addr = self[reg].clone();
self.unify(reg_addr, Addr::HeapCell(s));
},
MachineMode::Write => {
let addr = self.deref(self[reg].clone());
let h = self.heap.h;
if let Addr::HeapCell(hc) = addr {
if hc < h {
let val = self.heap[hc].clone();
self.heap.push(val);
self.s += 1;
return;
}
}
self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
self.bind(Ref::HeapCell(h), addr);
}
};
self.s += 1;
},
&FactInstruction::UnifyValue(reg) => {
let s = self.s;
match self.mode {
MachineMode::Read => {
let reg_addr = self[reg].clone();
self.unify(reg_addr, Addr::HeapCell(s));
},
MachineMode::Write => {
let heap_val = self.store(self[reg].clone());
self.heap.push(HeapCellValue::Addr(heap_val));
}
};
self.s += 1;
},
&FactInstruction::UnifyVoid(n) => {
match self.mode {
MachineMode::Read =>
self.s += n,
MachineMode::Write => {
let h = self.heap.h;
for i in h .. h + n {
self.heap.push(HeapCellValue::Addr(Addr::HeapCell(i)));
}
}
};
}
};
}
pub(super) fn execute_indexing_instr(&mut self, instr: &IndexingInstruction) {
match instr {
&IndexingInstruction::SwitchOnTerm(v, c, l, s) => {
let a1 = self.registers[1].clone();
let addr = self.store(self.deref(a1));
let offset = match addr {
Addr::HeapCell(_) | Addr::StackCell(_, _) => v,
Addr::Con(_) => c,
Addr::Lis(_) => l,
Addr::Str(_) => s
};
match offset {
0 => self.fail = true,
o => self.p += o
};
},
&IndexingInstruction::SwitchOnConstant(_, ref hm) => {
let a1 = self.registers[1].clone();
let addr = self.store(self.deref(a1));
let offset = match addr {
Addr::Con(constant) => {
match hm.get(&constant) {
Some(offset) => *offset,
_ => 0
}
},
_ => 0
};
match offset {
0 => self.fail = true,
o => self.p += o,
};
},
&IndexingInstruction::SwitchOnStructure(_, ref hm) => {
let a1 = self.registers[1].clone();
let addr = self.store(self.deref(a1));
let offset = match addr {
Addr::Str(s) => {
if let &HeapCellValue::NamedStr(arity, ref name, _) = &self.heap[s] {
match hm.get(&(name.clone(), arity)) {
Some(offset) => *offset,
_ => 0
}
} else {
0
}
},
_ => 0
};
match offset {
0 => self.fail = true,
o => self.p += o
};
}
};
}
pub(super) fn execute_query_instr(&mut self, instr: &QueryInstruction) {
match instr {
&QueryInstruction::GetVariable(norm, arg) =>
self[norm] = self.registers[arg].clone(),
&QueryInstruction::PutConstant(_, ref constant, reg) =>
self[reg] = Addr::Con(constant.clone()),
&QueryInstruction::PutList(_, reg) =>
self[reg] = Addr::Lis(self.heap.h),
&QueryInstruction::PutStructure(_, ref name, arity, reg, fixity) => {
let h = self.heap.h;
self.heap.push(HeapCellValue::NamedStr(arity, name.clone(), fixity));
self[reg] = Addr::Str(h);
},
&QueryInstruction::PutUnsafeValue(n, arg) => {
let e = self.e;
let addr = self.deref(Addr::StackCell(e, n));
if addr.is_protected(e) {
self.registers[arg] = self.store(addr);
} else {
let h = self.heap.h;
self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
self.bind(Ref::HeapCell(h), addr);
self.registers[arg] = self.heap[h].as_addr(h);
}
},
&QueryInstruction::PutValue(norm, arg) =>
self.registers[arg] = self[norm].clone(),
&QueryInstruction::PutVariable(norm, arg) => {
match norm {
RegType::Perm(n) => {
let e = self.e;
self[norm] = Addr::StackCell(e, n);
self.registers[arg] = self[norm].clone();
},
RegType::Temp(_) => {
let h = self.heap.h;
self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
self[norm] = Addr::HeapCell(h);
self.registers[arg] = Addr::HeapCell(h);
}
};
},
&QueryInstruction::SetConstant(ref c) => {
self.heap.push(HeapCellValue::Addr(Addr::Con(c.clone())));
},
&QueryInstruction::SetLocalValue(reg) => {
let addr = self.deref(self[reg].clone());
let h = self.heap.h;
if let Addr::HeapCell(hc) = addr {
if hc < h {
self.heap.push(HeapCellValue::Addr(addr));
return;
}
}
self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
self.bind(Ref::HeapCell(h), addr);
},
&QueryInstruction::SetVariable(reg) => {
let h = self.heap.h;
self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
self[reg] = Addr::HeapCell(h);
},
&QueryInstruction::SetValue(reg) => {
let heap_val = self[reg].clone();
self.heap.push(HeapCellValue::Addr(heap_val));
},
&QueryInstruction::SetVoid(n) => {
let h = self.heap.h;
for i in h .. h + n {
self.heap.push(HeapCellValue::Addr(Addr::HeapCell(i)));
}
}
}
}
fn try_call_predicate(&mut self, code_dir: &CodeDir, name: TabledRc<Atom>, arity: usize)
{
let compiled_tl_index = code_dir.get(&(name, arity)).map(|index| index.1);
match compiled_tl_index {
Some(compiled_tl_index) => {
self.cp = self.p + 1;
self.num_of_args = arity;
self.b0 = self.b;
self.p = CodePtr::DirEntry(compiled_tl_index);
},
None => self.fail = true
};
}
fn try_execute_predicate(&mut self, code_dir: &CodeDir, name: TabledRc<Atom>, arity: usize)
{
let compiled_tl_index = code_dir.get(&(name, arity)).map(|index| index.1);
match compiled_tl_index {
Some(compiled_tl_index) => {
self.num_of_args = arity;
self.b0 = self.b;
self.p = CodePtr::DirEntry(compiled_tl_index);
},
None => self.fail = true
};
}
fn handle_internal_call_n(&mut self, code_dir: &CodeDir)
{
let arity = self.num_of_args + 1;
let pred = self.registers[1].clone();
for i in 2 .. arity {
self.registers[i-1] = self.registers[i].clone();
}
if arity > 1 {
self.registers[arity - 1] = pred;
if let Some((name, arity)) = self.setup_call_n(arity - 1) {
self.try_execute_predicate(code_dir, name, arity);
}
} else {
self.fail = true;
}
}
fn goto_throw(&mut self) {
self.num_of_args = 1;
self.b0 = self.b;
self.p = CodePtr::DirEntry(59);
}
fn throw_exception(&mut self, hcv: Vec<HeapCellValue>) {
let h = self.heap.h;
self.registers[1] = Addr::HeapCell(h);
self.heap.append(hcv);
self.goto_throw();
}
fn setup_call_n(&mut self, arity: usize) -> Option<PredicateKey>
{
let addr = self.store(self.deref(self.registers[arity].clone()));
let (name, narity) = match addr {
Addr::Str(a) => {
let result = self.heap[a].clone();
if let HeapCellValue::NamedStr(narity, name, _) = result {
if narity + arity > 63 {
let atom_tbl = self.atom_tbl.clone();
self.throw_exception(functor!(atom_tbl,
"representation_error",
1,
[heap_atom!("exceeds_max_arity", atom_tbl)]));
return None;
}
for i in (1 .. arity).rev() {
self.registers[i + narity] = self.registers[i].clone();
}
for i in 1 .. narity + 1 {
self.registers[i] = self.heap[a + i].as_addr(a + i);
}
(name, narity)
} else {
self.fail = true;
return None;
}
},
Addr::Con(Constant::Atom(name)) => (name, 0),
Addr::HeapCell(_) | Addr::StackCell(_, _) => {
let atom_tbl = self.atom_tbl.clone();
self.throw_exception(functor!(atom_tbl, "instantiation_error", 0, []));
return None;
},
_ => {
let atom_tbl = self.atom_tbl.clone();
self.throw_exception(functor!(atom_tbl,
"type_error",
2,
[heap_atom!("callable", atom_tbl),
HeapCellValue::Addr(addr)]));
return None;
}
};
Some((name, arity + narity - 1))
}
pub(super) fn copy_and_align_ball_to_heap(&mut self) {
let diff = self.ball.0 - self.heap.h;
for heap_value in self.ball.1.iter().cloned() {
self.heap.push(match heap_value {
HeapCellValue::Addr(Addr::Con(c)) =>
HeapCellValue::Addr(Addr::Con(c)),
HeapCellValue::Addr(Addr::Lis(a)) =>
HeapCellValue::Addr(Addr::Lis(a - diff)),
HeapCellValue::Addr(Addr::HeapCell(hc)) =>
HeapCellValue::Addr(Addr::HeapCell(hc - diff)),
HeapCellValue::Addr(Addr::Str(s)) =>
HeapCellValue::Addr(Addr::Str(s - diff)),
_ => heap_value
});
}
}
fn try_get_arg(&mut self) -> Result<(), Vec<HeapCellValue>>
{
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
if let Addr::Con(Constant::Number(Number::Integer(i))) = a1 {
let a2 = self.store(self.deref(self[temp_v!(2)].clone()));
if let Addr::Str(o) = a2 {
match self.heap[o].clone() {
HeapCellValue::NamedStr(arity, _, _) =>
match i.to_usize() {
Some(i) if 1 <= i && i <= arity => {
let a3 = self[temp_v!(3)].clone();
let h_a = Addr::HeapCell(o + i);
self.unify(a3, h_a);
},
_ => self.fail = true
},
_ => self.fail = true
};
} else {
return Err(functor!(self.atom_tbl,
"type_error",
1,
[heap_atom!("compound_expected", self.atom_tbl)]));
}
}
Ok(())
}
fn compare_numbers(&mut self, cmp: CompareNumberQT, n1: Number, n2: Number) {
self.fail = match cmp {
CompareNumberQT::GreaterThan if !(n1.gt(n2)) => true,
CompareNumberQT::GreaterThanOrEqual if !(n1.gte(n2)) => true,
CompareNumberQT::LessThan if !(n1.lt(n2)) => true,
CompareNumberQT::LessThanOrEqual if !(n1.lte(n2)) => true,
CompareNumberQT::NotEqual if !(n1.ne(n2)) => true,
CompareNumberQT::Equal if !(n1.eq(n2)) => true,
_ => false
};
self.p += 1;
}
pub(super) fn execute_built_in_instr(&mut self, code_dir: &CodeDir, instr: &BuiltInInstruction)
{
match instr {
&BuiltInInstruction::CompareNumber(cmp, ref at_1, ref at_2) => {
let n1 = try_or_fail!(self, self.get_number(at_1));
let n2 = try_or_fail!(self, self.get_number(at_2));
self.compare_numbers(cmp, n1, n2);
},
&BuiltInInstruction::DynamicCompareNumber(cmp) => {
let n1 = try_or_fail!(self, self.arith_eval_by_metacall(temp_v!(1)));
let n2 = try_or_fail!(self, self.arith_eval_by_metacall(temp_v!(2)));
self.compare_numbers(cmp, n1, n2);
},
&BuiltInInstruction::DynamicIs => {
let a = self[temp_v!(1)].clone();
let result = try_or_fail!(self, self.arith_eval_by_metacall(temp_v!(2)));
self.unify(a, Addr::Con(Constant::Number(result)));
self.p += 1;
},
&BuiltInInstruction::GetArg =>
try_or_fail!(self, {
let val = self.try_get_arg();
self.p = self.cp;
val
}),
&BuiltInInstruction::GetCurrentBlock => {
let c = Constant::Usize(self.block);
let addr = self[temp_v!(1)].clone();
self.write_constant_to_var(addr, c);
self.p += 1;
},
&BuiltInInstruction::EraseBall => {
self.ball.0 = 0;
self.ball.1.truncate(0);
self.p += 1;
},
&BuiltInInstruction::GetBall => {
let addr = self.store(self.deref(self[temp_v!(1)].clone()));
let h = self.heap.h;
if self.ball.1.len() > 0 {
self.copy_and_align_ball_to_heap();
} else {
self.fail = true;
return;
}
let ball = self.heap[h].as_addr(h);
match addr.as_var() {
Some(r) => {
self.bind(r, ball);
self.p += 1;
},
_ => self.fail = true
};
},
&BuiltInInstruction::GetCutPoint(r) => {
let c = Constant::Usize(self.b);
self[r] = Addr::Con(c);
self.p += 1;
},
&BuiltInInstruction::SetBall => {
let addr = self[temp_v!(1)].clone();
self.ball.0 = self.heap.h;
{
let mut duplicator = DuplicateBallTerm::new(self);
duplicator.duplicate_term(addr);
}
self.p += 1;
},
&BuiltInInstruction::SetCutPoint(r) => {
let addr = self.store(self.deref(self[r].clone()));
match addr {
Addr::Con(Constant::Usize(nb)) => {
if self.b > nb {
self.b = nb;
self.tidy_trail();
}
self.p += 1;
},
_ => self.fail = true
};
},
&BuiltInInstruction::CleanUpBlock => {
let nb = self.store(self.deref(self[temp_v!(1)].clone()));
match nb {
Addr::Con(Constant::Usize(nb)) => {
let b = self.b - 1;
if nb > 0 && self.or_stack[b].b == nb {
self.b = self.or_stack[nb - 1].b;
self.or_stack.truncate(self.b);
}
self.p += 1;
},
_ => self.fail = true
};
},
&BuiltInInstruction::InstallNewBlock => {
self.block = self.b;
let c = Constant::Usize(self.block);
let addr = self[temp_v!(1)].clone();
self.write_constant_to_var(addr, c);
self.p += 1;
},
&BuiltInInstruction::ResetBlock => {
let addr = self.deref(self[temp_v!(1)].clone());
match self.store(addr) {
Addr::Con(Constant::Usize(b)) => {
self.block = b;
self.p += 1;
},
_ => self.fail = true
};
},
&BuiltInInstruction::UnwindStack => {
self.b = self.block;
self.or_stack.truncate(self.b);
self.fail = true;
},
&BuiltInInstruction::IsAtomic(r) => {
let d = self.store(self.deref(self[r].clone()));
match d {
Addr::Con(_) => self.p += 1,
_ => self.fail = true
};
},
&BuiltInInstruction::IsInteger(r) => {
let d = self.store(self.deref(self[r].clone()));
match d {
Addr::Con(Constant::Number(Number::Integer(_))) => self.p += 1,
_ => self.fail = true
};
},
&BuiltInInstruction::IsVar(r) => {
let d = self.store(self.deref(self[r].clone()));
match d {
Addr::HeapCell(_) | Addr::StackCell(_,_) => self.p += 1,
_ => self.fail = true
};
},
&BuiltInInstruction::InternalCallN =>
self.handle_internal_call_n(code_dir),
&BuiltInInstruction::Fail => {
self.fail = true;
self.p += 1;
},
&BuiltInInstruction::Succeed => {
self.p += 1;
},
&BuiltInInstruction::Unify => {
let a1 = self[temp_v!(1)].clone();
let a2 = self[temp_v!(2)].clone();
self.unify(a1, a2);
self.p += 1;
}
};
}
fn try_functor(&mut self) -> Result<(), Vec<HeapCellValue>> {
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
match a1.clone() {
Addr::Str(o) =>
match self.heap[o].clone() {
HeapCellValue::NamedStr(arity, name, _) => {
let name = Addr::Con(Constant::Atom(name)); // A2
let arity = Addr::Con(Constant::Number(rc_integer!(arity)));
let a2 = self[temp_v!(2)].clone();
self.unify(a2, name);
if !self.fail {
let a3 = self[temp_v!(3)].clone();
self.unify(a3, arity);
}
},
_ => self.fail = true
},
Addr::HeapCell(_) | Addr::StackCell(_, _) => {
let name = self.store(self.deref(self[temp_v!(2)].clone()));
let arity = self.store(self.deref(self[temp_v!(3)].clone()));
if let Addr::Con(Constant::Atom(name)) = name {
if let Addr::Con(Constant::Number(Number::Integer(arity))) = arity {
let f_a = Addr::Str(self.heap.h);
let arity = match arity.to_usize() {
Some(arity) => arity,
None => {
self.fail = true;
return Ok(());
}
};
self.heap.push(HeapCellValue::NamedStr(arity, name, None));
for _ in 0 .. arity {
let h = self.heap.h;
self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
}
self.unify(a1, f_a);
} else {
return Err(functor!(self.atom_tbl, "instantiation_error", 0, []));
}
} else {
return Err(functor!(self.atom_tbl, "instantiation_error", 0, []));
}
},
_ => {
let a2 = self[temp_v!(2)].clone();
self.unify(a1, a2);
if !self.fail {
let a3 = self[temp_v!(3)].clone();
self.unify(a3, Addr::Con(Constant::Number(rc_integer!(0))));
}
}
};
Ok(())
}
fn duplicate_term(&mut self) {
let old_h = self.heap.h;
let a1 = self[temp_v!(1)].clone();
let a2 = self[temp_v!(2)].clone();
// drop the mutable references contained in gadget
// once the term has been duplicated.
{
let mut gadget = DuplicateTerm::new(self);
gadget.duplicate_term(a1);
}
self.unify(Addr::HeapCell(old_h), a2);
}
pub(super) fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction)
{
match instr {
&ControlInstruction::Allocate(num_cells) => {
let gi = self.next_global_index();
self.p += 1;
if self.e + 1 < self.and_stack.len() {
let and_gi = self.and_stack[self.e].global_index;
let or_gi = self.or_stack.top()
.map(|or_fr| or_fr.global_index)
.unwrap_or(0);
if and_gi > or_gi {
let index = self.e + 1;
self.and_stack[index].e = self.e;
self.and_stack[index].cp = self.cp;
self.and_stack[index].global_index = gi;
self.and_stack.resize(index, num_cells);
self.e = index;
return;
}
}
self.and_stack.push(gi, self.e, self.cp, num_cells);
self.e = self.and_stack.len() - 1;
},
&ControlInstruction::ArgCall => {
self.cp = self.p + 1;
self.num_of_args = 3;
self.b0 = self.b;
self.p = CodePtr::DirEntry(150);
},
&ControlInstruction::ArgExecute => {
self.num_of_args = 3;
self.b0 = self.b;
self.p = CodePtr::DirEntry(150);
},
&ControlInstruction::Call(ref name, arity, _) =>
self.try_call_predicate(code_dir, name.clone(), arity),
&ControlInstruction::CatchCall => {
self.cp = self.p + 1;
self.num_of_args = 3;
self.b0 = self.b;
self.p = CodePtr::DirEntry(5);
},
&ControlInstruction::CatchExecute => {
self.num_of_args = 3;
self.b0 = self.b;
self.p = CodePtr::DirEntry(5);
},
&ControlInstruction::CallN(arity) =>
if let Some((name, arity)) = self.setup_call_n(arity) {
self.try_call_predicate(code_dir, name, arity);
},
&ControlInstruction::Deallocate => {
let e = self.e;
self.cp = self.and_stack[e].cp;
self.e = self.and_stack[e].e;
self.p += 1;
},
&ControlInstruction::DisplayCall => {
let output = self.print_term(&self[temp_v!(1)],
DisplayFormatter {},
PrinterOutputter::new());
println!("{}", output.result());
self.p += 1;
},
&ControlInstruction::DisplayExecute => {
let output = self.print_term(&self[temp_v!(1)],
DisplayFormatter {},
PrinterOutputter::new());
println!("{}", output.result());
self.p = self.cp;
},
&ControlInstruction::DuplicateTermCall => {
self.duplicate_term();
self.p += 1;
},
&ControlInstruction::DuplicateTermExecute => {
self.duplicate_term();
self.p = self.cp;
},
&ControlInstruction::Execute(ref name, arity) =>
self.try_execute_predicate(code_dir, name.clone(), arity),
&ControlInstruction::ExecuteN(arity) =>
if let Some((name, arity)) = self.setup_call_n(arity) {
self.try_execute_predicate(code_dir, name, arity);
},
&ControlInstruction::FunctorCall =>
try_or_fail!(self, {
let val = self.try_functor();
self.p += 1;
val
}),
&ControlInstruction::FunctorExecute =>
try_or_fail!(self, {
let val = self.try_functor();
self.p = self.cp;
val
}),
&ControlInstruction::Goto(p, arity) => {
self.num_of_args = arity;
self.b0 = self.b;
self.p = CodePtr::DirEntry(p);
},
&ControlInstruction::IsCall(r, ref at) => {
let a1 = self[r].clone();
let a2 = try_or_fail!(self, self.get_number(at));
self.unify(a1, Addr::Con(Constant::Number(a2)));
self.p += 1;
},
&ControlInstruction::IsExecute(r, ref at) => {
let a1 = self[r].clone();
let a2 = try_or_fail!(self, self.get_number(at));
self.unify(a1, Addr::Con(Constant::Number(a2)));
self.p = self.cp;
},
&ControlInstruction::Proceed =>
self.p = self.cp,
&ControlInstruction::ThrowCall => {
self.cp = self.p + 1;
self.goto_throw();
},
&ControlInstruction::ThrowExecute => {
self.goto_throw();
},
};
}
pub(super) fn execute_indexed_choice_instr(&mut self, instr: &IndexedChoiceInstruction)
{
match instr {
&IndexedChoiceInstruction::Try(l) => {
let n = self.num_of_args;
let gi = self.next_global_index();
self.or_stack.push(gi,
self.e,
self.cp,
self.b,
self.p + 1,
self.tr,
self.heap.h,
self.b0,
self.num_of_args);
self.b = self.or_stack.len();
let b = self.b - 1;
for i in 1 .. n + 1 {
self.or_stack[b][i] = self.registers[i].clone();
}
self.hb = self.heap.h;
self.p += l;
},
&IndexedChoiceInstruction::Retry(l) => {
let b = self.b - 1;
let n = self.or_stack[b].num_args();
for i in 1 .. n + 1 {
self.registers[i] = self.or_stack[b][i].clone();
}
self.e = self.or_stack[b].e;
self.cp = self.or_stack[b].cp;
self.or_stack[b].bp = self.p + 1;
let old_tr = self.or_stack[b].tr;
let curr_tr = self.tr;
self.unwind_trail(old_tr, curr_tr);
self.tr = self.or_stack[b].tr;
self.trail.truncate(self.tr);
self.heap.truncate(self.or_stack[b].h);
self.hb = self.heap.h;
self.p += l;
},
&IndexedChoiceInstruction::Trust(l) => {
let b = self.b - 1;
let n = self.or_stack[b].num_args();
for i in 1 .. n + 1 {
self.registers[i] = self.or_stack[b][i].clone();
}
self.e = self.or_stack[b].e;
self.cp = self.or_stack[b].cp;
let old_tr = self.or_stack[b].tr;
let curr_tr = self.tr;
self.unwind_trail(old_tr, curr_tr);
self.tr = self.or_stack[b].tr;
self.trail.truncate(self.tr);
self.heap.truncate(self.or_stack[b].h);
self.b = self.or_stack[b].b;
self.or_stack.truncate(self.b);
self.hb = self.heap.h;
self.p += l;
},
};
}
pub(super) fn execute_choice_instr(&mut self, instr: &ChoiceInstruction)
{
match instr {
&ChoiceInstruction::TryMeElse(offset) => {
let n = self.num_of_args;
let gi = self.next_global_index();
self.or_stack.push(gi,
self.e,
self.cp,
self.b,
self.p + offset,
self.tr,
self.heap.h,
self.b0,
self.num_of_args);
self.b = self.or_stack.len();
let b = self.b - 1;
for i in 1 .. n + 1 {
self.or_stack[b][i] = self.registers[i].clone();
}
self.hb = self.heap.h;
self.p += 1;
},
&ChoiceInstruction::RetryMeElse(offset) => {
let b = self.b - 1;
let n = self.or_stack[b].num_args();
for i in 1 .. n + 1 {
self.registers[i] = self.or_stack[b][i].clone();
}
self.e = self.or_stack[b].e;
self.cp = self.or_stack[b].cp;
self.or_stack[b].bp = self.p + offset;
let old_tr = self.or_stack[b].tr;
let curr_tr = self.tr;
self.unwind_trail(old_tr, curr_tr);
self.tr = self.or_stack[b].tr;
self.trail.truncate(self.tr);
self.heap.truncate(self.or_stack[b].h);
self.hb = self.heap.h;
self.p += 1;
},
&ChoiceInstruction::TrustMe => {
let b = self.b - 1;
let n = self.or_stack[b].num_args();
for i in 1 .. n + 1 {
self.registers[i] = self.or_stack[b][i].clone();
}
self.e = self.or_stack[b].e;
self.cp = self.or_stack[b].cp;
let old_tr = self.or_stack[b].tr;
let curr_tr = self.tr;
self.unwind_trail(old_tr, curr_tr);
self.tr = self.or_stack[b].tr;
self.trail.truncate(self.tr);
self.heap.truncate(self.or_stack[b].h);
self.b = self.or_stack[b].b;
self.or_stack.truncate(self.b);
self.hb = self.heap.h;
self.p += 1;
}
}
}
pub(super) fn execute_cut_instr(&mut self, instr: &CutInstruction) {
match instr {
&CutInstruction::NeckCut => {
let b = self.b;
let b0 = self.b0;
if b > b0 {
self.b = b0;
self.tidy_trail();
}
self.p += 1;
},
&CutInstruction::GetLevel => {
let b0 = self.b0;
let e = self.e;
self.and_stack[e].b0 = b0;
self.p += 1;
},
&CutInstruction::Cut => {
let b = self.b;
let e = self.e;
let b0 = self.and_stack[e].b0; // STACK[E+2+1]
if b > b0 {
self.b = b0;
self.tidy_trail();
}
self.p += 1;
}
}
}
pub(super) fn reset(&mut self) {
self.hb = 0;
self.e = 0;
self.b = 0;
self.b0 = 0;
self.s = 0;
self.tr = 0;
self.p = CodePtr::default();
self.cp = CodePtr::default();
self.num_of_args = 0;
self.fail = false;
self.trail.clear();
self.heap.clear();
self.mode = MachineMode::Write;
self.and_stack.clear();
self.or_stack.clear();
self.registers = vec![Addr::HeapCell(0); 64];
self.block = 0;
self.ball = (0, Vec::new());
}
}