initial commit for merge

This commit is contained in:
Mark Thom
2020-03-26 22:01:23 -06:00
parent 121c8d8a48
commit 194e5dc94e
25 changed files with 5077 additions and 3280 deletions

View File

@@ -0,0 +1,786 @@
use crate::prolog_parser::ast::*;
use crate::prolog::arithmetic::*;
use crate::prolog::clause_types::*;
use crate::prolog::forms::*;
use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::machine_state::*;
use crate::prolog::ordered_float::*;
use crate::prolog::rug::{Integer, Rational};
use std::cmp;
use std::f64;
use std::mem;
use std::rc::Rc;
#[macro_export]
macro_rules! try_numeric_result {
($s: ident, $e: expr, $caller: expr) => (
match $e {
Ok(val) => {
Ok(val)
}
Err(e) => {
let caller_copy =
$caller.iter().map(|v| v.context_free_clone()).collect();
Err($s.error_form(MachineError::evaluation_error(e), caller_copy))
}
}
);
}
impl MachineState {
pub(crate)
fn get_number(&mut self, at: &ArithmeticTerm) -> Result<Number, MachineStub> {
match at {
&ArithmeticTerm::Reg(r) => {
self.arith_eval_by_metacall(r)
}
&ArithmeticTerm::Interm(i) => Ok(mem::replace(
&mut self.interms[i - 1],
Number::Integer(Rc::new(Integer::from(0))),
)),
&ArithmeticTerm::Number(ref n) => {
Ok(n.clone())
}
}
}
pub(super)
fn rational_from_number(
&self,
n: Number,
) -> Result<Rc<Rational>, MachineError> {
match n {
Number::Rational(r) => {
Ok(r)
}
Number::Float(OrderedFloat(f)) => {
match Rational::from_f64(f) {
Some(r) => {
Ok(Rc::new(r))
}
None => {
Err(MachineError::instantiation_error())
}
}
}
Number::Integer(n) => {
Ok(Rc::new(Rational::from(&*n)))
}
}
}
pub(crate)
fn get_rational(
&mut self,
at: &ArithmeticTerm,
caller: MachineStub,
) -> Result<(Rc<Rational>, MachineStub), MachineStub> {
let n = self.get_number(at)?;
match self.rational_from_number(n) {
Ok(r) => Ok((r, caller)),
Err(e) => Err(self.error_form(e, caller))
}
}
pub(crate)
fn arith_eval_by_metacall(&self, r: RegType) -> Result<Number, MachineStub> {
let a = self[r].clone();
let caller = MachineError::functor_stub(clause_name!("(is)"), 2);
let mut interms: Vec<Number> = Vec::with_capacity(64);
for addr in self.post_order_iter(a) {
match self.heap.index_addr(&addr).as_ref() {
&HeapCellValue::NamedStr(2, ref name, _) => {
let a2 = interms.pop().unwrap();
let a1 = interms.pop().unwrap();
match name.as_str() {
"+" => interms.push(try_numeric_result!(self, a1 + a2, caller)?),
"-" => interms.push(try_numeric_result!(self, a1 - a2, caller)?),
"*" => interms.push(try_numeric_result!(self, a1 * a2, caller)?),
"/" => interms.push(self.div(a1, a2)?),
"**" => interms.push(self.pow(a1, a2, "(is)")?),
"^" => interms.push(self.int_pow(a1, a2)?),
"max" => interms.push(self.max(a1, a2)?),
"min" => interms.push(self.min(a1, a2)?),
"rdiv" => {
let r1 = self.rational_from_number(a1);
let r2 = r1.and_then(|r1| {
self.rational_from_number(a2).map(|r2| (r1, r2))
});
match r2 {
Ok((r1, r2)) => {
let result = Number::Rational(Rc::new(self.rdiv(r1, r2)?));
interms.push(result);
}
Err(e) => {
return Err(self.error_form(e, caller));
}
}
}
"//" => interms.push(Number::Integer(Rc::new(self.idiv(a1, a2)?))),
"div" => interms.push(Number::Integer(Rc::new(self.int_floor_div(a1, a2)?))),
">>" => interms.push(Number::Integer(Rc::new(self.shr(a1, a2)?))),
"<<" => interms.push(Number::Integer(Rc::new(self.shl(a1, a2)?))),
"/\\" => interms.push(Number::Integer(Rc::new(self.and(a1, a2)?))),
"\\/" => interms.push(Number::Integer(Rc::new(self.or(a1, a2)?))),
"xor" => interms.push(Number::Integer(Rc::new(self.xor(a1, a2)?))),
"mod" => interms.push(Number::Integer(Rc::new(self.modulus(a1, a2)?))),
"rem" => interms.push(Number::Integer(Rc::new(self.remainder(a1, a2)?))),
"atan2" => interms.push(Number::Float(OrderedFloat(self.atan2(a1, a2)?))),
"gcd" => interms.push(Number::Integer(Rc::new(self.gcd(a1, a2)?))),
_ => {
return Err(self.error_form(MachineError::instantiation_error(), caller))
}
}
}
&HeapCellValue::NamedStr(1, ref name, _) => {
let a1 = interms.pop().unwrap();
match name.as_str() {
"-" => interms.push(-a1),
"+" => interms.push(a1),
"cos" => interms.push(Number::Float(OrderedFloat(self.cos(a1)?))),
"sin" => interms.push(Number::Float(OrderedFloat(self.sin(a1)?))),
"tan" => interms.push(Number::Float(OrderedFloat(self.tan(a1)?))),
"sqrt" => interms.push(Number::Float(OrderedFloat(self.sqrt(a1)?))),
"log" => interms.push(Number::Float(OrderedFloat(self.log(a1)?))),
"exp" => interms.push(Number::Float(OrderedFloat(self.exp(a1)?))),
"acos" => interms.push(Number::Float(OrderedFloat(self.acos(a1)?))),
"asin" => interms.push(Number::Float(OrderedFloat(self.asin(a1)?))),
"atan" => interms.push(Number::Float(OrderedFloat(self.atan(a1)?))),
"abs" => interms.push(a1.abs()),
"float" => interms.push(Number::Float(OrderedFloat(self.float(a1)?))),
"truncate" => interms.push(Number::Integer(Rc::new(self.truncate(a1)))),
"round" => interms.push(Number::Integer(Rc::new(self.round(a1)?))),
"ceiling" => interms.push(Number::Integer(Rc::new(self.ceiling(a1)))),
"floor" => interms.push(Number::Integer(Rc::new(self.floor(a1)))),
"\\" => interms.push(Number::Integer(Rc::new(self.bitwise_complement(a1)?))),
"sign" => interms.push(Number::Integer(Rc::new(self.sign(a1)))),
_ => {
return Err(self.error_form(MachineError::instantiation_error(), caller));
}
}
}
&HeapCellValue::Integer(ref n) => {
interms.push(Number::Integer(n.clone()))
}
&HeapCellValue::Addr(Addr::Float(n)) => {
interms.push(Number::Float(n))
}
&HeapCellValue::Rational(ref n) => {
interms.push(Number::Rational(n.clone()))
}
&HeapCellValue::Atom(ref name, _) if name.as_str() == "pi" => {
interms.push(Number::Float(OrderedFloat(f64::consts::PI)))
}
_ => {
return Err(self.error_form(
MachineError::instantiation_error(),
caller,
));
}
}
}
Ok(interms.pop().unwrap())
}
pub(crate)
fn rdiv(&self, r1: Rc<Rational>, r2: Rc<Rational>) -> Result<Rational, MachineStub> {
if &*r2 == &0 {
let stub = MachineError::functor_stub(clause_name!("(rdiv)"), 2);
Err(self.error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub))
} else {
Ok(Rational::from(&*r1 / &*r2))
}
}
pub(crate)
fn int_floor_div(&self, n1: Number, n2: Number) -> Result<Integer, MachineStub> {
match n1 / n2 {
Ok(result) => Ok(rnd_i(&result).to_owned()),
Err(e) => {
let stub = MachineError::functor_stub(clause_name!("(div)"), 2);
Err(self.error_form(
MachineError::evaluation_error(
e
),
stub
))
}
}
}
pub(crate)
fn idiv(&self, n1: Number, n2: Number) -> Result<Integer, MachineStub> {
match (n1, n2) {
(Number::Integer(n1), Number::Integer(n2)) => {
if &*n2 == &0 {
let stub = MachineError::functor_stub(clause_name!("(//)"), 2);
Err(self.error_form(
MachineError::evaluation_error(
EvalError::ZeroDivisor
),
stub,
))
} else {
Ok(<(Integer, Integer)>::from(n1.div_rem_ref(&*n2)).0)
}
}
(Number::Integer(_), n2) => {
let stub = MachineError::functor_stub(clause_name!("(//)"), 2);
Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Integer,
n2,
),
stub,
))
}
(n1, _) => {
let stub = MachineError::functor_stub(clause_name!("(//)"), 2);
Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Integer,
n1,
),
stub,
))
}
}
}
pub(crate)
fn div(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
let stub = MachineError::functor_stub(clause_name!("(/)"), 2);
if n2.is_zero() {
Err(self.error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub))
} else {
try_numeric_result!(self, n1 / n2, stub)
}
}
pub(crate)
fn atan2(&self, n1: Number, n2: Number) -> Result<f64, MachineStub> {
let stub = MachineError::functor_stub(clause_name!("(is)"), 2);
if n1.is_zero() && n2.is_zero() {
Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub))
} else {
let f1 = self.float(n1)?;
let f2 = self.float(n2)?;
self.unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.atan2(f2))
}
}
pub(crate)
fn int_pow(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
if n1.is_zero() && n2.is_negative() {
let stub = MachineError::functor_stub(clause_name!("(is)"), 2);
return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub));
}
match (n1, n2) {
(Number::Integer(n1), Number::Integer(n2)) => {
if &*n1 != &1 && &*n2 < &0 {
let n = Number::Integer(n1);
let stub = MachineError::functor_stub(clause_name!("^"), 2);
Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Float,
n
),
stub,
))
} else {
Ok(Number::Integer(Rc::new(binary_pow(n1.as_ref().clone(), n2.as_ref()))))
}
}
(n1, Number::Integer(n2)) => {
let f1 = self.float(n1)?;
let f2 = self.float(Number::Integer(n2))?;
self.unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.powf(f2))
.map(|f| Number::Float(OrderedFloat(f)))
}
(n1, n2) => {
let f2 = self.float(n2)?;
if n1.is_negative() && f2 != f2.floor() {
let stub = MachineError::functor_stub(clause_name!("(is)"), 2);
return Err(
self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)
);
}
let f1 = self.float(n1)?;
self.unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.powf(f2))
.map(|f| Number::Float(OrderedFloat(f)))
}
}
}
pub(crate)
fn gcd(&self, n1: Number, n2: Number) -> Result<Integer, MachineStub> {
match (n1, n2) {
(Number::Integer(n1), Number::Integer(n2)) => {
Ok(Integer::from(n1.gcd_ref(&n2)))
}
(Number::Float(f), _) | (_, Number::Float(f)) => {
let n = Number::Float(f);
let stub = MachineError::functor_stub(clause_name!("gcd"), 2);
Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Integer,
n
),
stub,
))
}
(Number::Rational(r), _) | (_, Number::Rational(r)) => {
let n = Number::Rational(r);
let stub = MachineError::functor_stub(clause_name!("gcd"), 2);
Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Integer,
n,
),
stub,
))
}
}
}
pub(crate)
fn float_pow(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
let f1 = result_f(&n1, rnd_f);
let f2 = result_f(&n2, rnd_f);
let stub = MachineError::functor_stub(clause_name!("(**)"), 2);
let f1 = try_numeric_result!(self, f1, stub)?;
let f2 = try_numeric_result!(self, f2, stub)?;
let result = result_f(&Number::Float(OrderedFloat(f1.powf(f2))), rnd_f);
Ok(Number::Float(OrderedFloat(try_numeric_result!(
self, result, stub
)?)))
}
pub(crate)
fn pow(&self, n1: Number, n2: Number, culprit: &'static str) -> Result<Number, MachineStub> {
if n2.is_negative() && n1.is_zero() {
let stub = MachineError::functor_stub(clause_name!(culprit), 2);
return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub));
}
match (n1, n2) {
(Number::Integer(n1), Number::Integer(n2)) => {
Ok(Number::Integer(Rc::new(binary_pow(n1.as_ref().clone(), &*n2))))
}
(n1, n2) => {
self.float_pow(n1, n2)
}
}
}
pub(crate)
fn unary_float_fn_template<FloatFn>(&self, n1: Number, f: FloatFn) -> Result<f64, MachineStub>
where
FloatFn: Fn(f64) -> f64,
{
let stub = MachineError::functor_stub(clause_name!("(is)"), 2);
let f1 = try_numeric_result!(self, result_f(&n1, rnd_f), stub)?;
let f1 = result_f(&Number::Float(OrderedFloat(f(f1))), rnd_f);
try_numeric_result!(self, f1, stub)
}
pub(crate)
fn sin(&self, n1: Number) -> Result<f64, MachineStub> {
self.unary_float_fn_template(n1, |f| f.sin())
}
pub(crate)
fn cos(&self, n1: Number) -> Result<f64, MachineStub> {
self.unary_float_fn_template(n1, |f| f.cos())
}
pub(crate)
fn tan(&self, n1: Number) -> Result<f64, MachineStub> {
self.unary_float_fn_template(n1, |f| f.tan())
}
pub(crate)
fn log(&self, n1: Number) -> Result<f64, MachineStub> {
self.unary_float_fn_template(n1, |f| f.log(f64::consts::E))
}
pub(crate)
fn exp(&self, n1: Number) -> Result<f64, MachineStub> {
self.unary_float_fn_template(n1, |f| f.exp())
}
pub(crate)
fn asin(&self, n1: Number) -> Result<f64, MachineStub> {
self.unary_float_fn_template(n1, |f| f.asin())
}
pub(crate)
fn acos(&self, n1: Number) -> Result<f64, MachineStub> {
self.unary_float_fn_template(n1, |f| f.acos())
}
pub(crate)
fn atan(&self, n1: Number) -> Result<f64, MachineStub> {
self.unary_float_fn_template(n1, |f| f.atan())
}
pub(crate)
fn sqrt(&self, n1: Number) -> Result<f64, MachineStub> {
if n1.is_negative() {
let stub = MachineError::functor_stub(clause_name!("(is)"), 2);
return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub));
}
self.unary_float_fn_template(n1, |f| f.sqrt())
}
pub(crate)
fn float(&self, n: Number) -> Result<f64, MachineStub> {
let stub = MachineError::functor_stub(clause_name!("(is)"), 2);
try_numeric_result!(self, result_f(&n, rnd_f), stub)
}
pub(crate)
fn floor(&self, n1: Number) -> Integer {
rnd_i(&n1).to_owned()
}
pub(crate)
fn ceiling(&self, n1: Number) -> Integer {
-self.floor(-n1)
}
pub(crate)
fn truncate(&self, n: Number) -> Integer {
if n.is_negative() {
-self.floor(n.abs())
} else {
self.floor(n)
}
}
pub(crate)
fn round(&self, n: Number) -> Result<Integer, MachineStub> {
let stub = MachineError::functor_stub(clause_name!("(is)"), 2);
let result = n + Number::Float(OrderedFloat(0.5f64));
let result = try_numeric_result!(self, result, stub)?;
Ok(self.floor(result))
}
pub(crate)
fn shr(&self, n1: Number, n2: Number) -> Result<Integer, MachineStub> {
let stub = MachineError::functor_stub(clause_name!("(>>)"), 2);
match (n1, n2) {
(Number::Integer(n1), Number::Integer(n2)) =>
match n2.to_u32() {
Some(n2) => Ok(Integer::from(&*n1 >> n2)),
_ => Ok(Integer::from(&*n1 >> u32::max_value())),
},
(Number::Integer(_), n2) => Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Integer,
n2,
),
stub,
)),
(n1, _) => Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Integer,
n1,
),
stub,
)),
}
}
pub(crate)
fn shl(&self, n1: Number, n2: Number) -> Result<Integer, MachineStub> {
let stub = MachineError::functor_stub(clause_name!("(<<)"), 2);
match (n1, n2) {
(Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() {
Some(n2) => Ok(Integer::from(&*n1 << n2)),
_ => Ok(Integer::from(&*n1 << u32::max_value())),
},
(Number::Integer(_), n2) => Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Integer,
n2,
),
stub,
)),
(n1, _) => Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Integer,
n1,
),
stub,
)),
}
}
pub(crate)
fn bitwise_complement(&self, n1: Number) -> Result<Integer, MachineStub> {
let stub = MachineError::functor_stub(clause_name!("(\\)"), 2);
match n1 {
Number::Integer(n1) => Ok(Integer::from(!&*n1)),
_ => Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Integer,
n1,
),
stub,
)),
}
}
pub(crate)
fn xor(&self, n1: Number, n2: Number) -> Result<Integer, MachineStub> {
let stub = MachineError::functor_stub(clause_name!("(xor)"), 2);
match (n1, n2) {
(Number::Integer(n1), Number::Integer(n2)) => {
Ok(Integer::from(&*n1 ^ &*n2))
}
(Number::Integer(_), n2) => {
Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Integer,
n2
),
stub,
))
}
(n1, _) => {
Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Integer,
n1
),
stub,
))
}
}
}
pub(crate)
fn and(&self, n1: Number, n2: Number) -> Result<Integer, MachineStub> {
let stub = MachineError::functor_stub(clause_name!("(/\\)"), 2);
match (n1, n2) {
(Number::Integer(n1), Number::Integer(n2)) => Ok(Integer::from(&*n1 & &*n2)),
(Number::Integer(_), n2) => Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Integer,
n2,
),
stub,
)),
(n1, _) => Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Integer,
n1,
),
stub,
)),
}
}
pub(crate)
fn modulus(&self, x: Number, y: Number) -> Result<Integer, MachineStub> {
let stub = MachineError::functor_stub(clause_name!("(mod)"), 2);
match (x, y) {
(Number::Integer(x), Number::Integer(y)) => {
if &*y == &0 {
Err(self.error_form(
MachineError::evaluation_error(EvalError::ZeroDivisor),
stub,
))
} else {
Ok(<(Integer, Integer)>::from(x.div_rem_floor_ref(&*y)).1)
}
}
(Number::Integer(_), n2) => Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Integer,
n2,
),
stub,
)),
(n1, _) => Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Integer,
n1,
),
stub,
)),
}
}
pub(crate)
fn max(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
match (n1, n2) {
(Number::Integer(n1), Number::Integer(n2)) => {
if n1 > n2 {
Ok(Number::Integer(n1))
} else {
Ok(Number::Integer(n2))
}
}
(n1, n2) => {
let stub = MachineError::functor_stub(clause_name!("max"), 2);
let f1 = try_numeric_result!(self, result_f(&n1, rnd_f), stub)?;
let f2 = try_numeric_result!(self, result_f(&n2, rnd_f), stub)?;
Ok(Number::Float(cmp::max(OrderedFloat(f1), OrderedFloat(f2))))
}
}
}
pub(crate)
fn min(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
match (n1, n2) {
(Number::Integer(n1), Number::Integer(n2)) => {
if n1 < n2 {
Ok(Number::Integer(n1))
} else {
Ok(Number::Integer(n2))
}
}
(n1, n2) => {
let stub = MachineError::functor_stub(clause_name!("max"), 2);
let f1 = try_numeric_result!(self, result_f(&n1, rnd_f), stub)?;
let f2 = try_numeric_result!(self, result_f(&n2, rnd_f), stub)?;
Ok(Number::Float(cmp::min(OrderedFloat(f1), OrderedFloat(f2))))
}
}
}
pub(crate)
fn sign(&self, n: Number) -> Integer {
if n.is_positive() {
Integer::from(1)
} else if n.is_negative() {
Integer::from(-1)
} else {
Integer::from(0)
}
}
pub(crate)
fn remainder(&self, n1: Number, n2: Number) -> Result<Integer, MachineStub> {
let stub = MachineError::functor_stub(clause_name!("(rem)"), 2);
match (n1, n2) {
(Number::Integer(n1), Number::Integer(n2)) => {
if &*n2 == &0 {
Err(self
.error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub))
} else {
Ok(Integer::from(&*n1 % &*n2))
}
}
(Number::Integer(_), n2) => Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Integer,
n2,
),
stub,
)),
(n1, _) => Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Integer,
n1,
),
stub,
)),
}
}
pub(crate)
fn or(&self, n1: Number, n2: Number) -> Result<Integer, MachineStub> {
let stub = MachineError::functor_stub(clause_name!("(\\/)"), 2);
match (n1, n2) {
(Number::Integer(n1), Number::Integer(n2)) => {
Ok(Integer::from(&*n1 | &*n2))
}
(Number::Integer(_), n2) => {
Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Integer,
n2,
),
stub,
))
}
(n1, _) => {
Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Integer,
n1
),
stub,
))
}
}
}
}

View File

@@ -1,5 +1,6 @@
use crate::prolog::machine::*;
use std::cmp::Ordering;
use std::vec::IntoIter;
pub static VERIFY_ATTRS: &str = include_str!("attributed_variables.pl");
@@ -66,7 +67,7 @@ impl MachineState {
.attr_var_init
.bindings
.iter()
.map(|(ref h, _)| Addr::AttrVar(*h));
.map(|(ref h, _)| HeapCellValue::Addr(Addr::AttrVar(*h)));
let var_list_addr = Addr::HeapCell(self.heap.to_list(iter));
@@ -74,7 +75,7 @@ impl MachineState {
.attr_var_init
.bindings
.drain(0 ..)
.map(|(_, addr)| addr);
.map(|(_, addr)| HeapCellValue::Addr(addr));
let value_list_addr = Addr::HeapCell(self.heap.to_list(iter));
(var_list_addr, value_list_addr)
@@ -100,7 +101,9 @@ impl MachineState {
})
.collect();
attr_vars.sort_unstable_by(|a1, a2| self.compare_term_test(a1, a2));
attr_vars.sort_unstable_by(|a1, a2| {
self.compare_term_test(a1, a2).unwrap_or(Ordering::Less)
});
self.term_dedup(&mut attr_vars);
attr_vars.into_iter()
@@ -117,9 +120,9 @@ impl MachineState {
}
self.stack.index_and_frame_mut(e)[self.num_of_args + 1] =
Addr::Con(Constant::CutPoint(self.b0));
Addr::CutPoint(self.b0);
self.stack.index_and_frame_mut(e)[self.num_of_args + 2] =
Addr::Con(Constant::Usize(self.num_of_args));
Addr::Usize(self.num_of_args);
self.verify_attributes();

View File

@@ -1,6 +1,8 @@
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::stack::*;
use crate::prolog::machine::streams::*;
use std::mem;
use std::ops::IndexMut;
type Trail = Vec<(Ref, HeapCellValue)>;
@@ -11,12 +13,13 @@ pub enum AttrVarPolicy {
StripAttributes
}
pub(crate) trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
fn threshold(&self) -> usize;
fn push(&mut self, val: HeapCellValue);
fn store(&self, val: Addr) -> Addr;
pub(crate)
trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
fn deref(&self, val: Addr) -> Addr;
fn push(&mut self, val: HeapCellValue);
fn stack(&mut self) -> &mut Stack;
fn store(&self, val: Addr) -> Addr;
fn threshold(&self) -> usize;
}
pub(crate)
@@ -75,15 +78,15 @@ impl<T: CopierTarget> CopyTermState<T> {
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(threshold));
let ra = self.target[addr].as_addr(threshold);
let rd = self.target.store(self.target.deref(ra.clone()));
let rd = self.target.store(self.target.deref(ra));
self.target.push(HeapCellValue::Addr(ra.clone()));
self.target.push(HeapCellValue::Addr(ra));
let hcv = HeapCellValue::Addr(self.target[addr + 1].as_addr(addr + 1));
self.target.push(hcv);
match rd.clone() {
match rd {
Addr::AttrVar(h) | Addr::HeapCell(h)
if h >= self.old_h => {
self.target[threshold] = HeapCellValue::Addr(rd)
@@ -129,18 +132,18 @@ impl<T: CopierTarget> CopyTermState<T> {
fn copy_partial_string(&mut self, addr: usize, n: usize) {
let threshold = self.target.threshold();
let tail_addr = self.target[addr + 1].as_addr(addr + 1);
let trail_item = mem::replace(
&mut self.target[addr + 1],
HeapCellValue::Addr(Addr::PStrLocation(threshold, 0)),
);
self.trail.push((
Ref::HeapCell(addr + 1),
self.target[addr + 1].clone(),
trail_item,
));
let tail_addr = self.target[addr + 1].as_addr(addr + 1);
self.target[addr + 1] = HeapCellValue::Addr(
Addr::PStrLocation(threshold, 0)
);
let pstr =
match &self.target[addr] {
HeapCellValue::PartialString(ref pstr) => {
@@ -205,7 +208,7 @@ impl<T: CopierTarget> CopyTermState<T> {
if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
self.target.push(HeapCellValue::Addr(Addr::AttrVar(threshold)));
let list_val = self.target[h + 1].clone();
let list_val = self.target[h + 1].context_free_clone();
self.target.push(list_val);
}
}
@@ -214,9 +217,9 @@ impl<T: CopierTarget> CopyTermState<T> {
}
fn copy_var(&mut self, addr: Addr) {
let rd = self.target.store(self.target.deref(addr.clone()));
let rd = self.target.store(self.target.deref(addr));
match rd.clone() {
match rd {
Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => {
*self.value_at_scan() = HeapCellValue::Addr(rd);
self.scan += 1;
@@ -232,7 +235,7 @@ impl<T: CopierTarget> CopyTermState<T> {
}
fn copy_structure(&mut self, addr: usize) {
match self.target[addr].clone() {
match self.target[addr].context_free_clone() {
HeapCellValue::NamedStr(arity, name, fixity) => {
let threshold = self.target.threshold();
@@ -247,7 +250,7 @@ impl<T: CopierTarget> CopyTermState<T> {
self.target.push(HeapCellValue::NamedStr(arity, name, fixity));
for i in 0..arity {
let hcv = self.target[addr + 1 + i].clone();
let hcv = self.target[addr + 1 + i].context_free_clone();
self.target.push(hcv);
}
}
@@ -266,13 +269,18 @@ impl<T: CopierTarget> CopyTermState<T> {
while self.scan < self.target.threshold() {
match self.value_at_scan() {
HeapCellValue::NamedStr(..) => {
self.scan += 1;
}
HeapCellValue::Addr(ref addr) => {
match addr.clone() {
Addr::Lis(addr) => {
self.copy_list(addr);
&mut HeapCellValue::Addr(addr) => {
match addr {
Addr::Con(h) => {
self.target.push(self.target[h].context_free_clone());
self.scan += 1;
}
Addr::Stream(_) => {
self.target.push(HeapCellValue::Stream(Stream::null_stream()));
self.scan += 1;
}
Addr::Lis(h) => {
self.copy_list(h);
}
addr @ Addr::AttrVar(_)
| addr @ Addr::HeapCell(_)
@@ -285,12 +293,12 @@ impl<T: CopierTarget> CopyTermState<T> {
Addr::PStrLocation(addr, n) => {
self.copy_partial_string_from(addr, n);
}
Addr::Con(_) | Addr::DBRef(_) | Addr::Stream(_) => {
_ => {
self.scan += 1;
}
}
}
HeapCellValue::PartialString(_) => {
_ => {
self.scan += 1;
}
}

View File

@@ -41,12 +41,22 @@ impl Machine {
let arity = self.machine_st[arity].clone();
let name = match self.machine_st.store(self.machine_st.deref(name)) {
Addr::Con(Constant::Atom(name, _)) => name,
Addr::Con(h) =>
if let HeapCellValue::Atom(ref name, _) = &self.machine_st.heap[h] {
name.clone()
} else {
unreachable!()
},
_ => unreachable!(),
};
let arity = match self.machine_st.store(self.machine_st.deref(arity)) {
Addr::Con(Constant::Integer(arity)) => arity.to_usize().unwrap(),
Addr::Con(h) =>
if let HeapCellValue::Integer(ref arity) = &self.machine_st.heap[h] {
arity.to_usize().unwrap()
} else {
unreachable!()
},
_ => unreachable!(),
};
@@ -91,7 +101,7 @@ impl Machine {
let (name, arity) = self.get_predicate_key(name, arity);
self.make_undefined(name.clone(), arity);
self.indices.remove_code_index((name.clone(), arity));
self.indices.remove_clause_subsection(name.owning_module(), name, arity);
}
@@ -101,16 +111,21 @@ impl Machine {
let module_addr = self.machine_st[module].clone();
let module_name = match self.machine_st.store(self.machine_st.deref(module_addr)) {
Addr::Con(Constant::Atom(module, _)) => match self.indices.modules.get_mut(&module) {
Some(ref mut module) => {
module.code_dir.remove(&(name.clone(), arity));
module.module_decl.name.clone()
}
_ => {
self.machine_st.fail = true;
return;
}
},
Addr::Con(h) =>
if let HeapCellValue::Atom(ref module, _) = &self.machine_st.heap[h] {
match self.indices.modules.get_mut(module) {
Some(ref mut module) => {
module.code_dir.remove(&(name.clone(), arity));
module.module_decl.name.clone()
}
_ => {
self.machine_st.fail = true;
return;
}
}
} else {
unreachable!()
},
_ => unreachable!(),
};
@@ -162,21 +177,34 @@ impl Machine {
place.push_to_queue(&mut addrs, added_clause);
self.print_new_dynamic_clause(addrs, name.clone(), arity)
}
Err(err) => return self.machine_st.throw_exception(err),
Err(err) => {
return self.machine_st.throw_exception(err);
}
};
self.handle_eval_result_from_dynamic_compile(pred_str, name, arity, place.predicate_name());
self.handle_eval_result_from_dynamic_compile(
pred_str,
name,
arity,
place.predicate_name(),
);
}
fn set_module_atom_tbl(&mut self, module_addr: Addr, name: &mut ClauseName) -> bool {
let atom_tbl = match self.machine_st.store(self.machine_st.deref(module_addr)) {
Addr::Con(Constant::Atom(module, _)) => match self.indices.modules.get(&module) {
Some(ref module) => module.atom_tbl.clone(),
None => {
Addr::Con(h) =>
if let HeapCellValue::Atom(ref module, _) = &self.machine_st.heap[h] {
match self.indices.modules.get(module) {
Some(ref module) => module.atom_tbl.clone(),
None => {
self.machine_st.fail = true;
return false;
}
}
} else {
self.machine_st.fail = true;
return false;
}
},
},
_ => unreachable!(),
};
@@ -204,7 +232,12 @@ impl Machine {
fn retract_from_dynamic_predicate_in_module(&mut self) {
let index = self.machine_st[temp_v!(3)].clone();
let index = match self.machine_st.store(self.machine_st.deref(index)) {
Addr::Con(Constant::Integer(n)) => n.to_usize().unwrap(),
Addr::Con(h) =>
if let HeapCellValue::Integer(ref n) = &self.machine_st.heap[h] {
n.to_usize().unwrap()
} else {
unreachable!()
},
_ => unreachable!(),
};
@@ -224,7 +257,9 @@ impl Machine {
self.print_new_dynamic_clause(addrs, name.clone(), arity)
}
Err(err) => return self.machine_st.throw_exception(err),
Err(err) => {
return self.machine_st.throw_exception(err);
}
};
self.handle_eval_result_from_dynamic_compile(
@@ -239,8 +274,15 @@ impl Machine {
fn retract_from_dynamic_predicate(&mut self) {
let index = self.machine_st[temp_v!(3)].clone();
let index = match self.machine_st.store(self.machine_st.deref(index)) {
Addr::Con(Constant::Integer(n)) => n.to_usize().unwrap(),
_ => unreachable!(),
Addr::Con(h) =>
if let HeapCellValue::Integer(n) = &self.machine_st.heap[h] {
n.to_usize().unwrap()
} else {
unreachable!()
},
_ => {
unreachable!()
}
};
let (name, arity) = self.get_predicate_key(temp_v!(1), temp_v!(2));
@@ -257,7 +299,9 @@ impl Machine {
self.print_new_dynamic_clause(addrs, name.clone(), arity)
}
Err(err) => return self.machine_st.throw_exception(err),
Err(err) => {
return self.machine_st.throw_exception(err);
}
};
self.handle_eval_result_from_dynamic_compile(

View File

@@ -1,6 +1,6 @@
use core::marker::PhantomData;
use crate::prolog_parser::ast::*;
use crate::prolog_parser::ast::Constant;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::partial_string::*;
@@ -140,17 +140,175 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
#[inline]
pub(crate)
fn push(&mut self, val: HeapCellValue) {
unsafe {
let new_top = self.buf.new_block(mem::size_of::<HeapCellValue>());
ptr::write(self.buf.top as *mut _, val);
self.buf.top = new_top;
fn clone(&self, h: usize) -> HeapCellValue {
match &self[h] {
&HeapCellValue::Addr(addr) => {
HeapCellValue::Addr(addr)
}
&HeapCellValue::Atom(ref name, ref op) => {
HeapCellValue::Atom(name.clone(), op.clone())
}
&HeapCellValue::DBRef(ref db_ref) => {
HeapCellValue::DBRef(db_ref.clone())
}
&HeapCellValue::Integer(ref n) => {
HeapCellValue::Integer(n.clone())
}
&HeapCellValue::NamedStr(arity, ref name, ref op) => {
HeapCellValue::NamedStr(arity, name.clone(), op.clone())
}
&HeapCellValue::Rational(ref r) => {
HeapCellValue::Rational(r.clone())
}
&HeapCellValue::PartialString(_) => {
HeapCellValue::Addr(Addr::PStrLocation(h, 0))
}
&HeapCellValue::Stream(_) => {
HeapCellValue::Addr(Addr::Stream(h))
}
}
}
#[inline]
pub(crate)
fn allocate_pstr(&mut self, mut src: &str) -> Option<Addr> {
fn put_constant(&mut self, c: Constant) -> Addr {
match c {
Constant::Atom(name, op) => {
Addr::Con(self.push(HeapCellValue::Atom(name, op)))
}
Constant::Char(c) => {
self.push(HeapCellValue::Addr(Addr::Char(c)));
Addr::Char(c)
}
Constant::CharCode(c) => {
self.push(HeapCellValue::Addr(Addr::CharCode(c)));
Addr::CharCode(c)
}
Constant::CutPoint(cp) => {
self.push(HeapCellValue::Addr(Addr::CutPoint(cp)));
Addr::CutPoint(cp)
}
Constant::EmptyList => {
self.push(HeapCellValue::Addr(Addr::EmptyList));
Addr::EmptyList
}
Constant::Integer(n) => {
Addr::Con(self.push(HeapCellValue::Integer(n)))
}
Constant::Rational(r) => {
Addr::Con(self.push(HeapCellValue::Rational(r)))
}
Constant::Float(f) => {
self.push(HeapCellValue::Addr(Addr::Float(f)));
Addr::Float(f)
}
Constant::String(s) => {
let addr = self.allocate_pstr(&s);
let h = self.h();
self[h - 1] = HeapCellValue::Addr(Addr::EmptyList);
addr
}
Constant::Usize(n) => {
self.push(HeapCellValue::Addr(Addr::Usize(n)));
Addr::Usize(n)
}
}
}
#[inline]
pub(crate)
fn push(&mut self, val: HeapCellValue) -> usize {
let h = self.h();
unsafe {
let new_top = self.buf.new_block(mem::size_of::<HeapCellValue>());
ptr::write(self.buf.top as *mut _, val);
self.buf.top = new_top;
}
h
}
#[inline]
pub(crate)
fn rational_at(&self, h: usize) -> bool {
if let HeapCellValue::Rational(_) = &self[h] {
true
} else {
false
}
}
#[inline]
pub(crate)
fn integer_at(&self, h: usize) -> bool {
if let HeapCellValue::Integer(_) = &self[h] {
true
} else {
false
}
}
#[inline]
pub(crate)
fn atom_at(&self, h: usize) -> bool {
if let HeapCellValue::Atom(..) = &self[h] {
true
} else {
false
}
}
#[inline]
pub(crate)
fn to_unifiable(&mut self, non_heap_value: HeapCellValue) -> Addr {
match non_heap_value {
HeapCellValue::Addr(addr) => {
addr
}
val @ HeapCellValue::Atom(..)
| val @ HeapCellValue::Integer(_)
| val @ HeapCellValue::DBRef(_)
| val @ HeapCellValue::Rational(_) => {
Addr::Con(self.push(val))
}
val @ HeapCellValue::NamedStr(..) => {
Addr::Str(self.push(val))
}
val @ HeapCellValue::Stream(..) => {
Addr::Stream(self.push(val))
}
val @ HeapCellValue::PartialString(_) => {
let h = self.push(val);
self.push(HeapCellValue::Addr(Addr::EmptyList));
Addr::Con(h)
}
}
}
#[inline]
pub(crate)
fn allocate_pstr(&mut self, src: &str) -> Addr {
self.write_pstr(src)
.unwrap_or_else(|| {
let h = self.h();
self.push(HeapCellValue::PartialString(
PartialString::empty()
));
self.push(HeapCellValue::Addr(
Addr::HeapCell(h + 1)
));
Addr::PStrLocation(h, 0)
})
}
#[inline]
fn write_pstr(&mut self, mut src: &str) -> Option<Addr> {
let orig_h = self.h();
loop {
@@ -245,17 +403,21 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
}
pub(crate)
fn to_list<Iter: Iterator<Item = Addr>>(&mut self, values: Iter) -> usize {
fn to_list<Iter, SrcT>(&mut self, values: Iter) -> usize
where Iter: Iterator<Item = SrcT>,
SrcT: Into<HeapCellValue>
{
let head_addr = self.h();
let mut h = head_addr;
for value in values {
let h = self.h();
for value in values.map(|v| v.into()) {
self.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
self.push(HeapCellValue::Addr(value));
self.push(value);
h += mem::size_of::<HeapCellValue>() * 2;
}
self.push(HeapCellValue::Addr(Addr::Con(Constant::EmptyList)));
self.push(HeapCellValue::Addr(Addr::EmptyList));
head_addr
}
@@ -286,8 +448,8 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
pub(crate)
fn to_local_code_ptr(&self, addr: &Addr) -> Option<LocalCodePtr> {
let extract_integer = |s: usize| -> Option<usize> {
match self[s].as_addr(s) {
Addr::Con(Constant::Integer(n)) => n.to_usize(),
match &self[s] {
&HeapCellValue::Integer(ref n) => n.to_usize(),
_ => None
}
};
@@ -327,6 +489,19 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
_ => None
}
}
#[inline]
pub
fn index_addr<'a>(&'a self, addr: &Addr) -> RefOrOwned<'a, HeapCellValue> {
match addr {
&Addr::Con(h) | &Addr::Str(h) | &Addr::Stream(h) => {
RefOrOwned::Borrowed(&self[h])
}
addr => {
RefOrOwned::Owned(HeapCellValue::Addr(*addr))
}
}
}
}
impl<T: RawBlockTraits> Index<usize> for HeapTemplate<T> {

View File

@@ -1,6 +1,7 @@
use prolog_parser::ast::*;
use crate::prolog::forms::PredicateKey;
use crate::prolog::forms::{Number, PredicateKey};
use crate::prolog::machine::heap::*;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::machine_state::*;
use crate::prolog::rug::Integer;
@@ -21,19 +22,140 @@ pub(super) struct MachineError {
from: ErrorProvenance,
}
pub(super)
trait TypeError {
fn type_error(self, h: usize, valid_type: ValidType) -> MachineError;
}
impl TypeError for Addr {
fn type_error(self, _: usize, valid_type: ValidType) -> MachineError {
let stub = functor!(
"type_error",
[atom(valid_type.as_str()), addr(self)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received
}
}
}
impl TypeError for MachineStub {
fn type_error(self, h: usize, valid_type: ValidType) -> MachineError {
let stub = functor!(
"type_error",
[atom(valid_type.as_str()), aux(h, 0)],
[self]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed
}
}
}
impl TypeError for Number {
fn type_error(self, _h: usize, valid_type: ValidType) -> MachineError {
let stub = functor!(
"type_error",
[atom(valid_type.as_str()), number(self)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received
}
}
}
pub(super)
trait PermissionError {
fn permission_error(self, h: usize, index_str: &'static str, perm: Permission) -> MachineError;
}
impl PermissionError for Addr {
fn permission_error(self, _: usize, index_str: &'static str, perm: Permission) -> MachineError {
let stub = functor!(
"permission_error",
[atom(perm.as_str()), atom(index_str), addr(self)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received
}
}
}
impl PermissionError for MachineStub {
fn permission_error(self, h: usize, index_str: &'static str, perm: Permission) -> MachineError {
let stub = functor!(
"permission_error",
[atom(perm.as_str()), atom(index_str), aux(h, 0)],
[self]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed
}
}
}
pub(super)
trait DomainError {
fn domain_error(self, error: DomainErrorType) -> MachineError;
}
impl DomainError for Addr {
fn domain_error(self, error: DomainErrorType) -> MachineError {
let stub = functor!(
"domain_error",
[atom(error.as_str()), addr(self)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
}
impl DomainError for Number {
fn domain_error(self, error: DomainErrorType) -> MachineError {
let stub = functor!(
"domain_error",
[atom(error.as_str()), number(self)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
}
impl MachineError {
pub(super) fn functor_stub(name: ClauseName, arity: usize) -> MachineStub {
let name = HeapCellValue::Addr(Addr::Con(Constant::Atom(name, None)));
functor!(
"/",
2,
[name, heap_integer!(Integer::from(arity))],
SharedOpDesc::new(400, YFX)
SharedOpDesc::new(400, YFX),
[clause_name(name), integer(arity)]
)
}
pub(super) fn evaluation_error(eval_error: EvalError) -> Self {
let stub = functor!("evaluation_error", 1, [heap_atom!(eval_error.as_str())]);
let stub = functor!("evaluation_error", [atom(eval_error.as_str())]);
MachineError {
stub,
location: None,
@@ -42,21 +164,8 @@ impl MachineError {
}
pub(super)
fn type_error(valid_type: ValidType, culprit: Addr) -> Self {
let stub = functor!(
"type_error",
2,
[
heap_atom!(valid_type.as_str()),
HeapCellValue::Addr(culprit)
]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
fn type_error<T: TypeError>(h: usize, valid_type: ValidType, culprit: T) -> Self {
culprit.type_error(h, valid_type)
}
pub(super)
@@ -66,31 +175,24 @@ impl MachineError {
name: ClauseName,
arity: usize,
) -> Self {
let mod_name = HeapCellValue::Addr(Addr::Con(Constant::Atom(mod_name, None)));
let name = HeapCellValue::Addr(Addr::Con(Constant::Atom(name, None)));
let mut stub = functor!(
"evaluation_error",
1,
[HeapCellValue::Addr(Addr::HeapCell(h + 2))]
let res_stub = functor!(
":",
SharedOpDesc::new(600, XFY),
[clause_name(mod_name), clause_name(name)]
);
stub.append(&mut functor!(
let ind_stub = functor!(
"/",
2,
[
HeapCellValue::Addr(Addr::HeapCell(h + 2 + 3)),
heap_integer!(Integer::from(arity))
],
SharedOpDesc::new(400, YFX)
));
stub.append(&mut functor!(
":",
2,
[mod_name, name],
SharedOpDesc::new(600, XFY)
));
SharedOpDesc::new(400, YFX),
[aux(h + 2, 0), integer(arity)],
[res_stub]
);
let stub = functor!(
"evaluation_error",
[aux(h, 0)],
[ind_stub]
);
MachineError {
stub,
@@ -103,23 +205,29 @@ impl MachineError {
fn existence_error(h: usize, err: ExistenceError) -> Self {
match err {
ExistenceError::Module(name) => {
let name = HeapCellValue::Addr(Addr::Con(Constant::Atom(name, None)));
let stub = functor!("existence_error", 2, [heap_atom!("module"), name]);
let stub = functor!(
"existence_error",
[atom("module"), clause_name(name)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed,
from: ErrorProvenance::Received,
}
}
ExistenceError::Procedure(name, arity) => {
let mut stub = functor!(
"existence_error",
2,
[heap_atom!("procedure"), heap_str!(3 + h)]
let culprit = functor!(
"/",
SharedOpDesc::new(400, YFX),
[clause_name(name), integer(arity)]
);
stub.append(&mut Self::functor_stub(name, arity));
let stub = functor!(
"existence_error",
[atom("procedure"), aux(h, 0)],
[culprit]
);
MachineError {
stub,
@@ -127,99 +235,115 @@ impl MachineError {
from: ErrorProvenance::Constructed,
}
}
ExistenceError::Stream(addr) => {
let culprit = HeapCellValue::Addr(addr);
let stub = functor!("existence_error", 2, [heap_atom!("stream"), culprit]);
ExistenceError::Stream(culprit) => {
let stub = functor!(
"existence_error",
[atom("stream"), addr(culprit)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed,
from: ErrorProvenance::Received,
}
}
}
}
pub(super)
fn permission_error<T: PermissionError>(
h: usize,
err: Permission,
index_str: &'static str,
culprit: T,
) -> Self {
culprit.permission_error(
h,
index_str,
err,
)
}
fn arithmetic_error(h: usize, err: ArithmeticError) -> Self {
match err {
ArithmeticError::UninstantiatedVar => {
Self::instantiation_error()
}
ArithmeticError::NonEvaluableFunctor(name, arity) => {
let culprit = functor!(
"/",
SharedOpDesc::new(400, YFX),
[constant(h, &name), integer(arity)]
);
Self::type_error(h, ValidType::Evaluable, culprit)
}
}
}
#[inline]
pub(super)
fn domain_error<T: DomainError>(error: DomainErrorType, culprit: T) -> Self {
culprit.domain_error(error)
}
pub(super)
fn instantiation_error() -> Self {
let stub = functor!("instantiation_error");
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
pub(super)
fn session_error(h: usize, err: SessionError) -> Self {
match err {
SessionError::ParserError(err) => Self::syntax_error(h, err),
SessionError::ParserError(err) => {
Self::syntax_error(h, err)
}
SessionError::CannotOverwriteBuiltIn(pred_str)
| SessionError::CannotOverwriteImport(pred_str) => {
Self::permission_error(
PermissionError::Modify,
"private_procedure",
Addr::Con(Constant::Atom(pred_str, None)),
h,
Permission::Modify,
"private_procedure",
functor!(clause_name(pred_str)),
)
}
SessionError::InvalidFileName(filename) => {
Self::existence_error(h, ExistenceError::Module(filename))
}
SessionError::ModuleDoesNotContainExport(..) => Self::permission_error(
PermissionError::Access,
"private_procedure",
Addr::Con(atom!("module_does_not_contain_claimed_export")),
),
SessionError::ModuleNotFound => Self::permission_error(
PermissionError::Access,
"private_procedure",
Addr::Con(atom!("module_does_not_exist")),
),
SessionError::ModuleDoesNotContainExport(..) => {
Self::permission_error(
h,
Permission::Access,
"private_procedure",
functor!("module_does_not_contain_claimed_export"),
)
}
SessionError::ModuleNotFound => {
Self::permission_error(
h,
Permission::Access,
"private_procedure",
functor!("modules_does_not_exist"),
)
}
SessionError::OpIsInfixAndPostFix(op) => {
Self::permission_error(
PermissionError::Create,
h,
Permission::Create,
"operator",
Addr::Con(Constant::Atom(op, None)),
functor!(clause_name(op)),
)
}
_ => unreachable!(),
}
}
pub(super)
fn permission_error(
err: PermissionError,
index_str: &'static str,
culprit: Addr,
) -> Self {
let culprit = HeapCellValue::Addr(culprit);
let err = vec![heap_atom!(err.as_str()), heap_atom!(index_str), culprit];
let mut stub = functor!("permission_error", 3);
stub.extend(err.into_iter());
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed,
}
}
fn arithmetic_error(h: usize, err: ArithmeticError) -> Self {
match err {
ArithmeticError::UninstantiatedVar => Self::instantiation_error(),
ArithmeticError::NonEvaluableFunctor(name, arity) => {
let name = HeapCellValue::Addr(Addr::Con(name));
let culprit = functor!(
"/",
2,
[name, heap_integer!(Integer::from(arity))],
SharedOpDesc::new(400, YFX)
);
let mut stub = Self::type_error(ValidType::Evaluable, Addr::HeapCell(3 + h)).stub;
stub.extend(culprit.into_iter());
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed,
}
}
}
}
pub(super)
fn syntax_error(h: usize, err: ParserError) -> Self {
if let ParserError::Arithmetic(err) = err {
@@ -227,15 +351,13 @@ impl MachineError {
}
let location = err.line_and_col_num();
let err = vec![heap_atom!(err.as_str())];
let mut stub = if err.len() == 1 {
functor!("syntax_error", 1)
} else {
functor!("syntax_error", 1, [heap_str!(h + 2)])
};
stub.extend(err.into_iter());
let stub = functor!(err.as_str());
let stub = functor!(
"syntax_error",
[aux(h, 0)],
[stub]
);
MachineError {
stub,
@@ -244,33 +366,10 @@ impl MachineError {
}
}
pub(super)
fn domain_error(error: DomainError, culprit: Addr) -> Self {
let stub = functor!(
"domain_error",
2,
[heap_atom!(error.as_str()), HeapCellValue::Addr(culprit)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
pub(super)
fn instantiation_error() -> Self {
let stub = functor!("instantiation_error");
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
pub(super)
fn representation_error(flag: RepFlag) -> Self {
let stub = functor!("representation_error", 1, [heap_atom!(flag.as_str())]);
let stub = functor!("representation_error", [atom(flag.as_str())]);
MachineError {
stub,
location: None,
@@ -296,7 +395,7 @@ impl MachineError {
}
#[derive(Clone, Copy)]
pub enum PermissionError {
pub enum Permission {
Access,
Create,
InputStream,
@@ -304,14 +403,14 @@ pub enum PermissionError {
OutputStream,
}
impl PermissionError {
impl Permission {
pub fn as_str(self) -> &'static str {
match self {
PermissionError::Access => "access",
PermissionError::Create => "create",
PermissionError::InputStream => "input",
PermissionError::Modify => "modify",
PermissionError::OutputStream => "output",
Permission::Access => "access",
Permission::Create => "create",
Permission::InputStream => "input",
Permission::Modify => "modify",
Permission::OutputStream => "output",
}
}
}
@@ -363,18 +462,18 @@ impl ValidType {
}
#[derive(Clone, Copy)]
pub enum DomainError {
pub enum DomainErrorType {
NotLessThanZero,
Stream,
StreamOrAlias,
}
impl DomainError {
impl DomainErrorType {
pub fn as_str(self) -> &'static str {
match self {
DomainError::NotLessThanZero => "not_less_than_zero",
DomainError::Stream => "stream",
DomainError::StreamOrAlias => "stream_or_alias",
DomainErrorType::NotLessThanZero => "not_less_than_zero",
DomainErrorType::Stream => "stream",
DomainErrorType::StreamOrAlias => "stream_or_alias",
}
}
}
@@ -424,20 +523,20 @@ impl EvalError {
}
// used by '$skip_max_list'.
#[derive(Clone, Copy)]
pub(super) enum CycleSearchResult {
EmptyList,
NotList,
PartialList(usize, Ref), // the list length (up to max), and an offset into the heap.
ProperList(usize), // the list length.
CompleteString(usize, Rc<String>), // the string length (in bytes), the string.
UntouchedString(usize, Rc<String>), // the cut off, past which is the untouched string.
PartialList(usize, Ref), // the list length (up to max), and an offset into the heap.
ProperList(usize), // the list length.
PStrLocation(usize, usize, usize), // the list length (up to max), the heap offset, byte offset into the string.
UntouchedList(usize), // the address of an uniterated Addr::Lis(address).
UntouchedList(usize), // the address of an uniterated Addr::Lis(address).
}
impl MachineState {
// see 8.4.3 of Draft Technical Corrigendum 2.
pub(super) fn check_sort_errors(&self) -> CallResult {
pub(super)
fn check_sort_errors(&self) -> CallResult {
let stub = MachineError::functor_stub(clause_name!("sort"), 2);
let list = self.store(self.deref(self[temp_v!(1)].clone()));
let sorted = self.store(self.deref(self[temp_v!(2)].clone()));
@@ -447,14 +546,14 @@ impl MachineState {
return Err(self.error_form(MachineError::instantiation_error(), stub))
}
CycleSearchResult::NotList => {
return Err(self.error_form(MachineError::type_error(ValidType::List, list), stub))
return Err(self.error_form(MachineError::type_error(0, ValidType::List, list), stub))
}
_ => {}
};
match self.detect_cycles(sorted.clone()) {
CycleSearchResult::NotList if !sorted.is_ref() => {
Err(self.error_form(MachineError::type_error(ValidType::List, sorted), stub))
Err(self.error_form(MachineError::type_error(0, ValidType::List, sorted), stub))
}
_ => Ok(()),
}
@@ -465,7 +564,7 @@ impl MachineState {
match self.detect_cycles(list.clone()) {
CycleSearchResult::NotList if !list.is_ref() => {
Err(self.error_form(MachineError::type_error(ValidType::List, list), stub))
Err(self.error_form(MachineError::type_error(0, ValidType::List, list), stub))
}
_ => {
let mut addr = list;
@@ -474,18 +573,23 @@ impl MachineState {
let mut new_l = l;
loop {
match self.heap[new_l].clone() {
HeapCellValue::Addr(Addr::Str(l)) => new_l = l,
HeapCellValue::NamedStr(2, ref name, Some(_))
if name.as_str() == "-" =>
{
break
match self.heap.clone(new_l) {
HeapCellValue::Addr(Addr::Str(l)) => {
new_l = l;
}
HeapCellValue::NamedStr(2, ref name, Some(_))
if name.as_str() == "-" => {
break;
}
HeapCellValue::Addr(Addr::HeapCell(_)) => {
break;
}
HeapCellValue::Addr(Addr::StackCell(..)) => {
break;
}
HeapCellValue::Addr(Addr::HeapCell(_)) => break,
HeapCellValue::Addr(Addr::StackCell(..)) => break,
_ => {
return Err(self.error_form(
MachineError::type_error(ValidType::Pair, Addr::HeapCell(l)),
MachineError::type_error(0, ValidType::Pair, Addr::HeapCell(l)),
stub,
))
}
@@ -501,9 +605,11 @@ impl MachineState {
}
// see 8.4.4 of Draft Technical Corrigendum 2.
pub(super) fn check_keysort_errors(&self) -> CallResult {
pub(super)
fn check_keysort_errors(&self) -> CallResult {
let stub = MachineError::functor_stub(clause_name!("keysort"), 2);
let pairs = self.store(self.deref(self[temp_v!(1)].clone()));
let pairs = self.store(self.deref(self[temp_v!(1)].clone()));
let sorted = self.store(self.deref(self[temp_v!(2)].clone()));
match self.detect_cycles(pairs.clone()) {
@@ -511,7 +617,7 @@ impl MachineState {
Err(self.error_form(MachineError::instantiation_error(), stub))
}
CycleSearchResult::NotList => {
Err(self.error_form(MachineError::type_error(ValidType::List, pairs), stub))
Err(self.error_form(MachineError::type_error(0, ValidType::List, pairs), stub))
}
_ => Ok(()),
}?;
@@ -519,7 +625,8 @@ impl MachineState {
self.check_for_list_pairs(sorted)
}
pub(super) fn error_form(&self, err: MachineError, src: MachineStub) -> MachineStub {
pub(super)
fn error_form(&self, err: MachineError, src: MachineStub) -> MachineStub {
let location = err.location;
let err_len = err.len();
@@ -535,21 +642,17 @@ impl MachineState {
if let Some((line_num, _)) = location {
let colon_op_desc = Some(SharedOpDesc::new(600, XFY));
stub.extend(
vec![
HeapCellValue::NamedStr(2, clause_name!(":"), colon_op_desc),
HeapCellValue::Addr(Addr::HeapCell(h + 6 + err_len)),
heap_integer!(Integer::from(line_num)),
]
.into_iter(),
);
stub.push(HeapCellValue::NamedStr(2, clause_name!(":"), colon_op_desc));
stub.push(HeapCellValue::Addr(Addr::HeapCell(h + 6 + err_len)));
stub.push(HeapCellValue::Integer(Rc::new(Integer::from(line_num))));
}
stub.extend(src.into_iter());
stub
}
pub(super) fn throw_exception(&mut self, err: MachineStub) {
pub(super)
fn throw_exception(&mut self, err: MachineStub) {
let h = self.heap.h();
self.ball.boundary = 0;
@@ -602,4 +705,5 @@ impl From<ParserError> for EvalSession {
fn from(err: ParserError) -> Self {
EvalSession::from(SessionError::ParserError(err))
}
}

View File

@@ -7,11 +7,13 @@ use crate::prolog::forms::*;
use crate::prolog::machine::code_repo::CodeRepo;
use crate::prolog::machine::Ball;
use crate::prolog::machine::heap::*;
use crate::prolog::machine::machine_state::*;
use crate::prolog::machine::partial_string::*;
use crate::prolog::machine::raw_block::RawBlockTraits;
use crate::prolog::machine::streams::Stream;
use crate::prolog::instructions::*;
use crate::prolog::rug::Integer;
use crate::prolog::ordered_float::OrderedFloat;
use crate::prolog::rug::{Integer, Rational};
use indexmap::IndexMap;
@@ -39,20 +41,35 @@ pub enum DBRef {
),
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Addr {
AttrVar(usize),
Con(Constant),
DBRef(DBRef),
Lis(usize),
HeapCell(usize),
StackCell(usize, usize),
Str(usize),
PStrLocation(usize, usize), // location of pstr in heap, offset into string in bytes.
Stream(Stream),
// 7.2
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum TermOrderCategory {
Variable,
FloatingPoint,
Integer,
Atom,
Compound,
}
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum Addr {
AttrVar(usize),
Char(char),
CharCode(u32),
Con(usize),
CutPoint(usize),
EmptyList,
Float(OrderedFloat<f64>),
Lis(usize),
HeapCell(usize),
PStrLocation(usize, usize), // location of pstr in heap, offset into string in bytes.
StackCell(usize, usize),
Str(usize),
Stream(usize),
Usize(usize),
}
#[derive(Clone, Copy, Hash, Eq, PartialEq, PartialOrd)]
pub enum Ref {
AttrVar(usize),
HeapCell(usize),
@@ -69,6 +86,28 @@ impl Ref {
}
}
impl Ord for Ref {
fn cmp(&self, other: &Ref) -> Ordering {
match (self, other) {
(Ref::AttrVar(h1), Ref::AttrVar(h2))
| (Ref::HeapCell(h1), Ref::HeapCell(h2))
| (Ref::HeapCell(h1), Ref::AttrVar(h2))
| (Ref::AttrVar(h1), Ref::HeapCell(h2)) => {
h1.cmp(&h2)
}
(Ref::StackCell(fr1, sc1), Ref::StackCell(fr2, sc2)) => {
fr1.cmp(&fr2).then_with(|| sc1.cmp(&sc2))
}
(Ref::StackCell(..), _) => {
Ordering::Greater
}
(_, Ref::StackCell(..)) => {
Ordering::Less
}
}
}
}
impl PartialEq<Ref> for Addr {
fn eq(&self, r: &Ref) -> bool {
self.as_var() == Some(*r)
@@ -133,6 +172,83 @@ impl Addr {
}
}
pub(super)
fn order_category(&self, heap: &Heap) -> Option<TermOrderCategory> {
match self {
Addr::HeapCell(_) | Addr::AttrVar(_) | Addr::StackCell(..) => {
Some(TermOrderCategory::Variable)
}
Addr::Float(_) => {
Some(TermOrderCategory::FloatingPoint)
}
&Addr::Con(h) => {
match &heap[h] {
HeapCellValue::Atom(..) => {
Some(TermOrderCategory::Atom)
}
HeapCellValue::Integer(_) => {
Some(TermOrderCategory::Integer)
}
HeapCellValue::Rational(_) => {
Some(TermOrderCategory::Integer)
}
HeapCellValue::DBRef(_) => {
None
}
_ => {
unreachable!()
}
}
}
Addr::Char(_) | Addr::CharCode(_) | Addr::EmptyList => {
Some(TermOrderCategory::Atom)
}
Addr::Lis(_) | Addr::PStrLocation(..) | Addr::Str(_) => {
Some(TermOrderCategory::Compound)
}
Addr::CutPoint(_) | Addr::Usize(_) | Addr::Stream(_) => {
None
}
}
}
pub fn as_constant(&self, machine_st: &MachineState) -> Option<Constant> {
match self {
&Addr::Char(c) => {
Some(Constant::Char(c))
}
&Addr::CharCode(c) => {
Some(Constant::CharCode(c))
}
&Addr::Con(h) => {
match &machine_st.heap[h] {
&HeapCellValue::Atom(ref name, ref op) => {
Some(Constant::Atom(name.clone(), op.clone()))
}
&HeapCellValue::Integer(ref n) => {
Some(Constant::Integer(n.clone()))
}
&HeapCellValue::Rational(ref n) => {
Some(Constant::Rational(n.clone()))
}
_ => {
None
}
}
}
&Addr::Float(f) => {
Some(Constant::Float(f))
}
&Addr::PStrLocation(h, n) => {
machine_st.to_complete_string(h, n)
.map(|s| Constant::String(Rc::new(s)))
}
_ => {
None
}
}
}
pub fn is_protected(&self, e: usize) -> bool {
match self {
&Addr::StackCell(addr, _) if addr >= e => false,
@@ -209,27 +325,76 @@ impl From<Ref> for TrailRef {
}
}
#[derive(Clone, PartialEq)]
pub enum HeapCellValue {
Addr(Addr),
Atom(ClauseName, Option<SharedOpDesc>),
DBRef(DBRef),
Integer(Rc<Integer>),
NamedStr(usize, ClauseName, Option<SharedOpDesc>), // arity, name, precedence/Specifier if it has one.
Rational(Rc<Rational>),
PartialString(PartialString),
Stream(Stream),
}
impl HeapCellValue {
#[inline]
pub fn as_addr(&self, focus: usize) -> Addr {
match self {
HeapCellValue::Addr(ref a) => {
a.clone()
}
HeapCellValue::Atom(..) | HeapCellValue::DBRef(..) | HeapCellValue::Integer(..) |
HeapCellValue::Rational(..) => {
Addr::Con(focus)
}
HeapCellValue::NamedStr(_, _, _) => {
Addr::Str(focus)
}
HeapCellValue::PartialString(_) => {
Addr::PStrLocation(focus, 0)
}
HeapCellValue::Stream(_) => {
Addr::Stream(focus)
}
}
}
#[inline]
pub fn context_free_clone(&self) -> HeapCellValue {
match self {
&HeapCellValue::Addr(addr) => {
HeapCellValue::Addr(addr)
}
&HeapCellValue::Atom(ref name, ref op) => {
HeapCellValue::Atom(name.clone(), op.clone())
}
&HeapCellValue::DBRef(ref db_ref) => {
HeapCellValue::DBRef(db_ref.clone())
}
&HeapCellValue::Integer(ref n) => {
HeapCellValue::Integer(n.clone())
}
&HeapCellValue::NamedStr(arity, ref name, ref op) => {
HeapCellValue::NamedStr(arity, name.clone(), op.clone())
}
&HeapCellValue::Rational(ref r) => {
HeapCellValue::Rational(r.clone())
}
&HeapCellValue::PartialString(ref pstr) => {
HeapCellValue::PartialString(pstr.clone())
}
&HeapCellValue::Stream(_) => {
HeapCellValue::Stream(Stream::null_stream())
}
}
}
}
impl From<Addr> for HeapCellValue {
#[inline]
fn from(value: Addr) -> HeapCellValue {
HeapCellValue::Addr(value)
}
}
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
@@ -407,37 +572,31 @@ impl LocalCodePtr {
LocalCodePtr::DirEntry(p) => {
heap.append(functor!(
"dir_entry",
1,
[heap_integer!(Integer::from(*p))]
[integer(*p)]
));
}
LocalCodePtr::InSituDirEntry(p) => {
heap.append(functor!(
"in_situ_dir_entry",
1,
[heap_integer!(Integer::from(*p))]
[integer(*p)]
));
}
LocalCodePtr::TopLevel(chunk_num, offset) => {
heap.append(functor!(
"top_level",
2,
[heap_integer!(Integer::from(*chunk_num)),
heap_integer!(Integer::from(*offset))]
[integer(*chunk_num), integer(*offset)]
));
}
LocalCodePtr::UserGoalExpansion(p) => {
heap.append(functor!(
"user_goal_expansion",
1,
[heap_integer!(Integer::from(*p))]
[integer(*p)]
));
}
LocalCodePtr::UserTermExpansion(p) => {
heap.append(functor!(
"user_term_expansion",
1,
[heap_integer!(Integer::from(*p))]
[integer(*p)]
));
}
}
@@ -449,8 +608,12 @@ impl LocalCodePtr {
impl PartialOrd<CodePtr> for CodePtr {
fn partial_cmp(&self, other: &CodePtr) -> Option<Ordering> {
match (self, other) {
(&CodePtr::Local(ref l1), &CodePtr::Local(ref l2)) => l1.partial_cmp(l2),
_ => Some(Ordering::Greater),
(&CodePtr::Local(ref l1), &CodePtr::Local(ref l2)) => {
l1.partial_cmp(l2)
}
_ => {
Some(Ordering::Greater)
}
}
}
}
@@ -465,8 +628,12 @@ impl PartialOrd<LocalCodePtr> for LocalCodePtr {
| (&LocalCodePtr::TopLevel(_, p1), &LocalCodePtr::TopLevel(_, ref p2)) => {
p1.partial_cmp(p2)
}
(_, &LocalCodePtr::TopLevel(_, _)) => Some(Ordering::Less),
_ => Some(Ordering::Greater),
(_, &LocalCodePtr::TopLevel(_, _)) => {
Some(Ordering::Less)
}
_ => {
Some(Ordering::Greater)
}
}
}
}

View File

@@ -18,7 +18,6 @@ use std::cmp::Ordering;
use std::io::Write;
use std::mem;
use std::ops::{Index, IndexMut};
use std::rc::Rc;
pub struct Ball {
pub(super) boundary: usize,
@@ -58,11 +57,11 @@ impl Ball {
for heap_value in self.stub.iter_from(0) {
stub.push(match heap_value {
HeapCellValue::Addr(ref addr) => {
HeapCellValue::Addr(addr.clone() - diff)
&HeapCellValue::Addr(addr) => {
HeapCellValue::Addr(addr - diff)
}
heap_value => {
heap_value.clone()
heap_value.context_free_clone()
}
});
}
@@ -185,8 +184,12 @@ impl<'a> CopierTarget for CopyBallTerm<'a> {
let index = h - self.heap_boundary;
self.stub[index].as_addr(h)
}
Addr::StackCell(fr, sc) => self.stack.index_and_frame(fr)[sc].clone(),
addr => addr,
Addr::StackCell(fr, sc) => {
self.stack.index_and_frame(fr)[sc].clone()
}
addr => {
addr
}
}
}
@@ -250,8 +253,6 @@ pub(super) enum HeapPtr {
HeapCell(usize),
PStrChar(usize, usize),
PStrLocation(usize, usize),
StringChar(usize, Rc<String>),
StringLocation(usize, Rc<String>),
}
impl HeapPtr {
@@ -259,30 +260,23 @@ impl HeapPtr {
pub(super)
fn read(&self, heap: &Heap) -> Addr {
match self {
&HeapPtr::HeapCell(h) =>
Addr::HeapCell(h),
&HeapPtr::PStrChar(h, n) =>
&HeapPtr::HeapCell(h) => {
Addr::HeapCell(h)
}
&HeapPtr::PStrChar(h, n) => {
if let HeapCellValue::PartialString(ref pstr) = &heap[h] {
let s = pstr.block_as_str();
if let Some(c) = s[n ..].chars().next() {
Addr::Con(Constant::Char(c))
if let Some(c) = pstr.range_from(n ..).next() {
Addr::Char(c)
} else {
Addr::HeapCell(h + 1)
}
} else {
unreachable!()
},
&HeapPtr::PStrLocation(h, n) =>
Addr::PStrLocation(h, n),
&HeapPtr::StringChar(n, ref s) =>
if let Some(c) = s[n ..].chars().next() {
Addr::Con(Constant::Char(c))
} else {
Addr::Con(Constant::EmptyList)
},
&HeapPtr::StringLocation(n, ref s) =>
Addr::Con(Constant::String(n, s.clone())),
}
}
&HeapPtr::PStrLocation(h, n) => {
Addr::PStrLocation(h, n)
}
}
}
}
@@ -330,29 +324,27 @@ impl MachineState {
let addr = self.store(self.deref(addr.clone()));
match addr {
Addr::Con(Constant::String(n, ref s))
if self.flags.double_quotes.is_chars() => {
if s.len() < n {
chars += &s[n ..];
}
if iter.next().is_some() {
return Err(MachineError::type_error(ValidType::Character, addr.clone()));
}
}
Addr::Con(Constant::Char(c)) => {
Addr::Char(c) => {
chars.push(c);
continue;
}
Addr::Con(Constant::Atom(ref name, _))
if name.as_str().len() == 1 => {
chars += name.as_str();
Addr::Con(h) => {
if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
if name.is_char() {
chars += name.as_str();
continue;
}
}
_ => {
return Err(
MachineError::type_error(ValidType::Character, addr.clone())
);
}
}
_ => {
}
};
let h = self.heap.h();
return Err(
MachineError::type_error(h, ValidType::Character, addr)
);
}
Ok(chars)
@@ -738,32 +730,36 @@ pub(crate) trait CallPolicy: Any {
let a2 = machine_st[temp_v!(2)].clone();
let a3 = machine_st[temp_v!(3)].clone();
let c = match machine_st.compare_term_test(&a2, &a3) {
Ordering::Greater => {
let atom = match machine_st.compare_term_test(&a2, &a3) {
Some(Ordering::Greater) => {
let spec = fetch_atom_op_spec(clause_name!(">"), None, &indices.op_dir);
Addr::Con(Constant::Atom(clause_name!(">"), spec))
HeapCellValue::Atom(clause_name!(">"), spec)
}
Ordering::Equal => {
Some(Ordering::Equal) => {
let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir);
Addr::Con(Constant::Atom(clause_name!("="), spec))
HeapCellValue::Atom(clause_name!("="), spec)
}
Ordering::Less => {
None | Some(Ordering::Less) => {
let spec = fetch_atom_op_spec(clause_name!("<"), None, &indices.op_dir);
Addr::Con(Constant::Atom(clause_name!("<"), spec))
HeapCellValue::Atom(clause_name!("<"), spec)
}
};
machine_st.unify(a1, c);
let h = machine_st.heap.h();
machine_st.heap.push(atom);
machine_st.unify(a1, Addr::Con(h));
return_from_clause!(machine_st.last_call, machine_st)
}
&BuiltInClauseType::CompareTerm(qt) => {
machine_st.compare_term(qt);
return_from_clause!(machine_st.last_call, machine_st)
}
&BuiltInClauseType::Nl => {
&BuiltInClauseType::Nl => {
write!(current_output_stream, "\n").unwrap();
current_output_stream.flush().unwrap();
return_from_clause!(machine_st.last_call, machine_st)
}
&BuiltInClauseType::Read => {
@@ -811,11 +807,12 @@ pub(crate) trait CallPolicy: Any {
let a1 = machine_st[temp_v!(1)].clone();
let a2 = machine_st[temp_v!(2)].clone();
machine_st.fail = if let Ordering::Equal = machine_st.compare_term_test(&a1, &a2) {
true
} else {
false
};
machine_st.fail =
if let Some(Ordering::Equal) = machine_st.compare_term_test(&a1, &a2) {
true
} else {
false
};
return_from_clause!(machine_st.last_call, machine_st)
}
@@ -825,7 +822,10 @@ pub(crate) trait CallPolicy: Any {
let stub = MachineError::functor_stub(clause_name!("sort"), 2);
let mut list = machine_st.try_from_list(temp_v!(1), stub)?;
list.sort_unstable_by(|a1, a2| machine_st.compare_term_test(a1, a2));
list.sort_unstable_by(|a1, a2| {
machine_st.compare_term_test(a1, a2).unwrap_or(Ordering::Less)
});
machine_st.term_dedup(&mut list);
let heap_addr = Addr::HeapCell(machine_st.heap.to_list(list.into_iter()));
@@ -847,7 +847,9 @@ pub(crate) trait CallPolicy: Any {
key_pairs.push((key, val.clone()));
}
key_pairs.sort_by(|a1, a2| machine_st.compare_term_test(&a1.0, &a2.0));
key_pairs.sort_by(|a1, a2| {
machine_st.compare_term_test(&a1.0, &a2.0).unwrap_or(Ordering::Less)
});
let key_pairs = key_pairs.into_iter().map(|kp| kp.1);
let heap_addr = Addr::HeapCell(machine_st.heap.to_list(key_pairs));
@@ -859,9 +861,11 @@ pub(crate) trait CallPolicy: Any {
}
&BuiltInClauseType::Is(r, ref at) => {
let a1 = machine_st[r].clone();
let a2 = machine_st.get_number(at)?;
let n2 = machine_st.get_number(at)?;
let n2 = Addr::Con(machine_st.heap.push(n2.into()));
machine_st.unify(a1, n2);
machine_st.unify(a1, Addr::Con(a2.to_constant()));
return_from_clause!(machine_st.last_call, machine_st)
}
}
@@ -935,11 +939,13 @@ pub(crate) trait CallPolicy: Any {
}
}
ClauseType::Hook(_) | ClauseType::System(_) => {
let name = Addr::Con(Constant::Atom(name, None));
let name = functor!(clause_name(name));
let stub = MachineError::functor_stub(clause_name!("call"), arity + 1);
return Err(machine_st
.error_form(MachineError::type_error(ValidType::Callable, name), stub));
return Err(machine_st.error_form(
MachineError::type_error(machine_st.heap.h(), ValidType::Callable, name),
stub,
));
}
};
}
@@ -997,7 +1003,7 @@ impl CallPolicy for CWILCallPolicy {
current_input_stream,
current_output_stream
)?;
self.increment(machine_st)
}
@@ -1016,7 +1022,7 @@ impl CallPolicy for CWILCallPolicy {
current_input_stream,
current_output_stream,
)?;
self.increment(machine_st)
}
}
@@ -1035,7 +1041,8 @@ pub(crate) struct CWILCallPolicy {
}
impl CWILCallPolicy {
pub(crate) fn new_in_place(policy: &mut Box<dyn CallPolicy>) {
pub(crate)
fn new_in_place(policy: &mut Box<dyn CallPolicy>) {
let mut prev_policy: Box<dyn CallPolicy> = Box::new(DefaultCallPolicy {});
mem::swap(&mut prev_policy, policy);
@@ -1045,6 +1052,7 @@ impl CWILCallPolicy {
limits: vec![],
inference_limit_exceeded: false,
};
*policy = Box::new(new_policy);
}
@@ -1056,10 +1064,10 @@ impl CWILCallPolicy {
if let Some(&(ref limit, bp)) = self.limits.last() {
if self.count == *limit {
self.inference_limit_exceeded = true;
return Err(functor!(
"inference_limit_exceeded",
1,
[HeapCellValue::Addr(Addr::Con(Constant::Usize(bp)))]
[addr(Addr::Usize(bp))]
));
} else {
self.count += 1;
@@ -1069,7 +1077,8 @@ impl CWILCallPolicy {
Ok(())
}
pub(crate) fn add_limit(&mut self, mut limit: Integer, b: usize) -> &Integer {
pub(crate)
fn add_limit(&mut self, mut limit: Integer, b: usize) -> &Integer {
limit += &self.count;
match self.limits.last().cloned() {
@@ -1080,7 +1089,8 @@ impl CWILCallPolicy {
&self.count
}
pub(crate) fn remove_limit(&mut self, b: usize) -> &Integer {
pub(crate)
fn remove_limit(&mut self, b: usize) -> &Integer {
if let Some((_, bp)) = self.limits.last().cloned() {
if bp == b {
self.limits.pop();
@@ -1090,11 +1100,13 @@ impl CWILCallPolicy {
&self.count
}
pub(crate) fn is_empty(&self) -> bool {
pub(crate)
fn is_empty(&self) -> bool {
self.limits.is_empty()
}
pub(crate) fn into_inner(&mut self) -> Box<dyn CallPolicy> {
pub(crate)
fn into_inner(&mut self) -> Box<dyn CallPolicy> {
let mut new_inner: Box<dyn CallPolicy> = Box::new(DefaultCallPolicy {});
mem::swap(&mut self.prev_policy, &mut new_inner);
new_inner
@@ -1108,11 +1120,11 @@ pub(crate) trait CutPolicy: Any {
downcast!(dyn CutPolicy);
fn cut_body(machine_st: &mut MachineState, addr: Addr) -> bool {
fn cut_body(machine_st: &mut MachineState, addr: &Addr) -> bool {
let b = machine_st.b;
match addr {
Addr::Con(Constant::CutPoint(b0)) | Addr::Con(Constant::Usize(b0)) => {
&Addr::CutPoint(b0) | &Addr::Usize(b0) => {
if b > b0 {
machine_st.b = b0;
machine_st.tidy_trail();
@@ -1131,13 +1143,13 @@ pub(crate) struct DefaultCutPolicy {}
pub(super) fn deref_cut(machine_st: &mut MachineState, r: RegType) {
let addr = machine_st.store(machine_st.deref(machine_st[r].clone()));
cut_body(machine_st, addr);
cut_body(machine_st, &addr);
}
impl CutPolicy for DefaultCutPolicy {
fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool {
let addr = machine_st[r].clone();
cut_body(machine_st, addr)
cut_body(machine_st, &addr)
}
}
@@ -1175,7 +1187,7 @@ impl SCCCutPolicy {
let (idx, arity) = if machine_st.block < prev_block {
(dir_entry!(self.r_c_w_h), 0)
} else {
machine_st[temp_v!(1)] = Addr::Con(Constant::Usize(b_cutoff));
machine_st[temp_v!(1)] = Addr::Usize(b_cutoff);
(dir_entry!(self.r_c_wo_h), 1)
};
@@ -1198,7 +1210,7 @@ impl CutPolicy for SCCCutPolicy {
let b = machine_st.b;
match machine_st[r].clone() {
Addr::Con(Constant::Usize(b0)) | Addr::Con(Constant::CutPoint(b0)) => {
Addr::Usize(b0) | Addr::CutPoint(b0) => {
if b > b0 {
machine_st.b = b0;
machine_st.tidy_trail();

File diff suppressed because it is too large Load Diff

View File

@@ -19,13 +19,15 @@ pub mod machine_errors;
pub mod machine_indices;
pub(super) mod machine_state;
pub mod modules;
mod partial_string;
pub mod partial_string;
mod raw_block;
mod stack;
pub(crate) mod streams;
pub(super) mod term_expansion;
pub mod toplevel;
#[macro_use]
mod arithmetic_ops;
#[macro_use]
mod machine_state_impl;
mod system_calls;
@@ -340,8 +342,8 @@ impl Machine {
// the first of these is the path to the scryer-prolog executable, so skip
// it.
for filename in env::args().skip(1) {
let atom = atom!(filename, self.indices.atom_tbl);
filename_atoms.push(Addr::Con(atom));
let atom = clause_name!(filename, self.indices.atom_tbl);
filename_atoms.push(HeapCellValue::Atom(atom, None));
}
let list_addr =
@@ -547,14 +549,14 @@ impl Machine {
HeapCellValue::NamedStr(arity, ref name, _)
if *arity == 2 && name.as_str() == "/" => {
let name = match &self.machine_st.heap[s+1] {
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) =>
&HeapCellValue::Atom(ref name, _) =>
name.clone(),
_ =>
unreachable!()
};
let arity = match &self.machine_st.heap[s+2] {
&HeapCellValue::Addr(Addr::Con(Constant::Integer(ref arity))) =>
&HeapCellValue::Integer(ref arity) =>
arity.to_usize().unwrap(),
_ =>
unreachable!()
@@ -565,21 +567,21 @@ impl Machine {
HeapCellValue::NamedStr(arity, ref name, _)
if *arity == 3 && name.as_str() == "op" => {
let name = match &self.machine_st.heap[s+3] {
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) =>
&HeapCellValue::Atom(ref name, _) =>
name.clone(),
_ =>
unreachable!()
};
let spec = match &self.machine_st.heap[s+2] {
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) =>
&HeapCellValue::Atom(ref name, _) =>
name.clone(),
_ =>
unreachable!()
};
let prec = match &self.machine_st.heap[s+1] {
&HeapCellValue::Addr(Addr::Con(Constant::Integer(ref arity))) =>
&HeapCellValue::Integer(ref arity) =>
arity.to_usize().unwrap(),
_ =>
unreachable!()
@@ -610,9 +612,13 @@ impl Machine {
let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]);
let module_spec = self.machine_st[temp_v!(1)].clone();
let name = match self.machine_st.store(self.machine_st.deref(module_spec)) {
Addr::Con(Constant::Atom(name, _)) => name,
_ => unreachable!()
let name = {
let addr = self.machine_st.store(self.machine_st.deref(module_spec));
match self.machine_st.heap.index_addr(&addr).as_ref() {
HeapCellValue::Atom(name, _) => name.clone(),
_ => unreachable!(),
}
};
let load_result = match to_src(name) {
@@ -653,9 +659,13 @@ impl Machine {
let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]);
let module_spec = self.machine_st[temp_v!(1)].clone();
let name = match self.machine_st.store(self.machine_st.deref(module_spec)) {
Addr::Con(Constant::Atom(name, _)) => name,
_ => unreachable!()
let name = {
let addr = self.machine_st.store(self.machine_st.deref(module_spec));
match self.machine_st.heap.index_addr(&addr).as_ref() {
HeapCellValue::Atom(name, _) => name.clone(),
_ => unreachable!(),
}
};
let exports = match self.extract_module_export_list() {

View File

@@ -1,26 +1,11 @@
use crate::prolog::machine::raw_block::*;
use std::alloc;
use std::mem;
use std::ptr;
use std::slice;
use std::ops::{Range, RangeFrom};
use std::str;
pub(crate) struct PartialStringTraits {}
impl RawBlockTraits for PartialStringTraits {
#[inline]
fn init_size() -> usize {
0
}
#[inline]
fn align() -> usize {
mem::align_of::<char>()
}
}
pub struct PartialString {
pub(super) buf: RawBlock<PartialStringTraits>,
buf: *const u8,
}
impl Clone for PartialString {
@@ -30,17 +15,10 @@ impl Clone for PartialString {
}
}
impl PartialEq for PartialString {
#[inline]
fn eq(&self, other: &Self) -> bool {
self as *const _ == other as *const _
}
}
fn scan_for_terminator(src: &str) -> usize {
fn scan_for_terminator<Iter: Iterator<Item = char>>(iter: Iter) -> usize {
let mut terminator_idx = 0;
for c in src.chars() {
for c in iter {
if c == '\u{0}' {
break;
}
@@ -51,11 +29,82 @@ fn scan_for_terminator(src: &str) -> usize {
terminator_idx
}
pub struct PStrIter {
buf: *const u8,
}
impl PStrIter {
#[inline]
fn from(buf: *const u8, idx: usize) -> Self {
PStrIter {
buf: (buf as usize + idx) as *const _
}
}
}
impl Iterator for PStrIter {
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
let b = ptr::read(self.buf);
if b == 0u8 {
return None;
}
let c = ptr::read(self.buf as *const char);
self.buf = self.buf.offset(c.len_utf8() as isize);
Some(c)
}
}
}
pub struct PStrIterBounded {
buf: *const u8,
end: *const u8,
}
impl PStrIterBounded {
#[inline]
fn from(buf: *const u8, start: usize, end: usize) -> Self {
PStrIterBounded {
buf: (buf as usize + start) as *const _,
end: (buf as usize + end) as *const _,
}
}
}
impl Iterator for PStrIterBounded {
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
if self.buf >= self.end {
return None;
}
let b = ptr::read(self.buf);
if b == 0u8 {
return None;
}
let c = ptr::read(self.buf as *const char);
self.buf = self.buf.offset(c.len_utf8() as isize);
Some(c)
}
}
}
impl PartialString {
#[inline]
pub(super)
fn new(src: &str) -> Option<(Self, &str)> {
let pstr = PartialString {
buf: RawBlock::with_capacity(src.len() + '\u{0}'.len_utf8()),
buf: ptr::null_mut(),
};
unsafe {
@@ -63,22 +112,34 @@ impl PartialString {
}
}
#[inline]
pub(super)
fn empty() -> Self {
PartialString {
buf: "\u{0}".as_bytes()[0] as *const _,
}
}
unsafe fn append_chars(mut self, src: &str) -> Option<(Self, &str)> {
let terminator_idx = scan_for_terminator(src);
let terminator_idx = scan_for_terminator(src.chars());
if terminator_idx == 0 {
return None;
}
let new_top = self.buf.new_block(terminator_idx + '\u{0}'.len_utf8());
let layout = alloc::Layout::from_size_align_unchecked(
src.len() + '\u{0}'.len_utf8(),
mem::align_of::<u8>(),
);
self.buf = alloc::alloc(layout) as *const _;
ptr::copy(
src.as_ptr(),
self.buf.top as *mut _,
self.buf as *mut _,
terminator_idx,
);
self.buf.top = (new_top as usize - '\u{0}'.len_utf8()) as *const _;
self.write_terminator_at(terminator_idx);
Some(if terminator_idx != src.len() {
@@ -88,26 +149,40 @@ impl PartialString {
})
}
#[inline]
pub(crate)
fn iter(&self) -> PStrIter {
PStrIter {
buf: self.buf,
}
}
pub(super)
fn clone_from_offset(&self, n: usize) -> Self {
let mut pstr = PartialString {
buf: RawBlock::with_capacity(self.len() + '\u{0}'.len_utf8()),
buf: ptr::null_mut(),
};
unsafe {
let len = if self.len() > n { self.len() - n } else { 0 };
let new_top = pstr.buf.new_block(len + '\u{0}'.len_utf8());
let len = scan_for_terminator(self.range_from(0 ..));
let len = if len > n { len - n } else { 0 };
let layout = alloc::Layout::from_size_align_unchecked(
len + '\u{0}'.len_utf8(),
mem::align_of::<u8>(),
);
pstr.buf = alloc::alloc(layout);
if len > 0 {
ptr::copy(
(self.buf.base as usize + n) as *mut u8,
pstr.buf.base as *mut _,
(self.buf as usize + n) as *const u8,
pstr.buf as *mut _,
len,
);
}
pstr.write_terminator_at(len);
pstr.buf.top = (new_top as usize - '\u{0}'.len_utf8()) as *const _;
}
pstr
@@ -118,23 +193,26 @@ impl PartialString {
fn write_terminator_at(&mut self, index: usize) {
unsafe {
ptr::write(
(self.buf.base as usize + index) as *mut u8,
(self.buf as usize + index) as *mut u8,
0u8,
);
}
}
#[inline]
pub(crate)
fn block_as_str(&self) -> &str {
unsafe {
let slice = slice::from_raw_parts(self.buf.base, self.len());
str::from_utf8(slice).unwrap()
}
pub fn range(&self, index: Range<usize>) -> PStrIterBounded {
PStrIterBounded::from(self.buf, index.start, index.end)
}
#[inline]
pub fn len(&self) -> usize {
self.buf.top as usize - self.buf.base as usize
pub fn range_from(&self, index: RangeFrom<usize>) -> PStrIter {
PStrIter::from(self.buf, index.start)
}
#[inline]
pub fn at_end(&self, end_n: usize) -> bool {
unsafe {
ptr::read((self.buf as usize + end_n) as *const u8) == 0u8
}
}
}

View File

@@ -29,7 +29,8 @@ pub enum EOFAction {
pub enum StreamInstance {
Bytes(Cursor<Vec<u8>>),
DynReadSource(Box<dyn Read>),
File(File),
File(File),
Null,
ReadlineStream(ReadlineStream),
Stdin,
Stdout,
@@ -201,6 +202,17 @@ impl Stream {
}
}
#[inline]
pub(crate)
fn null_stream() -> Self {
Stream {
options: StreamOptions::default(), // TODO: null_options?
stream_inst: WrappedStreamInstance::new(
StreamInstance::Null
),
}
}
#[inline]
pub(crate)
fn is_stdout(&self) -> bool {
@@ -233,7 +245,7 @@ impl Stream {
match *self.stream_inst.0.borrow() {
StreamInstance::Stdin
| StreamInstance::TcpStream(_)
| StreamInstance::Bytes(_)
| StreamInstance::Bytes(_)
| StreamInstance::ReadlineStream(_)
| StreamInstance::DynReadSource(_)
| StreamInstance::File(_) => {
@@ -251,7 +263,7 @@ impl Stream {
match *self.stream_inst.0.borrow() {
StreamInstance::Stdout
| StreamInstance::TcpStream(_)
| StreamInstance::Bytes(_)
| StreamInstance::Bytes(_)
| StreamInstance::File(_) => {
true
}
@@ -283,7 +295,7 @@ impl Read for Stream {
StreamInstance::Stdin => {
stdin().read(buf)
}
StreamInstance::Stdout => {
StreamInstance::Stdout | StreamInstance::Null => {
Err(std::io::Error::new(
ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream,

File diff suppressed because it is too large Load Diff