Merge branch 'master' into library-use-case

# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	src/bin/scryer-prolog.rs
#	src/loader.pl
#	src/machine/mock_wam.rs
#	src/machine/mod.rs
#	src/machine/system_calls.rs
This commit is contained in:
Nicolas Luck
2023-08-03 20:16:32 +02:00
117 changed files with 17744 additions and 10848 deletions

View File

@@ -1,3 +1,6 @@
use dashu::base::Abs;
use dashu::base::Gcd;
use dashu::integer::IBig;
use divrem::*;
use crate::arena::*;
@@ -8,7 +11,7 @@ use crate::heap_iter::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_state::*;
use crate::parser::ast::*;
use crate::parser::rug::{Integer, Rational};
use crate::parser::dashu::{Integer, Rational};
use crate::types::*;
use crate::fixnum;
@@ -159,7 +162,7 @@ pub(crate) fn add(lhs: Number, rhs: Number, arena: &mut Arena) -> Result<Number,
Ok(Number::Float(add_f(float_fn_to_f(n1.get_num())?, n2)?))
}
(Number::Integer(n1), Number::Integer(n2)) => {
Ok(Number::arena_from(Integer::from(&*n1) + &*n2, arena)) // add_i
Ok(Number::arena_from(&*n1 + &*n2, arena)) // add_i
}
(Number::Integer(n1), Number::Float(OrderedFloat(n2)))
| (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
@@ -167,7 +170,7 @@ pub(crate) fn add(lhs: Number, rhs: Number, arena: &mut Arena) -> Result<Number,
}
(Number::Integer(n1), Number::Rational(n2))
| (Number::Rational(n2), Number::Integer(n1)) => {
Ok(Number::arena_from(Rational::from(&*n1) + &*n2, arena))
Ok(Number::arena_from(&*n1 + &*n2, arena))
}
(Number::Rational(n1), Number::Float(OrderedFloat(n2)))
| (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
@@ -177,7 +180,7 @@ pub(crate) fn add(lhs: Number, rhs: Number, arena: &mut Arena) -> Result<Number,
Ok(Number::Float(add_f(f1, f2)?))
}
(Number::Rational(r1), Number::Rational(r2)) => {
Ok(Number::arena_from(Rational::from(&*r1) + &*r2, arena))
Ok(Number::arena_from(&*r1 + &*r2, arena))
}
}
}
@@ -191,9 +194,15 @@ pub(crate) fn neg(n: Number, arena: &mut Arena) -> Number {
Number::arena_from(-Integer::from(n.get_num()), arena)
}
}
Number::Integer(n) => Number::arena_from(-Integer::from(&*n), arena),
Number::Integer(n) => {
let n_clone: Integer = (*n).clone();
Number::arena_from(-Integer::from(n_clone), arena)
},
Number::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)),
Number::Rational(r) => Number::arena_from(-Rational::from(&*r), arena),
Number::Rational(r) => {
let r_clone: Rational = (*r).clone();
Number::arena_from(-Rational::from(r_clone), arena)
},
}
}
@@ -203,12 +212,19 @@ pub(crate) fn abs(n: Number, arena: &mut Arena) -> Number {
if let Some(n) = n.get_num().checked_abs() {
fixnum!(Number, n, arena)
} else {
Number::arena_from(Integer::from(n.get_num()).abs(), arena)
let arena_int = Integer::from(n.get_num());
Number::arena_from(arena_int.abs(), arena)
}
}
Number::Integer(n) => Number::arena_from(Integer::from(n.abs_ref()), arena),
Number::Integer(n) => {
let n_clone: Integer = (*n).clone();
Number::arena_from(Integer::from(n_clone.abs()), arena)
},
Number::Float(f) => Number::Float(f.abs()),
Number::Rational(r) => Number::arena_from(Rational::from(r.abs_ref()), arena),
Number::Rational(r) => {
let r_clone: Rational = (*r).clone();
Number::arena_from(Rational::from(r_clone.abs()), arena)
},
}
}
@@ -247,7 +263,8 @@ pub(crate) fn mul(lhs: Number, rhs: Number, arena: &mut Arena) -> Result<Number,
Ok(Number::Float(mul_f(float_fn_to_f(n1.get_num())?, n2)?))
}
(Number::Integer(n1), Number::Integer(n2)) => {
Ok(Number::arena_from(Integer::from(&*n1) * &*n2, arena)) // mul_i
let n1_clone: Integer = (*n1).clone();
Ok(Number::arena_from(Integer::from(n1_clone) * &*n2, arena)) // mul_i
}
(Number::Integer(n1), Number::Float(OrderedFloat(n2)))
| (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
@@ -255,7 +272,8 @@ pub(crate) fn mul(lhs: Number, rhs: Number, arena: &mut Arena) -> Result<Number,
}
(Number::Integer(n1), Number::Rational(n2))
| (Number::Rational(n2), Number::Integer(n1)) => {
Ok(Number::arena_from(Rational::from(&*n1) * &*n2, arena))
let n1_clone: Integer = (*n1).clone();
Ok(Number::arena_from(Rational::from(n1_clone) * &*n2, arena))
}
(Number::Rational(n1), Number::Float(OrderedFloat(n2)))
| (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
@@ -265,7 +283,8 @@ pub(crate) fn mul(lhs: Number, rhs: Number, arena: &mut Arena) -> Result<Number,
Ok(Number::Float(mul_f(f1, f2)?))
}
(Number::Rational(r1), Number::Rational(r2)) => {
Ok(Number::arena_from(Rational::from(&*r1) * &*r2, arena))
let r1_clone: Rational = (*r1).clone();
Ok(Number::arena_from(Rational::from(r1_clone) * &*r2, arena))
}
}
}
@@ -338,7 +357,7 @@ pub(crate) fn int_pow(n1: Number, n2: Number, arena: &mut Arena) -> Result<Numbe
(Number::Fixnum(n1), Number::Integer(n2)) => {
let n1_i = n1.get_num();
if !(n1_i == 1 || n1_i == 0 || n1_i == -1) && &*n2 < &0 {
if !(n1_i == 1 || n1_i == 0 || n1_i == -1) && &*n2 < &Integer::from(0) {
let n = Number::Fixnum(n1);
Err(numerical_type_error(ValidType::Float, n, stub_gen))
} else {
@@ -349,7 +368,7 @@ pub(crate) fn int_pow(n1: Number, n2: Number, arena: &mut Arena) -> Result<Numbe
(Number::Integer(n1), Number::Fixnum(n2)) => {
let n2_i = n2.get_num();
if !(&*n1 == &1 || &*n1 == &0 || &*n1 == &-1) && n2_i < 0 {
if !(&*n1 == &Integer::from(1) || &*n1 == &Integer::from(0) || &*n1 == &Integer::from(-1)) && n2_i < 0 {
let n = Number::Integer(n1);
Err(numerical_type_error(ValidType::Float, n, stub_gen))
} else {
@@ -358,7 +377,7 @@ pub(crate) fn int_pow(n1: Number, n2: Number, arena: &mut Arena) -> Result<Numbe
}
}
(Number::Integer(n1), Number::Integer(n2)) => {
if !(&*n1 == &1 || &*n1 == &0 || &*n1 == &-1) && &*n2 < &0 {
if !(&*n1 == &Integer::from(1) || &*n1 == &Integer::from(0) || &*n1 == &Integer::from(-1)) && &*n2 < &Integer::from(0) {
let n = Number::Integer(n1);
Err(numerical_type_error(ValidType::Float, n, stub_gen))
} else {
@@ -521,7 +540,7 @@ pub fn rational_from_number(
match n {
Number::Fixnum(n) => Ok(arena_alloc!(Rational::from(n.get_num()), arena)),
Number::Rational(r) => Ok(r),
Number::Float(OrderedFloat(f)) => match Rational::from_f64(f) {
Number::Float(OrderedFloat(f)) => match Rational::simplest_from_f64(f) {
Some(r) => Ok(arena_alloc!(r, arena)),
None => Err(Box::new(move |machine_st| {
let instantiation_error = machine_st.instantiation_error();
@@ -530,7 +549,10 @@ pub fn rational_from_number(
machine_st.error_form(instantiation_error, stub)
})),
},
Number::Integer(n) => Ok(arena_alloc!(Rational::from(&*n), arena)),
Number::Integer(n) => {
let n_clone: Integer = (*n).clone();
Ok(arena_alloc!(Rational::from(n_clone), arena))
},
}
}
@@ -590,7 +612,7 @@ pub(crate) fn idiv(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number,
Err(zero_divisor_eval_error(stub_gen))
} else {
Ok(Number::arena_from(
<(Integer, Integer)>::from(n1.div_rem_ref(&*n2)).0,
<(Integer, Integer)>::from(n1.div_rem_floor_ref(&*n2)).0,
arena,
))
}
@@ -624,6 +646,10 @@ pub(crate) fn shr(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
functor_stub(shr_atom, 2)
};
if n2.is_integer() && n2.is_negative() {
return shl(n1, neg(n2, arena), arena);
}
match (n1, n2) {
(Number::Fixnum(n1), Number::Fixnum(n2)) => {
let n1_i = n1.get_num();
@@ -631,33 +657,33 @@ pub(crate) fn shr(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
let n1 = Integer::from(n1_i);
if let Ok(n2) = u32::try_from(n2_i) {
if let Ok(n2) = usize::try_from(n2_i) {
return Ok(Number::arena_from(n1 >> n2, arena));
} else {
return Ok(Number::arena_from(n1 >> u32::max_value(), arena));
} else {
return Ok(Number::arena_from(n1 >> usize::max_value(), arena));
}
}
(Number::Fixnum(n1), Number::Integer(n2)) => {
let n1 = Integer::from(n1.get_num());
match n2.to_u32() {
match n2.to_usize() {
Some(n2) => Ok(Number::arena_from(n1 >> n2, arena)),
_ => Ok(Number::arena_from(n1 >> u32::max_value(), arena)),
_ => {
Ok(Number::arena_from(n1 >> usize::max_value(), arena))
},
}
}
(Number::Integer(n1), Number::Fixnum(n2)) => match u32::try_from(n2.get_num()) {
(Number::Integer(n1), Number::Fixnum(n2)) => match usize::try_from(n2.get_num()) {
Ok(n2) => Ok(Number::arena_from(Integer::from(&*n1 >> n2), arena)),
_ => Ok(Number::arena_from(
Integer::from(&*n1 >> u32::max_value()),
arena,
)),
_ => {
Ok(Number::arena_from(Integer::from(&*n1 >> usize::max_value()),arena))
},
},
(Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() {
(Number::Integer(n1), Number::Integer(n2)) => match n2.to_usize() {
Some(n2) => Ok(Number::arena_from(Integer::from(&*n1 >> n2), arena)),
_ => Ok(Number::arena_from(
Integer::from(&*n1 >> u32::max_value()),
arena,
)),
_ => {
Ok(Number::arena_from(Integer::from(&*n1 >> usize::max_value()), arena))
},
},
(Number::Integer(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),
(Number::Fixnum(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),
@@ -667,10 +693,14 @@ pub(crate) fn shr(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
pub(crate) fn shl(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
let stub_gen = || {
let shl_atom = atom!(">>");
let shl_atom = atom!("<<");
functor_stub(shl_atom, 2)
};
if n2.is_integer() && n2.is_negative() {
return shr(n1, neg(n2, arena), arena);
}
match (n1, n2) {
(Number::Fixnum(n1), Number::Fixnum(n2)) => {
let n1_i = n1.get_num();
@@ -678,33 +708,33 @@ pub(crate) fn shl(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
let n1 = Integer::from(n1_i);
if let Ok(n2) = u32::try_from(n2_i) {
if let Ok(n2) = usize::try_from(n2_i) {
return Ok(Number::arena_from(n1 << n2, arena));
} else {
return Ok(Number::arena_from(n1 << u32::max_value(), arena));
} else {
return Ok(Number::arena_from(n1 << usize::max_value(), arena));
}
}
(Number::Fixnum(n1), Number::Integer(n2)) => {
let n1 = Integer::from(n1.get_num());
match n2.to_u32() {
Some(n2) => Ok(Number::arena_from(n1 << n2, arena)),
_ => Ok(Number::arena_from(n1 << u32::max_value(), arena)),
Some(n2) => Ok(Number::arena_from(n1.to_u64().unwrap() << n2, arena)),
_ => {
Ok(Number::arena_from(n1 << usize::max_value(), arena))
}
}
}
(Number::Integer(n1), Number::Fixnum(n2)) => match u32::try_from(n2.get_num()) {
(Number::Integer(n1), Number::Fixnum(n2)) => match usize::try_from(n2.get_num()) {
Ok(n2) => Ok(Number::arena_from(Integer::from(&*n1 << n2), arena)),
_ => Ok(Number::arena_from(
Integer::from(&*n1 << u32::max_value()),
arena,
)),
_ => {
Ok(Number::arena_from(Integer::from(&*n1 << usize::max_value()),arena))
}
},
(Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() {
Some(n2) => Ok(Number::arena_from(Integer::from(&*n1 << n2), arena)),
_ => Ok(Number::arena_from(
Integer::from(&*n1 << u32::max_value()),
arena,
)),
Some(n2) => Ok(Number::arena_from(Integer::from(n1.to_u64().unwrap() << n2), arena)),
_ => {
Ok(Number::arena_from(Integer::from(&*n1 << usize::max_value()),arena))
}
},
(Number::Integer(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),
(Number::Fixnum(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),
@@ -918,18 +948,21 @@ pub(crate) fn gcd(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
if let Some(result) = isize_gcd(n1_i, n2_i) {
Ok(Number::arena_from(result, arena))
} else {
let value: IBig = Integer::from(n1_i).gcd(&Integer::from(n2_i)).into();
Ok(Number::arena_from(
Integer::from(n1_i).gcd(&Integer::from(n2_i)),
value,
arena,
))
}
}
(Number::Fixnum(n1), Number::Integer(n2)) | (Number::Integer(n2), Number::Fixnum(n1)) => {
let n1 = Integer::from(n1.get_num());
Ok(Number::arena_from(Integer::from(n2.gcd_ref(&n1)), arena))
let n2_clone: Integer = (*n2).clone();
Ok(Number::arena_from(Integer::from(n2_clone.gcd(&n1)), arena))
}
(Number::Integer(n1), Number::Integer(n2)) => {
Ok(Number::arena_from(Integer::from(n1.gcd_ref(&n2)), arena))
let n1_clone: Integer = (*n1).clone();
Ok(Number::arena_from(Integer::from(n1_clone.gcd(&Integer::from(n2.to_isize().unwrap()))) as IBig, arena))
}
(Number::Float(f), _) | (_, Number::Float(f)) => {
let n = Number::Float(f);
@@ -998,6 +1031,63 @@ pub(crate) fn atan(n1: Number) -> Result<f64, MachineStubGen> {
unary_float_fn_template(n1, |f| f.atan())
}
#[inline]
pub(crate) fn asinh(n1: Number) -> Result<f64, MachineStubGen> {
unary_float_fn_template(n1, |f| f.asinh())
}
#[inline]
pub(crate) fn acosh(n1: Number) -> Result<f64, MachineStubGen> {
unary_float_fn_template(n1, |f| f.acosh())
}
#[inline]
pub(crate) fn atanh(n1: Number) -> Result<f64, MachineStubGen> {
let stub_gen = || {
let is_atom = atom!("is");
functor_stub(is_atom, 2)
};
let f1 = try_numeric_result!(result_f(&n1), stub_gen)?;
try_numeric_result!(if f1 == 1.0 || f1 == -1.0 {
Err(EvalError::Undefined)
} else {
result_f(&Number::Float(OrderedFloat(f1.atanh())))
},
stub_gen)
}
#[inline]
pub(crate) fn sinh(n1: Number) -> Result<f64, MachineStubGen> {
unary_float_fn_template(n1, |f| f.sinh())
}
#[inline]
pub(crate) fn cosh(n1: Number) -> Result<f64, MachineStubGen> {
unary_float_fn_template(n1, |f| f.cosh())
}
#[inline]
pub(crate) fn tanh(n1: Number) -> Result<f64, MachineStubGen> {
unary_float_fn_template(n1, |f| f.tanh())
}
#[inline]
pub(crate) fn log10(n1: Number) -> Result<f64, MachineStubGen> {
unary_float_fn_template(n1, |f| f.log(10f64))
}
#[inline]
pub(crate) fn float_fractional_part(n1: Number) -> Result<f64, MachineStubGen> {
unary_float_fn_template(n1, |f| f.fract())
}
#[inline]
pub(crate) fn float_integer_part(n1: Number) -> Result<f64, MachineStubGen> {
unary_float_fn_template(n1, |f| f.trunc())
}
#[inline]
pub(crate) fn sqrt(n1: Number) -> Result<f64, MachineStubGen> {
if n1.is_negative() {
@@ -1017,6 +1107,7 @@ pub(crate) fn floor(n1: Number, arena: &mut Arena) -> Number {
rnd_i(&n1, arena)
}
#[inline]
pub(crate) fn ceiling(n1: Number, arena: &mut Arena) -> Number {
let n1 = neg(n1, arena);
@@ -1098,7 +1189,7 @@ impl MachineState {
pub(crate) fn arith_eval_by_metacall(&mut self, value: HeapCellValue) -> Result<Number, MachineStub> {
let stub_gen = || functor_stub(atom!("is"), 2);
let mut iter = stackful_post_order_iter(&mut self.heap, value);
let mut iter = stackful_post_order_iter(&mut self.heap, &mut self.stack, value);
while let Some(value) = iter.next() {
if value.get_forwarding_bit() {
@@ -1115,7 +1206,7 @@ impl MachineState {
HeapCellValueTag::PStrLoc) => {
(atom!("."), 2)
}
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var) => {
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
let err = self.instantiation_error();
return Err(self.error_form(err, stub_gen()));
}
@@ -1247,6 +1338,33 @@ impl MachineState {
atom!("tan") => self.interms.push(Number::Float(OrderedFloat(
drop_iter_on_err!(self, iter, tan(a1))
))),
atom!("cosh") => self.interms.push(Number::Float(OrderedFloat(
drop_iter_on_err!(self, iter, cosh(a1))
))),
atom!("sinh") => self.interms.push(Number::Float(OrderedFloat(
drop_iter_on_err!(self, iter, sinh(a1))
))),
atom!("tanh") => self.interms.push(Number::Float(OrderedFloat(
drop_iter_on_err!(self, iter, tanh(a1))
))),
atom!("acosh") => self.interms.push(Number::Float(OrderedFloat(
drop_iter_on_err!(self, iter, acosh(a1))
))),
atom!("asinh") => self.interms.push(Number::Float(OrderedFloat(
drop_iter_on_err!(self, iter, asinh(a1))
))),
atom!("atanh") => self.interms.push(Number::Float(OrderedFloat(
drop_iter_on_err!(self, iter, atanh(a1))
))),
atom!("log10") => self.interms.push(Number::Float(OrderedFloat(
drop_iter_on_err!(self, iter, log10(a1))
))),
atom!("float_fractional_part") => self.interms.push(Number::Float(OrderedFloat(
drop_iter_on_err!(self, iter, float_fractional_part(a1))
))),
atom!("float_integer_part") => self.interms.push(Number::Float(OrderedFloat(
drop_iter_on_err!(self, iter, float_integer_part(a1))
))),
atom!("sqrt") => self.interms.push(Number::Float(OrderedFloat(
drop_iter_on_err!(self, iter, sqrt(a1))
))),

View File

@@ -1,11 +1,9 @@
:- module('$atts', []).
driver(Vars, Values) :-
iterate(Vars, Values, ListOfListsOfGoalLists),
!,
call_goals(ListOfListsOfGoalLists),
'$reset_attr_var_state',
'$return_from_verify_attr'.
iterate([Var|VarBindings], [Value|ValueBindings], [ListOfGoalLists | ListsCubed]) :-

View File

@@ -33,8 +33,8 @@ impl AttrVarInitializer {
}
#[inline]
pub(super) fn reset(&mut self) {
self.attr_var_queue.clear();
pub(super) fn reset(&mut self, len: usize) {
self.attr_var_queue.truncate(len);
self.bindings.clear();
}
}
@@ -52,6 +52,7 @@ impl MachineState {
self.cp = INSTALL_VERIFY_ATTR_INTERRUPT;
}
debug_assert_eq!(self.heap[h].get_tag(), HeapCellValueTag::AttrVar);
self.attr_var_init.bindings.push((h, addr));
}
@@ -63,10 +64,9 @@ impl MachineState {
.map(|(ref h, _)| attr_var_as_cell!(*h));
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(|(_, ref v)| *v);
let value_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter));
(var_list_addr, value_list_addr)
}
@@ -136,7 +136,7 @@ impl MachineState {
let mut seen_set = IndexSet::new();
let mut seen_vars = vec![];
let mut iter = stackful_preorder_iter(&mut self.heap, cell);
let mut iter = stackful_preorder_iter(&mut self.heap, &mut self.stack, cell);
while let Some(value) = iter.next() {
read_heap_cell!(value,
@@ -147,6 +147,16 @@ impl MachineState {
let value = unmark_cell_bits!(value);
if h != iter.focus().value() as usize {
let deref_value = heap_bound_store(iter.heap, heap_bound_deref(iter.heap, value));
if deref_value.is_compound(iter.heap) {
// a cyclic structure is bound to the attributed variable at h.
// it mustn't be included in seen_vars.
continue;
}
}
seen_vars.push(value);
seen_set.insert(h);
@@ -157,7 +167,7 @@ impl MachineState {
loop {
read_heap_cell!(iter.heap[l],
(HeapCellValueTag::Lis) => {
iter.push_stack(l);
iter.push_stack(IterStackLoc::iterable_loc(l, HeapOrStackTag::Heap));
// l = elem + 1;
break;
}

View File

@@ -1,5 +1,6 @@
use crate::instructions::*;
use fxhash::FxBuildHasher;
use indexmap::IndexSet;
fn capture_offset(line: &Instruction, index: usize, stack: &mut Vec<usize>) -> bool {
@@ -7,38 +8,24 @@ fn capture_offset(line: &Instruction, index: usize, stack: &mut Vec<usize>) -> b
&Instruction::TryMeElse(offset) if offset > 0 => {
stack.push(index + offset);
}
&Instruction::DefaultRetryMeElse(offset) |
&Instruction::RetryMeElse(offset)
if offset > 0 =>
{
&Instruction::DefaultRetryMeElse(offset) | &Instruction::RetryMeElse(offset) if offset > 0 => {
stack.push(index + offset);
}
&Instruction::DynamicElse(_, _, NextOrFail::Next(offset))
if offset > 0 =>
{
&Instruction::DynamicElse(_, _, NextOrFail::Next(offset)) if offset > 0 => {
stack.push(index + offset);
}
&Instruction::DynamicInternalElse(_, _, NextOrFail::Next(offset))
if offset > 0 =>
{
&Instruction::DynamicInternalElse(_, _, NextOrFail::Next(offset)) if offset > 0 => {
stack.push(index + offset);
}
&Instruction::JmpByCall(_, offset, _) => {
stack.push(index + offset);
}
&Instruction::JmpByExecute(_, offset, _) => {
stack.push(index + offset);
return true;
}
&Instruction::Proceed => {
&Instruction::Proceed | &Instruction::JmpByCall(_) => {
return true;
}
&Instruction::RevJmpBy(offset) => {
if offset > 0 {
stack.push(index - offset);
} else {
return true;
}
return true;
}
instr if instr.is_execute() => {
return true;
@@ -55,7 +42,7 @@ fn capture_offset(line: &Instruction, index: usize, stack: &mut Vec<usize>) -> b
*/
pub(crate) fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Instruction)) {
let mut stack = vec![p];
let mut visited_indices = IndexSet::new();
let mut visited_indices = IndexSet::with_hasher(FxBuildHasher::default());
while let Some(first_index) = stack.pop() {
if visited_indices.contains(&first_index) {
@@ -73,23 +60,3 @@ pub(crate) fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Instructi
}
}
}
/* A function for code walking that might result in modification to
* the code. Otherwise identical to walk_code.
*/
/*
pub(crate) fn walk_code_mut(code: &mut Code, p: usize, mut walker: impl FnMut(&mut Line))
{
let mut queue = VecDeque::from(vec![p]);
while let Some(first_idx) = queue.pop_front() {
let mut last_idx = first_idx;
capture_next_range(code, &mut queue, &mut last_idx);
for instr in &mut code[first_idx .. last_idx + 1] {
walker(instr);
}
}
}
*/

View File

@@ -44,60 +44,6 @@ pub(super) fn bootstrapping_compile(
Ok(())
}
// throw errors if declaration or query found.
pub(super) fn compile_relation(
cg: &mut CodeGenerator,
tl: &TopLevel,
) -> Result<Code, CompilationError> {
match tl {
&TopLevel::Query(_) => Err(CompilationError::ExpectedRel),
&TopLevel::Predicate(ref clauses) => cg.compile_predicate(&clauses),
&TopLevel::Fact(ref fact, ..) => cg.compile_fact(fact),
&TopLevel::Rule(ref rule, ..) => cg.compile_rule(rule),
}
}
pub(super) fn compile_appendix(
code: &mut Code,
mut queue: VecDeque<TopLevel>,
jmp_by_locs: Vec<usize>,
non_counted_bt: bool,
atom_tbl: &mut AtomTable,
) -> Result<(), CompilationError> {
let mut jmp_by_locs = VecDeque::from(jmp_by_locs);
while let Some(jmp_by_offset) = jmp_by_locs.pop_front() {
let code_len = code.len();
match &mut code[jmp_by_offset] {
&mut Instruction::JmpByCall(_, ref mut offset, ..) |
&mut Instruction::JmpByExecute(_, ref mut offset, ..) => {
*offset = code_len - jmp_by_offset;
}
_ => {
unreachable!()
}
}
// false because the inner predicate is a one-off, hence not extensible.
let settings = CodeGenSettings {
global_clock_tick: None,
is_extensible: false,
non_counted_bt,
};
let mut cg = CodeGenerator::new(atom_tbl, settings);
let tl = queue.pop_front().unwrap();
let decl_code = compile_relation(&mut cg, &tl)?;
jmp_by_locs.extend(cg.jmp_by_locs.into_iter().map(|offset| offset + code.len()));
code.extend(decl_code.into_iter());
}
Ok(())
}
fn lower_bound_of_target_clause(skeleton: &PredicateSkeleton, target_pos: usize) -> usize {
if target_pos == 0 {
return 0;
@@ -1342,22 +1288,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let mut preprocessor = Preprocessor::new(settings);
let clause = self.try_term_to_tl(term, &mut preprocessor)?;
let queue = preprocessor.parse_queue(self)?;
// let queue = preprocessor.parse_queue(self)?;
let mut cg = CodeGenerator::new(
&mut LS::machine_st(&mut self.payload).atom_tbl,
settings,
);
let mut clause_code = cg.compile_predicate(&vec![clause])?;
compile_appendix(
&mut clause_code,
queue,
cg.jmp_by_locs,
settings.non_counted_bt,
cg.atom_tbl,
)?;
let clause_code = cg.compile_predicate(vec![clause])?;
Ok(StandaloneCompileResult {
clause_code,
@@ -1385,22 +1323,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
clauses.push(self.try_term_to_tl(term, &mut preprocessor)?);
}
let queue = preprocessor.parse_queue(self)?;
let mut cg = CodeGenerator::new(
&mut LS::machine_st(&mut self.payload).atom_tbl,
settings,
);
let mut code = cg.compile_predicate(&clauses)?;
compile_appendix(
&mut code,
queue,
cg.jmp_by_locs,
settings.non_counted_bt,
cg.atom_tbl,
)?;
let mut code = cg.compile_predicate(clauses)?;
if settings.is_extensible {
let mut clause_clause_locs = VecDeque::new();
@@ -1869,7 +1797,13 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
skeleton.clauses[target_pos + 1].clause_start =
skeleton.clauses[target_pos].clause_start;
let index_ptr_opt = if target_pos == 0 {
let update_code_index = target_pos == 0 &&
skeleton.clauses[target_pos + 1]
.opt_arg_index_key
.switch_on_term_loc()
.is_none();
let index_ptr_opt = if update_code_index {
Some(IndexPtr::index(clause_loc))
} else {
None
@@ -2274,14 +2208,17 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
.ok_or(SessionError::NamelessEntry)?;
let listing_src_file_name = self.listing_src_file_name();
let payload_compilation_target = self.payload.compilation_target;
let mut predicate_info = self
.wam_prelude
.indices
.get_predicate_skeleton(&self.payload.predicates.compilation_target, &key)
.map(|skeleton| skeleton.predicate_info())
.unwrap_or_default();
// payload_compilation_target describes the compilation context,
// e.g. compiling
//
// table_wrapper:tabled(get_node(A), b).
//
// without a module declaration means self.payload.compilation_target
// is CompilationTarget::User while self.payload.predicates.compilation_target
// is CompilationTarget::Module(atom!("table_wrapper")).
let payload_compilation_target = self.payload.compilation_target;
let local_predicate_info = self
.wam_prelude
@@ -2295,34 +2232,37 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
.map(|skeleton| skeleton.predicate_info())
.unwrap_or_default();
if local_predicate_info.must_retract_local_clauses() {
let mut predicate_info = self
.wam_prelude
.indices
.get_predicate_skeleton(&self.payload.predicates.compilation_target, &key)
.map(|skeleton| skeleton.predicate_info())
.unwrap_or_default();
let is_cross_module_clause =
payload_compilation_target != self.payload.predicates.compilation_target;
if local_predicate_info.must_retract_local_clauses(is_cross_module_clause) {
self.retract_local_clauses(&key, predicate_info.is_dynamic);
}
let do_incremental_compile =
if payload_compilation_target == self.payload.predicates.compilation_target {
predicate_info.compile_incrementally()
} else {
local_predicate_info.is_multifile && predicate_info.compile_incrementally()
};
let predicates_len = self.payload.predicates.len();
let non_counted_bt = self.payload.non_counted_bt_preds.contains(&key);
if do_incremental_compile {
if predicate_info.compile_incrementally() {
let predicates = self.payload.predicates.take();
for term in predicates.predicates {
self.incremental_compile_clause(
key,
term,
payload_compilation_target,
self.payload.predicates.compilation_target,
non_counted_bt,
AppendOrPrepend::Append,
)?;
}
} else {
if payload_compilation_target != self.payload.predicates.compilation_target {
if is_cross_module_clause {
if !local_predicate_info.is_extensible {
if predicate_info.is_multifile {
println!(
@@ -2337,9 +2277,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
.indices
.remove_predicate_skeleton(&self.payload.predicates.compilation_target, &key)
{
let compilation_target = self.payload.predicates.compilation_target;
if predicate_info.is_dynamic {
let clause_clause_compilation_target =
match self.payload.predicates.compilation_target {
match compilation_target {
CompilationTarget::User => {
CompilationTarget::Module(atom!("builtins"))
}
@@ -2358,7 +2300,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
self.payload.retraction_info.push_record(
RetractionRecord::RemovedSkeleton(
payload_compilation_target,
compilation_target,
key,
skeleton,
),
@@ -2409,9 +2351,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
.clause_clauses.drain(0..std::cmp::min(predicates_len, clause_clauses_len))
.collect();
let compilation_target = self.payload.predicates.compilation_target;
self.compile_clause_clauses(
key,
payload_compilation_target,
compilation_target,
clauses_vec.into_iter(),
AppendOrPrepend::Append,
)?;

View File

@@ -28,7 +28,10 @@ pub(crate) fn copy_term<T: CopierTarget>(
attr_var_policy: AttrVarPolicy,
) {
let mut copy_term_state = CopyTermState::new(target, attr_var_policy);
copy_term_state.copy_term_impl(addr);
copy_term_state.copy_attr_var_lists();
copy_term_state.unwind_trail();
}
#[derive(Debug)]
@@ -38,6 +41,7 @@ struct CopyTermState<T: CopierTarget> {
old_h: usize,
target: T,
attr_var_policy: AttrVarPolicy,
attr_var_list_locs: Vec<(usize, HeapCellValue)>,
}
impl<T: CopierTarget> CopyTermState<T> {
@@ -48,6 +52,7 @@ impl<T: CopierTarget> CopyTermState<T> {
old_h: target.threshold(),
target,
attr_var_policy,
attr_var_list_locs: vec![],
}
}
@@ -86,16 +91,12 @@ impl<T: CopierTarget> CopyTermState<T> {
self.target.push(hcv);
}
let cdr = self
.target
.store(self.target.deref(heap_loc_as_cell!(addr + 1)));
let cdr = self.target.store(self.target.deref(heap_loc_as_cell!(addr + 1)));
if !cdr.is_var() {
self.trail_list_cell(addr + 1, threshold);
} else {
let car = self
.target
.store(self.target.deref(heap_loc_as_cell!(addr)));
let car = self.target.store(self.target.deref(heap_loc_as_cell!(addr)));
if !car.is_var() {
self.trail_list_cell(addr, threshold);
@@ -167,6 +168,51 @@ impl<T: CopierTarget> CopyTermState<T> {
self.trail.push((Ref::heap_cell(pstr_loc), trail_item));
}
fn copy_attr_var_lists(&mut self) {
while !self.attr_var_list_locs.is_empty() {
let iter = mem::replace(&mut self.attr_var_list_locs, vec![]);
for (threshold, list_loc) in iter {
self.target[threshold] = list_loc_as_cell!(self.target.threshold());
self.copy_attr_var_list(list_loc);
}
}
}
/*
* Attributed variable attribute lists adhere to a particular
* structure which is ensured by this function and not at all by
* the vanilla copier.
*/
fn copy_attr_var_list(&mut self, mut list_addr: HeapCellValue) {
while let HeapCellValueTag::Lis = list_addr.get_tag() {
let threshold = self.target.threshold();
let heap_loc = list_addr.get_value();
let str_loc = self.target[heap_loc].get_value();
self.target.push(heap_loc_as_cell!(threshold+2));
self.target.push(heap_loc_as_cell!(threshold+1));
read_heap_cell!(self.target[str_loc],
(HeapCellValueTag::Atom) => {
self.target.push(self.target[str_loc]);
}
(HeapCellValueTag::Str) => {
self.copy_term_impl(self.target[str_loc]);
}
_ => {
unreachable!();
}
);
list_addr = self.target[heap_loc + 1];
if HeapCellValueTag::Lis == list_addr.get_tag() {
self.target[threshold + 1] = list_loc_as_cell!(self.target.threshold());
}
}
}
fn reinstantiate_var(&mut self, addr: HeapCellValue, frontier: usize) {
read_heap_cell!(addr,
(HeapCellValueTag::Var, h) => {
@@ -195,9 +241,15 @@ impl<T: CopierTarget> CopyTermState<T> {
if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
self.target.push(attr_var_as_cell!(threshold));
self.target.push(heap_loc_as_cell!(threshold + 1));
let list_val = self.target[h + 1];
self.target.push(list_val);
let old_list_link = self.target[h + 1];
self.trail.push((Ref::heap_cell(h + 1), old_list_link));
self.target[h + 1] = heap_loc_as_cell!(threshold + 1);
if old_list_link.get_tag() == HeapCellValueTag::Lis {
self.attr_var_list_locs.push((threshold + 1, old_list_link));
}
}
}
_ => {
@@ -298,8 +350,6 @@ impl<T: CopierTarget> CopyTermState<T> {
}
);
}
self.unwind_trail();
}
fn unwind_trail(&mut self) {

837
src/machine/disjuncts.rs Normal file
View File

@@ -0,0 +1,837 @@
use crate::atom_table::*;
use crate::forms::*;
use crate::instructions::*;
use crate::iterators::*;
use crate::machine::loader::*;
use crate::machine::machine_errors::CompilationError;
use crate::machine::preprocessor::*;
use crate::parser::ast::*;
use crate::parser::dashu::Rational;
use crate::variable_records::*;
use dashu::Integer;
use indexmap::{IndexMap, IndexSet};
use std::cell::Cell;
use std::cmp::Ordering;
use std::collections::VecDeque;
use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut};
#[derive(Debug, Clone)] //, PartialOrd, PartialEq, Eq, Hash)]
pub struct BranchNumber {
branch_num: Rational,
delta: Rational,
}
impl Default for BranchNumber {
fn default() -> Self {
Self {
branch_num: Rational::from(1usize << 63),
delta: Rational::from(1),
}
}
}
impl PartialEq<BranchNumber> for BranchNumber {
#[inline]
fn eq(&self, rhs: &BranchNumber) -> bool {
self.branch_num == rhs.branch_num
}
}
impl Eq for BranchNumber {}
impl Hash for BranchNumber {
#[inline(always)]
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.branch_num.hash(hasher)
}
}
impl PartialOrd<BranchNumber> for BranchNumber {
#[inline]
fn partial_cmp(&self, rhs: &BranchNumber) -> Option<Ordering> {
self.branch_num.partial_cmp(&rhs.branch_num)
}
}
impl BranchNumber {
fn split(&self) -> BranchNumber {
BranchNumber {
branch_num: self.branch_num.clone() + &self.delta / Rational::from(2),
delta: &self.delta / Rational::from(4),
}
}
fn incr_by_delta(&self) -> BranchNumber {
BranchNumber {
branch_num: self.branch_num.clone() + &self.delta,
delta: self.delta.clone(),
}
}
fn halve_delta(&self) -> BranchNumber {
BranchNumber {
branch_num: self.branch_num.clone(),
delta : &self.delta / Rational::from(2),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct VarInfo {
var_ptr: VarPtr,
chunk_type: ChunkType,
classify_info: ClassifyInfo,
lvl: Level,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ChunkInfo {
chunk_num: usize,
term_loc: GenContext,
// pointer to incidence, term occurrence arity.
vars: Vec<VarInfo>,
}
#[derive(Debug)]
pub struct BranchArm {
pub arm_terms: Vec<QueryTerm>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct BranchInfo {
branch_num: BranchNumber,
chunks: Vec<ChunkInfo>,
}
impl BranchInfo {
fn new(branch_num: BranchNumber) -> Self {
Self { branch_num, chunks: vec![] }
}
}
type BranchMapInt = IndexMap<VarPtr, Vec<BranchInfo>>;
#[derive(Debug, Clone)]
pub struct BranchMap(BranchMapInt);
impl Deref for BranchMap {
type Target = BranchMapInt;
#[inline(always)]
fn deref(&self) -> &BranchMapInt {
&self.0
}
}
impl DerefMut for BranchMap {
#[inline(always)]
fn deref_mut(&mut self) -> &mut BranchMapInt {
&mut self.0
}
}
type RootSet = IndexSet<BranchNumber>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ClassifyInfo {
arg_c: usize,
arity: usize,
}
enum TraversalState {
// construct a QueryTerm::Branch with number of disjuncts, reset
// the chunk type to that of the chunk preceding the disjunct and the chunk_num.
BuildDisjunct(usize),
// add the last disjunct to a QueryTerm::Branch, continuing from
// where it leaves off.
BuildFinalDisjunct(usize),
Fail,
GetCutPoint{ var_num: usize, prev_b: bool },
Cut { var_num: usize, is_global: bool },
ResetCallPolicy(CallPolicy),
Term(Term),
RemoveBranchNum, // pop the current_branch_num and from the root set.
AddBranchNum(BranchNumber), // set current_branch_num, add it to the root set
RepBranchNum(BranchNumber), // replace current_branch_num and the latest in the root set
}
#[derive(Debug)]
pub struct VariableClassifier {
call_policy: CallPolicy,
current_branch_num: BranchNumber,
current_chunk_num: usize,
current_chunk_type: ChunkType,
branch_map: BranchMap,
var_num: usize,
root_set: RootSet,
global_cut_var_num: Option<usize>,
}
#[derive(Debug, Default)]
pub struct VarData {
pub records: VariableRecords,
pub global_cut_var_num: Option<usize>,
pub allocates: bool,
}
impl VarData {
fn emit_initial_get_level(&mut self, build_stack: &mut ChunkedTermVec) {
let global_cut_var_num =
if let &Some(global_cut_var_num) = &self.global_cut_var_num {
match &self.records[global_cut_var_num].allocation {
VarAlloc::Perm(..) => Some(global_cut_var_num),
VarAlloc::Temp { term_loc, .. } if term_loc.chunk_num() > 0 => {
Some(global_cut_var_num)
}
_ => None
}
} else {
None
};
if let Some(global_cut_var_num) = global_cut_var_num {
let term = QueryTerm::GetLevel(global_cut_var_num);
self.records[global_cut_var_num].allocation = VarAlloc::Perm(0, PermVarAllocation::Pending);
match build_stack.front_mut() {
Some(ChunkedTerms::Branch(_)) => {
build_stack.push_front(ChunkedTerms::Chunk(VecDeque::from(vec![term])));
}
Some(ChunkedTerms::Chunk(chunk)) => {
chunk.push_front(term);
}
None => {
unreachable!()
}
}
}
}
}
pub type ClassifyFactResult = (Term, VarData);
pub type ClassifyRuleResult = (Term, ChunkedTermVec, VarData);
fn merge_branch_seq(branches: impl Iterator<Item = BranchInfo>) -> BranchInfo {
let mut branch_info = BranchInfo::new(BranchNumber::default());
for mut branch in branches {
branch_info.branch_num = branch.branch_num;
branch_info.chunks.extend(branch.chunks.drain(..));
}
branch_info.branch_num.delta = branch_info.branch_num.delta * Integer::from(2);
branch_info.branch_num.branch_num -= &branch_info.branch_num.delta;
branch_info
}
fn flatten_into_disjunct(build_stack: &mut ChunkedTermVec, preceding_len: usize) {
let branch_vec = build_stack.drain(preceding_len + 1 ..).collect();
if let ChunkedTerms::Branch(ref mut disjuncts) = &mut build_stack[preceding_len] {
disjuncts.push(branch_vec);
} else {
unreachable!();
}
}
impl VariableClassifier {
pub fn new(call_policy: CallPolicy) -> Self {
Self {
call_policy,
current_branch_num: BranchNumber::default(),
current_chunk_num: 0,
current_chunk_type: ChunkType::Head,
branch_map: BranchMap(BranchMapInt::new()),
root_set: RootSet::new(),
var_num: 0,
global_cut_var_num: None,
}
}
pub fn classify_fact(mut self, term: Term) -> Result<ClassifyFactResult, CompilationError> {
self.classify_head_variables(&term)?;
Ok((term, self.branch_map.separate_and_classify_variables(
self.var_num,
self.global_cut_var_num,
self.current_chunk_num,
)))
}
pub fn classify_rule<'a, LS: LoadState<'a>>(
mut self,
loader: &mut Loader<'a, LS>,
head: Term,
body: Term,
) -> Result<ClassifyRuleResult, CompilationError> {
self.classify_head_variables(&head)?;
self.root_set.insert(self.current_branch_num.clone());
let mut query_terms = self.classify_body_variables(loader, body)?;
self.merge_branches();
let mut var_data = self.branch_map.separate_and_classify_variables(
self.var_num,
self.global_cut_var_num,
self.current_chunk_num,
);
var_data.emit_initial_get_level(&mut query_terms);
Ok((head, query_terms, var_data))
}
fn merge_branches(&mut self) {
for branches in self.branch_map.values_mut() {
let mut old_branches = std::mem::replace(branches, vec![]);
while let Some(last_branch_num) = old_branches.last().map(|bi| &bi.branch_num) {
let mut old_branches_len = old_branches.len();
for (rev_idx, bi) in old_branches.iter().rev().enumerate() {
if &bi.branch_num > last_branch_num {
old_branches_len = old_branches.len() - rev_idx;
}
}
let iter = old_branches.drain(old_branches_len - 1 ..);
branches.push(merge_branch_seq(iter));
}
branches.reverse();
}
}
fn try_set_chunk_at_inlined_boundary(&mut self) -> bool {
if self.current_chunk_type.is_last() {
self.current_chunk_type = ChunkType::Mid;
self.current_chunk_num += 1;
true
} else {
false
}
}
fn try_set_chunk_at_call_boundary(&mut self) -> bool {
if self.current_chunk_type.is_last() {
self.current_chunk_num += 1;
true
} else {
self.current_chunk_type = ChunkType::Last;
false
}
}
fn probe_body_term(&mut self, arg_c: usize, arity: usize, term: &Term) {
let classify_info = ClassifyInfo { arg_c, arity };
// second arg is true to iterate the root, which may be a variable
for term_ref in breadth_first_iter(term, RootIterationPolicy::Iterated) {
if let TermRef::Var(lvl, _, var_ptr) = term_ref {
// root terms are shallow here (since we're iterating a
// body term) so take the child level.
let lvl = lvl.child_level();
self.probe_body_var(VarInfo {
var_ptr,
lvl,
classify_info,
chunk_type: self.current_chunk_type,
});
}
}
}
fn probe_body_var(&mut self, var_info: VarInfo) {
let term_loc = self.current_chunk_type.to_gen_context(self.current_chunk_num);
let branch_info_v = self.branch_map.entry(var_info.var_ptr.clone())
.or_insert_with(|| vec![]);
let needs_new_branch = if let Some(last_bi) = branch_info_v.last() {
!self.root_set.contains(&last_bi.branch_num)
} else {
true
};
if needs_new_branch {
branch_info_v.push(BranchInfo::new(self.current_branch_num.clone()));
}
let branch_info = branch_info_v.last_mut().unwrap();
let needs_new_chunk = if let Some(last_ci) = branch_info.chunks.last() {
last_ci.chunk_num != self.current_chunk_num
} else {
true
};
if needs_new_chunk {
branch_info.chunks.push(ChunkInfo {
chunk_num: self.current_chunk_num,
term_loc,
vars: vec![],
});
}
let chunk_info = branch_info.chunks.last_mut().unwrap();
chunk_info.vars.push(var_info);
}
fn probe_in_situ_var(&mut self, var_num: usize) {
let classify_info = ClassifyInfo { arg_c: 1, arity: 1 };
let var_info = VarInfo {
var_ptr: VarPtr::from(Var::InSitu(var_num)),
classify_info,
chunk_type: self.current_chunk_type,
lvl: Level::Shallow,
};
self.probe_body_var(var_info);
}
fn classify_head_variables(&mut self, term: &Term) -> Result<(), CompilationError> {
match term {
Term::Clause(..) | Term::Literal(_, Literal::Atom(_)) => {
}
_ => return Err(CompilationError::InvalidRuleHead),
}
let mut classify_info = ClassifyInfo { arg_c: 1, arity: term.arity() };
match term {
Term::Clause(_, _, terms) => {
for term in terms.into_iter() {
for term_ref in breadth_first_iter(term, RootIterationPolicy::Iterated) {
if let TermRef::Var(lvl, _, var_ptr) = term_ref {
// a body term, so we need the child level here.
let lvl = lvl.child_level();
// the body of the if let here is an inlined
// "probe_head_var". note the difference between it
// and "probe_body_var".
let branch_info_v = self.branch_map.entry(var_ptr.clone())
.or_insert_with(|| vec![]);
let needs_new_branch = branch_info_v.is_empty();
if needs_new_branch {
branch_info_v.push(BranchInfo::new(self.current_branch_num.clone()));
}
let branch_info = branch_info_v.last_mut().unwrap();
let needs_new_chunk = branch_info.chunks.is_empty();
if needs_new_chunk {
branch_info.chunks.push(ChunkInfo {
chunk_num: self.current_chunk_num,
term_loc: GenContext::Head,
vars: vec![],
});
}
let chunk_info = branch_info.chunks.last_mut().unwrap();
let var_info = VarInfo {
var_ptr,
classify_info,
chunk_type: self.current_chunk_type,
lvl,
};
chunk_info.vars.push(var_info);
}
}
classify_info.arg_c += 1;
}
}
_ => {}
}
Ok(())
}
fn classify_body_variables<'a, LS: LoadState<'a>>(
&mut self,
loader: &mut Loader<'a, LS>,
term: Term,
) -> Result<ChunkedTermVec, CompilationError> {
let mut state_stack = vec![TraversalState::Term(term)];
let mut build_stack = ChunkedTermVec::new();
self.current_chunk_type = ChunkType::Mid;
while let Some(traversal_st) = state_stack.pop() {
match traversal_st {
TraversalState::AddBranchNum(branch_num) => {
self.root_set.insert(branch_num.clone());
self.current_branch_num = branch_num;
}
TraversalState::RemoveBranchNum => {
self.root_set.pop();
}
TraversalState::RepBranchNum(branch_num) => {
self.root_set.pop();
self.root_set.insert(branch_num.clone());
self.current_branch_num = branch_num;
}
TraversalState::ResetCallPolicy(call_policy) => {
self.call_policy = call_policy;
}
TraversalState::BuildDisjunct(preceding_len) => {
flatten_into_disjunct(&mut build_stack, preceding_len);
self.current_chunk_type = ChunkType::Mid;
self.current_chunk_num += 1;
}
TraversalState::BuildFinalDisjunct(preceding_len) => {
flatten_into_disjunct(&mut build_stack, preceding_len);
self.current_chunk_type = ChunkType::Mid;
self.current_chunk_num += 1;
}
TraversalState::GetCutPoint { var_num, prev_b } => {
if self.try_set_chunk_at_inlined_boundary() {
build_stack.add_chunk();
}
self.probe_in_situ_var(var_num);
build_stack.push_chunk_term(QueryTerm::GetCutPoint { var_num, prev_b });
}
TraversalState::Cut { var_num, is_global } => {
if self.try_set_chunk_at_inlined_boundary() {
build_stack.add_chunk();
}
self.probe_in_situ_var(var_num);
build_stack.push_chunk_term(
if is_global {
QueryTerm::GlobalCut(var_num)
} else {
QueryTerm::LocalCut(var_num)
}
);
}
TraversalState::Fail => {
build_stack.push_chunk_term(QueryTerm::Fail);
}
TraversalState::Term(term) => {
// return true iff new chunk should be added.
let update_chunk_data = |classifier: &mut Self, predicate_name, arity| {
if ClauseType::is_inlined(predicate_name, arity) {
classifier.try_set_chunk_at_inlined_boundary()
} else {
classifier.try_set_chunk_at_call_boundary()
}
};
match term {
Term::Clause(_, atom!(","), mut terms) if terms.len() == 2 => {
let tail = terms.pop().unwrap();
let head = terms.pop().unwrap();
let iter = unfold_by_str(tail, atom!(","))
.into_iter()
.rev()
.chain(std::iter::once(head))
.map(TraversalState::Term);
state_stack.extend(iter);
}
Term::Clause(_, atom!(";"), mut terms) if terms.len() == 2 => {
let tail = terms.pop().unwrap();
let head = terms.pop().unwrap();
let first_branch_num = self.current_branch_num.split();
let branches: Vec<_> = std::iter::once(head)
.chain(unfold_by_str(tail, atom!(";")).into_iter())
.collect();
let mut branch_numbers = vec![first_branch_num];
for idx in 1 .. branches.len() {
let succ_branch_number = branch_numbers[idx - 1].incr_by_delta();
branch_numbers.push(if idx + 1 < branches.len() {
succ_branch_number.split()
} else {
succ_branch_number
});
}
let build_stack_len = build_stack.len();
build_stack.reserve_branch(branches.len());
state_stack.push(TraversalState::RepBranchNum(
self.current_branch_num.halve_delta(),
));
let iter = branches.into_iter().zip(branch_numbers.into_iter());
let final_disjunct_loc = state_stack.len();
for (term, branch_num) in iter.rev() {
state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
state_stack.push(TraversalState::RemoveBranchNum);
state_stack.push(TraversalState::Term(term));
state_stack.push(TraversalState::AddBranchNum(branch_num));
}
if let TraversalState::BuildDisjunct(build_stack_len) = state_stack[final_disjunct_loc] {
state_stack[final_disjunct_loc] = TraversalState::BuildFinalDisjunct(build_stack_len);
}
self.current_chunk_type = ChunkType::Mid;
self.current_chunk_num += 1;
}
Term::Clause(_, atom!("->"), mut terms) if terms.len() == 2 => {
let then_term = terms.pop().unwrap();
let if_term = terms.pop().unwrap();
let prev_b = if matches!(state_stack.last(), Some(TraversalState::RemoveBranchNum)) {
// check if the second-to-last element is a regular BuildDisjunct, as we don't
// want to add GetPrevLevel in case of a TrustMe.
matches!(state_stack.iter().rev().nth(1), Some(TraversalState::BuildDisjunct(..)))
} else {
false
};
state_stack.push(TraversalState::Term(then_term));
state_stack.push(TraversalState::Cut { var_num: self.var_num, is_global: false });
state_stack.push(TraversalState::Term(if_term));
state_stack.push(TraversalState::GetCutPoint { var_num: self.var_num, prev_b });
self.var_num += 1;
}
Term::Clause(_, atom!("\\+"), mut terms) if terms.len() == 1 => {
let not_term = terms.pop().unwrap();
let build_stack_len = build_stack.len();
build_stack.reserve_branch(2);
state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len));
state_stack.push(TraversalState::Term(Term::Clause(Cell::default(), atom!("$succeed"), vec![])));
state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
state_stack.push(TraversalState::Fail);
state_stack.push(TraversalState::Cut { var_num: self.var_num, is_global: false });
state_stack.push(TraversalState::Term(not_term));
state_stack.push(TraversalState::GetCutPoint { var_num: self.var_num, prev_b: true });
self.current_chunk_type = ChunkType::Mid;
self.current_chunk_num += 1;
self.var_num += 1;
}
Term::Clause(_, atom!(":"), mut terms) if terms.len() == 2 => {
let predicate_name = terms.pop().unwrap();
let module_name = terms.pop().unwrap();
match (module_name, predicate_name) {
(
Term::Literal(_, Literal::Atom(module_name)),
Term::Literal(_, Literal::Atom(predicate_name)),
) => {
if update_chunk_data(self, predicate_name, 0) {
build_stack.add_chunk();
}
build_stack.push_chunk_term(
qualified_clause_to_query_term(
loader,
module_name,
predicate_name,
vec![],
self.call_policy,
),
);
}
(
Term::Literal(_, Literal::Atom(module_name)),
Term::Clause(_, name, terms),
) => {
if update_chunk_data(self, name, terms.len()) {
build_stack.add_chunk();
}
for (arg_c, term) in terms.iter().enumerate() {
self.probe_body_term(arg_c + 1, terms.len(), term);
}
build_stack.push_chunk_term(
qualified_clause_to_query_term(
loader,
module_name,
name,
terms,
self.call_policy,
),
);
}
(module_name, predicate_name) => {
if update_chunk_data(self, atom!("call"), 2) {
build_stack.add_chunk();
}
self.probe_body_term(1, 0, &module_name);
self.probe_body_term(2, 0, &predicate_name);
terms.push(module_name);
terms.push(predicate_name);
build_stack.push_chunk_term(
clause_to_query_term(
loader,
atom!("call"),
vec![Term::Clause(Cell::default(), atom!(":"), terms)],
self.call_policy,
),
);
}
}
}
Term::Clause(_, atom!("$call_with_inference_counting"), mut terms) if terms.len() == 1 => {
state_stack.push(TraversalState::ResetCallPolicy(self.call_policy));
state_stack.push(TraversalState::Term(terms.pop().unwrap()));
self.call_policy = CallPolicy::Counted;
}
Term::Clause(_, name, terms) => {
if update_chunk_data(self, name, terms.len()) {
build_stack.add_chunk();
}
for (arg_c, term) in terms.iter().enumerate() {
self.probe_body_term(arg_c + 1, terms.len(), term);
}
build_stack.push_chunk_term(
clause_to_query_term(
loader,
name,
terms,
self.call_policy,
),
);
}
var @ Term::Var(..) => {
if update_chunk_data(self, atom!("call"), 1) {
build_stack.add_chunk();
}
self.probe_body_term(1, 1, &var);
build_stack.push_chunk_term(
clause_to_query_term(
loader,
atom!("call"),
vec![var],
self.call_policy,
),
);
}
Term::Literal(_, Literal::Atom(atom!("!")) | Literal::Char('!')) => {
if self.global_cut_var_num.is_none() {
self.global_cut_var_num = Some(self.var_num);
self.var_num += 1;
}
self.probe_in_situ_var(self.global_cut_var_num.unwrap());
state_stack.push(TraversalState::Cut {
var_num: self.global_cut_var_num.unwrap(),
is_global: true,
});
}
Term::Literal(_, Literal::Atom(name)) => {
if update_chunk_data(self, name, 0) {
build_stack.add_chunk();
}
build_stack.push_chunk_term(
clause_to_query_term(
loader,
name,
vec![],
self.call_policy,
),
);
}
_ => {
return Err(CompilationError::InadmissibleQueryTerm);
}
}
}
}
}
Ok(build_stack)
}
}
impl BranchMap {
pub fn separate_and_classify_variables(
&mut self,
var_num: usize,
global_cut_var_num: Option<usize>,
current_chunk_num: usize,
) -> VarData {
let mut var_data = VarData {
records: VariableRecords::new(var_num),
global_cut_var_num,
allocates: current_chunk_num > 0,
};
for (var, branches) in self.iter_mut() {
let (mut var_num, var_num_incr) =
if let Var::InSitu(var_num) = *var.borrow() {
(var_num, false)
} else {
(var_data.records.len(), true)
};
for branch in branches.iter_mut() {
if var_num_incr {
var_num = var_data.records.len();
var_data.records.push(VariableRecord::default());
}
if branch.chunks.len() <= 1 { // true iff var is a temporary variable.
debug_assert_eq!(branch.chunks.len(), 1);
let chunk = &mut branch.chunks[0];
let mut temp_var_data = TempVarData::new();
for var_info in chunk.vars.iter_mut() {
if var_info.lvl == Level::Shallow {
let term_loc = var_info.chunk_type.to_gen_context(chunk.chunk_num);
temp_var_data.use_set.insert((term_loc, var_info.classify_info.arg_c));
}
}
var_data.records[var_num].allocation = VarAlloc::Temp {
term_loc: chunk.term_loc,
temp_reg: 0,
temp_var_data,
safety: VarSafetyStatus::Needed,
to_perm_var_num: None,
};
} // else VarAlloc is already a Perm variant, as it's the default.
for chunk in branch.chunks.iter_mut() {
var_data.records[var_num].num_occurrences += chunk.vars.len();
for var_info in chunk.vars.iter_mut() {
var_info.var_ptr.set(Var::Generated(var_num));
}
}
}
}
var_data.records.populate_restricting_sets();
var_data
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@ use crate::machine::heap::*;
use crate::types::*;
#[cfg(test)]
use crate::heap_iter::FocusedHeapIter;
use crate::heap_iter::{IterStackLoc, FocusedHeapIter, HeapOrStackTag};
use core::marker::PhantomData;
@@ -75,8 +75,8 @@ pub(crate) struct StacklessPreOrderHeapIter<'a, UMP: UnmarkPolicy> {
#[cfg(test)]
impl<'a> FocusedHeapIter for StacklessPreOrderHeapIter<'a, IteratorUMP> {
#[inline]
fn focus(&self) -> usize {
self.current
fn focus(&self) -> IterStackLoc {
IterStackLoc::iterable_loc(self.current, HeapOrStackTag::Heap)
}
}

View File

@@ -6,7 +6,7 @@ use crate::machine::partial_string::*;
use crate::parser::ast::*;
use crate::types::*;
use crate::parser::rug::{Integer, Rational};
use crate::parser::dashu::{Integer, Rational};
use std::convert::TryFrom;

View File

@@ -133,7 +133,7 @@ pub(super) fn import_module_exports<'a, LS: LoadState<'a>>(
meta_predicates.insert(key, meta_specs.clone());
}
if let Some(src_code_index) = imported_module.code_dir.get(&key) {
if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() {
let arena = &mut LS::machine_st(payload).arena;
let target_code_index = code_dir
@@ -148,6 +148,10 @@ pub(super) fn import_module_exports<'a, LS: LoadState<'a>>(
target_code_index,
src_code_index.get(),
);
if src_code_index.is_dynamic_undefined() {
code_dir.insert(key, src_code_index);
}
} else {
return Err(SessionError::ModuleDoesNotContainExport(
imported_module.module_decl.name,
@@ -441,13 +445,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
term: Term,
preprocessor: &mut Preprocessor,
) -> Result<PredicateClause, SessionError> {
let tl = preprocessor.try_term_to_tl(self, term, CutContext::BlocksCuts)?;
let tl = preprocessor.try_term_to_tl(self, term)?;
Ok(match tl {
TopLevel::Fact(fact) => PredicateClause::Fact(fact),
TopLevel::Rule(rule) => PredicateClause::Rule(rule),
TopLevel::Query(_) => return Err(SessionError::QueryCannotBeDefinedAsFact),
_ => unreachable!(),
TopLevel::Fact(fact, var_data) => PredicateClause::Fact(fact, var_data),
TopLevel::Rule(rule, var_data) => PredicateClause::Rule(rule, var_data),
})
}

View File

@@ -21,7 +21,6 @@ use std::convert::TryFrom;
use std::fmt;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
/*
* The loader compiles Prolog terms read from a TermStream instance,
@@ -329,6 +328,10 @@ impl<'a> LoadState<'a> for LiveLoadAndMachineState<'a> {
loader: &Loader<'a, Self>,
key: PredicateKey,
) -> Result<(), SessionError> {
if ClauseType::is_inbuilt(key.0, key.1) {
return Err(SessionError::CannotOverwriteBuiltIn(key));
}
if let Some(builtins) = loader.wam_prelude.indices.modules.get(&atom!("builtins")) {
if builtins.module_decl.exports.contains(&ModuleExport::PredicateKey(key)) {
return Err(SessionError::CannotOverwriteBuiltIn(key));
@@ -465,6 +468,13 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
}
}
pub(crate) fn read_term_from_heap(&mut self, r: RegType) -> Result<Term, SessionError> {
let machine_st = LS::machine_st(&mut self.payload);
let cell = machine_st[r];
machine_st.read_term_from_heap(cell)
}
pub(crate) fn load(mut self) -> Result<LS::Evacuable, SessionError> {
while let Some(decl) = self.dequeue_terms()? {
self.load_decl(decl)?;
@@ -531,106 +541,6 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
Ok(())
}
pub(super) fn read_term_from_heap(&mut self, heap_term_loc: RegType) -> Result<Term, SessionError> {
let machine_st = LS::machine_st(&mut self.payload);
let term_addr = machine_st[heap_term_loc];
let mut term_stack = vec![];
let mut iter = stackful_post_order_iter(&mut machine_st.heap, term_addr);
while let Some(addr) = iter.next() {
let addr = unmark_cell_bits!(addr);
read_heap_cell!(addr,
(HeapCellValueTag::Lis) => {
use crate::parser::parser::as_partial_string;
let tail = term_stack.pop().unwrap();
let head = term_stack.pop().unwrap();
match as_partial_string(head, tail) {
Ok((string, Some(tail))) => {
term_stack.push(Term::PartialString(Cell::default(), string, tail));
}
Ok((string, None)) => {
let atom = machine_st.atom_tbl.build_with(&string);
term_stack.push(Term::CompleteString(Cell::default(), atom));
}
Err(cons_term) => term_stack.push(cons_term),
}
}
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, h) => {
let offset_string = format!("_{}", h);
term_stack.push(Term::Var(Cell::default(), Rc::new(offset_string)));
}
(HeapCellValueTag::Cons | HeapCellValueTag::CStr | HeapCellValueTag::Fixnum |
HeapCellValueTag::Char | HeapCellValueTag::F64) => {
term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap()));
}
(HeapCellValueTag::Atom, (name, arity)) => {
let h = iter.focus();
let mut arity = arity;
if iter.heap.len() > h + arity + 1 {
let value = iter.heap[h + arity + 1];
if let Some(idx) = get_structure_index(value) {
// in the second condition, arity == 0,
// meaning idx cannot pertain to this atom
// if it is the direct subterm of a larger
// structure.
if arity > 0 || !iter.direct_subterm_of_str(h) {
term_stack.push(
Term::Literal(Cell::default(), Literal::CodeIndex(idx))
);
arity += 1;
}
}
}
if arity == 0 {
term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name)));
} else {
let subterms = term_stack
.drain(term_stack.len() - arity ..)
.collect();
term_stack.push(Term::Clause(Cell::default(), name, subterms));
}
}
(HeapCellValueTag::PStr, atom) => {
let tail = term_stack.pop().unwrap();
if let Term::Literal(_, Literal::Atom(atom!("[]"))) = &tail {
term_stack.push(Term::CompleteString(Cell::default(), atom));
} else {
term_stack.push(Term::PartialString(
Cell::default(),
atom.as_str().to_owned(),
Box::new(tail),
));
}
}
(HeapCellValueTag::PStrLoc, h) => {
let atom = cell_as_atom_cell!(iter.heap[h]).get_name();
let tail = term_stack.pop().unwrap();
term_stack.push(Term::PartialString(
Cell::default(),
atom.as_str().to_owned(),
Box::new(tail),
));
}
_ => {
}
);
}
debug_assert!(term_stack.len() == 1);
Ok(term_stack.pop().unwrap())
}
fn reset_machine(&mut self) {
while let Some(record) = self.payload.retraction_info.records.pop() {
match record {
@@ -1143,7 +1053,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
&mut self,
r: RegType,
) -> Result<IndexSet<ModuleExport>, SessionError> {
let export_list = self.read_term_from_heap(r)?;
let machine_st = LS::machine_st(&mut self.payload);
let cell = machine_st[r];
let export_list = machine_st.read_term_from_heap(cell)?;
let atom_tbl = &mut LS::machine_st(&mut self.payload).atom_tbl;
let export_list = setup_module_export_list(export_list, atom_tbl)?;
@@ -1493,6 +1406,104 @@ impl<'a> MachinePreludeView<'a> {
}
}
impl MachineState {
pub(super) fn read_term_from_heap(&mut self, term_addr: HeapCellValue) -> Result<Term, SessionError> {
let mut term_stack = vec![];
let mut iter = stackful_post_order_iter(&mut self.heap, &mut self.stack, term_addr);
while let Some(addr) = iter.next() {
let addr = unmark_cell_bits!(addr);
read_heap_cell!(addr,
(HeapCellValueTag::Lis) => {
use crate::parser::parser::as_partial_string;
let tail = term_stack.pop().unwrap();
let head = term_stack.pop().unwrap();
match as_partial_string(head, tail) {
Ok((string, Some(tail))) => {
term_stack.push(Term::PartialString(Cell::default(), string, tail));
}
Ok((string, None)) => {
let atom = self.atom_tbl.build_with(&string);
term_stack.push(Term::CompleteString(Cell::default(), atom));
}
Err(cons_term) => term_stack.push(cons_term),
}
}
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, h) => {
term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("_{}", h))));
}
(HeapCellValueTag::Cons | HeapCellValueTag::CStr | HeapCellValueTag::Fixnum |
HeapCellValueTag::Char | HeapCellValueTag::F64) => {
term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap()));
}
(HeapCellValueTag::Atom, (name, arity)) => {
let h = iter.focus().value() as usize;
let mut arity = arity;
if iter.heap.len() > h + arity + 1 {
let value = iter.heap[h + arity + 1];
if let Some(idx) = get_structure_index(value) {
// in the second condition, arity == 0,
// meaning idx cannot pertain to this atom
// if it is the direct subterm of a larger
// structure.
if arity > 0 || !iter.direct_subterm_of_str(h) {
term_stack.push(
Term::Literal(Cell::default(), Literal::CodeIndex(idx))
);
arity += 1;
}
}
}
if arity == 0 {
term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name)));
} else {
let subterms = term_stack
.drain(term_stack.len() - arity ..)
.collect();
term_stack.push(Term::Clause(Cell::default(), name, subterms));
}
}
(HeapCellValueTag::PStr, atom) => {
let tail = term_stack.pop().unwrap();
if let Term::Literal(_, Literal::Atom(atom!("[]"))) = &tail {
term_stack.push(Term::CompleteString(Cell::default(), atom));
} else {
term_stack.push(Term::PartialString(
Cell::default(),
atom.as_str().to_owned(),
Box::new(tail),
));
}
}
(HeapCellValueTag::PStrLoc, h) => {
let atom = cell_as_atom_cell!(iter.heap[h]).get_name();
let tail = term_stack.pop().unwrap();
term_stack.push(Term::PartialString(
Cell::default(),
atom.as_str().to_owned(),
Box::new(tail),
));
}
_ => {
}
);
}
debug_assert!(term_stack.len() == 1);
Ok(term_stack.pop().unwrap())
}
}
impl Machine {
pub(crate) fn use_module(&mut self) -> CallResult {
let subevacuable_addr = self
@@ -1620,25 +1631,18 @@ impl Machine {
usize,
) -> Result<(), SessionError>,
) -> CallResult {
let module_name = cell_as_atom!(
self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
);
let module_name = cell_as_atom!(self.deref_register(1));
let compilation_target = match module_name {
atom!("user") => CompilationTarget::User,
_ => CompilationTarget::Module(module_name),
};
let predicate_name = cell_as_atom!(
self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))
);
let arity = self
.machine_st
.store(self.machine_st.deref(self.machine_st.registers[3]));
let predicate_name = cell_as_atom!(self.deref_register(2));
let arity = self.deref_register(3);
let arity = match Number::try_from(arity) {
Ok(Number::Integer(n)) if &*n >= &0 && &*n <= &MAX_ARITY => Ok(n.to_usize().unwrap()),
Ok(Number::Integer(n)) if &*n >= &Integer::from(0) && &*n <= &Integer::from(MAX_ARITY) => Ok(n.to_usize().unwrap()),
Ok(Number::Fixnum(n)) if n.get_num() >= 0 && n.get_num() <= MAX_ARITY as i64 => {
Ok(usize::try_from(n.get_num()).unwrap())
}
@@ -1692,6 +1696,21 @@ impl Machine {
let add_clause = || {
let term = loader.read_term_from_heap(temp_v!(2))?;
let indexing_arg = match term.name() {
Some(atom!(":-")) => term.first_arg().and_then(Term::first_arg),
Some(_) => term.first_arg(),
None => None,
};
if let Some(indexing_term) = indexing_arg {
if let Some(indexing_name) = indexing_term.name() {
loader.wam_prelude
.indices
.goal_expansion_indices
.insert((indexing_name, indexing_term.arity()));
}
}
loader.incremental_compile_clause(
(atom!("goal_expansion"), 2),
term,
@@ -1962,11 +1981,8 @@ impl Machine {
}
}
pub(crate) fn compile_assert(&mut self, append_or_prepend: AppendOrPrepend) -> CallResult
{
let module_name = cell_as_atom!(
self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
);
pub(crate) fn compile_assert(&mut self, append_or_prepend: AppendOrPrepend) -> CallResult {
let module_name = cell_as_atom!(self.deref_register(1));
let compilation_target = match module_name {
atom!("user") => CompilationTarget::User,
@@ -1980,13 +1996,20 @@ impl Machine {
}
};
let head = self.deref_register(2);
if head.is_var() {
let err = self.machine_st.instantiation_error();
return Err(self.machine_st.error_form(err, stub_gen()));
}
let mut compile_assert = || {
let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> =
Loader::new(self, LiveTermStream::new(ListingSource::User));
loader.payload.compilation_target = compilation_target;
let head = loader.read_term_from_heap(temp_v!(2))?;
let head = LiveLoadAndMachineState::machine_st(&mut loader.payload).read_term_from_heap(head)?;
let name = if let Some(name) = head.name() {
name
@@ -1995,6 +2018,7 @@ impl Machine {
};
let arity = head.arity();
let is_builtin = loader.wam_prelude.indices.builtin_property((name, arity));
let is_dynamic_predicate = loader
.wam_prelude
@@ -2005,7 +2029,7 @@ impl Machine {
);
let no_such_predicate =
if !is_dynamic_predicate && !ClauseType::is_inbuilt(name, arity) {
if !is_dynamic_predicate && !is_builtin {
let idx_tag = loader
.wam_prelude
.indices
@@ -2017,8 +2041,9 @@ impl Machine {
.map(|code_idx| code_idx.get_tag())
.unwrap_or(IndexPtrTag::DynamicUndefined);
idx_tag == IndexPtrTag::DynamicUndefined ||
idx_tag == IndexPtrTag::Undefined
idx_tag == IndexPtrTag::DynamicUndefined || idx_tag == IndexPtrTag::Undefined
} else if is_builtin {
return Err(SessionError::CannotOverwriteBuiltIn((name, arity)));
} else {
is_dynamic_predicate
};
@@ -2445,21 +2470,6 @@ impl Machine {
}
}
}
pub(crate) fn builtin_property(&mut self) {
let (name, arity) = self
.machine_st
.read_predicate_key(self.machine_st.registers[1], self.machine_st.registers[2]);
if !ClauseType::is_inbuilt(name, arity) { // ClauseType::from(key.0, key.1, &mut self.machine_st.arena) {
if let Some(module) = self.indices.modules.get(&(atom!("builtins"))) {
self.machine_st.fail = !module.code_dir.contains_key(&(name, arity));
return;
}
}
self.machine_st.fail = true;
}
}
impl<'a> Loader<'a, LiveLoadAndMachineState<'a>> {

View File

@@ -1,10 +1,13 @@
use crate::arena::*;
use crate::atom_table::*;
use crate::parser::ast::*;
use crate::ffi::FFIError;
use crate::forms::*;
use crate::machine::heap::*;
use crate::machine::loader::CompilationTarget;
use crate::machine::machine_state::*;
use crate::machine::streams::*;
use crate::machine::system_calls::BrentAlgState;
use crate::types::*;
@@ -157,9 +160,29 @@ impl PermissionError for HeapCellValue {
index_atom: Atom,
perm: Permission,
) -> MachineError {
let cell = read_heap_cell!(self,
(HeapCellValueTag::Cons, ptr) => {
match_untyped_arena_ptr!(ptr,
(ArenaHeaderTag::Stream, stream) => {
if let Some(alias) = stream.options().get_alias() {
atom_as_cell!(alias)
} else {
self
}
}
_ => {
self
}
)
}
_ => {
self
}
);
let stub = functor!(
atom!("permission_error"),
[atom(perm.as_atom()), atom(index_atom), cell(self)]
[atom(perm.as_atom()), atom(index_atom), cell(cell)]
);
MachineError {
@@ -419,7 +442,7 @@ impl MachineState {
// SessionError::CannotOverwriteImport(pred_atom) => {
self.permission_error(
Permission::Modify,
atom!("private_procedure"),
atom!("static_procedure"),
functor_stub(key.0, key.1).into_iter().collect::<MachineStub>(),
)
}
@@ -515,6 +538,24 @@ impl MachineState {
}
}
pub(super) fn ffi_error(&mut self, err: FFIError) -> MachineError {
let error_atom = match err {
FFIError::ValueCast => atom!("value_cast"),
FFIError::ValueDontFit => atom!("value_dont_fit"),
FFIError::InvalidFFIType => atom!("invalid_ffi_type"),
FFIError::InvalidStructName => atom!("invalid_struct_name"),
FFIError::FunctionNotFound => atom!("function_not_found"),
FFIError::StructNotFound => atom!("struct_not_found"),
};
let stub = functor!(atom!("ffi_error"),[atom(error_atom)]);
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed,
}
}
pub(super) fn error_form(&mut self, err: MachineError, src: FunctorStub) -> MachineStub {
let h = self.heap.len();
let location = err.location;
@@ -661,7 +702,6 @@ impl CompilationError {
functor!(atom!("no_such_module"), [atom(module_name)])
}
&CompilationError::InvalidRuleHead => {
functor!(atom!("invalid_head_of_rule")) // TODO: type_error(callable, _).
}
&CompilationError::InvalidUseModuleDecl => {
@@ -780,7 +820,7 @@ pub enum CycleSearchResult {
NotList(usize, HeapCellValue), // the list length until the second argument in the heap
PartialList(usize, Ref), // the list length (up to max), and an offset into the heap.
ProperList(usize), // the list length.
PStrLocation(usize, usize), // list length (up to max), the heap address of the PStrOffset
PStrLocation(usize, usize, usize), // list length (up to max), the heap address of the PStr, the offset
UntouchedList(usize, usize), // list length (up to max), the address of an uniterated Addr::Lis(address).
UntouchedCStr(Atom, usize),
}

View File

@@ -2,21 +2,20 @@ use crate::parser::ast::*;
use crate::arena::*;
use crate::atom_table::*;
use crate::fixtures::*;
use crate::forms::*;
use crate::machine::ClauseType;
use crate::machine::loader::*;
use crate::machine::machine_state::*;
use crate::machine::streams::Stream;
use fxhash::FxBuildHasher;
use indexmap::IndexMap;
use indexmap::{IndexMap, IndexSet};
use modular_bitfield::{BitfieldSpecifier, bitfield};
use modular_bitfield::specifiers::*;
use std::cmp::Ordering;
use std::collections::BTreeSet;
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
use crate::types::*;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -228,8 +227,32 @@ impl CodeIndex {
}
}
pub(crate) type HeapVarDict = IndexMap<Rc<String>, HeapCellValue, FxBuildHasher>;
pub(crate) type AllocVarDict = IndexMap<Rc<String>, VarData, FxBuildHasher>;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum VarKey {
AnonVar(usize),
VarPtr(VarPtr),
}
impl VarKey {
#[inline]
pub(crate) fn to_string(&self) -> String {
match self {
VarKey::AnonVar(h) => format!("_{}", h),
VarKey::VarPtr(var) => var.borrow().to_string(),
}
}
#[inline(always)]
pub(crate) fn is_anon(&self) -> bool {
if let VarKey::AnonVar(_) = self {
true
} else {
false
}
}
}
pub(crate) type HeapVarDict = IndexMap<VarKey, HeapCellValue, FxBuildHasher>;
pub(crate) type GlobalVarDir = IndexMap<Atom, (Ball, Option<HeapCellValue>), FxBuildHasher>;
@@ -245,12 +268,15 @@ pub(crate) type LocalExtensiblePredicates =
pub(crate) type CodeDir = IndexMap<PredicateKey, CodeIndex, FxBuildHasher>;
pub(crate) type GoalExpansionIndices = IndexSet<PredicateKey, FxBuildHasher>;
#[derive(Debug)]
pub struct IndexStore {
pub(super) code_dir: CodeDir,
pub(super) extensible_predicates: ExtensiblePredicates,
pub(super) local_extensible_predicates: LocalExtensiblePredicates,
pub(super) global_variables: GlobalVarDir,
pub(super) goal_expansion_indices: GoalExpansionIndices,
pub(super) meta_predicates: MetaPredicateDir,
pub(super) modules: ModuleDir,
pub(super) op_dir: OpDir,
@@ -259,6 +285,23 @@ pub struct IndexStore {
}
impl IndexStore {
pub(crate) fn builtin_property(&self, key: PredicateKey) -> bool {
let (name, arity) = key;
if !ClauseType::is_inbuilt(name, arity) {
self.modules.get(&(atom!("builtins")))
.map(|module| module.code_dir.contains_key(&(name, arity)))
.unwrap_or(false)
} else {
true
}
}
#[inline(always)]
pub(crate) fn goal_expansion_defined(&self, key: PredicateKey) -> bool {
self.goal_expansion_indices.contains(&key)
}
pub(crate) fn get_predicate_skeleton_mut(
&mut self,
compilation_target: &CompilationTarget,
@@ -371,22 +414,11 @@ impl IndexStore {
module: Atom,
) -> Option<CodeIndex> {
if module == atom!("user") {
/*match ClauseType::from(name, arity) {
ClauseType::Named(arity, name, _) => */
self.code_dir.get(&(name, arity)).cloned()
/* _ => None,
}*/
} else {
self.modules
.get(&module)
.and_then(|module|/* |module| match ClauseType::from(name, arity) {
ClauseType::Named(arity, name, _) => { */
module.code_dir.get(&(name, arity)).cloned()
/*
}
_ => None,
} */
)
.and_then(|module| module.code_dir.get(&(name, arity)).cloned())
}
}

View File

@@ -12,16 +12,16 @@ use crate::machine::machine_indices::*;
use crate::machine::stack::*;
use crate::machine::streams::*;
use crate::parser::ast::*;
use crate::read::TermWriteResult;
use crate::types::*;
use crate::parser::rug::Integer;
use crate::parser::dashu::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];
@@ -50,6 +50,12 @@ pub enum FirstOrNext {
Next,
}
#[derive(Debug)]
pub enum OnEOF {
Return,
Continue,
}
pub struct MachineState {
pub atom_tbl: AtomTable,
pub arena: Arena,
@@ -74,11 +80,12 @@ pub struct MachineState {
pub(super) tr: usize,
pub(super) hb: usize,
pub(super) block: usize, // an offset into the OR stack.
pub(super) scc_block: usize, // an offset into the OR stack for setup_call_cleanup/3.
pub(super) ball: Ball,
pub(super) ball_stack: Vec<Ball>, // save current ball before jumping via, e.g., verify_attr interrupt.
pub(super) lifted_heap: Heap,
pub(super) interms: Vec<Number>, // intermediate numbers.
// locations of cleaners, cut points, the previous block. for setup_call_cleanup.
// locations of cleaners, cut points, the previous scc_block. for setup_call_cleanup/3.
pub(super) cont_pts: Vec<(HeapCellValue, usize, usize)>,
pub(super) cwil: CWIL,
pub(crate) flags: MachineFlags,
@@ -113,6 +120,7 @@ impl fmt::Debug for MachineState {
.field("tr", &self.tr)
.field("hb", &self.hb)
.field("block", &self.block)
.field("scc_block", &self.scc_block)
.field("ball", &self.ball)
.field("ball_stack", &self.ball_stack)
.field("lifted_heap", &self.lifted_heap)
@@ -192,6 +200,27 @@ pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixn
)
}
fn push_var_eq_functors<'a>(
heap: &mut Heap,
iter: impl Iterator<Item = (&'a VarKey, &'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.to_string());
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
}
#[derive(Debug)]
pub struct Ball {
pub(super) boundary: usize,
@@ -481,6 +510,133 @@ impl MachineState {
}
}
pub fn write_read_term_options(
&mut self,
mut var_list: Vec<(VarKey, HeapCellValue, usize)>,
singleton_var_list: Vec<HeapCellValue>,
) -> CallResult {
var_list.sort_by(|(_,_,idx_1),(_,_,idx_2)| idx_1.cmp(idx_2));
let list_of_var_eqs = push_var_eq_functors(
&mut self.heap,
var_list.iter().filter_map(|(var_name, var,_)| if var_name.is_anon() { None } else { Some((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())
);
Ok(unify_fn!(*self, var_names_offset, var_names_addr))
}
pub fn read_term_body(&mut self, mut term_write_result: TermWriteResult) -> CallResult {
let heap_loc = read_heap_cell!(self.heap[term_write_result.heap_loc],
(HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
pstr_loc_as_cell!(term_write_result.heap_loc)
}
_ => {
heap_loc_as_cell!(term_write_result.heap_loc)
}
);
unify_fn!(*self, heap_loc, self.registers[2]);
if self.fail {
return Ok(());
}
for var in term_write_result.var_dict.values_mut() {
*var = heap_bound_deref(&self.heap, *var);
}
let mut singleton_var_set: IndexMap<Ref, bool> = IndexMap::new();
for cell in stackful_preorder_iter(&mut self.heap, &mut self.stack, heap_loc) {
let cell = unmark_cell_bits!(cell);
if let Some(var) = cell.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(|(var_name, binding)| {
if var_name.is_anon() {
return false;
}
if let Some(r) = binding.as_var() {
*singleton_var_set.get(&r).unwrap_or(&false)
} else {
false
}
}),
&mut self.atom_tbl,
);
for var in term_write_result.var_dict.values_mut() {
*var = heap_bound_deref(&self.heap, *var);
}
let mut var_list = Vec::with_capacity(singleton_var_set.len());
for (var_name, addr) in term_write_result.var_dict {
if let Some(var) = addr.as_var() {
if let Some(idx) = singleton_var_set.get_index_of(&var) {
var_list.push((var_name, addr, idx));
}
}
}
self.write_read_term_options(var_list, singleton_var_list)
}
pub fn read_term_from_user_input_eof_handler(&mut self, stream: Stream) -> Result<OnEOF, MachineStub> {
self.eof_action(
self.registers[2],
stream,
atom!("read_term"),
3,
)?;
if stream.options().eof_action() == EOFAction::Reset {
if self.fail == false {
return Ok(OnEOF::Continue);
}
}
Ok(OnEOF::Return)
}
// Safety: the atom_tbl lives for the lifetime of the machine, as does the helper, so the ptr
// will always be valid.
pub fn read_term_from_user_input(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult {
@@ -490,40 +646,54 @@ impl MachineState {
unsafe {
let readline = ptr.as_ptr().as_mut().unwrap();
readline.set_atoms_for_completion(atoms_ptr);
let ret = self.read_term(stream, indices);
return ret
return self.read_term(
stream,
indices,
MachineState::read_term_from_user_input_eof_handler,
);
}
}
if let Stream::Byte(_) = stream {
return self.read_term(stream, indices)
return self.read_term(
stream,
indices,
MachineState::read_term_from_user_input_eof_handler
)
}
unreachable!("Stream must be a Stream::Readline(_)")
}
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![];
pub fn read_term_eof_handler(&mut self, mut stream: Stream) -> Result<OnEOF, MachineStub> {
if stream.at_end_of_stream() {
unify!(self, self.registers[2], atom_as_cell!(atom!("end_of_file")));
stream.set_past_end_of_stream(true);
return Ok(OnEOF::Return);
} else if stream.past_end_of_stream() {
self.eof_action(
self.registers[2],
stream,
atom!("read_term"),
3,
)?;
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));
if stream.options().eof_action() == EOFAction::Reset {
if self.fail == false {
return Ok(OnEOF::Continue);
}
}
list_of_var_eqs
}
Ok(OnEOF::Return)
}
pub fn read_term(
&mut self,
stream: Stream,
indices: &mut IndexStore,
eof_handler: impl Fn(&mut Self, Stream) -> Result<OnEOF, MachineStub>,
) -> CallResult {
self.check_stream_properties(
stream,
StreamType::Text,
@@ -542,116 +712,16 @@ impl MachineState {
loop {
match self.read(stream, &indices.op_dir) {
Ok(mut term_write_result) => {
let heap_loc = read_heap_cell!(self.heap[term_write_result.heap_loc],
(HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
pstr_loc_as_cell!(term_write_result.heap_loc)
}
_ => {
heap_loc_as_cell!(term_write_result.heap_loc)
}
);
let term = self.registers[2];
unify_fn!(*self, heap_loc, term);
let term = 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);
}
}
}
for var in term_write_result.var_dict.values_mut() {
*var = heap_bound_deref(&self.heap, *var);
}
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));
}
Ok(term_write_result) => return self.read_term_body(term_write_result),
Err(err) => {
if let CompilationError::ParserError(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;
match &err {
CompilationError::ParserError(e) if e.is_unexpected_eof() => {
match eof_handler(self, stream)? {
OnEOF::Return => return self.write_read_term_options(vec![], vec![]),
OnEOF::Continue => continue,
}
}
return Ok(());
_ => {}
}
let stub = functor_stub(atom!("read_term"), 3);
@@ -671,13 +741,14 @@ impl MachineState {
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 double_quotes = self.store(self.deref(self.registers[8]));
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();
let mut var_names: IndexMap<HeapCellValue, VarPtr> = IndexMap::new();
for addr in addrs {
read_heap_cell!(addr,
@@ -695,18 +766,18 @@ impl MachineState {
read_heap_cell!(atom,
(HeapCellValueTag::Char, c) => {
var_names.insert(var, Rc::new(c.to_string()));
var_names.insert(var, VarPtr::from(c.to_string()));
}
(HeapCellValueTag::Atom, (name, _arity)) => {
debug_assert_eq!(_arity, 0);
var_names.insert(var, Rc::new(name.as_str().to_owned()));
var_names.insert(var, VarPtr::from(name.as_str()));
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
var_names.insert(var, Rc::new(name.as_str().to_owned()));
var_names.insert(var, VarPtr::from(name.as_str()));
}
_ => {
unreachable!();
@@ -752,7 +823,25 @@ impl MachineState {
);
let quoted = read_heap_cell!(quoted,
(HeapCellValueTag::Atom, (name, _arity)) => {
(HeapCellValueTag::Atom, (name, arity)) => {
debug_assert_eq!(arity, 0);
name == atom!("true")
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
name == atom!("true")
}
_ => {
unreachable!()
}
);
let double_quotes = read_heap_cell!(double_quotes,
(HeapCellValueTag::Atom, (name, arity)) => {
debug_assert_eq!(arity, 0);
name == atom!("true")
}
(HeapCellValueTag::Str, s) => {
@@ -769,6 +858,8 @@ impl MachineState {
let mut printer = HCPrinter::new(
&mut self.heap,
&mut self.atom_tbl,
&mut self.stack,
op_dir,
PrinterOutputter::new(),
term_to_be_printed,
@@ -777,6 +868,7 @@ impl MachineState {
printer.ignore_ops = ignore_ops;
printer.numbervars = numbervars;
printer.quoted = quoted;
printer.double_quotes = double_quotes;
match Number::try_from(max_depth) {
Ok(Number::Fixnum(n)) => {
@@ -824,7 +916,7 @@ impl MachineState {
let b = self.b;
read_heap_cell!(value,
(HeapCellValueTag::Fixnum, b0) => {
(HeapCellValueTag::CutPoint, b0) => {
let b0 = b0.get_num() as usize;
if b > b0 {
@@ -836,63 +928,6 @@ impl MachineState {
}
);
}
#[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)]

File diff suppressed because it is too large Load Diff

View File

@@ -61,6 +61,8 @@ impl MockWAM {
let mut printer = HCPrinter::new(
&mut self.machine_st.heap,
&mut self.machine_st.atom_tbl,
&mut self.machine_st.stack,
&self.op_dir,
PrinterOutputter::new(),
heap_loc_as_cell!(term_write_result.heap_loc),
@@ -69,7 +71,12 @@ impl MockWAM {
printer.var_names = term_write_result
.var_dict
.into_iter()
.map(|(var, cell)| (cell, var))
.map(|(var, cell)| {
match var {
VarKey::VarPtr(var) => (cell, var.clone()),
VarKey::AnonVar(_) => (cell, VarPtr::from(var.to_string()))
}
})
.collect();
Ok(printer.print().result())

View File

@@ -19,16 +19,19 @@ pub mod machine_state_impl;
pub mod mock_wam;
pub mod parsed_results;
pub mod partial_string;
pub mod disjuncts;
pub mod preprocessor;
pub mod stack;
pub mod streams;
pub mod system_calls;
pub mod term_stream;
pub mod unify;
use crate::arena::*;
use crate::arithmetic::*;
use crate::atom_table::*;
use crate::forms::*;
use crate::ffi::ForeignFunctionTable;
use crate::instructions::*;
use crate::machine::args::*;
use crate::machine::compile::*;
@@ -41,7 +44,7 @@ use crate::machine::machine_state::*;
use crate::machine::stack::*;
use crate::machine::streams::*;
use crate::parser::ast::*;
use crate::parser::rug::{Integer, Rational};
use crate::parser::dashu::{Integer, Rational};
use crate::types::*;
use indexmap::IndexMap;
@@ -70,6 +73,7 @@ pub struct Machine {
pub(super) user_output: Stream,
pub(super) user_error: Stream,
pub(super) load_contexts: Vec<LoadContext>,
pub(super) foreign_function_table: ForeignFunctionTable,
}
#[derive(Debug)]
@@ -205,7 +209,7 @@ impl Machine {
self.machine_st.throw_exception(err);
}
fn run_module_predicate(&mut self, module_name: Atom, key: PredicateKey) {
fn run_module_predicate(&mut self, module_name: Atom, key: PredicateKey) -> std::process::ExitCode {
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();
@@ -255,31 +259,22 @@ impl Machine {
let mut path_buf = current_dir();
path_buf.push("machine/attributed_variables.pl");
bootstrapping_compile(
Stream::from_static_string(
include_str!("attributed_variables.pl"),
&mut self.machine_st.arena,
),
self,
ListingSource::from_file_and_path(
atom!("attributed_variables"),
path_buf,
),
)
.unwrap();
let stream = Stream::from_static_string(
include_str!("attributed_variables.pl"),
&mut self.machine_st.arena,
);
self.load_file(path_buf.to_str().unwrap(), stream);
let mut path_buf = current_dir();
path_buf.push("machine/project_attributes.pl");
bootstrapping_compile(
Stream::from_static_string(
include_str!("project_attributes.pl"),
&mut self.machine_st.arena,
),
self,
ListingSource::from_file_and_path(atom!("project_attributes"), path_buf),
)
.unwrap();
let stream = Stream::from_static_string(
include_str!("project_attributes.pl"),
&mut self.machine_st.arena,
);
self.load_file(path_buf.to_str().unwrap(), stream);
if let Some(module) = self.indices.modules.get(&atom!("$atts")) {
if let Some(code_index) = module.code_dir.get(&(atom!("driver"), 2)) {
@@ -288,7 +283,7 @@ impl Machine {
}
}
pub fn run_top_level(&mut self, module_name: Atom, key: PredicateKey) {
pub fn run_top_level(&mut self, module_name: Atom, key: PredicateKey) -> std::process::ExitCode {
let mut arg_pstrs = vec![];
for arg in env::args() {
@@ -304,7 +299,7 @@ impl Machine {
arg_pstrs.into_iter()
));
self.run_module_predicate(module_name, key);
self.run_module_predicate(module_name, key)
}
pub fn set_user_input(&mut self, input: String) {
@@ -380,46 +375,45 @@ impl Machine {
Instruction::BreakFromDispatchLoop,
Instruction::InstallVerifyAttr,
Instruction::VerifyAttrInterrupt,
Instruction::ExecuteTermGreaterThan(0),
Instruction::ExecuteTermLessThan(0),
Instruction::ExecuteTermGreaterThanOrEqual(0),
Instruction::ExecuteTermLessThanOrEqual(0),
Instruction::ExecuteTermEqual(0),
Instruction::ExecuteTermNotEqual(0),
Instruction::ExecuteNumberGreaterThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
Instruction::ExecuteNumberLessThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
Instruction::ExecuteNumberGreaterThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
Instruction::ExecuteNumberLessThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
Instruction::ExecuteNumberEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
Instruction::ExecuteNumberNotEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
Instruction::ExecuteIs(temp_v!(1), ar_reg!(temp_v!(2)), 0),
Instruction::ExecuteAcyclicTerm(0),
Instruction::ExecuteArg(0),
Instruction::ExecuteCompare(0),
Instruction::ExecuteCopyTerm(0),
Instruction::ExecuteFunctor(0),
Instruction::ExecuteGround(0),
Instruction::ExecuteKeySort(0),
Instruction::ExecuteRead(0),
Instruction::ExecuteSort(0),
Instruction::ExecuteN(1, 0),
Instruction::ExecuteN(2, 0),
Instruction::ExecuteN(3, 0),
Instruction::ExecuteN(4, 0),
Instruction::ExecuteN(5, 0),
Instruction::ExecuteN(6, 0),
Instruction::ExecuteN(7, 0),
Instruction::ExecuteN(8, 0),
Instruction::ExecuteN(9, 0),
Instruction::ExecuteIsAtom(temp_v!(1), 0),
Instruction::ExecuteIsAtomic(temp_v!(1), 0),
Instruction::ExecuteIsCompound(temp_v!(1), 0),
Instruction::ExecuteIsInteger(temp_v!(1), 0),
Instruction::ExecuteIsNumber(temp_v!(1), 0),
Instruction::ExecuteIsRational(temp_v!(1), 0),
Instruction::ExecuteIsFloat(temp_v!(1), 0),
Instruction::ExecuteIsNonVar(temp_v!(1), 0),
Instruction::ExecuteIsVar(temp_v!(1), 0)
Instruction::ExecuteTermGreaterThan,
Instruction::ExecuteTermLessThan,
Instruction::ExecuteTermGreaterThanOrEqual,
Instruction::ExecuteTermLessThanOrEqual,
Instruction::ExecuteTermEqual,
Instruction::ExecuteTermNotEqual,
Instruction::ExecuteNumberGreaterThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
Instruction::ExecuteNumberLessThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
Instruction::ExecuteNumberGreaterThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
Instruction::ExecuteNumberLessThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
Instruction::ExecuteNumberEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
Instruction::ExecuteNumberNotEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
Instruction::ExecuteIs(temp_v!(1), ar_reg!(temp_v!(2))),
Instruction::ExecuteAcyclicTerm,
Instruction::ExecuteArg,
Instruction::ExecuteCompare,
Instruction::ExecuteCopyTerm,
Instruction::ExecuteFunctor,
Instruction::ExecuteGround,
Instruction::ExecuteKeySort,
Instruction::ExecuteSort,
Instruction::ExecuteN(1),
Instruction::ExecuteN(2),
Instruction::ExecuteN(3),
Instruction::ExecuteN(4),
Instruction::ExecuteN(5),
Instruction::ExecuteN(6),
Instruction::ExecuteN(7),
Instruction::ExecuteN(8),
Instruction::ExecuteN(9),
Instruction::ExecuteIsAtom(temp_v!(1)),
Instruction::ExecuteIsAtomic(temp_v!(1)),
Instruction::ExecuteIsCompound(temp_v!(1)),
Instruction::ExecuteIsInteger(temp_v!(1)),
Instruction::ExecuteIsNumber(temp_v!(1)),
Instruction::ExecuteIsRational(temp_v!(1)),
Instruction::ExecuteIsFloat(temp_v!(1)),
Instruction::ExecuteIsNonVar(temp_v!(1)),
Instruction::ExecuteIsVar(temp_v!(1))
].into_iter());
for (p, instr) in self.code[impls_offset ..].iter().enumerate() {
@@ -458,6 +452,7 @@ impl Machine {
user_output,
user_error,
load_contexts: vec![],
foreign_function_table: Default::default(),
};
let mut lib_path = current_dir();
@@ -566,103 +561,436 @@ impl Machine {
self.machine_st.verify_attr_interrupt(p, arity);
}
fn next_clause_applicable(&mut self, mut offset: usize) -> bool {
loop {
match &self.code[offset] {
Instruction::IndexingCode(indexing_lines) => {
let mut oip = 0;
let mut cell = empty_list_as_cell!();
loop {
let indexing_code_ptr = match &indexing_lines[oip] {
&IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(arg, v, c, l, s)) => {
cell = self.deref_register(arg);
self.machine_st.select_switch_on_term_index(cell, v, c, l, s)
}
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(hm)) => {
let lit = self.machine_st.constant_to_literal(cell);
hm.get(&lit).cloned().unwrap_or(IndexingCodePtr::Fail)
}
IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(hm)) => {
self.machine_st.select_switch_on_structure_index(cell, hm)
}
_ => {
offset += 1;
break;
}
};
match indexing_code_ptr {
IndexingCodePtr::External(_) | IndexingCodePtr::DynamicExternal(_) => {
offset += 1;
break;
}
IndexingCodePtr::Internal(i) => oip += i,
IndexingCodePtr::Fail => return false,
}
}
}
&Instruction::GetConstant(Level::Shallow, lit, RegType::Temp(t)) => {
let cell = self.deref_register(t);
if cell.is_var() {
offset += 1;
} else if lit.get_tag() == HeapCellValueTag::CStr {
read_heap_cell!(cell,
(HeapCellValueTag::CStr) => {
if cell == lit {
offset += 1;
} else {
return false;
}
}
(HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {
offset += 1;
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
.get_name_and_arity();
if name == atom!(".") && arity == 2 {
offset += 1;
} else {
return false;
}
}
_ => {
return false;
}
);
} else {
self.machine_st.write_literal_to_var(cell, lit);
if self.machine_st.fail {
self.machine_st.fail = false;
return false;
} else {
offset += 1;
}
}
}
&Instruction::GetList(Level::Shallow, RegType::Temp(t)) => {
let cell = self.deref_register(t);
read_heap_cell!(cell,
(HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => {
offset += 1;
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]).get_name_and_arity();
if name == atom!(".") && arity == 2 {
offset += 1;
} else {
return false;
}
}
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
offset += 1;
}
_ => {
return false;
}
);
}
&Instruction::GetStructure(Level::Shallow, name, arity, RegType::Temp(t)) => {
let cell = self.deref_register(t);
read_heap_cell!(cell,
(HeapCellValueTag::Str, s) => {
if (name, arity) == cell_as_atom_cell!(self.machine_st.heap[s]).get_name_and_arity() {
offset += 1;
} else {
return false;
}
}
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
offset += 1;
}
_ => {
return false;
}
);
}
&Instruction::GetPartialString(Level::Shallow, string, RegType::Temp(t), has_tail) => {
let cell = self.deref_register(t);
read_heap_cell!(cell,
(HeapCellValueTag::CStr, cstr) => {
if !has_tail && string != cstr {
return false;
}
offset += 1;
}
(HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {
offset += 1;
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]).get_name_and_arity();
if name == atom!(".") && arity == 2 {
offset += 1;
} else {
return false;
}
}
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
offset += 1;
}
_ => {
return false;
}
);
}
Instruction::GetConstant(..) |
Instruction::GetList(..) |
Instruction::GetStructure(..) |
Instruction::GetPartialString(..) |
&Instruction::UnifyVoid(..) |
&Instruction::UnifyConstant(..) |
&Instruction::GetVariable(..) |
&Instruction::GetValue(..) |
&Instruction::UnifyVariable(..) |
&Instruction::UnifyValue(..) |
&Instruction::UnifyLocalValue(..) => {
offset += 1;
}
_ => {
break;
}
}
}
true
}
fn next_applicable_clause(&mut self, mut offset: usize) -> Option<usize> {
while !self.next_clause_applicable(self.machine_st.p + offset + 1) {
match &self.code[self.machine_st.p + offset] {
&Instruction::DefaultRetryMeElse(o) | &Instruction::RetryMeElse(o) |
&Instruction::DynamicElse(.., NextOrFail::Next(o)) |
&Instruction::DynamicInternalElse(.., NextOrFail::Next(o)) => offset += o,
_ => {
return None;
}
}
}
Some(offset)
}
fn next_inner_applicable_clause(&mut self) -> Option<u32> {
let mut inner_offset = 1u32;
loop {
match &self.code[self.machine_st.p] {
Instruction::IndexingCode(indexing_lines) => {
match &indexing_lines[self.machine_st.oip as usize] {
IndexingLine::IndexedChoice(indexed_choice) => {
match &indexed_choice[(self.machine_st.iip + inner_offset) as usize] {
&IndexedChoiceInstruction::Retry(o) => {
if self.next_clause_applicable(self.machine_st.p + o) {
return Some(inner_offset);
}
inner_offset += 1;
}
&IndexedChoiceInstruction::Trust(o) => {
return if self.next_clause_applicable(self.machine_st.p + o) {
Some(inner_offset)
} else {
None
};
}
_ => unreachable!(),
}
}
IndexingLine::DynamicIndexedChoice(indexed_choice) => {
let idx = (self.machine_st.iip + inner_offset) as usize;
let o = indexed_choice[idx];
if idx + 1 == indexed_choice.len() {
return if self.next_clause_applicable(self.machine_st.p + o) {
Some(inner_offset)
} else {
None
};
} else {
if self.next_clause_applicable(self.machine_st.p + o) {
return Some(inner_offset);
}
inner_offset += 1;
}
}
_ => unreachable!(),
}
}
_ => unreachable!(),
}
}
}
#[inline(always)]
pub(super) fn try_me_else(&mut self, offset: usize) {
if let Some(offset) = self.next_applicable_clause(offset) {
let n = self.machine_st.num_of_args;
let b = self.machine_st.stack.allocate_or_frame(n);
let or_frame = self.machine_st.stack.index_or_frame_mut(b);
or_frame.prelude.num_cells = n;
or_frame.prelude.e = self.machine_st.e;
or_frame.prelude.cp = self.machine_st.cp;
or_frame.prelude.b = self.machine_st.b;
or_frame.prelude.bp = self.machine_st.p + offset;
or_frame.prelude.boip = 0;
or_frame.prelude.biip = 0;
or_frame.prelude.tr = self.machine_st.tr;
or_frame.prelude.h = self.machine_st.heap.len();
or_frame.prelude.b0 = self.machine_st.b0;
or_frame.prelude.attr_var_queue_len = self.machine_st.attr_var_init.attr_var_queue.len();
self.machine_st.b = b;
for i in 0..n {
or_frame[i] = self.machine_st.registers[i+1];
}
self.machine_st.hb = self.machine_st.heap.len();
}
self.machine_st.p += 1;
}
#[inline(always)]
pub(super) fn indexed_try(&mut self, offset: usize) {
if let Some(iip_offset) = self.next_inner_applicable_clause() {
let n = self.machine_st.num_of_args;
let b = self.machine_st.stack.allocate_or_frame(n);
let or_frame = self.machine_st.stack.index_or_frame_mut(b);
or_frame.prelude.num_cells = n;
or_frame.prelude.e = self.machine_st.e;
or_frame.prelude.cp = self.machine_st.cp;
or_frame.prelude.b = self.machine_st.b;
or_frame.prelude.bp = self.machine_st.p;
or_frame.prelude.boip = self.machine_st.oip;
or_frame.prelude.biip = self.machine_st.iip + iip_offset; // 1
or_frame.prelude.tr = self.machine_st.tr;
or_frame.prelude.h = self.machine_st.heap.len();
or_frame.prelude.b0 = self.machine_st.b0;
or_frame.prelude.attr_var_queue_len = self.machine_st.attr_var_init.attr_var_queue.len();
self.machine_st.b = b;
for i in 0..n {
or_frame[i] = self.machine_st.registers[i+1];
}
self.machine_st.hb = self.machine_st.heap.len();
self.machine_st.oip = 0;
self.machine_st.iip = 0;
}
self.machine_st.p += offset;
}
#[inline(always)]
fn retry_me_else(&mut self, offset: usize) {
let b = self.machine_st.b;
let or_frame = self.machine_st.stack.index_or_frame_mut(b);
let n = or_frame.prelude.univ_prelude.num_cells;
let n = or_frame.prelude.num_cells;
let old_tr = or_frame.prelude.tr;
let curr_tr = self.machine_st.tr;
for i in 0..n {
self.machine_st.registers[i + 1] = or_frame[i];
}
self.machine_st.num_of_args = n;
self.machine_st.e = or_frame.prelude.e;
self.machine_st.cp = or_frame.prelude.cp;
or_frame.prelude.bp = self.machine_st.p + offset;
let old_tr = or_frame.prelude.tr;
let curr_tr = self.machine_st.tr;
let target_h = or_frame.prelude.h;
self.machine_st.tr = or_frame.prelude.tr;
self.reset_attr_var_state();
self.machine_st.hb = target_h;
self.unwind_trail(old_tr, curr_tr);
self.machine_st.trail.truncate(self.machine_st.tr);
self.machine_st.heap.truncate(target_h);
if let Some(offset) = self.next_applicable_clause(offset) {
let or_frame = self.machine_st.stack.index_or_frame_mut(b);
self.machine_st.p += 1;
self.machine_st.num_of_args = n;
self.machine_st.e = or_frame.prelude.e;
self.machine_st.cp = or_frame.prelude.cp;
or_frame.prelude.bp = self.machine_st.p + offset;
let target_h = or_frame.prelude.h;
let attr_var_queue_len = or_frame.prelude.attr_var_queue_len;
self.machine_st.tr = or_frame.prelude.tr;
self.reset_attr_var_state(attr_var_queue_len);
self.machine_st.hb = target_h;
self.machine_st.trail.truncate(self.machine_st.tr);
self.machine_st.heap.truncate(target_h);
self.machine_st.p += 1;
} else {
self.trust_me_epilogue();
}
}
#[inline(always)]
fn retry(&mut self, offset: usize) {
let b = self.machine_st.b;
let or_frame = self.machine_st.stack.index_or_frame_mut(b);
let n = or_frame.prelude.univ_prelude.num_cells;
let n = or_frame.prelude.num_cells;
let old_tr = or_frame.prelude.tr;
let curr_tr = self.machine_st.tr;
for i in 0..n {
self.machine_st.registers[i+1] = or_frame[i];
}
self.machine_st.num_of_args = n;
self.machine_st.e = or_frame.prelude.e;
self.machine_st.cp = or_frame.prelude.cp;
or_frame.prelude.biip += 1;
let old_tr = or_frame.prelude.tr;
let curr_tr = self.machine_st.tr;
let target_h = or_frame.prelude.h;
self.machine_st.tr = or_frame.prelude.tr;
self.reset_attr_var_state();
self.machine_st.hb = target_h;
self.machine_st.p = self.machine_st.p + offset;
self.unwind_trail(old_tr, curr_tr);
self.machine_st.trail.truncate(self.machine_st.tr);
self.machine_st.heap.truncate(target_h);
if let Some(iip_offset) = self.next_inner_applicable_clause() {
let or_frame = self.machine_st.stack.index_or_frame_mut(b);
self.machine_st.oip = 0;
self.machine_st.iip = 0;
self.machine_st.num_of_args = n;
self.machine_st.e = or_frame.prelude.e;
self.machine_st.cp = or_frame.prelude.cp;
or_frame.prelude.biip += iip_offset;
let target_h = or_frame.prelude.h;
let attr_var_queue_len = or_frame.prelude.attr_var_queue_len;
self.machine_st.tr = or_frame.prelude.tr;
self.machine_st.trail.truncate(self.machine_st.tr);
self.reset_attr_var_state(attr_var_queue_len);
self.machine_st.hb = target_h;
self.machine_st.p += offset;
self.machine_st.heap.truncate(target_h);
self.machine_st.oip = 0;
self.machine_st.iip = 0;
} else {
self.trust_epilogue(offset);
}
}
#[inline(always)]
fn trust(&mut self, offset: usize) {
let b = self.machine_st.b;
let or_frame = self.machine_st.stack.index_or_frame(b);
let n = or_frame.prelude.univ_prelude.num_cells;
let n = or_frame.prelude.num_cells;
let old_tr = or_frame.prelude.tr;
let curr_tr = self.machine_st.tr;
for i in 0..n {
self.machine_st.registers[i+1] = or_frame[i];
}
self.unwind_trail(old_tr, curr_tr);
self.trust_epilogue(offset);
}
#[inline(always)]
fn trust_epilogue(&mut self, offset: usize) {
let b = self.machine_st.b;
let or_frame = self.machine_st.stack.index_or_frame(b);
let n = or_frame.prelude.num_cells;
self.machine_st.num_of_args = n;
self.machine_st.e = or_frame.prelude.e;
self.machine_st.cp = or_frame.prelude.cp;
let old_tr = or_frame.prelude.tr;
let curr_tr = self.machine_st.tr;
let target_h = or_frame.prelude.h;
self.machine_st.tr = or_frame.prelude.tr;
self.machine_st.trail.truncate(self.machine_st.tr);
self.machine_st.b = or_frame.prelude.b;
self.reset_attr_var_state();
self.reset_attr_var_state(or_frame.prelude.attr_var_queue_len);
self.machine_st.hb = target_h;
self.machine_st.p = self.machine_st.p + offset;
self.unwind_trail(old_tr, curr_tr);
self.machine_st.trail.truncate(self.machine_st.tr);
self.machine_st.stack.truncate(b);
self.machine_st.heap.truncate(target_h);
@@ -674,35 +1002,63 @@ impl Machine {
fn trust_me(&mut self) {
let b = self.machine_st.b;
let or_frame = self.machine_st.stack.index_or_frame(b);
let n = or_frame.prelude.univ_prelude.num_cells;
let n = or_frame.prelude.num_cells;
for i in 0..n {
self.machine_st.registers[i+1] = or_frame[i];
}
let old_tr = or_frame.prelude.tr;
let curr_tr = self.machine_st.tr;
self.unwind_trail(old_tr, curr_tr);
self.trust_me_epilogue();
}
#[inline(always)]
fn trust_me_epilogue(&mut self) {
let b = self.machine_st.b;
let or_frame = self.machine_st.stack.index_or_frame(b);
let n = or_frame.prelude.num_cells;
self.machine_st.num_of_args = n;
self.machine_st.e = or_frame.prelude.e;
self.machine_st.cp = or_frame.prelude.cp;
let old_tr = or_frame.prelude.tr;
let curr_tr = self.machine_st.tr;
let target_h = or_frame.prelude.h;
self.machine_st.tr = or_frame.prelude.tr;
self.machine_st.b = or_frame.prelude.b;
self.reset_attr_var_state();
self.reset_attr_var_state(or_frame.prelude.attr_var_queue_len);
self.machine_st.hb = target_h;
self.machine_st.p += 1;
self.unwind_trail(old_tr, curr_tr);
self.machine_st.trail.truncate(self.machine_st.tr);
self.machine_st.stack.truncate(b);
self.machine_st.heap.truncate(target_h);
}
#[inline(always)]
fn undefined_procedure(&mut self, name: Atom, arity: usize) -> CallResult {
match self.machine_st.flags.unknown {
Unknown::Error => {
Err(self.machine_st.throw_undefined_error(name, arity))
}
Unknown::Fail => {
self.machine_st.fail = true;
Ok(())
}
Unknown::Warn => {
println!("warning: predicate {}/{} is undefined", name.as_str(), arity);
self.machine_st.fail = true;
Ok(())
}
}
}
#[inline(always)]
fn try_call(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
let compiled_tl_index = idx.p() as usize;
@@ -712,7 +1068,7 @@ impl Machine {
self.machine_st.fail = true;
}
IndexPtrTag::Undefined => {
return Err(self.machine_st.throw_undefined_error(name, arity));
return self.undefined_procedure(name, arity);
}
IndexPtrTag::DynamicIndex => {
self.machine_st.dynamic_mode = FirstOrNext::First;
@@ -735,7 +1091,7 @@ impl Machine {
self.machine_st.fail = true;
}
IndexPtrTag::Undefined => {
return Err(self.machine_st.throw_undefined_error(name, arity));
return self.undefined_procedure(name, arity);
}
IndexPtrTag::DynamicIndex => {
self.machine_st.dynamic_mode = FirstOrNext::First;
@@ -764,7 +1120,7 @@ impl Machine {
if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() {
self.try_call(name, arity, idx.get())
} else {
Err(self.machine_st.throw_undefined_error(name, arity))
self.undefined_procedure(name, arity)
}
} else {
let stub = functor_stub(name, arity);
@@ -783,14 +1139,14 @@ impl Machine {
if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() {
self.try_execute(name, arity, idx.get())
} else {
Err(self.machine_st.throw_undefined_error(name, arity))
self.undefined_procedure(name, arity)
}
} else {
if let Some(module) = self.indices.modules.get(&module_name) {
if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() {
self.try_execute(name, arity, idx.get())
} else {
Err(self.machine_st.throw_undefined_error(name, arity))
self.undefined_procedure(name, arity)
}
} else {
let stub = functor_stub(name, arity);
@@ -841,7 +1197,7 @@ impl Machine {
if let Some(&(_, b_cutoff, prev_block)) = self.machine_st.cont_pts.last() {
if self.machine_st.b < b_cutoff {
let (idx, arity) = if self.machine_st.block > prev_block {
let (idx, arity) = if self.machine_st.effective_block() > prev_block {
(r_c_w_h, 0)
} else {
self.machine_st.registers[1] = fixnum_as_cell!(
@@ -876,14 +1232,22 @@ impl Machine {
TrailEntryTag::TrailedAttrVar => {
self.machine_st.heap[h] = attr_var_as_cell!(h);
}
TrailEntryTag::TrailedAttrVarHeapLink => {
self.machine_st.heap[h] = heap_loc_as_cell!(h);
}
TrailEntryTag::TrailedAttrVarListLink => {
let l = self.machine_st.trail[i + 1].get_value() as usize;
if l < self.machine_st.hb {
self.machine_st.heap[h] = list_loc_as_cell!(l);
if h == l {
self.machine_st.heap[h] = heap_loc_as_cell!(h);
} else {
read_heap_cell!(self.machine_st.heap[l],
(HeapCellValueTag::Var) => {
self.machine_st.heap[h] = list_loc_as_cell!(l);
}
_ => {
self.machine_st.heap[h] = heap_loc_as_cell!(l);
}
);
}
} else {
self.machine_st.heap[h] = heap_loc_as_cell!(h);
}
@@ -910,4 +1274,4 @@ impl Machine {
}
}
}
}
}

View File

@@ -1,6 +1,6 @@
use crate::atom_table::*;
use ordered_float::OrderedFloat;
use rug::*;
use dashu::*;
use std::collections::BTreeMap;
use regex::Regex;
use std::collections::HashMap;

View File

@@ -181,7 +181,7 @@ impl<'a> HeapPStrIter<'a> {
self.brent_st.hare = result.focus;
} else {
read_heap_cell!(self.heap[result.focus],
(HeapCellValueTag::Lis | HeapCellValueTag::Str) => {
(HeapCellValueTag::Lis | HeapCellValueTag::Str | HeapCellValueTag::PStr) => {
self.focus = self.heap[self.brent_st.hare];
}
_ => {

View File

@@ -2,7 +2,7 @@ use crate::atom_table::*;
use crate::codegen::CodeGenSettings;
use crate::forms::*;
use crate::instructions::*;
use crate::iterators::*;
use crate::machine::disjuncts::*;
use crate::machine::loader::*;
use crate::machine::machine_errors::*;
use crate::parser::ast::*;
@@ -10,35 +10,7 @@ use crate::parser::ast::*;
use indexmap::IndexSet;
use std::cell::Cell;
use std::collections::VecDeque;
use std::convert::TryFrom;
use std::rc::Rc;
/*
* The preprocessor fabricates if-then-else ( .. -> ... ; ...)
* clauses into nameless standalone predicates, which it queues for
* later preprocessing and compilation. Fabricated predicates inherit
* explicit "cut variables" from the handwritten predicate
* surrounding their source if-then-else. They must be specially
* handled.
*/
#[derive(Clone, Copy, Debug)]
pub(crate) enum CutContext {
BlocksCuts,
HasCutVariable,
}
pub(crate) fn fold_by_str<I>(terms: I, mut term: Term, sym: Atom) -> Term
where
I: DoubleEndedIterator<Item = Term>,
{
for prec in terms.rev() {
term = Term::Clause(Cell::default(), sym, vec![prec, term]);
}
term
}
pub(crate) fn to_op_decl(
prec: u16,
@@ -132,6 +104,13 @@ fn setup_module_export(
})
}
pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term {
let head_term = Term::Clause(Cell::default(), atom!(""), vars.iter().cloned().collect());
let rule = vec![head_term, body_term];
Term::Clause(Cell::default(), atom!(":-"), rule)
}
pub(super) fn setup_module_export_list(
mut export_list: Term,
atom_tbl: &mut AtomTable,
@@ -325,110 +304,6 @@ fn setup_meta_predicate<'a, LS: LoadState<'a>>(
}
}
fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, CompilationError> {
let mut clauses = vec![];
while let Some(tl) = tls.pop_front() {
match tl {
TopLevel::Query(_) if clauses.is_empty() && tls.is_empty() => {
return Ok(tl);
}
TopLevel::Query(_) => {
return Err(CompilationError::InconsistentEntry);
}
TopLevel::Fact(fact) => {
let clause = PredicateClause::Fact(fact);
clauses.push(clause);
}
TopLevel::Rule(rule) => {
let clause = PredicateClause::Rule(rule);
clauses.push(clause);
}
TopLevel::Predicate(predicate) => clauses.extend(predicate.into_iter()),
}
}
if clauses.is_empty() {
Err(CompilationError::InconsistentEntry)
} else {
Ok(TopLevel::Predicate(clauses))
}
}
fn mark_cut_variables_as(terms: &mut Vec<Term>, name: Atom) {
for term in terms.iter_mut() {
match term {
&mut Term::Literal(_, Literal::Atom(ref mut var)) if *var == atom!("!") => {
*var = name;
}
_ => {}
}
}
}
fn mark_cut_variable(term: &mut Term) -> bool {
let cut_var_found = match term {
&mut Term::Literal(_, Literal::Atom(ref var)) if *var == atom!("!") => true,
_ => false,
};
if cut_var_found {
*term = Term::Var(Cell::default(), Rc::new(String::from("!")));
true
} else {
false
}
}
fn mark_cut_variables(terms: &mut Vec<Term>) -> bool {
let mut found_cut_var = false;
for item in terms.iter_mut() {
found_cut_var = mark_cut_variable(item) || found_cut_var;
}
found_cut_var
}
// terms is a list of goals composing one clause in a (;) functor. it
// checks that the first (and only) of these clauses is a ->. if so,
// it expands its terms using a blocked_!.
fn check_for_internal_if_then(terms: &mut Vec<Term>) {
if terms.len() != 1 {
return;
}
if let Some(Term::Clause(_, name, ref subterms)) = terms.last() {
if *name != atom!("->") || 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(), atom!(",")));
let mut pre_cut_terms = VecDeque::from(unfold_by_str(subterms.pop().unwrap(), atom!(",")));
conq_terms.push_front(Term::Literal(
Cell::default(),
Literal::Atom(atom!("blocked_!")),
));
while let Some(term) = pre_cut_terms.pop_back() {
conq_terms.push_front(term);
}
let tail_term = conq_terms.pop_back().unwrap();
terms.push(fold_by_str(
conq_terms.into_iter(),
tail_term,
atom!(","),
));
}
}
pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>,
mut terms: Vec<Term>,
@@ -570,7 +445,7 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
}
#[inline]
fn clause_to_query_term<'a, LS: LoadState<'a>>(
pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>,
name: Atom,
mut terms: Vec<Term>,
@@ -609,7 +484,7 @@ fn clause_to_query_term<'a, LS: LoadState<'a>>(
}
#[inline]
fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>,
module_name: Atom,
name: Atom,
@@ -647,308 +522,58 @@ fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
}
fn compute_head(term: &Term) -> Vec<Term> {
let mut vars = IndexSet::new();
for term in post_order_iter(term) {
if let TermRef::Var(_, _, v) = term {
vars.insert(v.clone());
}
}
vars.insert(Rc::new(String::from("!")));
vars.into_iter()
.map(|v| Term::Var(Cell::default(), v))
.collect()
}
pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term {
let head_term = Term::Clause(Cell::default(), atom!(""), vars.iter().cloned().collect());
let rule = vec![head_term, body_term];
Term::Clause(Cell::default(), atom!(":-"), rule)
}
// the terms form the body of the rule. We create a head, by
// gathering variables from the body of terms and recording them
// in the head clause.
fn build_rule(body_term: Term) -> (JumpStub, VecDeque<Term>) {
// collect the vars of body_term into a head, return the num_vars
// (the arity) as well.
let vars = compute_head(&body_term);
let rule = build_rule_body(&vars, body_term);
(vars, VecDeque::from(vec![rule]))
}
fn build_disjunct(body_term: Term) -> (JumpStub, VecDeque<Term>) {
let vars = compute_head(&body_term);
let results = unfold_by_str(body_term, atom!(";"))
.into_iter()
.map(|term| {
let mut subterms = unfold_by_str(term, atom!(","));
mark_cut_variables(&mut subterms);
check_for_internal_if_then(&mut subterms);
let term = subterms.pop().unwrap();
let clause = fold_by_str(subterms.into_iter(), term, atom!(","));
build_rule_body(&vars, clause)
})
.collect();
(vars, results)
}
fn build_if_then(prec: Term, conq: Term) -> (JumpStub, VecDeque<Term>) {
let mut prec_seq = unfold_by_str(prec, atom!(","));
let comma_sym = atom!(",");
let cut_sym = Literal::Atom(atom!("!"));
prec_seq.push(Term::Literal(Cell::default(), cut_sym));
mark_cut_variables_as(&mut prec_seq, atom!("blocked_!"));
let mut conq_seq = unfold_by_str(conq, atom!(","));
mark_cut_variables(&mut conq_seq);
prec_seq.extend(conq_seq.into_iter());
let back_term = prec_seq.pop().unwrap();
let front_term = prec_seq.pop().unwrap();
let body_term = Term::Clause(
Cell::default(),
comma_sym,
vec![front_term, back_term],
);
build_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym))
}
#[derive(Debug)]
pub(crate) struct Preprocessor {
queue: VecDeque<VecDeque<Term>>,
settings: CodeGenSettings,
}
impl Preprocessor {
pub(super) fn new(settings: CodeGenSettings) -> Self {
Preprocessor {
queue: VecDeque::new(),
settings,
}
}
fn setup_fact(&mut self, term: Term) -> Result<Term, CompilationError> {
fn setup_fact(&mut self, term: Term) -> Result<(Fact, VarData), CompilationError> {
match term {
Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => Ok(term),
Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => {
let classifier = VariableClassifier::new(
self.settings.default_call_policy(),
);
let (head, var_data) = classifier.classify_fact(term)?;
Ok((Fact { head }, var_data))
}
_ => Err(CompilationError::InadmissibleFact),
}
}
fn to_query_term<'a, LS: LoadState<'a>>(
&mut self,
loader: &mut Loader<'a, LS>,
term: Term,
) -> Result<QueryTerm, CompilationError> {
match term {
Term::Literal(_, Literal::Atom(name)) => {
if name == atom!("!") || name == atom!("blocked_!") {
Ok(QueryTerm::BlockedCut)
} else {
Ok(clause_to_query_term(
loader,
name,
vec![],
self.settings.default_call_policy(),
))
}
}
Term::Literal(_, Literal::Char('!')) => Ok(QueryTerm::BlockedCut),
Term::Var(_, ref v) if v.as_str() == "!" => {
Ok(QueryTerm::UnblockedCut(Cell::default()))
}
Term::Clause(r, name, mut terms) => match (name, terms.len()) {
(atom!(";"), 2) => {
let term = Term::Clause(r, name, terms);
let (stub, clauses) = build_disjunct(term);
self.queue.push_back(clauses);
Ok(QueryTerm::Jump(stub))
}
(atom!("->"), 2) => {
let conq = terms.pop().unwrap();
let prec = terms.pop().unwrap();
let (stub, clauses) = build_if_then(prec, conq);
self.queue.push_back(clauses);
Ok(QueryTerm::Jump(stub))
}
(atom!("\\+"), 1) => {
terms.push(Term::Literal(
Cell::default(),
Literal::Atom(atom!("$fail")),
));
let conq = Term::Literal(Cell::default(), Literal::Atom(atom!("true")));
let prec = Term::Clause(Cell::default(), atom!("->"), terms);
let terms = vec![prec, conq];
let term = Term::Clause(Cell::default(), atom!(";"), terms);
let (stub, clauses) = build_disjunct(term);
debug_assert!(clauses.len() > 0);
self.queue.push_back(clauses);
Ok(QueryTerm::Jump(stub))
}
(atom!("$get_level"), 1) => {
if let Term::Var(_, ref var) = &terms[0] {
Ok(QueryTerm::GetLevelAndUnify(Cell::default(), var.clone()))
} else {
Err(CompilationError::InadmissibleQueryTerm)
}
}
(atom!(":"), 2) => {
let predicate_name = terms.pop().unwrap();
let module_name = terms.pop().unwrap();
match (module_name, predicate_name) {
(
Term::Literal(_, Literal::Atom(module_name)),
Term::Literal(_, Literal::Atom(predicate_name)),
) => Ok(qualified_clause_to_query_term(
loader,
module_name,
predicate_name,
vec![],
self.settings.default_call_policy(),
)),
(
Term::Literal(_, Literal::Atom(module_name)),
Term::Clause(_, name, terms),
) => Ok(qualified_clause_to_query_term(
loader,
module_name,
name,
terms,
self.settings.default_call_policy()
)),
(module_name, predicate_name) => {
terms.push(module_name);
terms.push(predicate_name);
Ok(clause_to_query_term(
loader,
atom!("call"),
vec![Term::Clause(r, name, terms)],
self.settings.default_call_policy(),
))
}
}
}
_ => Ok(clause_to_query_term(loader, name, terms,
self.settings.default_call_policy())),
},
Term::Var(..) => Ok(QueryTerm::Clause(
Cell::default(),
ClauseType::CallN(1),
vec![term],
self.settings.default_call_policy(),
)),
_ => Err(CompilationError::InadmissibleQueryTerm),
}
}
fn pre_query_term<'a, LS: LoadState<'a>>(
&mut self,
loader: &mut Loader<'a, LS>,
term: Term,
) -> Result<QueryTerm, CompilationError> {
match term {
Term::Clause(r, name, mut subterms) => {
if subterms.len() == 1 && name == atom!("$call_with_inference_counting") {
self.to_query_term(loader, subterms.pop().unwrap())
.map(|mut query_term| {
query_term.set_call_policy(CallPolicy::Counted);
query_term
})
} else {
let clause = Term::Clause(r, name, subterms);
self.to_query_term(loader, clause)
}
}
_ => self.to_query_term(loader, term),
}
}
fn setup_query<'a, LS: LoadState<'a>>(
&mut self,
loader: &mut Loader<'a, LS>,
terms: Vec<Term>,
cut_context: CutContext,
) -> Result<Vec<QueryTerm>, CompilationError> {
let mut query_terms = vec![];
let mut work_queue = VecDeque::from(terms);
while let Some(term) = work_queue.pop_front() {
let mut term = term;
if let Term::Clause(cell, name, terms) = term {
if name == atom!(",") && 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(subterm);
}
continue;
} else {
term = Term::Clause(cell, name, terms);
}
}
if let CutContext::HasCutVariable = cut_context {
mark_cut_variable(&mut term);
}
query_terms.push(self.pre_query_term(loader, term)?);
}
Ok(query_terms)
}
fn setup_rule<'a, LS: LoadState<'a>>(
&mut self,
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(loader, post_head_terms, cut_context)?;
head: Term,
body: Term,
) -> Result<(Rule, VarData), CompilationError> {
let classifier = VariableClassifier::new(
self.settings.default_call_policy(),
);
let clauses = query_terms.drain(1..).collect();
let qt = query_terms.pop().unwrap();
let (head, clauses, var_data) = classifier.classify_rule(loader, head, body)?;
match terms.pop().unwrap() {
Term::Clause(_, name, terms) => Ok(Rule {
head: (name, terms, qt),
match head {
Term::Clause(_, name, terms) => Ok((Rule {
head: (name, terms),
clauses,
}),
Term::Literal(_, Literal::Atom(name)) => Ok(Rule {
head: (name, vec![], qt),
}, var_data)),
Term::Literal(_, Literal::Atom(name)) => Ok((Rule {
head: (name, vec![]),
clauses,
}),
}, var_data)),
_ => Err(CompilationError::InvalidRuleHead),
}
}
/*
fn try_term_to_query<'a, LS: LoadState<'a>>(
&mut self,
loader: &mut Loader<'a, LS>,
@@ -961,63 +586,49 @@ impl Preprocessor {
cut_context,
)?))
}
*/
pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>(
&mut self,
loader: &mut Loader<'a, LS>,
term: Term,
cut_context: CutContext,
) -> Result<TopLevel, CompilationError> {
match term {
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(
loader,
terms,
cut_context,
)?))
Term::Clause(r, name, mut terms) => {
let is_rule = name == atom!(":-") && terms.len() == 2;
if is_rule {
let tail = terms.pop().unwrap();
let head = terms.pop().unwrap();
let (rule, var_data) = self.setup_rule(loader, head, tail)?;
Ok(TopLevel::Rule(rule, var_data))
} else {
let term = Term::Clause(r, name, terms);
Ok(TopLevel::Fact(self.setup_fact(term)?))
let (fact, var_data) = self.setup_fact(term)?;
Ok(TopLevel::Fact(fact, var_data))
}
}
term => Ok(TopLevel::Fact(self.setup_fact(term)?)),
term => {
let (fact, var_data) = self.setup_fact(term)?;
Ok(TopLevel::Fact(fact, var_data))
}
}
}
/*
fn try_terms_to_tls<'a, I: IntoIterator<Item = Term>, LS: LoadState<'a>>(
&mut self,
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(loader, term, cut_context)?);
results.push_back(self.try_term_to_tl(loader, term)?);
}
Ok(results)
}
pub(super) fn parse_queue<'a, LS: LoadState<'a>>(
&mut self,
loader: &mut Loader<'a, LS>,
) -> Result<VecDeque<TopLevel>, CompilationError> {
let mut queue = VecDeque::new();
while let Some(terms) = self.queue.pop_front() {
let clauses = merge_clauses(&mut self.try_terms_to_tls(
loader,
terms,
CutContext::HasCutVariable,
)?)?;
queue.push_back(clauses);
}
Ok(queue)
}
*/
}

View File

@@ -1,7 +1,12 @@
:- module('$project_atts', [copy_term/3]).
:- use_module(library(dcgs)).
:- use_module(library(error), [can_be/2]).
:- use_module(library(lambda)).
:- use_module(library(lists), [foldl/4, maplist/2]).
project_attributes(QueryVars, AttrVars) :-
gather_attr_modules(AttrVars, Modules0),
phrase(gather_attr_modules(AttrVars), Modules0),
sort(Modules0, Modules),
call_project_attributes(Modules, QueryVars, AttrVars).
@@ -17,19 +22,14 @@ project_attributes(QueryVars, AttrVars) :-
call_project_attributes([], _, _).
call_project_attributes([Module|Modules], QueryVars, AttrVars) :-
( catch(Module:project_attributes(QueryVars, AttrVars),
E,
'$project_atts':'$print_project_attributes_exception'(Module, E)
)
E,
'$project_atts':'$print_project_attributes_exception'(Module, E)
)
-> true
; true
),
call_project_attributes(Modules, QueryVars, AttrVars).
call_attribute_goals([], _, _).
call_attribute_goals([Module|Modules], GoalCaller, AttrVars) :-
call(GoalCaller, AttrVars, Module, Goals),
call_attribute_goals(Modules, GoalCaller, AttrVars).
'$print_attribute_goals_exception'(Module, E) :-
( E = error(evaluation_error((Module:attribute_goals)/3), attribute_goals/3)
; E = error(existence_error(procedure, attribute_goals/3), attribute_goals/3)
@@ -38,20 +38,6 @@ call_attribute_goals([Module|Modules], GoalCaller, AttrVars) :-
nl
).
call_query_var_goals([], _, []).
call_query_var_goals([AttrVar|AttrVars], Module, Goals) :-
( catch(( Module:attribute_goals(AttrVar, Goals, RGoals0),
atts:'$default_attr_list'(Module, AttrVar, RGoals0, RGoals)
),
E,
( '$project_atts':'$print_attribute_goals_exception'(Module, E),
atts:'$default_attr_list'(Module, AttrVar, Goals, RGoals)
))
-> true
; atts:'$default_attr_list'(Module, AttrVar, Goals, RGoals)
),
call_query_var_goals(AttrVars, Module, RGoals).
call_attr_var_goals([], _, []).
call_attr_var_goals([AttrVar|AttrVars], Module, Goals) :-
( catch(Module:attribute_goals(AttrVar, Goals, RGoals),
@@ -77,25 +63,52 @@ call_attribute_goals_with_module_prefix([Module | Modules], GoalCaller, AttrVars
module_prefixed_goals(Goals0, Module, Goals, Gs),
call_attribute_goals_with_module_prefix(Modules, GoalCaller, AttrVars, Gs).
gather_attr_modules([]) --> [].
gather_attr_modules([AttrVar|AttrVars]) -->
{ '$get_attr_list'(AttrVar, Attrs) },
copy_attribute_modules(Attrs),
gather_attr_modules(AttrVars).
gather_attr_modules([], []).
gather_attr_modules([AttrVar|AttrVars], Modules) :-
'$get_attr_list'(AttrVar, Attrs),
copy_attribute_modules(Attrs, Modules, Modules0),
gather_attr_modules(AttrVars, Modules0).
copy_attribute_modules(Attrs) -->
{ var(Attrs) },
!.
copy_attribute_modules([Module:_|Attrs]) -->
[Module],
copy_attribute_modules(Attrs).
copy_attribute_modules(Attrs, Ls, Ls) :-
var(Attrs), !.
copy_attribute_modules([Module:_|Attrs], [Module|Modules0], Modules1) :-
copy_attribute_modules(Attrs, Modules0, Modules1).
gather_residual_goals_(M, V, V0, V1) :-
( catch(M:attribute_goals(V, V0, V1),
E,
('$project_atts':'$print_attribute_goals_exception'(M, E),
V0 = V1)
) ->
true
; V0 = V1
).
gather_residual_goals(M, V) -->
gather_residual_goals_(M, V),
atts:'$default_attr_list'(M, V).
copy_term(Source, Dest, Goals) :-
'$term_attributed_variables'(Source, AttrVars),
gather_attr_modules(AttrVars, Modules0),
sort(Modules0, Modules),
call_attribute_goals_with_module_prefix(Modules, '$project_atts':call_query_var_goals,
AttrVars, Goals0),
sort(Goals0, Goals1),
!,
'$copy_term_without_attr_vars'([Source | Goals1], [Dest | Goals]).
gather_residual_goals([]) --> [].
gather_residual_goals([V|Vs]) -->
{ '$get_attr_list'(V, Attrs),
phrase(copy_attribute_modules(Attrs), Modules0),
sort(Modules0, Modules) },
foldl(V+\M^gather_residual_goals(M, V), Modules),
gather_residual_goals(Vs).
delete_all_attributes_from_var(V) :- '$delete_all_attributes_from_var'(V).
copy_term(Term, Copy, Gs) :-
can_be(list, Gs),
findall(Term-Rs, term_residual_goals(Term,Rs), [Copy-Gs]),
( var(Gs) ->
Gs = []
; true
).
term_residual_goals(Term,Rs) :-
'$term_attributed_variables'(Term, Vs),
phrase(gather_residual_goals(Vs), Rs),
maplist(delete_all_attributes_from_var, Vs).

View File

@@ -36,14 +36,9 @@ impl Drop for Stack {
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct FramePrelude {
pub(crate) num_cells: usize,
}
#[derive(Debug)]
pub(crate) struct AndFramePrelude {
pub(crate) univ_prelude: FramePrelude,
pub(crate) num_cells: usize,
pub(crate) e: usize,
pub(crate) cp: usize,
}
@@ -113,7 +108,7 @@ impl IndexMut<usize> for Stack {
#[derive(Debug)]
pub(crate) struct OrFramePrelude {
pub(crate) univ_prelude: FramePrelude,
pub(crate) num_cells: usize,
pub(crate) e: usize,
pub(crate) cp: usize,
pub(crate) b: usize,
@@ -123,6 +118,7 @@ pub(crate) struct OrFramePrelude {
pub(crate) tr: usize,
pub(crate) h: usize,
pub(crate) b0: usize,
pub(crate) attr_var_queue_len: usize,
}
#[derive(Debug)]
@@ -206,8 +202,8 @@ impl Stack {
offset += mem::size_of::<HeapCellValue>();
}
let and_frame = &mut *(new_ptr as *mut AndFrame);
and_frame.prelude.univ_prelude.num_cells = num_cells;
let and_frame = self.index_and_frame_mut(e);
and_frame.prelude.num_cells = num_cells;
e
}
@@ -230,8 +226,8 @@ impl Stack {
offset += mem::size_of::<HeapCellValue>();
}
let or_frame = &mut *(new_ptr as *mut OrFrame);
or_frame.prelude.univ_prelude.num_cells = num_cells;
let or_frame = self.index_or_frame_mut(b);
or_frame.prelude.num_cells = num_cells;
b
}
@@ -297,7 +293,7 @@ mod tests {
0// 10 * mem::size_of::<HeapCellValue>() + prelude_size::<AndFrame>()
);
assert_eq!(and_frame.prelude.univ_prelude.num_cells, 10);
assert_eq!(and_frame.prelude.num_cells, 10);
for idx in 0..10 {
assert_eq!(and_frame[idx + 1], stack_loc_as_cell!(AndFrame, e, idx + 1));

View File

@@ -9,6 +9,7 @@ use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::*;
use crate::types::*;
use crate::http::HttpResponse;
pub use modular_bitfield::prelude::*;
@@ -26,7 +27,6 @@ use std::ops::{Deref, DerefMut};
use std::ptr;
use native_tls::TlsStream;
use hyper::body::{Bytes, Sender};
#[derive(Debug, BitfieldSpecifier, Clone, Copy, PartialEq, Eq, Hash)]
#[bits = 1]
@@ -102,6 +102,13 @@ impl EOFAction {
#[derive(Debug)]
pub struct ByteStream(Cursor<Vec<u8>>);
impl ByteStream {
#[inline(always)]
pub fn from_string(string: String) -> Self {
ByteStream(Cursor::new(string.into()))
}
}
impl Read for ByteStream {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
@@ -269,28 +276,42 @@ impl Read for HttpReadStream {
}
pub struct HttpWriteStream {
body_writer: Sender,
status_code: u16,
headers: hyper::HeaderMap,
response: TypedArenaPtr<HttpResponse>,
buffer: Vec<u8>,
}
impl Debug for HttpWriteStream {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Http Write Stream")
write!(f, "Http Write Stream")
}
}
impl Write for HttpWriteStream {
#[inline]
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let bytes = Bytes::copy_from_slice(buf);
let len = bytes.len();
match self.body_writer.try_send_data(bytes) {
Ok(()) => Ok(len),
Err(_) => Err(std::io::Error::from(ErrorKind::Interrupted))
}
self.buffer.extend_from_slice(buf);
Ok(buf.len())
}
#[inline]
fn flush(&mut self) -> std::io::Result<()> {
let (ready, response, cvar) = &**self.response;
let mut ready = ready.lock().unwrap();
{
let mut response = response.lock().unwrap();
let bytes = bytes::Bytes::copy_from_slice(&self.buffer);
let mut response_ = hyper::Response::builder()
.status(self.status_code);
*response_.headers_mut().unwrap() = self.headers.clone();
*response = Some(response_.body(http_body_util::Full::new(bytes)).unwrap());
}
*ready = true;
cvar.notify_one();
Ok(())
}
}
@@ -505,7 +526,7 @@ impl Stream {
ArenaHeaderTag::NamedTcpStream => Stream::NamedTcp(TypedArenaPtr::new(ptr as *mut _)),
ArenaHeaderTag::NamedTlsStream => Stream::NamedTls(TypedArenaPtr::new(ptr as *mut _)),
ArenaHeaderTag::HttpReadStream => Stream::HttpRead(TypedArenaPtr::new(ptr as *mut _)),
ArenaHeaderTag::HttpWriteStream => Stream::HttpWrite(TypedArenaPtr::new(ptr as *mut _)),
ArenaHeaderTag::HttpWriteStream => Stream::HttpWrite(TypedArenaPtr::new(ptr as *mut _)),
ArenaHeaderTag::ReadlineStream => Stream::Readline(TypedArenaPtr::new(ptr as *mut _)),
ArenaHeaderTag::StaticStringStream => {
Stream::StaticString(TypedArenaPtr::new(ptr as *mut _))
@@ -559,7 +580,7 @@ impl Stream {
Stream::NamedTcp(ptr) => ptr.header_ptr(),
Stream::NamedTls(ptr) => ptr.header_ptr(),
Stream::HttpRead(ptr) => ptr.header_ptr(),
Stream::HttpWrite(ptr) => ptr.header_ptr(),
Stream::HttpWrite(ptr) => ptr.header_ptr(),
Stream::Null(_) => ptr::null(),
Stream::Readline(ptr) => ptr.header_ptr(),
Stream::StandardOutput(ptr) => ptr.header_ptr(),
@@ -576,7 +597,7 @@ impl Stream {
Stream::NamedTcp(ref ptr) => &ptr.options,
Stream::NamedTls(ref ptr) => &ptr.options,
Stream::HttpRead(ref ptr) => &ptr.options,
Stream::HttpWrite(ref ptr) => &ptr.options,
Stream::HttpWrite(ref ptr) => &ptr.options,
Stream::Null(ref options) => options,
Stream::Readline(ref ptr) => &ptr.options,
Stream::StandardOutput(ref ptr) => &ptr.options,
@@ -593,7 +614,7 @@ impl Stream {
Stream::NamedTcp(ref mut ptr) => &mut ptr.options,
Stream::NamedTls(ref mut ptr) => &mut ptr.options,
Stream::HttpRead(ref mut ptr) => &mut ptr.options,
Stream::HttpWrite(ref mut ptr) => &mut ptr.options,
Stream::HttpWrite(ref mut ptr) => &mut ptr.options,
Stream::Null(ref mut options) => options,
Stream::Readline(ref mut ptr) => &mut ptr.options,
Stream::StandardOutput(ref mut ptr) => &mut ptr.options,
@@ -611,7 +632,7 @@ impl Stream {
Stream::NamedTcp(ptr) => ptr.lines_read += incr_num_lines_read,
Stream::NamedTls(ptr) => ptr.lines_read += incr_num_lines_read,
Stream::HttpRead(ptr) => ptr.lines_read += incr_num_lines_read,
Stream::HttpWrite(_) => {}
Stream::HttpWrite(_) => {}
Stream::Null(_) => {}
Stream::Readline(ptr) => ptr.lines_read += incr_num_lines_read,
Stream::StandardOutput(ptr) => ptr.lines_read += incr_num_lines_read,
@@ -629,7 +650,7 @@ impl Stream {
Stream::NamedTcp(ptr) => ptr.lines_read = value,
Stream::NamedTls(ptr) => ptr.lines_read = value,
Stream::HttpRead(ptr) => ptr.lines_read = value,
Stream::HttpWrite(_) => {}
Stream::HttpWrite(_) => {}
Stream::Null(_) => {}
Stream::Readline(ptr) => ptr.lines_read = value,
Stream::StandardOutput(ptr) => ptr.lines_read = value,
@@ -647,7 +668,7 @@ impl Stream {
Stream::NamedTcp(ptr) => ptr.lines_read,
Stream::NamedTls(ptr) => ptr.lines_read,
Stream::HttpRead(ptr) => ptr.lines_read,
Stream::HttpWrite(_) => 0,
Stream::HttpWrite(_) => 0,
Stream::Null(_) => 0,
Stream::Readline(ptr) => ptr.lines_read,
Stream::StandardOutput(ptr) => ptr.lines_read,
@@ -669,7 +690,7 @@ impl CharRead for Stream {
Stream::OutputFile(_) |
Stream::StandardError(_) |
Stream::StandardOutput(_) |
Stream::HttpWrite(_) |
Stream::HttpWrite(_) |
Stream::Null(_) => Some(Err(std::io::Error::new(
ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream,
@@ -689,7 +710,7 @@ impl CharRead for Stream {
Stream::OutputFile(_) |
Stream::StandardError(_) |
Stream::StandardOutput(_) |
Stream::HttpWrite(_) |
Stream::HttpWrite(_) |
Stream::Null(_) => Some(Err(std::io::Error::new(
ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream,
@@ -709,7 +730,7 @@ impl CharRead for Stream {
Stream::OutputFile(_) |
Stream::StandardError(_) |
Stream::StandardOutput(_) |
Stream::HttpWrite(_) |
Stream::HttpWrite(_) |
Stream::Null(_) => {}
}
}
@@ -726,7 +747,7 @@ impl CharRead for Stream {
Stream::OutputFile(_) |
Stream::StandardError(_) |
Stream::StandardOutput(_) |
Stream::HttpWrite(_) |
Stream::HttpWrite(_) |
Stream::Null(_) => {}
}
}
@@ -744,13 +765,13 @@ impl Read for Stream {
Stream::StaticString(src) => (*src).read(buf),
Stream::Byte(cursor) => (*cursor).read(buf),
Stream::OutputFile(_)
| Stream::StandardError(_)
| Stream::StandardOutput(_)
| Stream::HttpWrite(_)
| Stream::Null(_) => Err(std::io::Error::new(
ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream,
)),
| Stream::StandardError(_)
| Stream::StandardOutput(_)
| Stream::HttpWrite(_)
| Stream::Null(_) => Err(std::io::Error::new(
ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream,
)),
};
bytes_read
@@ -766,7 +787,7 @@ impl Write for Stream {
Stream::Byte(ref mut cursor) => cursor.get_mut().write(buf),
Stream::StandardOutput(stream) => stream.write(buf),
Stream::StandardError(stream) => stream.write(buf),
Stream::HttpWrite(ref mut stream) => stream.get_mut().write(buf),
Stream::HttpWrite(ref mut stream) => stream.get_mut().write(buf),
Stream::HttpRead(_) |
Stream::StaticString(_) |
Stream::Readline(_) |
@@ -786,7 +807,7 @@ impl Write for Stream {
Stream::Byte(ref mut cursor) => cursor.stream.get_mut().flush(),
Stream::StandardError(stream) => stream.stream.flush(),
Stream::StandardOutput(stream) => stream.stream.flush(),
Stream::HttpWrite(ref mut stream) => stream.stream.get_mut().flush(),
Stream::HttpWrite(ref mut stream) => stream.stream.get_mut().flush(),
Stream::HttpRead(_) |
Stream::StaticString(_) |
Stream::Readline(_) |
@@ -863,19 +884,38 @@ impl PartialEq for Stream {
impl Eq for Stream {}
fn cursor_position<T>(past_end_of_stream: &mut bool, cursor: &Cursor<T>, cursor_len: u64) -> AtEndOfStream {
let position = cursor.position();
let at_end_of_stream = match position.cmp(&cursor_len) {
Ordering::Equal => AtEndOfStream::At,
Ordering::Greater => {
*past_end_of_stream = true;
AtEndOfStream::Past
}
Ordering::Less => AtEndOfStream::Not,
};
at_end_of_stream
}
impl Stream {
#[inline]
pub(crate) fn position(&mut self) -> Option<(u64, usize)> {
// returns lines_read, position.
let result = match self {
Stream::Byte(byte_stream_layout) => {
Some(byte_stream_layout.stream.get_ref().0.position())
}
Stream::StaticString(string_stream_layout) => {
Some(string_stream_layout.stream.stream.position())
}
Stream::InputFile(file_stream) => {
file_stream.position()
}
Stream::NamedTcp(..)
| Stream::NamedTls(..)
| Stream::Readline(..)
| Stream::StaticString(..)
| Stream::Byte(..) => Some(0),
Stream::NamedTcp(..) | Stream::NamedTls(..) | Stream::Readline(..) => {
Some(0)
}
_ => None,
};
@@ -913,7 +953,7 @@ impl Stream {
Stream::NamedTcp(stream) => stream.past_end_of_stream,
Stream::NamedTls(stream) => stream.past_end_of_stream,
Stream::HttpRead(stream) => stream.past_end_of_stream,
Stream::HttpWrite(stream) => stream.past_end_of_stream,
Stream::HttpWrite(stream) => stream.past_end_of_stream,
Stream::Null(_) => false,
Stream::Readline(stream) => stream.past_end_of_stream,
Stream::StandardOutput(stream) => stream.past_end_of_stream,
@@ -936,7 +976,7 @@ impl Stream {
Stream::NamedTcp(stream) => stream.past_end_of_stream = value,
Stream::NamedTls(stream) => stream.past_end_of_stream = value,
Stream::HttpRead(stream) => stream.past_end_of_stream = value,
Stream::HttpWrite(stream) => stream.past_end_of_stream = value,
Stream::HttpWrite(stream) => stream.past_end_of_stream = value,
Stream::Null(_) => {}
Stream::Readline(stream) => stream.past_end_of_stream = value,
Stream::StandardOutput(stream) => stream.past_end_of_stream = value,
@@ -950,38 +990,61 @@ impl Stream {
return AtEndOfStream::Past;
}
if let Stream::InputFile(stream_layout) = self {
let position = stream_layout.position();
match self {
Stream::Byte(stream_layout) => {
let StreamLayout {
past_end_of_stream,
stream,
..
} = &mut **stream_layout;
let StreamLayout {
past_end_of_stream,
stream,
..
} = &mut **stream_layout;
let cursor_len = stream.get_ref().0.get_ref().len() as u64;
cursor_position(past_end_of_stream, &stream.get_ref().0, cursor_len)
}
Stream::StaticString(stream_layout) => {
let StreamLayout {
past_end_of_stream,
stream,
..
} = &mut **stream_layout;
match stream.get_ref().file.metadata() {
Ok(metadata) => {
if let Some(position) = position {
return match position.cmp(&metadata.len()) {
Ordering::Equal => AtEndOfStream::At,
Ordering::Less => AtEndOfStream::Not,
Ordering::Greater => {
*past_end_of_stream = true;
AtEndOfStream::Past
let cursor_len = stream.stream.get_ref().len() as u64;
cursor_position(past_end_of_stream, &stream.stream, cursor_len)
}
Stream::InputFile(stream_layout) => {
let position = stream_layout.position();
let StreamLayout {
past_end_of_stream,
stream,
..
} = &mut **stream_layout;
match stream.get_ref().file.metadata() {
Ok(metadata) => {
if let Some(position) = position {
match position.cmp(&metadata.len()) {
Ordering::Equal => AtEndOfStream::At,
Ordering::Less => AtEndOfStream::Not,
Ordering::Greater => {
*past_end_of_stream = true;
AtEndOfStream::Past
}
}
};
} else {
} else {
*past_end_of_stream = true;
AtEndOfStream::Past
}
}
_ => {
*past_end_of_stream = true;
AtEndOfStream::Past
}
}
_ => {
*past_end_of_stream = true;
AtEndOfStream::Past
}
}
} else {
AtEndOfStream::Not
_ => {
AtEndOfStream::Not
}
}
}
@@ -1000,10 +1063,10 @@ impl Stream {
pub(crate) fn mode(&self) -> Atom {
match self {
Stream::Byte(_)
| Stream::Readline(_)
| Stream::StaticString(_)
| Stream::HttpRead(_)
| Stream::InputFile(..) => atom!("read"),
| Stream::Readline(_)
| Stream::StaticString(_)
| Stream::HttpRead(_)
| Stream::InputFile(..) => atom!("read"),
Stream::NamedTcp(..) | Stream::NamedTls(..) => atom!("read_append"),
Stream::OutputFile(file) if file.is_append => atom!("append"),
Stream::OutputFile(_) | Stream::StandardError(_) | Stream::StandardOutput(_) | Stream::HttpWrite(_) => atom!("write"),
@@ -1077,12 +1140,17 @@ impl Stream {
#[inline]
pub(crate) fn from_http_sender(
body_writer: Sender,
response: TypedArenaPtr<HttpResponse>,
status_code: u16,
headers: hyper::HeaderMap,
arena: &mut Arena,
) -> Self {
Stream::HttpWrite(arena_alloc!(
StreamLayout::new(CharReader::new(HttpWriteStream {
body_writer
response,
status_code,
headers,
buffer: Vec::new(),
})),
arena
))
@@ -1135,11 +1203,11 @@ impl Stream {
Stream::HttpWrite(ref mut http_stream) => {
unsafe {
http_stream.set_tag(ArenaHeaderTag::Dropped);
std::ptr::drop_in_place(&mut http_stream.inner_mut().body_writer as *mut _);
std::ptr::drop_in_place(&mut http_stream.inner_mut().buffer as *mut _);
}
Ok(())
}
}
Stream::InputFile(mut file_stream) => {
// close the stream by dropping the inner File.
unsafe {
@@ -1175,12 +1243,12 @@ impl Stream {
pub(crate) fn is_input_stream(&self) -> bool {
match self {
Stream::NamedTcp(..)
| Stream::NamedTls(..)
| Stream::HttpRead(..)
| Stream::Byte(_)
| Stream::Readline(_)
| Stream::StaticString(_)
| Stream::InputFile(..) => true,
| Stream::NamedTls(..)
| Stream::HttpRead(..)
| Stream::Byte(_)
| Stream::Readline(_)
| Stream::StaticString(_)
| Stream::InputFile(..) => true,
_ => false,
}
}
@@ -1189,12 +1257,12 @@ impl Stream {
pub(crate) fn is_output_stream(&self) -> bool {
match self {
Stream::StandardError(_)
| Stream::StandardOutput(_)
| Stream::NamedTcp(..)
| Stream::NamedTls(..)
| Stream::HttpWrite(..)
| Stream::Byte(_)
| Stream::OutputFile(..) => true,
| Stream::StandardOutput(_)
| Stream::NamedTcp(..)
| Stream::NamedTls(..)
| Stream::HttpWrite(..)
| Stream::Byte(_)
| Stream::OutputFile(..) => true,
_ => false,
}
}
@@ -1242,12 +1310,9 @@ impl Stream {
}
}
Stream::InputFile(ref mut file) => {
let mut b = [0u8; 1];
match file.read(&mut b)? {
1 => {
file.stream.get_mut().file.seek(SeekFrom::Current(-1))?;
Ok(b[0])
match file.peek_byte() {
Some(result) => {
Ok(result?)
}
_ => Err(std::io::Error::new(
ErrorKind::UnexpectedEof,
@@ -1283,7 +1348,7 @@ impl MachineState {
match eof_action {
EOFAction::Error => {
stream.set_past_end_of_stream(true);
return Err(self.open_past_eos_error(stream, caller, arity));
Err(self.open_past_eos_error(stream, caller, arity))
}
EOFAction::EOFCode => {
let end_of_stream = if stream.options().stream_type() == StreamType::Binary {
@@ -1313,101 +1378,101 @@ impl MachineState {
stream_type: HeapCellValue,
) -> StreamOptions {
let alias = read_heap_cell!(self.store(MachineState::deref(self, alias)),
(HeapCellValueTag::Atom, (name, arity)) => {
debug_assert_eq!(arity, 0);
(HeapCellValueTag::Atom, (name, arity)) => {
debug_assert_eq!(arity, 0);
if name != atom!("[]") {
Some(name)
} else {
None
}
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
if name != atom!("[]") {
Some(name)
} else {
None
}
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
debug_assert_eq!(arity, 0);
if name != atom!("[]") {
Some(name)
} else {
None
}
}
_ => {
None
}
if name != atom!("[]") {
Some(name)
} else {
None
}
}
_ => {
None
}
);
let eof_action = read_heap_cell!(self.store(MachineState::deref(self, eof_action)),
(HeapCellValueTag::Atom, (name, arity)) => {
debug_assert_eq!(arity, 0);
(HeapCellValueTag::Atom, (name, arity)) => {
debug_assert_eq!(arity, 0);
match name {
atom!("eof_code") => EOFAction::EOFCode,
atom!("error") => EOFAction::Error,
atom!("reset") => EOFAction::Reset,
_ => unreachable!(),
}
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
match name {
atom!("eof_code") => EOFAction::EOFCode,
atom!("error") => EOFAction::Error,
atom!("reset") => EOFAction::Reset,
_ => unreachable!(),
}
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
debug_assert_eq!(arity, 0);
match name {
atom!("eof_code") => EOFAction::EOFCode,
atom!("error") => EOFAction::Error,
atom!("reset") => EOFAction::Reset,
_ => unreachable!(),
}
}
_ => {
unreachable!()
}
match name {
atom!("eof_code") => EOFAction::EOFCode,
atom!("error") => EOFAction::Error,
atom!("reset") => EOFAction::Reset,
_ => unreachable!(),
}
}
_ => {
unreachable!()
}
);
let reposition = read_heap_cell!(self.store(MachineState::deref(self, reposition)),
(HeapCellValueTag::Atom, (name, arity)) => {
debug_assert_eq!(arity, 0);
name == atom!("true")
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
(HeapCellValueTag::Atom, (name, arity)) => {
debug_assert_eq!(arity, 0);
name == atom!("true")
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
name == atom!("true")
}
_ => {
unreachable!()
}
debug_assert_eq!(arity, 0);
name == atom!("true")
}
_ => {
unreachable!()
}
);
let stream_type = read_heap_cell!(self.store(MachineState::deref(self, stream_type)),
(HeapCellValueTag::Atom, (name, arity)) => {
debug_assert_eq!(arity, 0);
match name {
atom!("text") => StreamType::Text,
atom!("binary") => StreamType::Binary,
_ => unreachable!(),
}
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
(HeapCellValueTag::Atom, (name, arity)) => {
debug_assert_eq!(arity, 0);
match name {
atom!("text") => StreamType::Text,
atom!("binary") => StreamType::Binary,
_ => unreachable!(),
}
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
match name {
atom!("text") => StreamType::Text,
atom!("binary") => StreamType::Binary,
_ => unreachable!(),
}
}
_ => {
unreachable!()
}
debug_assert_eq!(arity, 0);
match name {
atom!("text") => StreamType::Text,
atom!("binary") => StreamType::Binary,
_ => unreachable!(),
}
}
_ => {
unreachable!()
}
);
let mut options = StreamOptions::default();
@@ -1430,60 +1495,60 @@ impl MachineState {
let addr = self.store(MachineState::deref(self, addr));
read_heap_cell!(addr,
(HeapCellValueTag::Atom, (name, arity)) => {
debug_assert_eq!(arity, 0);
(HeapCellValueTag::Atom, (name, arity)) => {
debug_assert_eq!(arity, 0);
return match stream_aliases.get(&name) {
Some(stream) if !stream.is_null_stream() => Ok(*stream),
_ => {
let stub = functor_stub(caller, arity);
let addr = atom_as_cell!(name);
return match stream_aliases.get(&name) {
Some(stream) if !stream.is_null_stream() => Ok(*stream),
_ => {
let stub = functor_stub(caller, arity);
let addr = atom_as_cell!(name);
let existence_error = self.existence_error(ExistenceError::Stream(addr));
let existence_error = self.existence_error(ExistenceError::Stream(addr));
Err(self.error_form(existence_error, stub))
}
};
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
Err(self.error_form(existence_error, stub))
}
};
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
debug_assert_eq!(arity, 0);
return match stream_aliases.get(&name) {
Some(stream) if !stream.is_null_stream() => Ok(*stream),
_ => {
let stub = functor_stub(caller, arity);
let addr = atom_as_cell!(name);
return match stream_aliases.get(&name) {
Some(stream) if !stream.is_null_stream() => Ok(*stream),
_ => {
let stub = functor_stub(caller, arity);
let addr = atom_as_cell!(name);
let existence_error = self.existence_error(ExistenceError::Stream(addr));
let existence_error = self.existence_error(ExistenceError::Stream(addr));
Err(self.error_form(existence_error, stub))
}
};
}
(HeapCellValueTag::Cons, ptr) => {
match_untyped_arena_ptr!(ptr,
(ArenaHeaderTag::Stream, stream) => {
return if stream.is_null_stream() {
Err(self.open_permission_error(stream_as_cell!(stream), caller, arity))
} else {
Ok(stream)
};
}
(ArenaHeaderTag::Dropped, _value) => {
let stub = functor_stub(caller, arity);
let err = self.existence_error(ExistenceError::Stream(addr));
Err(self.error_form(existence_error, stub))
}
};
}
(HeapCellValueTag::Cons, ptr) => {
match_untyped_arena_ptr!(ptr,
(ArenaHeaderTag::Stream, stream) => {
return if stream.is_null_stream() {
Err(self.open_permission_error(stream_as_cell!(stream), caller, arity))
} else {
Ok(stream)
};
}
(ArenaHeaderTag::Dropped, _value) => {
let stub = functor_stub(caller, arity);
let err = self.existence_error(ExistenceError::Stream(addr));
return Err(self.error_form(err, stub));
}
_ => {
}
);
}
_ => {
}
return Err(self.error_form(err, stub));
}
_ => {
}
);
}
_ => {
}
);
let stub = functor_stub(caller, arity);
@@ -1497,20 +1562,10 @@ impl MachineState {
}
}
pub(crate) fn open_parsing_stream(
&mut self,
mut stream: Stream,
stub_name: Atom,
stub_arity: usize,
) -> Result<Stream, MachineStub> {
pub(crate) fn open_parsing_stream(&mut self, mut stream: Stream) -> Result<Stream, ParserError> {
match stream.peek_char() {
None => Ok(stream), // empty stream is handled gracefully by Lexer::eof
Some(Err(e)) => {
let err = self.session_error(SessionError::from(e));
let stub = functor_stub(stub_name, stub_arity);
Err(self.error_form(err, stub))
}
Some(Err(e)) => Err(ParserError::IO(e)),
Some(Ok(c)) => {
if c == '\u{feff}' {
// skip UTF-8 BOM
@@ -1531,7 +1586,15 @@ impl MachineState {
arity: usize,
) -> MachineStub {
let stub = functor_stub(caller, arity);
let err = self.permission_error(perm, err_atom, stream_as_cell!(stream));
let err = self.permission_error(
perm,
err_atom,
if let Some(alias) = stream.options().get_alias() {
atom_as_cell!(alias)
} else {
stream_as_cell!(stream)
},
);
self.error_form(err, stub)
}
@@ -1699,7 +1762,7 @@ impl MachineState {
}
ErrorKind::PermissionDenied => {
// 8.11.5.3k)
return Err(self.open_permission_error(self[temp_v!(1)], atom!("open"), 4));
return Err(self.open_permission_error(self.registers[1], atom!("open"), 4));
}
_ => {
let stub = functor_stub(atom!("open"), 4);

File diff suppressed because it is too large Load Diff

View File

@@ -5,6 +5,7 @@ use crate::machine::loader::*;
use crate::machine::machine_errors::*;
use crate::parser::ast::*;
use crate::parser::parser::*;
use crate::read::devour_whitespace;
use crate::predicate_queue;
@@ -52,14 +53,14 @@ impl<'a> TermStream for BootstrappingTermStream<'a> {
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError> {
self.parser.reset();
self.parser
.read_term(op_dir)
.read_term(op_dir, Tokens::Default)
.map_err(CompilationError::from)
}
#[inline]
fn eof(&mut self) -> Result<bool, CompilationError> {
self.parser.devour_whitespace()?; // eliminate dangling comments before checking for EOF.
Ok(self.parser.eof()?)
devour_whitespace(&mut self.parser) // eliminate dangling comments before checking for EOF.
.map_err(CompilationError::from)
}
#[inline]
@@ -111,7 +112,7 @@ impl TermStream for LiveTermStream {
#[inline]
fn eof(&mut self) -> Result<bool, CompilationError> {
return Ok(self.term_queue.is_empty());
Ok(self.term_queue.is_empty())
}
#[inline]
@@ -125,15 +126,15 @@ pub struct InlineTermStream {
impl TermStream for InlineTermStream {
fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
Err(CompilationError::from(ParserError::UnexpectedEOF))
Err(CompilationError::from(ParserError::unexpected_eof()))
}
fn eof(&mut self) -> Result<bool, CompilationError> {
Ok(true)
Ok(true)
}
fn listing_src(&self) -> &ListingSource {
&ListingSource::User
&ListingSource::User
}
}

788
src/machine/unify.rs Normal file
View File

@@ -0,0 +1,788 @@
use crate::arena::*;
use crate::forms::*;
use crate::heap_iter::stackful_preorder_iter;
use crate::machine::*;
use crate::machine::machine_state::*;
use crate::machine::partial_string::*;
use crate::types::*;
use std::cmp::Ordering;
use std::ops::{Deref, DerefMut};
use derive_deref::*;
use fxhash::FxBuildHasher;
use indexmap::IndexSet;
pub(crate) trait Unifier: DerefMut<Target = MachineState> {
fn unify_structure(&mut self, s1: usize, value: HeapCellValue) {
// s1 is the value of a STR cell.
let (n1, a1) = cell_as_atom_cell!(self.heap[s1]).get_name_and_arity();
read_heap_cell!(value,
(HeapCellValueTag::Str, s2) => {
let (n2, a2) = cell_as_atom_cell!(self.heap[s2])
.get_name_and_arity();
if n1 == n2 && a1 == a2 {
for idx in (0..a1).rev() {
self.pdl.push(heap_loc_as_cell!(s2+1+idx));
self.pdl.push(heap_loc_as_cell!(s1+1+idx));
}
} else {
self.fail = true;
}
}
(HeapCellValueTag::Lis, l2) => {
if a1 == 2 && n1 == atom!(".") {
for idx in (0..2).rev() {
self.pdl.push(heap_loc_as_cell!(l2+1+idx));
self.pdl.push(heap_loc_as_cell!(s1+1+idx));
}
} else {
self.fail = true;
}
}
(HeapCellValueTag::Atom, (n2, a2)) => {
self.fail = !(a1 == 0 && a2 == 0 && n1 == n2);
}
(HeapCellValueTag::AttrVar, h) => {
Self::bind(self, Ref::attr_var(h), str_loc_as_cell!(s1));
}
(HeapCellValueTag::Var, h) => {
Self::bind(self, Ref::heap_cell(h), str_loc_as_cell!(s1));
}
(HeapCellValueTag::StackVar, s) => {
Self::bind(self, Ref::stack_cell(s), str_loc_as_cell!(s1));
}
_ => {
self.fail = true;
}
);
}
fn unify_list(&mut self, l1: usize, value: HeapCellValue) {
read_heap_cell!(value,
(HeapCellValueTag::Lis, l2) => {
for idx in (0..2).rev() {
self.pdl.push(heap_loc_as_cell!(l2 + idx));
self.pdl.push(heap_loc_as_cell!(l1 + idx));
}
}
(HeapCellValueTag::Str, s2) => {
let (n2, a2) = cell_as_atom_cell!(self.heap[s2])
.get_name_and_arity();
if a2 == 2 && n2 == atom!(".") {
for idx in (0..2).rev() {
self.pdl.push(heap_loc_as_cell!(s2+1+idx));
self.pdl.push(heap_loc_as_cell!(l1+idx));
}
} else {
self.fail = true;
}
}
(HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr | HeapCellValueTag::PStr) => {
Self::unify_partial_string(self, list_loc_as_cell!(l1), value)
}
(HeapCellValueTag::AttrVar, h) => {
Self::bind(self, Ref::attr_var(h), list_loc_as_cell!(l1));
}
(HeapCellValueTag::Var, h) => {
Self::bind(self, Ref::heap_cell(h), list_loc_as_cell!(l1));
}
(HeapCellValueTag::StackVar, s) => {
Self::bind(self, Ref::stack_cell(s), list_loc_as_cell!(l1));
}
_ => {
self.fail = true;
}
);
}
fn unify_complete_string(&mut self, atom: Atom, value: HeapCellValue) {
if let Some(r) = value.as_var() {
if atom == atom!("") {
Self::bind(self, r, atom_as_cell!(atom!("[]")));
} else {
Self::bind(self, r, atom_as_cstr_cell!(atom));
}
return;
}
read_heap_cell!(value,
(HeapCellValueTag::Atom, (cstr_atom, arity)) if atom == atom!("") => {
debug_assert_eq!(arity, 0);
self.fail = cstr_atom != atom!("[]");
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
if arity == 0 {
self.fail = atom == atom!("") && name != atom!("[]");
} else {
// this is intentionally the same policy for
// value.tag() == Lis and PStrLoc. they're not
// grouped together to allow for arity == 0.
Self::unify_partial_string(self, atom_as_cstr_cell!(atom), value);
if !self.pdl.is_empty() {
Self::unify_internal(self);
}
}
}
(HeapCellValueTag::CStr, cstr_atom) => {
self.fail = atom != cstr_atom;
}
(HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {
Self::unify_partial_string(self, atom_as_cstr_cell!(atom), value);
if !self.pdl.is_empty() {
Self::unify_internal(self);
}
}
_ => {
self.fail = true;
}
);
}
// the return value of unify_partial_string is interpreted as
// follows:
//
// Some(None) -- the strings are equal, nothing to unify
// Some(Some(f2,f1)) -- prefixes equal, try to unify focus values f2, f1
// None -- prefixes not equal, unification fails
//
// d1's tag is assumed to be one of LIS, STR or PSTRLOC.
fn unify_partial_string(&mut self, value_1: HeapCellValue, value_2: HeapCellValue) {
if let Some(r) = value_2.as_var() {
Self::bind(self, r, value_1);
return;
}
let machine_st = self.deref_mut();
let s1 = machine_st.heap.len();
machine_st.heap.push(value_1);
machine_st.heap.push(value_2);
let mut pstr_iter1 = HeapPStrIter::new(&machine_st.heap, s1);
let mut pstr_iter2 = HeapPStrIter::new(&machine_st.heap, s1 + 1);
match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) {
PStrCmpResult::Ordered(Ordering::Equal) => {}
PStrCmpResult::Ordered(Ordering::Less) => {
if pstr_iter2.focus.as_var().is_none() {
machine_st.fail = true;
} else {
machine_st.pdl.push(empty_list_as_cell!());
machine_st.pdl.push(pstr_iter2.focus);
}
}
PStrCmpResult::Ordered(Ordering::Greater) => {
if pstr_iter1.focus.as_var().is_none() {
machine_st.fail = true;
} else {
machine_st.pdl.push(empty_list_as_cell!());
machine_st.pdl.push(pstr_iter1.focus);
}
}
continuable @ PStrCmpResult::FirstIterContinuable(iteratee) |
continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => {
if continuable.is_second_iter() {
std::mem::swap(&mut pstr_iter1, &mut pstr_iter2);
}
let mut chars_iter = PStrCharsIter {
iter: pstr_iter1,
item: Some(iteratee),
};
let mut focus = pstr_iter2.focus;
'outer: loop {
while let Some(c) = chars_iter.peek() {
read_heap_cell!(focus,
(HeapCellValueTag::Lis, l) => {
let val = pstr_iter2.heap[l];
machine_st.pdl.push(val);
machine_st.pdl.push(char_as_cell!(c));
focus = pstr_iter2.heap[l+1];
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(pstr_iter2.heap[s])
.get_name_and_arity();
if name == atom!(".") && arity == 2 {
machine_st.pdl.push(pstr_iter2.heap[s+1]);
machine_st.pdl.push(char_as_cell!(c));
focus = pstr_iter2.heap[s+2];
} else {
machine_st.fail = true;
break 'outer;
}
}
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
match chars_iter.item.unwrap() {
PStrIteratee::Char(focus, _) => {
machine_st.pdl.push(machine_st.heap[focus]);
machine_st.pdl.push(heap_loc_as_cell!(h));
}
PStrIteratee::PStrSegment(focus, _, n) => {
read_heap_cell!(machine_st.heap[focus],
(HeapCellValueTag::CStr | HeapCellValueTag::PStr, pstr_atom) => {
if focus < machine_st.heap.len() - 2 {
machine_st.heap.pop();
machine_st.heap.pop();
}
if n == 0 {
let target_cell = match machine_st.heap[focus].get_tag() {
HeapCellValueTag::CStr => {
atom_as_cstr_cell!(pstr_atom)
}
HeapCellValueTag::PStr => {
pstr_loc_as_cell!(focus)
}
_ => {
unreachable!()
}
};
machine_st.pdl.push(target_cell);
machine_st.pdl.push(heap_loc_as_cell!(h));
} else {
let h_len = machine_st.heap.len();
machine_st.heap.push(pstr_offset_as_cell!(focus));
machine_st.heap.push(fixnum_as_cell!(
Fixnum::build_with(n as i64)
));
machine_st.pdl.push(pstr_loc_as_cell!(h_len));
machine_st.pdl.push(heap_loc_as_cell!(h));
}
return;
}
(HeapCellValueTag::PStrOffset, pstr_loc) => {
let n0 = cell_as_fixnum!(machine_st.heap[focus+1])
.get_num() as usize;
if pstr_loc < machine_st.heap.len() - 2 {
machine_st.heap.pop();
machine_st.heap.pop();
}
if n == n0 {
machine_st.pdl.push(pstr_loc_as_cell!(focus));
machine_st.pdl.push(heap_loc_as_cell!(h));
} else {
let h_len = machine_st.heap.len();
machine_st.heap.push(pstr_offset_as_cell!(pstr_loc));
machine_st.heap.push(fixnum_as_cell!(
Fixnum::build_with(n as i64)
));
machine_st.pdl.push(pstr_loc_as_cell!(h_len));
machine_st.pdl.push(heap_loc_as_cell!(h));
}
return;
}
_ => {
}
);
if focus < machine_st.heap.len() - 2 {
machine_st.heap.pop();
machine_st.heap.pop();
}
machine_st.pdl.push(machine_st.heap[focus]);
machine_st.pdl.push(heap_loc_as_cell!(h));
return;
}
}
break 'outer;
}
_ => {
machine_st.fail = true;
break 'outer;
}
);
chars_iter.next();
}
chars_iter.iter.next();
machine_st.pdl.push(focus);
machine_st.pdl.push(chars_iter.iter.focus);
break;
}
}
PStrCmpResult::Unordered => {
machine_st.pdl.push(pstr_iter1.focus);
machine_st.pdl.push(pstr_iter2.focus);
}
}
machine_st.heap.pop();
machine_st.heap.pop();
}
fn unify_atom(&mut self, atom: Atom, value: HeapCellValue) {
read_heap_cell!(value,
(HeapCellValueTag::Atom, (name, arity)) => {
self.fail = !(arity == 0 && name == atom);
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
self.fail = !(arity == 0 && name == atom);
}
(HeapCellValueTag::CStr, cstr_atom) if atom == atom!("[]") => {
self.fail = cstr_atom != atom!("");
}
(HeapCellValueTag::Char, c1) => {
if let Some(c2) = atom.as_char() {
self.fail = c1 != c2;
} else {
self.fail = true;
}
}
(HeapCellValueTag::AttrVar, h) => {
Self::bind(self, Ref::attr_var(h), atom_as_cell!(atom));
}
(HeapCellValueTag::Var, h) => {
Self::bind(self, Ref::heap_cell(h), atom_as_cell!(atom));
}
(HeapCellValueTag::StackVar, s) => {
Self::bind(self, Ref::stack_cell(s), atom_as_cell!(atom));
}
_ => {
self.fail = true;
}
);
}
fn unify_char(&mut self, c: char, value: HeapCellValue) {
read_heap_cell!(value,
(HeapCellValueTag::Atom, (name, arity)) => {
if let Some(c2) = name.as_char() {
self.fail = !(c == c2 && arity == 0);
} else {
self.fail = true;
}
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
if let Some(c2) = name.as_char() {
self.fail = !(c == c2 && arity == 0);
} else {
self.fail = true;
}
}
(HeapCellValueTag::Char, c2) => {
if c != c2 {
self.fail = true;
}
}
(HeapCellValueTag::AttrVar, h) => {
Self::bind(self, Ref::attr_var(h), char_as_cell!(c));
}
(HeapCellValueTag::Var, h) => {
Self::bind(self, Ref::heap_cell(h), char_as_cell!(c));
}
(HeapCellValueTag::StackVar, s) => {
Self::bind(self, Ref::stack_cell(s), char_as_cell!(c));
}
_ => {
self.fail = true;
}
);
}
fn unify_fixnum(&mut self, n1: Fixnum, value: HeapCellValue) {
if let Some(r) = value.as_var() {
Self::bind(self, r, fixnum_as_cell!(n1));
return;
}
match Number::try_from(value) {
Ok(n2) => match n2 {
Number::Fixnum(n2) if n1.get_num() == n2.get_num() => {}
Number::Integer(n2) if n1.get_num() == *n2 => {}
Number::Rational(n2) if n1.get_num() == *n2 => {}
_ => {
self.fail = true;
}
},
Err(_) => {
self.fail = true;
}
}
}
fn unify_big_num<N>(&mut self, n1: TypedArenaPtr<N>, value: HeapCellValue)
where N: PartialEq<Rational>
+ PartialEq<Integer>
+ PartialEq<i64>
+ ArenaAllocated
{
if let Some(r) = value.as_var() {
Self::bind(self, r, typed_arena_ptr_as_cell!(n1));
return;
}
match Number::try_from(value) {
Ok(n2) => match n2 {
Number::Fixnum(n2) if *n1 == n2.get_num() => {}
Number::Integer(n2) if *n1 == *n2 => {}
Number::Rational(n2) if *n1 == *n2 => {}
_ => {
self.fail = true;
}
},
Err(_) => {
self.fail = true;
}
}
}
fn unify_f64(&mut self, f1: F64Ptr, value: HeapCellValue) {
if let Some(r) = value.as_var() {
Self::bind(self, r, HeapCellValue::from(f1));
return;
}
read_heap_cell!(value,
(HeapCellValueTag::F64, f2) => {
self.fail = **f1 != **f2;
}
_ => {
self.fail = true;
}
);
}
fn unify_constant(&mut self, ptr: UntypedArenaPtr, value: HeapCellValue) {
if let Some(ptr2) = value.to_untyped_arena_ptr() {
if ptr.get_ptr() == ptr2.get_ptr() {
return;
}
}
match_untyped_arena_ptr!(ptr,
(ArenaHeaderTag::Integer, int_ptr) => {
Self::unify_big_num(self, int_ptr, value);
}
(ArenaHeaderTag::Rational, rat_ptr) => {
Self::unify_big_num(self, rat_ptr, value);
}
(ArenaHeaderTag::Stream, stream) => {
read_heap_cell!(value,
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
Self::bind(self, value.as_var().unwrap(), untyped_arena_ptr_as_cell!(ptr));
}
(HeapCellValueTag::Atom, (name, arity)) => {
if arity > 0 {
self.fail = true;
} else {
let stream_options = stream.options();
if let Some(alias) = stream_options.get_alias() {
self.fail = name != alias;
} else {
self.fail = true;
}
}
}
_ => {
self.fail = true;
}
);
}
_ => {
if let Some(r) = value.as_var() {
Self::bind(self, r, untyped_arena_ptr_as_cell!(ptr));
} else {
self.fail = true;
}
}
);
}
fn unify_internal(&mut self) {
let mut tabu_list = IndexSet::with_hasher(FxBuildHasher::default());
while !(self.pdl.is_empty() || self.fail) {
let s1 = self.pdl.pop().unwrap();
let s1 = (self.deref() as &MachineState).deref(s1);
let s2 = self.pdl.pop().unwrap();
let s2 = (self.deref() as &MachineState).deref(s2);
if s1 != s2 {
let d1 = self.store(s1);
let d2 = self.store(s2);
read_heap_cell!(d1,
(HeapCellValueTag::AttrVar, h) => {
Self::bind(self, Ref::attr_var(h), d2);
}
(HeapCellValueTag::Var, h) => {
Self::bind(self, Ref::heap_cell(h), d2);
}
(HeapCellValueTag::StackVar, s) => {
Self::bind(self, Ref::stack_cell(s), d2);
}
(HeapCellValueTag::Atom, (name, arity)) => {
debug_assert_eq!(arity, 0);
Self::unify_atom(self, name, d2);
}
(HeapCellValueTag::Str, s1) => {
if tabu_list.contains(&(d1, d2)) {
continue;
}
Self::unify_structure(self, s1, d2);
if !self.fail {
let d2 = self.store(d2);
tabu_list.insert((d1, d2));
}
}
(HeapCellValueTag::Lis, l1) => {
if d2.is_ref() {
if tabu_list.contains(&(d1, d2)) {
continue;
}
}
Self::unify_list(self, l1, d2);
if !self.fail {
let d2 = self.store(d2);
tabu_list.insert((d1, d2));
}
}
(HeapCellValueTag::PStrLoc) => {
read_heap_cell!(d2,
(HeapCellValueTag::PStrLoc |
HeapCellValueTag::Lis |
HeapCellValueTag::Str) => {
if tabu_list.contains(&(d1, d2)) {
continue;
}
}
(HeapCellValueTag::CStr |
HeapCellValueTag::AttrVar |
HeapCellValueTag::Var |
HeapCellValueTag::StackVar) => {
}
_ => {
self.fail = true;
break;
}
);
Self::unify_partial_string(self, d1, d2);
if !self.fail && !d2.is_constant() {
let d2 = self.store(d2);
tabu_list.insert((d1, d2));
}
}
(HeapCellValueTag::CStr) => {
read_heap_cell!(d2,
(HeapCellValueTag::AttrVar, h) => {
Self::bind(self, Ref::attr_var(h), d1);
continue;
}
(HeapCellValueTag::Var, h) => {
Self::bind(self, Ref::heap_cell(h), d1);
continue;
}
(HeapCellValueTag::StackVar, s) => {
Self::bind(self, Ref::stack_cell(s), d1);
continue;
}
(HeapCellValueTag::Str |
HeapCellValueTag::Lis |
HeapCellValueTag::PStrLoc) => {
}
(HeapCellValueTag::CStr) => {
self.fail = d1 != d2;
continue;
}
_ => {
self.fail = true;
return;
}
);
Self::unify_partial_string(self, d2, d1);
}
(HeapCellValueTag::F64, f1) => {
Self::unify_f64(self, f1, d2);
}
(HeapCellValueTag::Fixnum, n1) => {
Self::unify_fixnum(self, n1, d2);
}
(HeapCellValueTag::Char, c1) => {
Self::unify_char(self, c1, d2);
}
(HeapCellValueTag::Cons, ptr_1) => {
Self::unify_constant(self, ptr_1, d2);
}
_ => {
unreachable!();
}
);
}
}
}
fn bind(&mut self, r: Ref, value: HeapCellValue);
}
#[inline]
fn bind_with_occurs_check<U: Unifier>(unifier: &mut U, r: Ref, value: HeapCellValue) -> bool {
if let RefTag::StackCell = r.get_tag() {
// local variable optimization -- r cannot occur in the
// heap structure bound to value, so don't bother
// traversing value.
U::bind(unifier, r, value);
return false;
}
let mut occurs_triggered = false;
if !value.is_constant() {
let machine_st: &mut MachineState = unifier.deref_mut();
for cell in stackful_preorder_iter(&mut machine_st.heap, &mut machine_st.stack, value) {
let cell = unmark_cell_bits!(cell);
if let Some(inner_r) = cell.as_var() {
if r == inner_r {
occurs_triggered = true;
break;
}
}
}
}
if occurs_triggered {
unifier.fail = true;
} else {
U::bind(unifier, r, value);
}
return occurs_triggered;
}
#[derive(Deref, DerefMut)]
pub(crate) struct DefaultUnifier<'a> {
machine_st: &'a mut MachineState,
}
impl<'a> From<&'a mut MachineState> for DefaultUnifier<'a> {
#[inline(always)]
fn from(machine_st: &'a mut MachineState) -> Self {
Self { machine_st }
}
}
impl<'a> Unifier for DefaultUnifier<'a> {
fn bind(&mut self, r: Ref, value: HeapCellValue) {
self.machine_st.bind(r, value);
}
}
pub(crate) struct CompositeUnifierForOccursCheck<U> {
unifier: U,
}
impl<U: Unifier> Deref for CompositeUnifierForOccursCheck<U> {
type Target = MachineState;
#[inline(always)]
fn deref(&self) -> &Self::Target {
self.unifier.deref()
}
}
impl<U: Unifier> DerefMut for CompositeUnifierForOccursCheck<U> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
self.unifier.deref_mut()
}
}
impl<U: Unifier> From<U> for CompositeUnifierForOccursCheck<U> {
#[inline(always)]
fn from(unifier: U) -> Self {
Self { unifier }
}
}
impl<U: Unifier> Unifier for CompositeUnifierForOccursCheck<U> {
fn bind(&mut self, r: Ref, value: HeapCellValue) {
bind_with_occurs_check(&mut self.unifier, r, value);
}
}
pub(crate) struct CompositeUnifierForOccursCheckWithError<U: Unifier> {
unifier: U,
}
impl<U: Unifier> Deref for CompositeUnifierForOccursCheckWithError<U> {
type Target = MachineState;
#[inline(always)]
fn deref(&self) -> &Self::Target {
self.unifier.deref()
}
}
impl<U: Unifier> DerefMut for CompositeUnifierForOccursCheckWithError<U> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
self.unifier.deref_mut()
}
}
impl<U: Unifier> From<U> for CompositeUnifierForOccursCheckWithError<U> {
#[inline(always)]
fn from(unifier: U) -> Self {
Self { unifier }
}
}
impl<U: Unifier> Unifier for CompositeUnifierForOccursCheckWithError<U> {
fn bind(&mut self, r: Ref, value: HeapCellValue) {
if bind_with_occurs_check(&mut self.unifier, r, value) {
let err = self.representation_error(RepFlag::Term);
let stub = functor_stub(atom!("unify_with_occurs_check"), 2);
let err = self.error_form(err, stub);
self.throw_exception(err);
}
}
}