Merge pull request #843 from mthom/rebis-dev

Merge rebis-dev into master
This commit is contained in:
Mark Thom
2021-02-28 18:29:35 -07:00
99 changed files with 21246 additions and 14487 deletions

View File

@@ -17,11 +17,16 @@ jobs:
profile: minimal
toolchain: ${{ matrix.rust-version }}
override: true
- name: Build
- name: Build lib
uses: actions-rs/cargo@v1
with:
command: rustc
args: --verbose -- -D warnings
args: --verbose --lib -- -D warnings
- name: Build bin
uses: actions-rs/cargo@v1
with:
command: rustc
args: --verbose --bin scryer-prolog -- -D warnings
- name: Test
uses: actions-rs/cargo@v1
with:

38
Cargo.lock generated
View File

@@ -23,9 +23,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "az"
version = "1.0.0"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9bcd47d94aa4eb8c076b50fc61a75020789394ffb9bd74a180b3379130f6569"
checksum = "d84e1d907bfc5795a6addb95ef8666141ee73c8f2f5250ff2a46bf4e4f4aec8a"
[[package]]
name = "base64"
@@ -470,9 +470,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.84"
version = "0.2.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cca32fa0182e8c0989459524dc356b8f2b5c10f1b9eb521b7d182c03cf8c5ff"
checksum = "7ccac4b00700875e6a07c6cde370d44d32fa01c5a65cdd2fca6858c479d28bb3"
[[package]]
name = "libsodium-sys"
@@ -509,6 +509,15 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
[[package]]
name = "mach"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa"
dependencies = [
"libc",
]
[[package]]
name = "markup5ever"
version = "0.8.1"
@@ -670,9 +679,7 @@ dependencies = [
[[package]]
name = "num-rug-adapter"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7470b6acf85abce0771203112db4181d03f7b8a6be49f0e842a78030192f8a58"
version = "0.1.5"
dependencies = [
"libc",
"num-bigint",
@@ -872,6 +879,7 @@ dependencies = [
name = "prolog_parser"
version = "0.8.68"
dependencies = [
"indexmap",
"lexical",
"num-rug-adapter",
"ordered-float",
@@ -1094,9 +1102,9 @@ dependencies = [
[[package]]
name = "ring"
version = "0.16.19"
version = "0.16.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "024a1e66fea74c66c66624ee5622a7ff0e4b73a13b4f5c326ddb50c708944226"
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
dependencies = [
"cc",
"libc",
@@ -1221,6 +1229,7 @@ dependencies = [
"rustyline",
"select",
"sha3",
"slice-deque",
"sodiumoxide",
"unicode_reader",
]
@@ -1346,6 +1355,17 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
[[package]]
name = "slice-deque"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31ef6ee280cdefba6d2d0b4b78a84a1c1a3f3a4cec98c2d4231c8bc225de0f25"
dependencies = [
"libc",
"mach",
"winapi 0.3.9",
]
[[package]]
name = "smallvec"
version = "1.6.1"

View File

@@ -12,7 +12,7 @@ categories = ["command-line-utilities"]
build = "build.rs"
[workspace]
members = ["crates/prolog_parser"]
members = ["crates/prolog_parser", "crates/num-rug-adapter"]
[build-dependencies]
indexmap = "1.0.2"
@@ -33,7 +33,7 @@ indexmap = "1.0.2"
lazy_static = "1.4.0"
libc = "0.2.62"
nix = "0.15.0"
num-rug-adapter = { optional = true, version = "0.1.4" }
num-rug-adapter = { optional = true, path = "./crates/num-rug-adapter" }
ordered-float = "0.5.0"
prolog_parser = { path = "./crates/prolog_parser", default-features = false }
ref_thread_local = "0.0.0"
@@ -51,3 +51,4 @@ select = "0.4.3"
roxmltree = "0.11.0"
base64 = "0.12.3"
sodiumoxide = "0.2.6"
slice-deque = "0.3.0"

View File

@@ -59,11 +59,10 @@ Extend Scryer Prolog to include the following, among other features:
- [x] clp(B) and clp() as builtin libraries.
- [x] Streams and predicates for stream control.
- [x] A simple sockets library representing TCP connections as streams.
- [ ] Incremental compilation and loading process, newly written,
primarily in Prolog. (_in progress_, see
[#775](https://github.com/mthom/scryer-prolog/issues/775))
- [ ] A compacting garbage collector satisfying the five
properties of "Precise Garbage Collection in Prolog."
- [x] Incremental compilation and loading process, newly written,
primarily in Prolog.
- [ ] A compacting garbage collector satisfying the five properties of
"Precise Garbage Collection in Prolog." (_in progress_)
- [ ] Mode declarations.
## Phase 3
@@ -418,6 +417,8 @@ The modules that ship with Scryer Prolog are also called
file, reading lazily only as much as is needed. Due to the compact
internal string representation, also extremely large files can be
efficiently processed with Scryer Prolog in this way.
* [`lambda`](src/lib/lambda.pl)
Lambda expressions to simplify higher order programming.
* [`charsio`](src/lib/charsio.pl) Various predicates that are useful
for parsing and reasoning about characters, notably `char_type/2` to
classify characters according to their type, and conversion
@@ -490,6 +491,7 @@ The modules that ship with Scryer Prolog are also called
public key signatures and signature verification with Ed25519,
ECDH key exchange over Curve25519 (X25519), authenticated symmetric
encryption with ChaCha20-Poly1305, and reasoning about elliptic curves.
* [`uuid`](src/lib/uuid.pl) UUIDv4 generation and hex representation
To use predicates provided by the `lists` library, write:

View File

@@ -1,5 +1,3 @@
extern crate indexmap;
use std::env;
use std::fs;
use std::fs::File;
@@ -11,19 +9,19 @@ fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) {
Ok(entries) => entries,
Err(_) => return,
};
for entry in entries.filter_map(Result::ok).map(|e| e.path()) {
if entry.is_dir() {
if let Some(file_name) = entry.file_name() {
let new_prefix =
prefix.to_owned() + file_name.to_str().unwrap() + "/";
let new_prefix = prefix.to_owned() + file_name.to_str().unwrap() + "/";
find_prolog_files(libraries, &new_prefix, &entry);
}
} else if entry.is_file() {
let ext = std::ffi::OsStr::new("pl");
if entry.extension() == Some(ext) {
let contain =
String::from_utf8(fs::read(&entry).unwrap()).unwrap();
let contain = String::from_utf8(fs::read(&entry).unwrap()).unwrap();
let name = entry.file_stem().unwrap().to_str().unwrap();
let line = format!(
" m.insert(\"{}\",\n{:?});\n",
prefix.to_owned() + name,
@@ -45,8 +43,8 @@ fn main() {
libraries
.write_all(
b"ref_thread_local! {
pub static managed LIBRARIES: IndexMap<&'static str, &'static str> = {
b"ref_thread_local::ref_thread_local! {
pub(crate) static managed LIBRARIES: IndexMap<&'static str, &'static str> = {
let mut m = IndexMap::new();\n",
)
.unwrap();

View File

@@ -0,0 +1,18 @@
[package]
name = "num-rug-adapter"
version = "0.1.5"
authors = ["Marco A L Barbosa <malbarbo@gmail.com>"]
edition = "2018"
description = "An adapter to use num crate where rug is needed."
license = "MIT/Apache-2.0"
repository = "https://github.com/malbarbo/num-rug-adapter"
keywords = ["mathematics", "numerics", "bignum"]
categories = ["api-bindings", "science"]
readme = "README.md"
[dependencies]
libc = "0.2"
num-bigint = "0.2"
num-integer = "0.1.41"
num-rational = "0.2"
num-traits = "0.2"

View File

@@ -0,0 +1,883 @@
use num_bigint::{BigInt, ParseBigIntError};
use num_integer::Integer as _;
use num_rational::BigRational;
use num_traits::{FromPrimitive, Num, Signed, ToPrimitive};
use num_traits::identities::One;
use std::cmp::Ordering;
use std::fmt::{self, Display, Formatter};
use std::ops::*;
use std::str::FromStr;
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Integer(BigInt);
impl Integer {
#[inline]
pub fn new() -> Self {
Integer(BigInt::default())
}
#[inline]
pub fn from_str_radix(s: &str, radix: u32) -> Result<Self, ParseBigIntError> {
BigInt::from_str_radix(s, radix).map(Integer)
}
#[inline]
pub fn to_u8(&self) -> Option<u8> {
self.0.to_u8()
}
#[inline]
pub fn to_u32(&self) -> Option<u32> {
self.0.to_u32()
}
#[inline]
pub fn to_u64(&self) -> Option<u64> {
self.0.to_u64()
}
#[inline]
pub fn to_usize(&self) -> Option<usize> {
self.0.to_usize()
}
#[inline]
pub fn to_i32(&self) -> Option<i32> {
self.0.to_i32()
}
#[inline]
pub fn to_isize(&self) -> Option<isize> {
self.0.to_isize()
}
#[inline]
pub fn to_f64(&self) -> f64 {
self.0.to_f64().unwrap()
}
#[inline]
pub fn abs(&self) -> Self {
Integer(self.0.abs())
}
#[inline]
pub fn abs_ref(&self) -> Self {
Integer(self.0.abs())
}
#[inline]
pub fn div_rem(&self, other: Self) -> (Self, Self) {
let (a, b) = num_integer::Integer::div_rem(&self.0, &other.0);
(Integer(a), Integer(b))
}
#[inline]
pub fn div_rem_ref(&self, other: &Self) -> (Self, Self) {
let (a, b) = num_integer::Integer::div_rem(&self.0, &other.0);
(Integer(a), Integer(b))
}
#[inline]
pub fn div_rem_floor(&self, other: Self) -> (Self, Self) {
let (a, b) = num_integer::Integer::div_mod_floor(&self.0, &other.0);
(Integer(a), Integer(b))
}
#[inline]
pub fn div_rem_floor_ref(&self, other: &Self) -> (Self, Self) {
let (a, b) = num_integer::Integer::div_mod_floor(&self.0, &other.0);
(Integer(a), Integer(b))
}
#[inline]
pub fn mod_u(&self, modulo: u32) -> u32 {
(self.0.abs() % modulo).to_u32().unwrap()
}
#[inline]
pub fn is_odd(&self) -> bool {
num_integer::Integer::is_odd(&self.0)
}
#[inline]
pub fn from_f64(v: f64) -> Option<Self> {
BigInt::from_f64(v).map(Integer)
}
#[inline]
pub fn gcd_ref(&self, other: &Self) -> Self {
Integer(num_integer::Integer::gcd(&self.0, &other.0))
}
#[inline]
pub fn gcd(&self, other: &Self) -> Self {
Integer(num_integer::Integer::gcd(&self.0, &other.0))
}
}
impl From<&Integer> for Integer {
#[inline]
fn from(s: &Integer) -> Self {
s.clone()
}
}
impl From<i32> for Integer {
#[inline]
fn from(s: i32) -> Self {
Integer(BigInt::from(s))
}
}
impl From<isize> for Integer {
#[inline]
fn from(s: isize) -> Self {
Integer(BigInt::from(s))
}
}
impl From<u8> for Integer {
#[inline]
fn from(s: u8) -> Self {
Integer(BigInt::from(s))
}
}
impl From<u32> for Integer {
#[inline]
fn from(s: u32) -> Self {
Integer(BigInt::from(s))
}
}
impl From<u64> for Integer {
#[inline]
fn from(s: u64) -> Self {
Integer(BigInt::from(s))
}
}
impl From<usize> for Integer {
#[inline]
fn from(s: usize) -> Self {
Integer(BigInt::from(s))
}
}
impl Mul for Integer {
type Output = Integer;
#[inline]
fn mul(self, other: Integer) -> Self::Output {
Integer(self.0 * other.0)
}
}
impl Mul<u32> for Integer {
type Output = Integer;
#[inline]
fn mul(self, other: u32) -> Self::Output {
Integer(self.0 * other)
}
}
impl Mul<&Integer> for Integer {
type Output = Integer;
fn mul(self, other: &Integer) -> Self::Output {
Integer(self.0 * &other.0)
}
}
impl MulAssign<&Integer> for Integer {
#[inline]
fn mul_assign(&mut self, other: &Integer) {
self.0 *= &other.0;
}
}
impl Add for Integer {
type Output = Integer;
#[inline]
fn add(self, other: Integer) -> Self::Output {
Integer(self.0 + other.0)
}
}
impl Add<Integer> for &Integer {
type Output = Integer;
#[inline]
fn add(self, other: Integer) -> Self::Output {
Integer(&self.0 + other.0)
}
}
impl Add<&Integer> for Integer {
type Output = Integer;
#[inline]
fn add(self, other: &Integer) -> Self::Output {
Integer(self.0 + &other.0)
}
}
impl Add<&Integer> for &Integer {
type Output = Integer;
#[inline]
fn add(self, other: &Integer) -> Self::Output {
Integer(&self.0 + &other.0)
}
}
impl AddAssign<i64> for Integer {
#[inline]
fn add_assign(&mut self, other: i64) {
self.0 += other;
}
}
impl AddAssign<&Integer> for Integer {
#[inline]
fn add_assign(&mut self, other: &Integer) {
self.0 += &other.0;
}
}
impl Div for Integer {
type Output = Integer;
#[inline]
fn div(self, other: Integer) -> Integer {
Integer(self.0 / other.0)
}
}
impl Div<&Integer> for Integer {
type Output = Integer;
#[inline]
fn div(self, other: &Integer) -> Integer {
Integer(self.0 / &other.0)
}
}
impl Div<Integer> for &Integer {
type Output = Integer;
#[inline]
fn div(self, other: Integer) -> Integer {
Integer(&self.0 / &other.0)
}
}
impl Shr<u32> for Integer {
type Output = Integer;
#[inline]
fn shr(self, rhs: u32) -> Self::Output {
Integer(self.0 >> rhs as usize)
}
}
impl Shr<u32> for &Integer {
type Output = Integer;
#[inline]
fn shr(self, rhs: u32) -> Self::Output {
Integer(&self.0 >> rhs as usize)
}
}
impl ShrAssign<u32> for Integer {
#[inline]
fn shr_assign(&mut self, rhs: u32) {
self.0 >>= rhs as usize;
}
}
impl Shl<u32> for Integer {
type Output = Integer;
#[inline]
fn shl(self, rhs: u32) -> Self::Output {
Integer(self.0 << rhs as usize)
}
}
impl Shl<u32> for &Integer {
type Output = Integer;
#[inline]
fn shl(self, rhs: u32) -> Self::Output {
Integer(&self.0 << rhs as usize)
}
}
impl Not for Integer {
type Output = Integer;
#[inline]
fn not(self) -> Self::Output {
Integer(!self.0)
}
}
impl Not for &Integer {
type Output = Integer;
#[inline]
fn not(self) -> Self::Output {
Integer(!&self.0)
}
}
impl Rem for Integer {
type Output = Integer;
#[inline]
fn rem(self, other: Integer) -> Self::Output {
Integer(self.0.mod_floor(&other.0))
}
}
impl Rem<&Integer> for Integer {
type Output = Integer;
#[inline]
fn rem(self, other: &Integer) -> Self::Output {
Integer(self.0.mod_floor(&other.0))
}
}
impl Rem<&Integer> for &Integer {
type Output = Integer;
#[inline]
fn rem(self, other: &Integer) -> Self::Output {
Integer(self.0.mod_floor(&other.0))
}
}
impl Rem<Integer> for &Integer {
type Output = Integer;
#[inline]
fn rem(self, other: Integer) -> Self::Output {
Integer(self.0.mod_floor(&other.0))
}
}
impl BitAnd for Integer {
type Output = Integer;
#[inline]
fn bitand(self, other: Integer) -> Self::Output {
Integer(self.0 & &other.0)
}
}
impl BitAnd<&Integer> for Integer {
type Output = Integer;
#[inline]
fn bitand(self, other: &Integer) -> Self::Output {
Integer(self.0 & &other.0)
}
}
impl BitAnd<Integer> for &Integer {
type Output = Integer;
#[inline]
fn bitand(self, other: Integer) -> Self::Output {
Integer(&self.0 & other.0)
}
}
impl BitAnd for &Integer {
type Output = Integer;
#[inline]
fn bitand(self, other: &Integer) -> Self::Output {
Integer(&self.0 & &other.0)
}
}
impl BitOr for Integer {
type Output = Integer;
#[inline]
fn bitor(self, other: Integer) -> Self::Output {
Integer(self.0 | other.0)
}
}
impl BitOr<&Integer> for Integer {
type Output = Integer;
#[inline]
fn bitor(self, other: &Integer) -> Self::Output {
Integer(self.0 | &other.0)
}
}
impl BitOr<Integer> for &Integer {
type Output = Integer;
#[inline]
fn bitor(self, other: Integer) -> Self::Output {
Integer(&self.0 | other.0)
}
}
impl BitOr for &Integer {
type Output = Integer;
#[inline]
fn bitor(self, other: &Integer) -> Self::Output {
Integer(&self.0 | &other.0)
}
}
impl BitXor for Integer {
type Output = Integer;
#[inline]
fn bitxor(self, other: Integer) -> Self::Output {
Integer(self.0 ^ other.0)
}
}
impl BitXor<&Integer> for Integer {
type Output = Integer;
#[inline]
fn bitxor(self, other: &Integer) -> Self::Output {
Integer(self.0 ^ &other.0)
}
}
impl BitXor<Integer> for &Integer {
type Output = Integer;
#[inline]
fn bitxor(self, other: Integer) -> Self::Output {
Integer(&self.0 ^ other.0)
}
}
impl BitXor<&Integer> for &Integer {
type Output = Integer;
#[inline]
fn bitxor(self, other: &Integer) -> Self::Output {
Integer(&self.0 ^ &other.0)
}
}
impl PartialEq<i32> for Integer {
#[inline]
fn eq(&self, other: &i32) -> bool {
self.0 == BigInt::from(*other)
}
}
impl PartialEq<i64> for Integer {
#[inline]
fn eq(&self, other: &i64) -> bool {
self.0 == BigInt::from(*other)
}
}
impl PartialEq<isize> for Integer {
#[inline]
fn eq(&self, other: &isize) -> bool {
self.0 == BigInt::from(*other)
}
}
impl PartialEq<usize> for Integer {
#[inline]
fn eq(&self, other: &usize) -> bool {
self.0 == BigInt::from(*other)
}
}
impl PartialEq<Integer> for isize {
#[inline]
fn eq(&self, other: &Integer) -> bool {
other.0 == BigInt::from(*self)
}
}
impl PartialOrd<i32> for Integer {
#[inline]
fn partial_cmp(&self, other: &i32) -> Option<Ordering> {
self.0.partial_cmp(&BigInt::from(*other))
}
}
impl PartialOrd<i64> for Integer {
#[inline]
fn partial_cmp(&self, other: &i64) -> Option<Ordering> {
self.0.partial_cmp(&BigInt::from(*other))
}
}
impl PartialOrd<isize> for Integer {
#[inline]
fn partial_cmp(&self, other: &isize) -> Option<Ordering> {
self.0.partial_cmp(&BigInt::from(*other))
}
}
impl PartialOrd<usize> for Integer {
#[inline]
fn partial_cmp(&self, other: &usize) -> Option<Ordering> {
self.0.partial_cmp(&BigInt::from(*other))
}
}
impl FromStr for Integer {
type Err = <BigInt as FromStr>::Err;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Integer(s.parse()?))
}
}
impl Neg for Integer {
type Output = Integer;
#[inline]
fn neg(self) -> Self {
Integer(-self.0)
}
}
impl Display for Integer {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
// Rational
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Rational(BigRational);
impl Rational {
#[inline]
pub fn new() -> Self {
Rational(BigRational::from(BigInt::default()))
}
#[inline]
pub fn from_f64(v: f64) -> Option<Self> {
BigRational::from_f64(v).map(Rational)
}
#[inline]
pub fn to_f64(&self) -> f64 {
self.0.numer().to_f64().unwrap() / self.0.denom().to_f64().unwrap()
}
#[inline]
pub fn numer(&self) -> &Integer {
unsafe { ::std::mem::transmute(self.0.numer()) }
}
#[inline]
pub fn denom(&self) -> &Integer {
unsafe { ::std::mem::transmute(self.0.denom()) }
}
#[inline]
pub fn abs(self) -> Self {
Rational(self.0.abs())
}
#[inline]
pub fn abs_ref(&self) -> Self {
Rational(self.0.abs())
}
#[inline]
pub fn fract_floor_ref(&self) -> &Self {
panic!()
}
}
impl From<isize> for Rational {
#[inline]
fn from(s: isize) -> Self {
Rational(BigRational::new_raw(BigInt::from(s), One::one()))
}
}
impl From<&Integer> for Rational {
#[inline]
fn from(s: &Integer) -> Self {
Rational::from(s.clone())
}
}
impl From<&Rational> for Rational {
#[inline]
fn from(s: &Rational) -> Self {
s.clone()
}
}
impl From<Integer> for Rational {
#[inline]
fn from(i: Integer) -> Self {
Rational(BigRational::from(i.0))
}
}
impl Add for Rational {
type Output = Rational;
#[inline]
fn add(self, other: Rational) -> Self::Output {
Rational(self.0 + other.0)
}
}
impl Add<&Rational> for Rational {
type Output = Rational;
#[inline]
fn add(self, other: &Rational) -> Self::Output {
Rational(self.0 + &other.0)
}
}
impl PartialEq<i32> for Rational {
#[inline]
fn eq(&self, other: &i32) -> bool {
self.0 == BigRational::from(BigInt::from(*other))
}
}
impl PartialEq<i64> for Rational {
#[inline]
fn eq(&self, other: &i64) -> bool {
self.0 == BigRational::from(BigInt::from(*other))
}
}
impl PartialEq<isize> for Rational {
#[inline]
fn eq(&self, other: &isize) -> bool {
self == &Rational::from(*other)
}
}
impl PartialEq<Rational> for isize {
#[inline]
fn eq(&self, other: &Rational) -> bool {
other == &Rational::from(*self)
}
}
impl PartialOrd<isize> for Rational {
#[inline]
fn partial_cmp(&self, other: &isize) -> Option<Ordering> {
self.0.partial_cmp(&BigRational::from(BigInt::from(*other)))
}
}
impl PartialOrd<i64> for Rational {
#[inline]
fn partial_cmp(&self, other: &i64) -> Option<Ordering> {
self.0.partial_cmp(&BigRational::from(BigInt::from(*other)))
}
}
impl PartialOrd<i32> for Rational {
#[inline]
fn partial_cmp(&self, other: &i32) -> Option<Ordering> {
self.0.partial_cmp(&BigRational::from(BigInt::from(*other)))
}
}
impl Neg for Rational {
type Output = Rational;
#[inline]
fn neg(self) -> Self {
Rational(-self.0)
}
}
impl Mul for Rational {
type Output = Rational;
#[inline]
fn mul(self, other: Rational) -> Self::Output {
Rational(self.0 * other.0)
}
}
impl Mul<&Rational> for Rational {
type Output = Rational;
fn mul(self, other: &Rational) -> Self::Output {
Rational(self.0 * &other.0)
}
}
impl Div for Rational {
type Output = Rational;
#[inline]
fn div(self, other: Rational) -> Self::Output {
Rational(self.0 / other.0)
}
}
impl Div<&Rational> for &Rational {
type Output = Rational;
#[inline]
fn div(self, other: &Rational) -> Self::Output {
Rational(&self.0 / &other.0)
}
}
impl Display for Rational {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
pub trait Assign<Src = Self> {
fn assign(&mut self, src: Src);
}
impl Assign<&Rational> for (&mut Rational, &mut Integer) {
fn assign(&mut self, _src: &Rational) {
panic!()
}
}
pub mod ops {
use super::{Integer, Rational};
pub trait Pow<Rhs> {
type Output;
fn pow(self, rhs: Rhs) -> Self::Output;
}
impl Pow<u32> for Integer {
type Output = Integer;
fn pow(self, rhs: u32) -> Self::Output {
Integer(num_traits::Pow::pow(&self.0, rhs))
}
}
pub trait PowAssign<Rhs> {
fn pow_assign(&mut self, rhs: Rhs);
}
impl PowAssign<u32> for Integer {
fn pow_assign(&mut self, rhs: u32) {
// FIXME: make it efficient
self.0 = num_traits::Pow::pow(&self.0, rhs);
}
}
pub trait NegAssign {
fn neg_assign(&mut self);
}
impl NegAssign for Integer {
fn neg_assign(&mut self) {
self.0 = -std::mem::replace(self, Integer::new()).0;
}
}
impl NegAssign for Rational {
#[inline]
fn neg_assign(&mut self) {
self.0 = -std::mem::replace(self, Rational::new()).0;
}
}
}
pub mod rand {
use super::Integer;
use std::marker::PhantomData;
pub struct RandState<'a>{
_marker: PhantomData<&'a ()>,
}
impl<'a> RandState<'a> {
pub fn new() -> Self {
unsafe { libc::srand(libc::time(std::ptr::null_mut()) as _) };
RandState { _marker: PhantomData }
}
pub fn borrow_mut(&self) -> &Self {
self
}
pub fn bits(&mut self, bits: u32) -> u32 {
assert!(bits <= 32);
(unsafe { libc::rand() } as u32) & (u32::max_value() >> (32 - bits))
}
pub fn seed(&mut self, seed: &Integer) {
unsafe { libc::srand(seed.to_f64() as _)}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use super::ops::NegAssign;
#[test]
fn bits() {
let mut rand = rand::RandState::new();
for bits in 1..32 {
for _ in 0..100 {
let r = rand.bits(bits);
let max = 1 << bits;
assert!(max > r, "{} > {}", max, r);
}
}
}
#[test]
fn neg_rational() {
let mut x = Rational::from_f64(5.0).unwrap();
let x_neg = Rational::from_f64(-5.0).unwrap();
x.neg_assign();
assert_eq!(x, x_neg);
}
#[test]
fn neg_integer() {
let mut x = Integer::from(5);
let x_neg = Integer::from(-5);
x.neg_assign();
assert_eq!(x, x_neg);
}
}

265
crates/prolog_parser/Cargo.lock generated Normal file
View File

@@ -0,0 +1,265 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "arrayvec"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
dependencies = [
"nodrop",
]
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "az"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d84e1d907bfc5795a6addb95ef8666141ee73c8f2f5250ff2a46bf4e4f4aec8a"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "gmp-mpfr-sys"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a57fdb339d49833021b1fded600ed240ae907e33909d5511a61dff884df7f16e"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "lexical"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e0d09e60c187a6d0a3fa418aec8587c6a4ae9de872f6126f2134f319b5ed10d"
dependencies = [
"cfg-if",
"lexical-core",
"rustc_version",
]
[[package]]
name = "lexical-core"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304bccb228c4b020f3a4835d247df0a02a7c4686098d4167762cfbbe4c5cb14"
dependencies = [
"arrayvec",
"cfg-if",
"rustc_version",
"ryu",
"static_assertions",
]
[[package]]
name = "libc"
version = "0.2.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ccac4b00700875e6a07c6cde370d44d32fa01c5a65cdd2fca6858c479d28bb3"
[[package]]
name = "nodrop"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
[[package]]
name = "num-bigint"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
dependencies = [
"autocfg",
"num-integer",
"num-traits 0.2.14",
]
[[package]]
name = "num-integer"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg",
"num-traits 0.2.14",
]
[[package]]
name = "num-rational"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef"
dependencies = [
"autocfg",
"num-bigint",
"num-integer",
"num-traits 0.2.14",
]
[[package]]
name = "num-rug-adapter"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7470b6acf85abce0771203112db4181d03f7b8a6be49f0e842a78030192f8a58"
dependencies = [
"libc",
"num-bigint",
"num-integer",
"num-rational",
"num-traits 0.2.14",
]
[[package]]
name = "num-traits"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
dependencies = [
"num-traits 0.2.14",
]
[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg",
]
[[package]]
name = "ordered-float"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7eb5259643245d3f292c7a146b2df53bba24d7eab159410e648eb73dc164669d"
dependencies = [
"num-traits 0.1.43",
"unreachable",
]
[[package]]
name = "prolog_parser"
version = "0.8.68"
dependencies = [
"lexical",
"num-rug-adapter",
"ordered-float",
"rug",
"unicode_reader",
]
[[package]]
name = "rug"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e538d00da450a8e48aac7e6322e67b2dc86ec71a1feeac0e3954c4f07f01bc45"
dependencies = [
"az",
"gmp-mpfr-sys",
"libc",
]
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
dependencies = [
"semver",
]
[[package]]
name = "ryu"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "smallvec"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]]
name = "static_assertions"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3"
[[package]]
name = "unicode-segmentation"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
[[package]]
name = "unicode_reader"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b639121690b27acd92c97ed2b52c5e5e8d3d39482e943b4559695cef62f771a"
dependencies = [
"smallvec",
"unicode-segmentation",
]
[[package]]
name = "unreachable"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
dependencies = [
"void",
]
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@@ -2,15 +2,17 @@
name = "prolog_parser"
version = "0.8.68"
authors = ["Mark Thom <markjordanthom@gmail.com>"]
edition = "2018"
repository = "https://github.com/mthom/scryer-prolog"
description = " An operator precedence parser for scryer-prolog, an up and coming ISO Prolog implementation."
description = " An operator precedence parser for the Rebis development version of Scryer Prolog, an up and coming ISO Prolog implementation."
license = "BSD-3-Clause"
[dependencies]
indexmap = "1.0.2"
lexical = "2.1.0"
ordered-float = "0.5.0"
rug = { optional = true, version = "1.4.0" }
num-rug-adapter = { optional = true, version = "0.1.3" }
num-rug-adapter = { optional = true, path = "../num-rug-adapter" }
unicode_reader = "1.0.0"
[lib]

View File

@@ -1,18 +1,19 @@
use crate::rug::{Integer, Rational};
use crate::tabled_rc::*;
use ordered_float::*;
use rug::{Integer, Rational};
use tabled_rc::*;
use put_back_n::*;
use crate::put_back_n::*;
use std::cell::Cell;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::io::{Bytes, Error as IOError, Read};
use std::ops::Deref;
use std::rc::Rc;
use std::vec::Vec;
use indexmap::IndexMap;
use unicode_reader::CodePoints;
pub type Atom = String;
@@ -39,20 +40,23 @@ pub const NEGATIVE_SIGN: u32 = 0x0200;
#[macro_export]
macro_rules! clause_name {
($name: expr, $tbl: expr) => {
ClauseName::User(TabledRc::new($name, $tbl.clone()))
$crate::ast::ClauseName::User($crate::tabled_rc::TabledRc::new($name, $tbl.clone()))
};
($name: expr) => {
ClauseName::BuiltIn($name)
$crate::ast::ClauseName::BuiltIn($name)
};
}
#[macro_export]
macro_rules! atom {
($e:expr, $tbl:expr) => {
Constant::Atom(ClauseName::User(tabled_rc!($e, $tbl)), None)
$crate::ast::Constant::Atom(
$crate::ast::ClauseName::User($crate::tabled_rc!($e, $tbl)),
None,
)
};
($e:expr) => {
Constant::Atom(clause_name!($e), None)
$crate::ast::Constant::Atom($crate::clause_name!($e), None)
};
}
@@ -64,95 +68,102 @@ macro_rules! rc_atom {
}
macro_rules! is_term {
($x:expr) => {
($x & TERM) != 0
($x & $crate::ast::TERM) != 0
};
}
macro_rules! is_lterm {
($x:expr) => {
($x & LTERM) != 0
($x & $crate::ast::LTERM) != 0
};
}
macro_rules! is_op {
($x:expr) => {
$x & (XF | YF | FX | FY | XFX | XFY | YFX) != 0
$x & ($crate::ast::XF
| $crate::ast::YF
| $crate::ast::FX
| $crate::ast::FY
| $crate::ast::XFX
| $crate::ast::XFY
| $crate::ast::YFX)
!= 0
};
}
macro_rules! is_negate {
($x:expr) => {
($x & NEGATIVE_SIGN) != 0
($x & $crate::ast::NEGATIVE_SIGN) != 0
};
}
#[macro_export]
macro_rules! is_prefix {
($x:expr) => {
$x & (FX | FY) != 0
$x & ($crate::ast::FX | $crate::ast::FY) != 0
};
}
#[macro_export]
macro_rules! is_postfix {
($x:expr) => {
$x & (XF | YF) != 0
$x & ($crate::ast::XF | $crate::ast::YF) != 0
};
}
#[macro_export]
macro_rules! is_infix {
($x:expr) => {
($x & (XFX | XFY | YFX)) != 0
($x & ($crate::ast::XFX | $crate::ast::XFY | $crate::ast::YFX)) != 0
};
}
#[macro_export]
macro_rules! is_xfx {
($x:expr) => {
($x & XFX) != 0
($x & $crate::ast::XFX) != 0
};
}
#[macro_export]
macro_rules! is_xfy {
($x:expr) => {
($x & XFY) != 0
($x & $crate::ast::XFY) != 0
};
}
#[macro_export]
macro_rules! is_yfx {
($x:expr) => {
($x & YFX) != 0
($x & $crate::ast::YFX) != 0
};
}
#[macro_export]
macro_rules! is_yf {
($x:expr) => {
($x & YF) != 0
($x & $crate::ast::YF) != 0
};
}
#[macro_export]
macro_rules! is_xf {
($x:expr) => {
($x & XF) != 0
($x & $crate::ast::XF) != 0
};
}
#[macro_export]
macro_rules! is_fx {
($x:expr) => {
($x & FX) != 0
($x & $crate::ast::FX) != 0
};
}
#[macro_export]
macro_rules! is_fy {
($x:expr) => {
($x & FY) != 0
($x & $crate::ast::FY) != 0
};
}
@@ -176,18 +187,15 @@ impl RegType {
}
pub fn is_perm(self) -> bool {
match self {
RegType::Perm(_) => true,
_ => false,
}
matches!(self, RegType::Perm(_))
}
}
impl fmt::Display for RegType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&RegType::Perm(val) => write!(f, "Y{}", val),
&RegType::Temp(val) => write!(f, "X{}", val),
RegType::Perm(val) => write!(f, "Y{}", val),
RegType::Temp(val) => write!(f, "X{}", val),
}
}
}
@@ -209,10 +217,10 @@ impl VarReg {
impl fmt::Display for VarReg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg),
&VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg),
&VarReg::ArgAndNorm(RegType::Perm(reg), arg) => write!(f, "Y{} A{}", reg, arg),
&VarReg::ArgAndNorm(RegType::Temp(reg), arg) => write!(f, "X{} A{}", reg, arg),
VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg),
VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg),
VarReg::ArgAndNorm(RegType::Perm(reg), arg) => write!(f, "Y{} A{}", reg, arg),
VarReg::ArgAndNorm(RegType::Temp(reg), arg) => write!(f, "X{} A{}", reg, arg),
}
}
}
@@ -226,14 +234,14 @@ impl Default for VarReg {
#[macro_export]
macro_rules! temp_v {
($x:expr) => {
RegType::Temp($x)
$crate::ast::RegType::Temp($x)
};
}
#[macro_export]
macro_rules! perm_v {
($x:expr) => {
RegType::Perm($x)
$crate::ast::RegType::Perm($x)
};
}
@@ -256,26 +264,21 @@ impl GenContext {
pub type OpDirKey = (ClauseName, Fixity);
#[derive(Debug, Clone)]
pub struct OpDirValue(pub SharedOpDesc, pub ClauseName);
pub struct OpDirValue(pub SharedOpDesc);
impl OpDirValue {
pub fn new(spec: Specifier, priority: usize, module_name: ClauseName) -> Self {
OpDirValue(SharedOpDesc::new(priority, spec), module_name)
pub fn new(spec: Specifier, priority: usize) -> Self {
OpDirValue(SharedOpDesc::new(priority, spec))
}
#[inline]
pub fn shared_op_desc(&self) -> SharedOpDesc {
self.0.clone()
}
#[inline]
pub fn owning_module(&self) -> ClauseName {
self.1.clone()
}
}
// name and fixity -> operator type and precedence.
pub type OpDir = HashMap<OpDirKey, OpDirValue>;
pub type OpDir = IndexMap<OpDirKey, OpDirValue>;
#[derive(Debug, Clone, Copy)]
pub struct MachineFlags {
@@ -299,27 +302,15 @@ pub enum DoubleQuotes {
impl DoubleQuotes {
pub fn is_chars(self) -> bool {
if let DoubleQuotes::Chars = self {
true
} else {
false
}
matches!(self, DoubleQuotes::Chars)
}
pub fn is_atom(self) -> bool {
if let DoubleQuotes::Atom = self {
true
} else {
false
}
matches!(self, DoubleQuotes::Atom)
}
pub fn is_codes(self) -> bool {
if let DoubleQuotes::Codes = self {
true
} else {
false
}
matches!(self, DoubleQuotes::Codes)
}
}
@@ -330,30 +321,17 @@ impl Default for DoubleQuotes {
}
pub fn default_op_dir() -> OpDir {
let module_name = clause_name!("builtins");
let mut op_dir = OpDir::new();
op_dir.insert(
(clause_name!(":-"), Fixity::In),
OpDirValue::new(XFX, 1200, module_name.clone()),
);
op_dir.insert(
(clause_name!(":-"), Fixity::Pre),
OpDirValue::new(FX, 1200, module_name.clone()),
);
op_dir.insert(
(clause_name!("?-"), Fixity::Pre),
OpDirValue::new(FX, 1200, module_name.clone()),
);
op_dir.insert(
(clause_name!(","), Fixity::In),
OpDirValue::new(XFY, 1000, module_name.clone()),
);
op_dir.insert((clause_name!(":-"), Fixity::In), OpDirValue::new(XFX, 1200));
op_dir.insert((clause_name!(":-"), Fixity::Pre), OpDirValue::new(FX, 1200));
op_dir.insert((clause_name!("?-"), Fixity::Pre), OpDirValue::new(FX, 1200));
op_dir.insert((clause_name!(","), Fixity::In), OpDirValue::new(XFY, 1000));
op_dir
}
#[derive(PartialEq, Debug, Clone)]
#[derive(Debug, Clone)]
pub enum ArithmeticError {
NonEvaluableFunctor(Constant, usize),
UninstantiatedVar,
@@ -361,31 +339,15 @@ pub enum ArithmeticError {
#[derive(Debug)]
pub enum ParserError {
Arithmetic(ArithmeticError),
BackQuotedString(usize, usize),
BadPendingByte,
CannotParseCyclicTerm,
UnexpectedChar(char, usize, usize),
UnexpectedEOF,
IO(IOError),
ExpectedRel,
ExpectedTopLevelTerm,
InadmissibleFact,
InadmissibleQueryTerm,
IncompleteReduction(usize, usize),
InconsistentEntry,
InvalidDoubleQuotesDecl,
InvalidHook,
InvalidModuleDecl,
InvalidModuleExport,
InvalidRuleHead,
InvalidUseModuleDecl,
InvalidModuleResolution,
InvalidSingleQuotedCharacter(char),
MissingQuote(usize, usize),
NonPrologChar(usize, usize),
ParseBigInt(usize, usize),
ParseFloat(usize, usize),
Utf8Error(usize, usize),
}
@@ -398,7 +360,6 @@ impl ParserError {
| &ParserError::MissingQuote(line_num, col_num)
| &ParserError::NonPrologChar(line_num, col_num)
| &ParserError::ParseBigInt(line_num, col_num)
| &ParserError::ParseFloat(line_num, col_num)
| &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)),
_ => None,
}
@@ -406,42 +367,20 @@ impl ParserError {
pub fn as_str(&self) -> &'static str {
match self {
&ParserError::Arithmetic(..) => "arithmetic_error",
&ParserError::BackQuotedString(..) => "back_quoted_string",
&ParserError::BadPendingByte => "bad_pending_byte",
&ParserError::UnexpectedChar(..) => "unexpected_char",
&ParserError::UnexpectedEOF => "unexpected_end_of_file",
&ParserError::ExpectedRel => "expected_relation",
&ParserError::ExpectedTopLevelTerm => "expected_atom_or_cons_or_clause",
&ParserError::InadmissibleFact => "inadmissible_fact",
&ParserError::InadmissibleQueryTerm => "inadmissible_query_term",
&ParserError::IncompleteReduction(..) => "incomplete_reduction",
&ParserError::InconsistentEntry => "inconsistent_entry",
&ParserError::InvalidDoubleQuotesDecl => "invalid_double_quotes_declaration",
&ParserError::InvalidHook => "invalid_hook",
&ParserError::InvalidModuleDecl => "invalid_module_declaration",
&ParserError::InvalidModuleExport => "invalid_module_export",
&ParserError::InvalidModuleResolution => "invalid_module_resolution",
&ParserError::InvalidRuleHead => "invalid_head_of_rule",
&ParserError::InvalidUseModuleDecl => "invalid_use_module_declaration",
&ParserError::InvalidSingleQuotedCharacter(..) => "invalid_single_quoted_character",
&ParserError::IO(_) => "input_output_error",
&ParserError::MissingQuote(..) => "missing_quote",
&ParserError::NonPrologChar(..) => "non_prolog_character",
&ParserError::ParseBigInt(..) => "cannot_parse_big_int",
&ParserError::ParseFloat(..) => "cannot_parse_float",
&ParserError::Utf8Error(..) => "utf8_conversion_error",
&ParserError::CannotParseCyclicTerm => "cannot_parse_cyclic_term",
ParserError::BackQuotedString(..) => "back_quoted_string",
ParserError::UnexpectedChar(..) => "unexpected_char",
ParserError::UnexpectedEOF => "unexpected_end_of_file",
ParserError::IncompleteReduction(..) => "incomplete_reduction",
ParserError::InvalidSingleQuotedCharacter(..) => "invalid_single_quoted_character",
ParserError::IO(_) => "input_output_error",
ParserError::MissingQuote(..) => "missing_quote",
ParserError::NonPrologChar(..) => "non_prolog_character",
ParserError::ParseBigInt(..) => "cannot_parse_big_int",
ParserError::Utf8Error(..) => "utf8_conversion_error",
}
}
}
impl From<ArithmeticError> for ParserError {
fn from(err: ArithmeticError) -> ParserError {
ParserError::Arithmetic(err)
}
}
impl From<IOError> for ParserError {
fn from(err: IOError) -> ParserError {
ParserError::IO(err)
@@ -458,6 +397,33 @@ impl From<&IOError> for ParserError {
}
}
#[derive(Debug, Clone, Copy)]
pub struct CompositeOpDir<'a, 'b> {
pub primary_op_dir: Option<&'b OpDir>,
pub secondary_op_dir: &'a OpDir,
}
impl<'a, 'b> CompositeOpDir<'a, 'b> {
#[inline]
pub fn new(secondary_op_dir: &'a OpDir, primary_op_dir: Option<&'b OpDir>) -> Self {
CompositeOpDir {
primary_op_dir,
secondary_op_dir,
}
}
#[inline]
pub(crate) fn get(&self, name: ClauseName, fixity: Fixity) -> Option<&OpDirValue> {
let entry = if let Some(ref primary_op_dir) = &self.primary_op_dir {
primary_op_dir.get(&(name.clone(), fixity))
} else {
None
};
entry.or_else(move || self.secondary_op_dir.get(&(name, fixity)))
}
}
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub enum Fixity {
In,
@@ -509,6 +475,15 @@ impl SharedOpDesc {
}
}
impl Deref for SharedOpDesc {
type Target = Cell<(usize, Specifier)>;
#[inline]
fn deref(&self) -> &Self::Target {
self.0.deref()
}
}
// this ensures that SharedOpDesc (which is not consistently placed in
// every atom!) doesn't affect the value of an atom hash. If
// SharedOpDesc values are to be indexed, a BTreeMap or BTreeSet
@@ -519,7 +494,7 @@ impl Hash for SharedOpDesc {
}
}
#[derive(Debug, Clone, Hash)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Constant {
Atom(ClauseName, Option<SharedOpDesc>),
Char(char),
@@ -535,58 +510,27 @@ pub enum Constant {
impl fmt::Display for Constant {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Constant::Atom(ref atom, _) => {
Constant::Atom(ref atom, _) => {
if atom.as_str().chars().any(|c| "`.$'\" ".contains(c)) {
write!(f, "'{}'", atom.as_str())
} else {
write!(f, "{}", atom.as_str())
}
}
&Constant::Char(c) => write!(f, "'{}'", c as u32),
&Constant::EmptyList => write!(f, "[]"),
&Constant::Fixnum(n) => write!(f, "{}", n),
&Constant::Integer(ref n) => write!(f, "{}", n),
&Constant::Rational(ref n) => write!(f, "{}", n),
&Constant::Float(ref n) => write!(f, "{}", n),
&Constant::String(ref s) => write!(f, "\"{}\"", &s),
&Constant::Usize(integer) => write!(f, "u{}", integer),
Constant::Char(c) => write!(f, "'{}'", *c as u32),
Constant::EmptyList => write!(f, "[]"),
Constant::Fixnum(n) => write!(f, "{}", n),
Constant::Integer(ref n) => write!(f, "{}", n),
Constant::Rational(ref n) => write!(f, "{}", n),
Constant::Float(ref n) => write!(f, "{}", n),
Constant::String(ref s) => write!(f, "\"{}\"", &s),
Constant::Usize(integer) => write!(f, "u{}", integer),
}
}
}
impl PartialEq for Constant {
fn eq(&self, other: &Constant) -> bool {
match (self, other) {
(&Constant::Atom(ref atom, _), &Constant::Char(c))
| (&Constant::Char(c), &Constant::Atom(ref atom, _)) => {
atom.is_char() && Some(c) == atom.as_str().chars().next()
}
(&Constant::Atom(ref a1, _), &Constant::Atom(ref a2, _)) => a1.as_str() == a2.as_str(),
(&Constant::Char(c1), &Constant::Char(c2)) => c1 == c2,
(&Constant::Fixnum(n1), &Constant::Fixnum(n2)) => n1 == n2,
(&Constant::Fixnum(n1), &Constant::Integer(ref n2))
| (&Constant::Integer(ref n2), &Constant::Fixnum(n1)) => {
if let Some(n2) = n2.to_isize() {
n1 == n2
} else {
false
}
}
(&Constant::Integer(ref n1), &Constant::Integer(ref n2)) => n1 == n2,
(&Constant::Rational(ref n1), &Constant::Rational(ref n2)) => n1 == n2,
(&Constant::Float(ref n1), &Constant::Float(ref n2)) => n1 == n2,
(&Constant::String(ref s1), &Constant::String(ref s2)) => &s1 == &s2,
(&Constant::EmptyList, &Constant::EmptyList) => true,
(&Constant::Usize(u1), &Constant::Usize(u2)) => u1 == u2,
_ => false,
}
}
}
impl Eq for Constant {}
impl Constant {
pub fn to_atom(self) -> Option<ClauseName> {
pub fn to_atom(&self) -> Option<ClauseName> {
match self {
Constant::Atom(a, _) => Some(a.defrock_brackets()),
_ => None,
@@ -642,7 +586,7 @@ impl ClauseName {
#[inline]
pub fn owning_module(&self) -> Self {
match self {
&ClauseName::User(ref name) => {
ClauseName::User(ref name) => {
let module = name.owning_module();
ClauseName::User(TabledRc {
atom: module.clone(),
@@ -656,8 +600,8 @@ impl ClauseName {
#[inline]
pub fn to_rc(&self) -> Rc<String> {
match self {
&ClauseName::BuiltIn(s) => Rc::new(s.to_string()),
&ClauseName::User(ref rc) => rc.inner(),
ClauseName::BuiltIn(s) => Rc::new(s.to_string()),
ClauseName::User(ref rc) => rc.inner(),
}
}
@@ -684,11 +628,7 @@ impl ClauseName {
pub fn has_table_of(&self, other: &ClauseName) -> bool {
match self {
ClauseName::BuiltIn(_) => {
if let ClauseName::BuiltIn(_) = other {
true
} else {
false
}
matches!(other, ClauseName::BuiltIn(_))
}
ClauseName::User(ref name) => other.has_table(&name.table),
}
@@ -697,17 +637,17 @@ impl ClauseName {
#[inline]
pub fn as_str(&self) -> &str {
match self {
&ClauseName::BuiltIn(s) => s,
&ClauseName::User(ref name) => name.as_ref(),
ClauseName::BuiltIn(s) => s,
ClauseName::User(ref name) => name.as_ref(),
}
}
#[inline]
pub fn is_char(&self) -> bool {
!self.as_str().is_empty() && self.as_str().chars().skip(1).next().is_none()
!self.as_str().is_empty() && self.as_str().chars().nth(1).is_none()
}
pub fn defrock_brackets(self) -> Self {
pub fn defrock_brackets(&self) -> Self {
fn defrock_brackets(s: &str) -> &str {
if s.starts_with('(') && s.ends_with(')') {
&s[1..s.len() - 1]
@@ -727,12 +667,12 @@ impl ClauseName {
impl AsRef<str> for ClauseName {
#[inline]
fn as_ref(self: &Self) -> &str {
fn as_ref(&self) -> &str {
self.as_str()
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
#[derive(Debug, Clone)]
pub enum Term {
AnonVar,
Clause(
@@ -749,13 +689,13 @@ pub enum Term {
impl Term {
pub fn shared_op_desc(&self) -> Option<SharedOpDesc> {
match self {
&Term::Clause(_, _, _, ref spec) => spec.clone(),
&Term::Constant(_, Constant::Atom(_, ref spec)) => spec.clone(),
Term::Clause(_, _, _, ref spec) => spec.clone(),
Term::Constant(_, Constant::Atom(_, ref spec)) => spec.clone(),
_ => None,
}
}
pub fn to_constant(self) -> Option<Constant> {
pub fn into_constant(self) -> Option<Constant> {
match self {
Term::Constant(_, c) => Some(c),
_ => None,
@@ -764,7 +704,7 @@ impl Term {
pub fn first_arg(&self) -> Option<&Term> {
match self {
&Term::Clause(_, _, ref terms, _) => terms.first().map(|bt| bt.as_ref()),
Term::Clause(_, _, ref terms, _) => terms.first().map(|bt| bt.as_ref()),
_ => None,
}
}
@@ -790,55 +730,14 @@ impl Term {
pub fn arity(&self) -> usize {
match self {
&Term::Clause(_, _, ref child_terms, ..) => child_terms.len(),
Term::Clause(_, _, ref child_terms, ..) => child_terms.len(),
_ => 0,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct CompositeOp<'a, 'b> {
pub op_dir: &'a OpDir,
pub static_op_dir: Option<&'b OpDir>,
}
#[macro_export]
macro_rules! composite_op {
($include_machine_p:expr, $op_dir:expr, $machine_op_dir:expr) => {
CompositeOp {
op_dir: $op_dir,
static_op_dir: if !$include_machine_p {
Some($machine_op_dir)
} else {
None
},
}
};
($op_dir:expr) => {
CompositeOp {
op_dir: $op_dir,
static_op_dir: None,
}
};
}
impl<'a, 'b> CompositeOp<'a, 'b> {
#[inline]
pub(crate) fn get(&self, name: ClauseName, fixity: Fixity) -> Option<OpDirValue> {
let entry = if let Some(ref static_op_dir) = &self.static_op_dir {
static_op_dir.get(&(name.clone(), fixity))
} else {
None
};
entry
.or_else(move || self.op_dir.get(&(name, fixity)))
.cloned()
}
}
fn unfold_by_str_once(term: &mut Term, s: &str) -> Option<(Term, Term)> {
if let &mut Term::Clause(_, ref name, ref mut subterms, _) = term {
if let Term::Clause(_, ref name, ref mut subterms, _) = term {
if name.as_str() == s && subterms.len() == 2 {
let snd = *subterms.pop().unwrap();
let fst = *subterms.pop().unwrap();

View File

@@ -1,9 +1,9 @@
use crate::lexical::parse_lossy;
use crate::ordered_float::*;
use crate::rug::Integer;
use lexical::parse_lossy;
use ordered_float::*;
use ast::*;
use tabled_rc::*;
use crate::ast::*;
use crate::tabled_rc::*;
use std::convert::TryFrom;
use std::fmt;
@@ -11,13 +11,13 @@ use std::io::Read;
use std::rc::Rc;
macro_rules! is_not_eof {
($c:expr) => (
($c:expr) => {
match $c {
Ok(c) => c,
Err(ParserError::UnexpectedEOF) => return Ok(true),
Err(e) => return Err(e)
Err($crate::ast::ParserError::UnexpectedEOF) => return Ok(true),
Err(e) => return Err(e),
}
)
};
}
macro_rules! consume_chars_with {
@@ -26,27 +26,38 @@ macro_rules! consume_chars_with {
match $e {
Ok(Some(c)) => $token.push(c),
Ok(None) => continue,
Err(ParserError::UnexpectedChar(..)) => break,
Err(e) => return Err(e)
Err($crate::ast::ParserError::UnexpectedChar(..)) => break,
Err(e) => return Err(e),
}
}
}
};
}
#[derive(Debug, Clone, PartialEq)]
pub enum Token {
Constant(Constant),
Var(Rc<Atom>),
Open, // '('
OpenCT, // '('
Close, // ')'
OpenList, // '['
CloseList, // ']'
OpenCurly, // '{'
CloseCurly, // '}'
Open, // '('
OpenCT, // '('
Close, // ')'
OpenList, // '['
CloseList, // ']'
OpenCurly, // '{'
CloseCurly, // '}'
HeadTailSeparator, // '|'
Comma, // ','
End
Comma, // ','
End,
}
impl Token {
#[inline]
pub(super) fn is_end(&self) -> bool {
if let Token::End = self {
true
} else {
false
}
}
}
pub struct Lexer<'a, R: Read> {
@@ -54,17 +65,17 @@ pub struct Lexer<'a, R: Read> {
pub(crate) reader: &'a mut ParsingStream<R>,
pub(crate) flags: MachineFlags,
pub(crate) line_num: usize,
pub(crate) col_num: usize
pub(crate) col_num: usize,
}
impl<'a, R: Read + fmt::Debug> fmt::Debug for Lexer<'a, R> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Lexer")
.field("atom_tbl", &self.atom_tbl)
.field("reader", &"&'a mut ParsingStream<R>") // Hacky solution.
.field("line_num", &self.line_num)
.field("col_num", &self.col_num)
.finish()
.field("atom_tbl", &self.atom_tbl)
.field("reader", &"&'a mut ParsingStream<R>") // Hacky solution.
.field("line_num", &self.line_num)
.field("col_num", &self.col_num)
.finish()
}
}
@@ -74,7 +85,13 @@ impl<'a, R: Read> Lexer<'a, R> {
flags: MachineFlags,
src: &'a mut ParsingStream<R>,
) -> Self {
Lexer { atom_tbl, flags, reader: src, line_num: 0, col_num: 0 }
Lexer {
atom_tbl,
flags,
reader: src,
line_num: 0,
col_num: 0,
}
}
fn return_char(&mut self, c: char) {
@@ -128,8 +145,7 @@ impl<'a, R: Read> Lexer<'a, R> {
}
}
fn single_line_comment(&mut self) -> Result<(), ParserError>
{
fn single_line_comment(&mut self) -> Result<(), ParserError> {
loop {
if self.reader.peek().is_none() || new_line_char!(self.skip_char()?) {
break;
@@ -229,8 +245,7 @@ impl<'a, R: Read> Lexer<'a, R> {
}
}
fn get_single_quoted_item(&mut self) -> Result<Option<char>, ParserError>
{
fn get_single_quoted_item(&mut self) -> Result<Option<char>, ParserError> {
if backslash_char!(self.lookahead_char()?) {
let c = self.skip_char()?;
@@ -264,14 +279,13 @@ impl<'a, R: Read> Lexer<'a, R> {
}
}
fn get_double_quoted_item(&mut self) -> Result<Option<char>, ParserError>
{
fn get_double_quoted_item(&mut self) -> Result<Option<char>, ParserError> {
if backslash_char!(self.lookahead_char()?) {
let c = self.skip_char()?;
if new_line_char!(self.lookahead_char()?) {
self.skip_char()?;
return Ok(None)
return Ok(None);
} else {
self.return_char(c);
}
@@ -299,8 +313,7 @@ impl<'a, R: Read> Lexer<'a, R> {
}
}
fn get_control_escape_sequence(&mut self) -> Result<char, ParserError>
{
fn get_control_escape_sequence(&mut self) -> Result<char, ParserError> {
let escaped = match self.lookahead_char()? {
'a' => '\u{07}', // UTF-8 alert
'b' => '\u{08}', // UTF-8 backspace
@@ -309,20 +322,18 @@ impl<'a, R: Read> Lexer<'a, R> {
't' => '\t',
'n' => '\n',
'r' => '\r',
c => return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
c => return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)),
};
self.skip_char()?;
return Ok(escaped);
}
fn get_octal_escape_sequence(&mut self) -> Result<char, ParserError>
{
fn get_octal_escape_sequence(&mut self) -> Result<char, ParserError> {
self.escape_sequence_to_char(|c| octal_digit_char!(c), 8)
}
fn get_hexadecimal_escape_sequence(&mut self) -> Result<char, ParserError>
{
fn get_hexadecimal_escape_sequence(&mut self) -> Result<char, ParserError> {
self.skip_char()?;
let c = self.lookahead_char()?;
@@ -354,12 +365,13 @@ impl<'a, R: Read> Lexer<'a, R> {
if backslash_char!(c) {
self.skip_char()?;
u32::from_str_radix(&token, radix)
.map_or_else(
|_| Err(ParserError::ParseBigInt(self.line_num, self.col_num)),
|n| char::try_from(n)
u32::from_str_radix(&token, radix).map_or_else(
|_| Err(ParserError::ParseBigInt(self.line_num, self.col_num)),
|n| {
char::try_from(n)
.map_err(|_| ParserError::Utf8Error(self.line_num, self.col_num))
)
},
)
} else {
// on failure, restore the token characters and backslash.
self.reader.put_back_all(token.chars().map(Ok));
@@ -423,11 +435,8 @@ impl<'a, R: Read> Lexer<'a, R> {
.map(|n| Token::Constant(Constant::Fixnum(n)))
.or_else(|_| {
Integer::from_str_radix(&token, 16)
.map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
.map_err(|_| ParserError::ParseBigInt(
self.line_num,
self.col_num,
))
.map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
.map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
})
} else {
self.return_char('x');
@@ -449,11 +458,8 @@ impl<'a, R: Read> Lexer<'a, R> {
.map(|n| Token::Constant(Constant::Fixnum(n)))
.or_else(|_| {
Integer::from_str_radix(&token, 8)
.map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
.map_err(|_| ParserError::ParseBigInt(
self.line_num,
self.col_num,
))
.map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
.map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
})
} else {
self.return_char('o');
@@ -475,11 +481,8 @@ impl<'a, R: Read> Lexer<'a, R> {
.map(|n| Token::Constant(Constant::Fixnum(n)))
.or_else(|_| {
Integer::from_str_radix(&token, 2)
.map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
.map_err(|_| ParserError::ParseBigInt(
self.line_num,
self.col_num,
))
.map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
.map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
})
} else {
self.return_char('b');
@@ -525,18 +528,20 @@ impl<'a, R: Read> Lexer<'a, R> {
if single_quote_char!(self.lookahead_char()?) {
self.skip_char()?;
if !token.is_empty() && token.chars().skip(1).next().is_none() {
if !token.is_empty() && token.chars().nth(1).is_none() {
if let Some(c) = token.chars().next() {
return Ok(Token::Constant(Constant::Char(c)));
}
}
} else {
return Err(ParserError::InvalidSingleQuotedCharacter(self.lookahead_char()?))
return Err(ParserError::InvalidSingleQuotedCharacter(
self.lookahead_char()?,
));
}
} else {
match self.get_back_quoted_string() {
Ok(_) => return Err(ParserError::BackQuotedString(self.line_num, self.col_num)),
Err(e) => return Err(e)
Ok(_) => return Err(ParserError::BackQuotedString(self.line_num, self.col_num)),
Err(e) => return Err(e),
}
}
@@ -575,12 +580,10 @@ impl<'a, R: Read> Lexer<'a, R> {
isize::from_str_radix(&token, 10)
.map(|n| Token::Constant(Constant::Fixnum(n)))
.or_else(|_| {
token.parse::<Integer>()
.map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
.map_err(|_| ParserError::ParseBigInt(
self.line_num,
self.col_num,
))
token
.parse::<Integer>()
.map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
.map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
})
} else if decimal_digit_char!(self.lookahead_char()?) {
token.push('.');
@@ -599,7 +602,7 @@ impl<'a, R: Read> Lexer<'a, R> {
let c = match self.lookahead_char() {
Err(_) => return Ok(self.vacate_with_float(token)),
Ok(c) => c
Ok(c) => c,
};
if !sign_char!(c) && !decimal_digit_char!(c) {
@@ -613,8 +616,8 @@ impl<'a, R: Read> Lexer<'a, R> {
Err(_) => {
self.return_char(token.pop().unwrap());
return Ok(self.vacate_with_float(token));
},
Ok(c) => c
}
Ok(c) => c,
};
if !decimal_digit_char!(c) {
@@ -645,70 +648,65 @@ impl<'a, R: Read> Lexer<'a, R> {
isize::from_str_radix(&token, 10)
.map(|n| Token::Constant(Constant::Fixnum(n)))
.or_else(|_| {
token.parse::<Integer>()
.map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
.map_err(|_| ParserError::ParseBigInt(
self.line_num,
self.col_num,
))
token
.parse::<Integer>()
.map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
.map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
})
}
} else {
if token.starts_with('0') && token.len() == 1 {
if c == 'x' {
self.hexadecimal_constant()
.or_else(|e| {
if let ParserError::ParseBigInt(..) = e {
isize::from_str_radix(&token, 10)
.map(|n| Token::Constant(Constant::Fixnum(n)))
.or_else(|_| {
token.parse::<Integer>()
.map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
.map_err(|_| ParserError::ParseBigInt(
self.line_num,
self.col_num,
))
})
} else {
Err(e)
}
})
self.hexadecimal_constant().or_else(|e| {
if let ParserError::ParseBigInt(..) = e {
isize::from_str_radix(&token, 10)
.map(|n| Token::Constant(Constant::Fixnum(n)))
.or_else(|_| {
token
.parse::<Integer>()
.map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
.map_err(|_| {
ParserError::ParseBigInt(self.line_num, self.col_num)
})
})
} else {
Err(e)
}
})
} else if c == 'o' {
self.octal_constant()
.or_else(|e| {
if let ParserError::ParseBigInt(..) = e {
isize::from_str_radix(&token, 10)
.map(|n| Token::Constant(Constant::Fixnum(n)))
.or_else(|_| {
token.parse::<Integer>()
.map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
.map_err(|_| ParserError::ParseBigInt(
self.line_num,
self.col_num,
))
})
} else {
Err(e)
}
})
self.octal_constant().or_else(|e| {
if let ParserError::ParseBigInt(..) = e {
isize::from_str_radix(&token, 10)
.map(|n| Token::Constant(Constant::Fixnum(n)))
.or_else(|_| {
token
.parse::<Integer>()
.map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
.map_err(|_| {
ParserError::ParseBigInt(self.line_num, self.col_num)
})
})
} else {
Err(e)
}
})
} else if c == 'b' {
self.binary_constant()
.or_else(|e| {
if let ParserError::ParseBigInt(..) = e {
isize::from_str_radix(&token, 10)
.map(|n| Token::Constant(Constant::Fixnum(n)))
.or_else(|_| {
token.parse::<Integer>()
.map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
.map_err(|_| ParserError::ParseBigInt(
self.line_num,
self.col_num,
))
})
} else {
Err(e)
}
})
self.binary_constant().or_else(|e| {
if let ParserError::ParseBigInt(..) = e {
isize::from_str_radix(&token, 10)
.map(|n| Token::Constant(Constant::Fixnum(n)))
.or_else(|_| {
token
.parse::<Integer>()
.map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
.map_err(|_| {
ParserError::ParseBigInt(self.line_num, self.col_num)
})
})
} else {
Err(e)
}
})
} else if single_quote_char!(c) {
self.skip_char()?;
@@ -726,45 +724,39 @@ impl<'a, R: Read> Lexer<'a, R> {
}
self.get_single_quoted_char()
.and_then(|c| {
Ok(Token::Constant(Constant::Fixnum(c as isize)))
})
.map(|c| Token::Constant(Constant::Fixnum(c as isize)))
.or_else(|_| {
self.return_char(c);
isize::from_str_radix(&token, 10)
.map(|n| Token::Constant(Constant::Fixnum(n)))
.or_else(|_| {
token.parse::<Integer>()
.map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
.map_err(|_| ParserError::ParseBigInt(
self.line_num,
self.col_num,
))
token
.parse::<Integer>()
.map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
.map_err(|_| {
ParserError::ParseBigInt(self.line_num, self.col_num)
})
})
})
} else {
isize::from_str_radix(&token, 10)
.map(|n| Token::Constant(Constant::Fixnum(n)))
.or_else(|_| {
token.parse::<Integer>()
.map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
.map_err(|_| ParserError::ParseBigInt(
self.line_num,
self.col_num,
))
token
.parse::<Integer>()
.map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
.map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
})
}
} else {
isize::from_str_radix(&token, 10)
.map(|n| Token::Constant(Constant::Fixnum(n)))
.or_else(|_| {
token.parse::<Integer>()
.map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
.map_err(|_| ParserError::ParseBigInt(
self.line_num,
self.col_num,
))
token
.parse::<Integer>()
.map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
.map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
})
}
}
@@ -781,18 +773,19 @@ impl<'a, R: Read> Lexer<'a, R> {
Ok(c) if layout_char!(c) || new_line_char!(c) => {
self.skip_char()?;
layout_inserted = true;
},
}
Ok(c) if end_line_comment_char!(c) => {
self.single_line_comment()?;
layout_inserted = true;
},
Ok(c) if comment_1_char!(c) =>
}
Ok(c) if comment_1_char!(c) => {
if self.bracketed_comment()? {
layout_inserted = true;
} else {
more_layout = false;
},
_ => more_layout = false
}
}
_ => more_layout = false,
};
if !more_layout {
@@ -825,8 +818,11 @@ impl<'a, R: Read> Lexer<'a, R> {
if c == '(' {
self.skip_char()?;
return Ok(if layout_inserted { Token::Open }
else { Token::OpenCT });
return Ok(if layout_inserted {
Token::Open
} else {
Token::OpenCT
});
}
if c == '.' {
@@ -839,7 +835,7 @@ impl<'a, R: Read> Lexer<'a, R> {
}
return Ok(Token::End);
},
}
Err(ParserError::UnexpectedEOF) => {
return Ok(Token::End);
}
@@ -891,8 +887,8 @@ impl<'a, R: Read> Lexer<'a, R> {
}
self.name_token(c)
},
Err(e) => Err(e)
}
Err(e) => Err(e),
}
}
}

View File

@@ -1,14 +1,14 @@
extern crate lexical;
extern crate ordered_float;
#[cfg(feature = "rug")]
extern crate rug;
#[cfg(feature = "num-rug-adapter")]
extern crate num_rug_adapter as rug;
extern crate unicode_reader;
use num_rug_adapter as rug;
#[cfg(feature = "rug")]
use rug;
#[macro_use] pub mod tabled_rc;
#[macro_use] pub mod ast;
#[macro_use] pub mod macros;
#[macro_use]
pub mod tabled_rc;
#[macro_use]
pub mod ast;
#[macro_use]
pub mod macros;
pub mod parser;
pub mod put_back_n;

View File

@@ -1,187 +1,246 @@
#[macro_export]
macro_rules! char_class {
($c: expr, [$head:expr]) => ($c == $head);
($c: expr, [$head:expr $(, $cs:expr)+]) => ($c == $head || char_class!($c, [$($cs),*]));
($c: expr, [$head:expr $(, $cs:expr)+]) => ($c == $head || $crate::char_class!($c, [$($cs),*]));
}
#[macro_export]
macro_rules! symbolic_control_char {
($c: expr) => (char_class!($c, ['a', 'b', 'f', 'n', 'r', 't', 'v', '0']))
($c: expr) => {
$crate::char_class!($c, ['a', 'b', 'f', 'n', 'r', 't', 'v', '0'])
};
}
#[macro_export]
macro_rules! space_char {
($c: expr) => ($c == ' ')
($c: expr) => {
$c == ' '
};
}
#[macro_export]
macro_rules! layout_char {
($c: expr) => (char_class!($c, [' ', '\n', '\t', '\u{0B}', '\u{0C}']))
($c: expr) => {
$crate::char_class!($c, [' ', '\n', '\t', '\u{0B}', '\u{0C}'])
};
}
#[macro_export]
macro_rules! symbolic_hexadecimal_char {
($c: expr) => ($c == 'x')
($c: expr) => {
$c == 'x'
};
}
#[macro_export]
macro_rules! octal_digit_char {
($c: expr) => ($c >= '0' && $c <= '7')
($c: expr) => {
('0'..='7').contains(&$c)
};
}
#[macro_export]
macro_rules! binary_digit_char {
($c: expr) => ($c >= '0' && $c <= '1')
($c: expr) => {
$c >= '0' && $c <= '1'
};
}
#[macro_export]
macro_rules! hexadecimal_digit_char {
($c: expr) => ($c >= '0' && $c <= '9' ||
$c >= 'A' && $c <= 'F' ||
$c >= 'a' && $c <= 'f')
($c: expr) => {
('0'..='9').contains(&$c) || ('A'..='F').contains(&$c) || ('a'..='f').contains(&$c)
};
}
#[macro_export]
macro_rules! exponent_char {
($c: expr) => ($c == 'e' || $c == 'E')
($c: expr) => {
$c == 'e' || $c == 'E'
};
}
#[macro_export]
macro_rules! sign_char {
($c: expr) => ($c == '-' || $c == '+')
($c: expr) => {
$c == '-' || $c == '+'
};
}
#[macro_export]
macro_rules! new_line_char {
($c: expr) => ($c == '\n')
($c: expr) => {
$c == '\n'
};
}
#[macro_export]
macro_rules! end_line_comment_char {
($c: expr) => ($c == '%')
($c: expr) => {
$c == '%'
};
}
#[macro_export]
macro_rules! comment_1_char {
($c: expr) => ($c == '/')
($c: expr) => {
$c == '/'
};
}
#[macro_export]
macro_rules! comment_2_char {
($c: expr) => ($c == '*')
($c: expr) => {
$c == '*'
};
}
#[macro_export]
macro_rules! capital_letter_char {
($c: expr) => ($c >= 'A' && $c <= 'Z')
($c: expr) => {
('A'..='Z').contains(&$c)
};
}
#[macro_export]
macro_rules! small_letter_char {
($c: expr) => ($c >= 'a' && $c <= 'z')
($c: expr) => {
('a'..='z').contains(&$c)
};
}
#[macro_export]
macro_rules! variable_indicator_char {
($c: expr) => ($c == '_')
($c: expr) => {
$c == '_'
};
}
#[macro_export]
macro_rules! graphic_char {
($c: expr) => (char_class!($c, ['#', '$', '&', '*', '+', '-', '.', '/', ':',
($c: expr) => ($crate::char_class!($c, ['#', '$', '&', '*', '+', '-', '.', '/', ':',
'<', '=', '>', '?', '@', '^', '~']))
}
#[macro_export]
macro_rules! graphic_token_char {
($c: expr) => (graphic_char!($c) || backslash_char!($c))
($c: expr) => {
$crate::graphic_char!($c) || $crate::backslash_char!($c)
};
}
#[macro_export]
macro_rules! alpha_char {
($c: expr) =>
(match $c {
'a' ..= 'z' => true,
'A' ..= 'Z' => true,
($c: expr) => {
match $c {
'a'..='z' => true,
'A'..='Z' => true,
'_' => true,
'\u{00A0}' ..= '\u{00BF}' => true,
'\u{00C0}' ..= '\u{00D6}' => true,
'\u{00D8}' ..= '\u{00F6}' => true,
'\u{00F8}' ..= '\u{00FF}' => true,
'\u{0100}' ..= '\u{017F}' => true, // Latin Extended-A
'\u{0180}' ..= '\u{024F}' => true, // Latin Extended-B
'\u{0250}' ..= '\u{02AF}' => true, // IPA Extensions
'\u{02B0}' ..= '\u{02FF}' => true, // Spacing Modifier Letters
'\u{0300}' ..= '\u{036F}' => true, // Combining Diacritical Marks
'\u{0370}' ..= '\u{03FF}' => true, // Greek/Coptic
'\u{0400}' ..= '\u{04FF}' => true, // Cyrillic
'\u{0500}' ..= '\u{052F}' => true, // Cyrillic Supplement
'\u{0530}' ..= '\u{058F}' => true, // Armenian
'\u{0590}' ..= '\u{05FF}' => true, // Hebrew
'\u{0600}' ..= '\u{06FF}' => true, // Arabic
'\u{0700}' ..= '\u{074F}' => true, // Syriac
_ => false
})
'\u{00A0}'..='\u{00BF}' => true,
'\u{00C0}'..='\u{00D6}' => true,
'\u{00D8}'..='\u{00F6}' => true,
'\u{00F8}'..='\u{00FF}' => true,
'\u{0100}'..='\u{017F}' => true, // Latin Extended-A
'\u{0180}'..='\u{024F}' => true, // Latin Extended-B
'\u{0250}'..='\u{02AF}' => true, // IPA Extensions
'\u{02B0}'..='\u{02FF}' => true, // Spacing Modifier Letters
'\u{0300}'..='\u{036F}' => true, // Combining Diacritical Marks
'\u{0370}'..='\u{03FF}' => true, // Greek/Coptic
'\u{0400}'..='\u{04FF}' => true, // Cyrillic
'\u{0500}'..='\u{052F}' => true, // Cyrillic Supplement
'\u{0530}'..='\u{058F}' => true, // Armenian
'\u{0590}'..='\u{05FF}' => true, // Hebrew
'\u{0600}'..='\u{06FF}' => true, // Arabic
'\u{0700}'..='\u{074F}' => true, // Syriac
_ => false,
}
};
}
#[macro_export]
macro_rules! decimal_digit_char {
($c: expr) => ($c >= '0' && $c <= '9')
($c: expr) => {
('0'..='9').contains(&$c)
};
}
#[macro_export]
macro_rules! decimal_point_char {
($c: expr) => ($c == '.')
($c: expr) => {
$c == '.'
};
}
#[macro_export]
macro_rules! alpha_numeric_char {
($c: expr) => (alpha_char!($c) || decimal_digit_char!($c))
($c: expr) => {
$crate::alpha_char!($c) || $crate::decimal_digit_char!($c)
};
}
#[macro_export]
macro_rules! cut_char {
($c: expr) => ($c == '!')
($c: expr) => {
$c == '!'
};
}
#[macro_export]
macro_rules! semicolon_char {
($c: expr) => ($c == ';')
($c: expr) => {
$c == ';'
};
}
#[macro_export]
macro_rules! backslash_char {
($c: expr) => ($c == '\\')
($c: expr) => {
$c == '\\'
};
}
#[macro_export]
macro_rules! single_quote_char {
($c: expr) => ($c == '\'')
($c: expr) => {
$c == '\''
};
}
#[macro_export]
macro_rules! double_quote_char {
($c: expr) => ($c == '"')
($c: expr) => {
$c == '"'
};
}
#[macro_export]
macro_rules! back_quote_char {
($c: expr) => ($c == '`')
($c: expr) => {
$c == '`'
};
}
#[macro_export]
macro_rules! meta_char {
($c: expr) => ( char_class!($c, ['\\', '\'', '"', '`']) )
($c: expr) => {
$crate::char_class!($c, ['\\', '\'', '"', '`'])
};
}
#[macro_export]
macro_rules! solo_char {
($c: expr) => ( char_class!($c, ['!', '(', ')', ',', ';', '[', ']',
'{', '}', '|', '%']) )
($c: expr) => {
$crate::char_class!($c, ['!', '(', ')', ',', ';', '[', ']', '{', '}', '|', '%'])
};
}
#[macro_export]
macro_rules! prolog_char {
($c: expr) => (graphic_char!($c) || alpha_numeric_char!($c) || solo_char!($c) ||
layout_char!($c) || meta_char!($c))
($c: expr) => {
$crate::graphic_char!($c)
|| $crate::alpha_numeric_char!($c)
|| $crate::solo_char!($c)
|| $crate::layout_char!($c)
|| $crate::meta_char!($c)
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,11 +4,11 @@ use std::collections::HashSet;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::rc::{Rc};
use std::rc::Rc;
pub struct TabledData<T> {
table: Rc<RefCell<HashSet<Rc<T>>>>,
pub(crate) module_name: Rc<String>
pub(crate) module_name: Rc<String>,
}
impl<T: Hash + Eq + fmt::Debug> fmt::Debug for TabledData<T> {
@@ -22,14 +22,15 @@ impl<T: Hash + Eq + fmt::Debug> fmt::Debug for TabledData<T> {
impl<T> Clone for TabledData<T> {
fn clone(&self) -> Self {
TabledData { table: self.table.clone(),
module_name: self.module_name.clone() }
TabledData {
table: self.table.clone(),
module_name: self.module_name.clone(),
}
}
}
impl<T: PartialEq> PartialEq for TabledData<T> {
fn eq(&self, other: &TabledData<T>) -> bool
{
fn eq(&self, other: &TabledData<T>) -> bool {
Rc::ptr_eq(&self.table, &other.table) && self.module_name == other.module_name
}
}
@@ -39,7 +40,7 @@ impl<T: Hash + Eq> TabledData<T> {
pub fn new(module_name: Rc<String>) -> Self {
TabledData {
table: Rc::new(RefCell::new(HashSet::new())),
module_name
module_name,
}
}
@@ -51,7 +52,7 @@ impl<T: Hash + Eq> TabledData<T> {
pub struct TabledRc<T: Hash + Eq> {
pub(crate) atom: Rc<T>,
pub table: TabledData<T>
pub table: TabledData<T>,
}
impl<T: Hash + Eq + fmt::Debug> fmt::Debug for TabledRc<T> {
@@ -67,27 +68,27 @@ impl<T: Hash + Eq + fmt::Debug> fmt::Debug for TabledRc<T> {
// from complaining when deriving Clone for StringList.
impl<T: Hash + Eq> Clone for TabledRc<T> {
fn clone(&self) -> Self {
TabledRc { atom: self.atom.clone(), table: self.table.clone() }
TabledRc {
atom: self.atom.clone(),
table: self.table.clone(),
}
}
}
impl<T: Ord + Hash + Eq> PartialOrd for TabledRc<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering>
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.atom.cmp(&other.atom))
}
}
impl<T: Ord + Hash + Eq> Ord for TabledRc<T> {
fn cmp(&self, other: &Self) -> Ordering
{
fn cmp(&self, other: &Self) -> Ordering {
self.atom.cmp(&other.atom)
}
}
impl<T: Hash + Eq> PartialEq for TabledRc<T> {
fn eq(&self, other: &TabledRc<T>) -> bool
{
fn eq(&self, other: &TabledRc<T>) -> bool {
self.atom == other.atom
}
}
@@ -103,8 +104,8 @@ impl<T: Hash + Eq> Hash for TabledRc<T> {
impl<T: Hash + Eq + ToString> TabledRc<T> {
pub fn new(atom: T, table: TabledData<T>) -> Self {
let atom = match table.borrow_mut().take(&atom) {
Some(atom) => atom.clone(),
None => Rc::new(atom)
Some(atom) => atom,
None => Rc::new(atom),
};
table.borrow_mut().insert(atom.clone());
@@ -147,7 +148,7 @@ impl<T: Hash + Eq + fmt::Display> fmt::Display for TabledRc<T> {
#[macro_export]
macro_rules! tabled_rc {
($e:expr, $tbl:expr) => (
TabledRc::new(String::from($e), $tbl.clone())
)
($e:expr, $tbl:expr) => {
$crate::tabled_rc::TabledRc::new(String::from($e), $tbl.clone())
};
}

View File

@@ -1,5 +1,3 @@
extern crate prolog_parser;
use prolog_parser::ast::*;
use prolog_parser::lexer::{Lexer, Token};
use prolog_parser::tabled_rc::TabledData;
@@ -27,7 +25,7 @@ fn skip_utf8_bom() {
let mut lexer = Lexer::new(atom_tbl, flags, &mut stream);
match lexer.next_token() {
Ok(Token::Constant(Constant::Fixnum(4))) => (),
_ => assert!(false)
_ => assert!(false),
}
}
@@ -37,7 +35,6 @@ fn invalid_utf16_bom() {
let stream = parsing_stream(bytes);
match stream {
Err(ParserError::Utf8Error(0, 0)) => (),
_ => assert!(false)
_ => assert!(false),
}
}

View File

@@ -1,5 +1,3 @@
extern crate prolog_parser;
use prolog_parser::ast::*;
use prolog_parser::lexer::{Lexer, Token};
use prolog_parser::tabled_rc::TabledData;

View File

@@ -1,4 +1,5 @@
use crate::prolog_parser::ast::*;
use prolog_parser::ast::*;
use prolog_parser::temp_v;
use crate::fixtures::*;
use crate::forms::*;
@@ -8,14 +9,19 @@ use crate::targets::*;
use std::cell::Cell;
use std::rc::Rc;
pub trait Allocator<'a> {
pub(crate) trait Allocator<'a> {
fn new() -> Self;
fn mark_anon_var<Target>(&mut self, _: Level, _: GenContext, _: &mut Vec<Target>)
where
Target: CompilationTarget<'a>;
fn mark_non_var<Target>(&mut self, _: Level, _: GenContext, _: &'a Cell<RegType>, _: &mut Vec<Target>)
where
fn mark_non_var<Target>(
&mut self,
_: Level,
_: GenContext,
_: &'a Cell<RegType>,
_: &mut Vec<Target>,
) where
Target: CompilationTarget<'a>;
fn mark_reserved_var<Target>(
&mut self,
@@ -28,8 +34,14 @@ pub trait Allocator<'a> {
_: bool,
) where
Target: CompilationTarget<'a>;
fn mark_var<Target>(&mut self, _: Rc<Var>, _: Level, _: &'a Cell<VarReg>, _: GenContext, _: &mut Vec<Target>)
where
fn mark_var<Target>(
&mut self,
_: Rc<Var>,
_: Level,
_: &'a Cell<VarReg>,
_: GenContext,
_: &mut Vec<Target>,
) where
Target: CompilationTarget<'a>;
fn reset(&mut self);
@@ -47,7 +59,7 @@ pub trait Allocator<'a> {
fn drain_var_data(
&mut self,
vs: VariableFixtures<'a>,
num_of_chunks: usize
num_of_chunks: usize,
) -> VariableFixtures<'a> {
let mut perm_vs = VariableFixtures::new();

View File

@@ -1,4 +1,5 @@
use crate::prolog_parser::ast::*;
use prolog_parser::ast::*;
use prolog_parser::{atom, clause_name};
use crate::clause_types::*;
use crate::fixtures::*;
@@ -10,9 +11,9 @@ use crate::machine::heap::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::ordered_float::*;
use crate::rug::ops::PowAssign;
use crate::rug::{Assign, Integer, Rational};
use ordered_float::*;
use std::cell::Cell;
use std::cmp::{max, min, Ordering};
@@ -24,11 +25,11 @@ use std::rc::Rc;
use std::vec::Vec;
#[derive(Debug)]
pub struct ArithInstructionIterator<'a> {
pub(crate) struct ArithInstructionIterator<'a> {
state_stack: Vec<TermIterState<'a>>,
}
pub type ArithCont = (Code, Option<ArithmeticTerm>);
pub(crate) type ArithCont = (Code, Option<ArithmeticTerm>);
impl<'a> ArithInstructionIterator<'a> {
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
@@ -70,7 +71,7 @@ impl<'a> ArithInstructionIterator<'a> {
}
#[derive(Debug)]
pub enum ArithTermRef<'a> {
pub(crate) enum ArithTermRef<'a> {
Constant(&'a Constant),
Op(ClauseName, usize), // name, arity.
Var(&'a Cell<VarReg>, Rc<Var>),
@@ -112,13 +113,13 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
}
#[derive(Debug)]
pub struct ArithmeticEvaluator<'a> {
pub(crate) struct ArithmeticEvaluator<'a> {
bindings: &'a AllocVarDict,
interm: Vec<ArithmeticTerm>,
interm_c: usize,
}
pub trait ArithmeticTermIter<'a> {
pub(crate) trait ArithmeticTermIter<'a> {
type Iter: Iterator<Item = Result<ArithTermRef<'a>, ArithmeticError>>;
fn iter(self) -> Result<Self::Iter, ArithmeticError>;
@@ -133,7 +134,7 @@ impl<'a> ArithmeticTermIter<'a> for &'a Term {
}
impl<'a> ArithmeticEvaluator<'a> {
pub fn new(bindings: &'a AllocVarDict, target_int: usize) -> Self {
pub(crate) fn new(bindings: &'a AllocVarDict, target_int: usize) -> Self {
ArithmeticEvaluator {
bindings,
interm: Vec::new(),
@@ -267,9 +268,7 @@ impl<'a> ArithmeticEvaluator<'a> {
fn push_constant(&mut self, c: &Constant) -> Result<(), ArithmeticError> {
match c {
&Constant::Fixnum(n) => self
.interm
.push(ArithmeticTerm::Number(Number::Fixnum(n))),
&Constant::Fixnum(n) => self.interm.push(ArithmeticTerm::Number(Number::Fixnum(n))),
&Constant::Integer(ref n) => self
.interm
.push(ArithmeticTerm::Number(Number::Integer(n.clone()))),
@@ -279,6 +278,12 @@ impl<'a> ArithmeticEvaluator<'a> {
&Constant::Rational(ref n) => self
.interm
.push(ArithmeticTerm::Number(Number::Rational(n.clone()))),
&Constant::Atom(ref name, _) if name.as_str() == "e" => {
self.interm
.push(ArithmeticTerm::Number(Number::Float(OrderedFloat(
f64::consts::E,
))))
}
&Constant::Atom(ref name, _) if name.as_str() == "pi" => {
self.interm
.push(ArithmeticTerm::Number(Number::Float(OrderedFloat(
@@ -291,7 +296,7 @@ impl<'a> ArithmeticEvaluator<'a> {
Ok(())
}
pub fn eval<Iter>(&mut self, src: Iter) -> Result<ArithCont, ArithmeticError>
pub(crate) fn eval<Iter>(&mut self, src: Iter) -> Result<ArithCont, ArithmeticError>
where
Iter: ArithmeticTermIter<'a>,
{
@@ -324,19 +329,13 @@ impl<'a> ArithmeticEvaluator<'a> {
}
// integer division rounding function -- 9.1.3.1.
pub fn rnd_i<'a>(n: &'a Number) -> RefOrOwned<'a, Number> {
pub(crate) fn rnd_i<'a>(n: &'a Number) -> RefOrOwned<'a, Number> {
match n {
&Number::Integer(_) => {
RefOrOwned::Borrowed(n)
}
&Number::Float(OrderedFloat(f)) => {
RefOrOwned::Owned(Number::from(
Integer::from_f64(f.floor()).unwrap_or_else(|| Integer::from(0))
))
}
&Number::Fixnum(n) => {
RefOrOwned::Owned(Number::from(n))
}
&Number::Integer(_) => RefOrOwned::Borrowed(n),
&Number::Float(OrderedFloat(f)) => RefOrOwned::Owned(Number::from(
Integer::from_f64(f.floor()).unwrap_or_else(|| Integer::from(0)),
)),
&Number::Fixnum(n) => RefOrOwned::Owned(Number::from(n)),
&Number::Rational(ref r) => {
let r_ref = r.fract_floor_ref();
let (mut fract, mut floor) = (Rational::new(), Integer::new());
@@ -348,7 +347,7 @@ pub fn rnd_i<'a>(n: &'a Number) -> RefOrOwned<'a, Number> {
}
// floating point rounding function -- 9.1.4.1.
pub fn rnd_f(n: &Number) -> f64 {
pub(crate) fn rnd_f(n: &Number) -> f64 {
match n {
&Number::Fixnum(n) => n as f64,
&Number::Integer(ref n) => n.to_f64(),
@@ -358,7 +357,7 @@ pub fn rnd_f(n: &Number) -> f64 {
}
// floating point result function -- 9.1.4.2.
pub fn result_f<Round>(n: &Number, round: Round) -> Result<f64, EvalError>
pub(crate) fn result_f<Round>(n: &Number, round: Round) -> Result<f64, EvalError>
where
Round: Fn(&Number) -> f64,
{
@@ -432,31 +431,31 @@ impl Add<Number> for Number {
Number::from(Integer::from(n1) + Integer::from(n2))
})
}
(Number::Fixnum(n1), Number::Integer(n2)) |
(Number::Integer(n2), Number::Fixnum(n1)) => {
(Number::Fixnum(n1), Number::Integer(n2))
| (Number::Integer(n2), Number::Fixnum(n1)) => {
Ok(Number::from(Integer::from(n1) + &*n2))
}
(Number::Fixnum(n1), Number::Rational(n2)) |
(Number::Rational(n2), Number::Fixnum(n1)) => {
(Number::Fixnum(n1), Number::Rational(n2))
| (Number::Rational(n2), Number::Fixnum(n1)) => {
Ok(Number::from(Rational::from(n1) + &*n2))
}
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) |
(Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => {
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2)))
| (Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => {
Ok(Number::Float(add_f(float_fn_to_f(n1)?, n2)?))
}
(Number::Integer(n1), Number::Integer(n2)) => {
Ok(Number::from(Integer::from(&*n1) + &*n2)) // add_i
}
(Number::Integer(n1), Number::Float(OrderedFloat(n2)))
| (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
| (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
Ok(Number::Float(add_f(float_i_to_f(&n1)?, n2)?))
}
(Number::Integer(n1), Number::Rational(n2))
| (Number::Rational(n2), Number::Integer(n1)) => {
| (Number::Rational(n2), Number::Integer(n1)) => {
Ok(Number::from(Rational::from(&*n1) + &*n2))
}
(Number::Rational(n1), Number::Float(OrderedFloat(n2)))
| (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
| (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
Ok(Number::Float(add_f(float_r_to_f(&n1)?, n2)?))
}
(Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => {
@@ -474,12 +473,13 @@ impl Neg for Number {
fn neg(self) -> Self::Output {
match self {
Number::Fixnum(n) =>
Number::Fixnum(n) => {
if let Some(n) = n.checked_neg() {
Number::Fixnum(n)
} else {
Number::from(-Integer::from(n))
}
}
Number::Integer(n) => Number::Integer(Rc::new(-Integer::from(&*n))),
Number::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)),
Number::Rational(r) => Number::Rational(Rc::new(-Rational::from(&*r))),
@@ -507,16 +507,16 @@ impl Mul<Number> for Number {
Number::from(Integer::from(n1) * Integer::from(n2))
})
}
(Number::Fixnum(n1), Number::Integer(n2)) |
(Number::Integer(n2), Number::Fixnum(n1)) => {
(Number::Fixnum(n1), Number::Integer(n2))
| (Number::Integer(n2), Number::Fixnum(n1)) => {
Ok(Number::from(Integer::from(n1) * &*n2))
}
(Number::Fixnum(n1), Number::Rational(n2)) |
(Number::Rational(n2), Number::Fixnum(n1)) => {
(Number::Fixnum(n1), Number::Rational(n2))
| (Number::Rational(n2), Number::Fixnum(n1)) => {
Ok(Number::from(Rational::from(n1) * &*n2))
}
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) |
(Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => {
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2)))
| (Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => {
Ok(Number::Float(mul_f(float_fn_to_f(n1)?, n2)?))
}
(Number::Integer(n1), Number::Integer(n2)) => {
@@ -549,72 +549,50 @@ impl Div<Number> for Number {
fn div(self, rhs: Number) -> Self::Output {
match (self, rhs) {
(Number::Fixnum(n1), Number::Fixnum(n2)) => {
Ok(Number::Float(div_f(
float_fn_to_f(n1)?,
float_fn_to_f(n2)?,
)?))
}
(Number::Fixnum(n1), Number::Integer(n2)) => {
Ok(Number::Float(div_f(
float_fn_to_f(n1)?,
float_i_to_f(&n2)?,
)?))
}
(Number::Integer(n1), Number::Fixnum(n2)) => {
Ok(Number::Float(div_f(
float_i_to_f(&n1)?,
float_fn_to_f(n2)?,
)?))
}
(Number::Fixnum(n1), Number::Rational(n2)) => {
Ok(Number::Float(div_f(
float_fn_to_f(n1)?,
float_r_to_f(&n2)?,
)?))
}
(Number::Rational(n1), Number::Fixnum(n2)) => {
Ok(Number::Float(div_f(
float_r_to_f(&n1)?,
float_fn_to_f(n2)?,
)?))
}
(Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f(
float_fn_to_f(n1)?,
float_fn_to_f(n2)?,
)?)),
(Number::Fixnum(n1), Number::Integer(n2)) => Ok(Number::Float(div_f(
float_fn_to_f(n1)?,
float_i_to_f(&n2)?,
)?)),
(Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f(
float_i_to_f(&n1)?,
float_fn_to_f(n2)?,
)?)),
(Number::Fixnum(n1), Number::Rational(n2)) => Ok(Number::Float(div_f(
float_fn_to_f(n1)?,
float_r_to_f(&n2)?,
)?)),
(Number::Rational(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f(
float_r_to_f(&n1)?,
float_fn_to_f(n2)?,
)?)),
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) => {
Ok(Number::Float(div_f(
float_fn_to_f(n1)?,
n2,
)?))
Ok(Number::Float(div_f(float_fn_to_f(n1)?, n2)?))
}
(Number::Float(OrderedFloat(n1)), Number::Fixnum(n2)) => {
Ok(Number::Float(div_f(
n1,
float_fn_to_f(n2)?,
)?))
}
(Number::Integer(n1), Number::Integer(n2)) => {
Ok(Number::Float(div_f(
float_i_to_f(&n1)?,
float_i_to_f(&n2)?,
)?))
Ok(Number::Float(div_f(n1, float_fn_to_f(n2)?)?))
}
(Number::Integer(n1), Number::Integer(n2)) => Ok(Number::Float(div_f(
float_i_to_f(&n1)?,
float_i_to_f(&n2)?,
)?)),
(Number::Integer(n1), Number::Float(OrderedFloat(n2))) => {
Ok(Number::Float(div_f(float_i_to_f(&n1)?, n2)?))
}
(Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
Ok(Number::Float(div_f(n2, float_i_to_f(&n1)?)?))
}
(Number::Integer(n1), Number::Rational(n2)) => {
Ok(Number::Float(div_f(
float_i_to_f(&n1)?,
float_r_to_f(&n2)?,
)?))
}
(Number::Rational(n2), Number::Integer(n1)) => {
Ok(Number::Float(div_f(
float_r_to_f(&n2)?,
float_i_to_f(&n1)?,
)?))
}
(Number::Integer(n1), Number::Rational(n2)) => Ok(Number::Float(div_f(
float_i_to_f(&n1)?,
float_r_to_f(&n2)?,
)?)),
(Number::Rational(n2), Number::Integer(n1)) => Ok(Number::Float(div_f(
float_r_to_f(&n2)?,
float_i_to_f(&n1)?,
)?)),
(Number::Rational(n1), Number::Float(OrderedFloat(n2))) => {
Ok(Number::Float(div_f(float_r_to_f(&n1)?, n2)?))
}
@@ -727,12 +705,8 @@ impl<'a> TryFrom<(Addr, &'a Heap)> for Number {
fn try_from((addr, heap): (Addr, &'a Heap)) -> Result<Number, Self::Error> {
match addr {
Addr::Fixnum(n) => {
Ok(Number::from(n))
}
Addr::Float(n) => {
Ok(Number::Float(n))
}
Addr::Fixnum(n) => Ok(Number::from(n)),
Addr::Float(n) => Ok(Number::Float(n)),
Addr::Usize(n) => {
if let Ok(n) = isize::try_from(n) {
Ok(Number::from(n))
@@ -740,12 +714,8 @@ impl<'a> TryFrom<(Addr, &'a Heap)> for Number {
Ok(Number::from(Integer::from(n)))
}
}
Addr::Con(h) => {
Number::try_from(&heap[h])
}
_ => {
Err(())
}
Addr::Con(h) => Number::try_from(&heap[h]),
_ => Err(()),
}
}
}
@@ -755,35 +725,21 @@ impl<'a> TryFrom<&'a HeapCellValue> for Number {
fn try_from(value: &'a HeapCellValue) -> Result<Number, Self::Error> {
match value {
HeapCellValue::Addr(addr) => {
match addr {
&Addr::Fixnum(n) => {
HeapCellValue::Addr(addr) => match addr {
&Addr::Fixnum(n) => Ok(Number::from(n)),
&Addr::Float(n) => Ok(Number::Float(n)),
&Addr::Usize(n) => {
if let Ok(n) = isize::try_from(n) {
Ok(Number::from(n))
}
&Addr::Float(n) => {
Ok(Number::Float(n))
}
&Addr::Usize(n) => {
if let Ok(n) = isize::try_from(n) {
Ok(Number::from(n))
} else {
Ok(Number::from(Integer::from(n)))
}
}
_ => {
Err(())
} else {
Ok(Number::from(Integer::from(n)))
}
}
}
HeapCellValue::Integer(n) => {
Ok(Number::Integer(n.clone()))
}
HeapCellValue::Rational(n) => {
Ok(Number::Rational(n.clone()))
}
_ => {
Err(())
}
_ => Err(()),
},
HeapCellValue::Integer(n) => Ok(Number::Integer(n.clone())),
HeapCellValue::Rational(n) => Ok(Number::Rational(n.clone())),
_ => Err(()),
}
}
}
@@ -796,7 +752,7 @@ impl<'a> From<&'a Integer> for Number {
}
// Computes n ^ power. Ignores the sign of power.
pub fn binary_pow(mut n: Integer, power: &Integer) -> Integer {
pub(crate) fn binary_pow(mut n: Integer, power: &Integer) -> Integer {
let mut power = Integer::from(power.abs_ref());
if power == 0 {

20
src/bin/scryer-prolog.rs Normal file
View File

@@ -0,0 +1,20 @@
fn main() {
use nix::sys::signal;
use scryer_prolog::read::readline;
use scryer_prolog::*;
let handler = signal::SigHandler::Handler(handle_sigint);
unsafe { signal::signal(signal::Signal::SIGINT, handler) }.unwrap();
let mut wam = machine::Machine::new(readline::input_stream(), machine::Stream::stdout());
wam.run_top_level();
}
pub extern "C" fn handle_sigint(signal: libc::c_int) {
use nix::sys::signal;
use std::sync::atomic::Ordering;
let signal = signal::Signal::from_c_int(signal).unwrap();
if signal == signal::Signal::SIGINT {
scryer_prolog::machine::INTERRUPT.store(true, Ordering::Relaxed);
}
}

View File

@@ -1,15 +1,16 @@
use crate::prolog_parser::ast::*;
use prolog_parser::ast::*;
use prolog_parser::{clause_name, temp_v};
use crate::forms::Number;
use crate::machine::machine_indices::*;
use crate::rug::rand::RandState;
use crate::ref_thread_local::RefThreadLocal;
use ref_thread_local::{ref_thread_local, RefThreadLocal};
use std::collections::BTreeMap;
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum CompareNumberQT {
pub(crate) enum CompareNumberQT {
GreaterThan,
LessThan,
GreaterThanOrEqual,
@@ -32,7 +33,7 @@ impl CompareNumberQT {
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompareTermQT {
pub(crate) enum CompareTermQT {
LessThan,
LessThanOrEqual,
GreaterThanOrEqual,
@@ -51,14 +52,14 @@ impl CompareTermQT {
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ArithmeticTerm {
pub(crate) enum ArithmeticTerm {
Reg(RegType),
Interm(usize),
Number(Number),
}
impl ArithmeticTerm {
pub fn interm_or(&self, interm: usize) -> usize {
pub(crate) fn interm_or(&self, interm: usize) -> usize {
if let &ArithmeticTerm::Interm(interm) = self {
interm
} else {
@@ -68,7 +69,7 @@ impl ArithmeticTerm {
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum InlinedClauseType {
pub(crate) enum InlinedClauseType {
CompareNumber(CompareNumberQT, ArithmeticTerm, ArithmeticTerm),
IsAtom(RegType),
IsAtomic(RegType),
@@ -82,11 +83,11 @@ pub enum InlinedClauseType {
}
ref_thread_local! {
pub static managed RANDOM_STATE: RandState<'static> = RandState::new();
pub(crate)static managed RANDOM_STATE: RandState<'static> = RandState::new();
}
ref_thread_local! {
pub static managed CLAUSE_TYPE_FORMS: BTreeMap<(&'static str, usize), ClauseType> = {
pub(crate)static managed CLAUSE_TYPE_FORMS: BTreeMap<(&'static str, usize), ClauseType> = {
let mut m = BTreeMap::new();
let r1 = temp_v!(1);
@@ -132,7 +133,7 @@ ref_thread_local! {
}
impl InlinedClauseType {
pub fn name(&self) -> &'static str {
pub(crate) fn name(&self) -> &'static str {
match self {
&InlinedClauseType::CompareNumber(qt, ..) => qt.name(),
&InlinedClauseType::IsAtom(..) => "atom",
@@ -149,12 +150,7 @@ impl InlinedClauseType {
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum SystemClauseType {
AbolishClause,
AbolishModuleClause,
AssertDynamicPredicateToBack,
AssertDynamicPredicateToFront,
AtEndOfExpansion,
pub(crate) enum SystemClauseType {
AtomChars,
AtomCodes,
AtomLength,
@@ -189,10 +185,7 @@ pub enum SystemClauseType {
DynamicModuleResolution(usize),
EnqueueAttributeGoal,
EnqueueAttributedVar,
ExpandGoal,
ExpandTerm,
FetchGlobalVar,
FetchGlobalVarWithOffset,
FirstStream,
FlushOutput,
GetByte,
@@ -207,16 +200,13 @@ pub enum SystemClauseType {
GetAttrVarQueueDelimiter,
GetAttrVarQueueBeyond,
GetBValue,
GetClause,
GetContinuationChunk,
GetModuleClause,
GetNextDBRef,
GetNextOpDBRef,
IsPartialString,
LookupDBRef,
LookupOpDBRef,
Halt,
ModuleHeadIsDynamic,
GetLiftedHeapFromOffset,
GetLiftedHeapFromOffsetDiff,
GetSCCCleaner,
@@ -224,11 +214,8 @@ pub enum SystemClauseType {
InstallSCCCleaner,
InstallInferenceCounter,
LiftedHeapLength,
ModuleAssertDynamicPredicateToFront,
ModuleAssertDynamicPredicateToBack,
LoadLibraryAsStream,
ModuleExists,
ModuleOf,
ModuleRetractClause,
NextEP,
NoSuchPredicate,
NumberToChars,
@@ -252,15 +239,12 @@ pub enum SystemClauseType {
RemoveCallPolicyCheck,
RemoveInferenceCounter,
ResetContinuationMarker,
ResetGlobalVarAtKey,
ResetGlobalVarAtOffset,
RetractClause,
RestoreCutPolicy,
SetCutPoint(RegType),
SetInput,
SetOutput,
StoreBacktrackableGlobalVar,
StoreGlobalVar,
StoreGlobalVarWithOffset,
StreamProperty,
SetStreamPosition,
InferenceLevel,
@@ -319,16 +303,17 @@ pub enum SystemClauseType {
SetEnv,
UnsetEnv,
CharsBase64,
DevourWhitespace,
IsSTOEnabled,
SetSTOAsUnify,
SetNSTOAsUnify,
SetSTOWithErrorAsUnify,
HomeDirectory,
}
impl SystemClauseType {
pub fn name(&self) -> ClauseName {
pub(crate) fn name(&self) -> ClauseName {
match self {
&SystemClauseType::AbolishClause => clause_name!("$abolish_clause"),
&SystemClauseType::AbolishModuleClause => clause_name!("$abolish_module_clause"),
&SystemClauseType::AssertDynamicPredicateToBack => clause_name!("$assertz"),
&SystemClauseType::AssertDynamicPredicateToFront => clause_name!("$asserta"),
&SystemClauseType::AtEndOfExpansion => clause_name!("$at_end_of_expansion"),
&SystemClauseType::AtomChars => clause_name!("$atom_chars"),
&SystemClauseType::AtomCodes => clause_name!("$atom_codes"),
&SystemClauseType::AtomLength => clause_name!("$atom_length"),
@@ -341,7 +326,9 @@ impl SystemClauseType {
&SystemClauseType::ClearAttributeGoals => clause_name!("$clear_attribute_goals"),
&SystemClauseType::CloneAttributeGoals => clause_name!("$clone_attribute_goals"),
&SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"),
&SystemClauseType::CopyTermWithoutAttrVars => clause_name!("$copy_term_without_attr_vars"),
&SystemClauseType::CopyTermWithoutAttrVars => {
clause_name!("$copy_term_without_attr_vars")
}
&SystemClauseType::CreatePartialString => clause_name!("$create_partial_string"),
&SystemClauseType::CurrentInput => clause_name!("$current_input"),
&SystemClauseType::CurrentHostname => clause_name!("$current_hostname"),
@@ -356,16 +343,90 @@ impl SystemClauseType {
&SystemClauseType::WorkingDirectory => clause_name!("$working_directory"),
&SystemClauseType::PathCanonical => clause_name!("$path_canonical"),
&SystemClauseType::FileTime => clause_name!("$file_time"),
&SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"),
&SystemClauseType::REPL(REPLCodePtr::AddDiscontiguousPredicate) => {
clause_name!("$add_discontiguous_predicate")
}
&SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate) => {
clause_name!("$add_dynamic_predicate")
}
&SystemClauseType::REPL(REPLCodePtr::AddMultifilePredicate) => {
clause_name!("$add_multifile_predicate")
}
&SystemClauseType::REPL(REPLCodePtr::AddGoalExpansionClause) => {
clause_name!("$add_goal_expansion_clause")
}
&SystemClauseType::REPL(REPLCodePtr::AddTermExpansionClause) => {
clause_name!("$add_term_expansion_clause")
}
&SystemClauseType::REPL(REPLCodePtr::ClauseToEvacuable) => {
clause_name!("$clause_to_evacuable")
}
&SystemClauseType::REPL(REPLCodePtr::ScopedClauseToEvacuable) => {
clause_name!("$scoped_clause_to_evacuable")
}
&SystemClauseType::REPL(REPLCodePtr::ConcludeLoad) => clause_name!("$conclude_load"),
&SystemClauseType::REPL(REPLCodePtr::DeclareModule) => clause_name!("$declare_module"),
&SystemClauseType::REPL(REPLCodePtr::LoadCompiledLibrary) => {
clause_name!("$load_compiled_library")
}
&SystemClauseType::REPL(REPLCodePtr::PushLoadStatePayload) => {
clause_name!("$push_load_state_payload")
}
&SystemClauseType::REPL(REPLCodePtr::Asserta) => clause_name!("$asserta"),
&SystemClauseType::REPL(REPLCodePtr::Assertz) => clause_name!("$assertz"),
&SystemClauseType::REPL(REPLCodePtr::Retract) => clause_name!("$retract_clause"),
&SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"),
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule) => {
clause_name!("$use_qualified_module")
&SystemClauseType::REPL(REPLCodePtr::PushLoadContext) => {
clause_name!("$push_load_context")
}
&SystemClauseType::REPL(REPLCodePtr::UseModuleFromFile) => {
clause_name!("$use_module_from_file")
&SystemClauseType::REPL(REPLCodePtr::PopLoadContext) => {
clause_name!("$pop_load_context")
}
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile) => {
clause_name!("$use_qualified_module_from_file")
&SystemClauseType::REPL(REPLCodePtr::PopLoadStatePayload) => {
clause_name!("$pop_load_state_payload")
}
&SystemClauseType::REPL(REPLCodePtr::LoadContextSource) => {
clause_name!("$prolog_lc_source")
}
&SystemClauseType::REPL(REPLCodePtr::LoadContextFile) => {
clause_name!("$prolog_lc_file")
}
&SystemClauseType::REPL(REPLCodePtr::LoadContextDirectory) => {
clause_name!("$prolog_lc_dir")
}
&SystemClauseType::REPL(REPLCodePtr::LoadContextModule) => {
clause_name!("$prolog_lc_module")
}
&SystemClauseType::REPL(REPLCodePtr::LoadContextStream) => {
clause_name!("$prolog_lc_stream")
}
&SystemClauseType::REPL(REPLCodePtr::MetaPredicateProperty) => {
clause_name!("$cpp_meta_predicate_property")
}
&SystemClauseType::REPL(REPLCodePtr::BuiltInProperty) => {
clause_name!("$cpp_built_in_property")
}
&SystemClauseType::REPL(REPLCodePtr::DynamicProperty) => {
clause_name!("$cpp_dynamic_property")
}
&SystemClauseType::REPL(REPLCodePtr::MultifileProperty) => {
clause_name!("$cpp_multifile_property")
}
&SystemClauseType::REPL(REPLCodePtr::DiscontiguousProperty) => {
clause_name!("$cpp_discontiguous_property")
}
&SystemClauseType::REPL(REPLCodePtr::AbolishClause) => clause_name!("$abolish_clause"),
&SystemClauseType::REPL(REPLCodePtr::IsConsistentWithTermQueue) => {
clause_name!("$is_consistent_with_term_queue")
}
&SystemClauseType::REPL(REPLCodePtr::FlushTermQueue) => {
clause_name!("$flush_term_queue")
}
&SystemClauseType::REPL(REPLCodePtr::RemoveModuleExports) => {
clause_name!("$remove_module_exports")
}
&SystemClauseType::REPL(REPLCodePtr::AddNonCountedBacktracking) => {
clause_name!("$add_non_counted_backtracking")
}
&SystemClauseType::Close => clause_name!("$close"),
&SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"),
@@ -374,12 +435,7 @@ impl SystemClauseType {
&SystemClauseType::DynamicModuleResolution(_) => clause_name!("$module_call"),
&SystemClauseType::EnqueueAttributeGoal => clause_name!("$enqueue_attribute_goal"),
&SystemClauseType::EnqueueAttributedVar => clause_name!("$enqueue_attr_var"),
&SystemClauseType::ExpandTerm => clause_name!("$expand_term"),
&SystemClauseType::ExpandGoal => clause_name!("$expand_goal"),
&SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"),
&SystemClauseType::FetchGlobalVarWithOffset => {
clause_name!("$fetch_global_var_with_offset")
}
&SystemClauseType::FirstStream => clause_name!("$first_stream"),
&SystemClauseType::FlushOutput => clause_name!("$flush_output"),
&SystemClauseType::GetByte => clause_name!("$get_byte"),
@@ -405,13 +461,13 @@ impl SystemClauseType {
clause_name!("$get_lh_from_offset_diff")
}
&SystemClauseType::GetBValue => clause_name!("$get_b_value"),
&SystemClauseType::GetClause => clause_name!("$get_clause"),
// &SystemClauseType::GetClause => clause_name!("$get_clause"),
&SystemClauseType::GetNextDBRef => clause_name!("$get_next_db_ref"),
&SystemClauseType::GetNextOpDBRef => clause_name!("$get_next_op_db_ref"),
&SystemClauseType::LookupDBRef => clause_name!("$lookup_db_ref"),
&SystemClauseType::LookupOpDBRef => clause_name!("$lookup_op_db_ref"),
&SystemClauseType::GetDoubleQuotes => clause_name!("$get_double_quotes"),
&SystemClauseType::GetModuleClause => clause_name!("$get_module_clause"),
// &SystemClauseType::GetModuleClause => clause_name!("$get_module_clause"),
&SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"),
&SystemClauseType::Halt => clause_name!("$halt"),
&SystemClauseType::HeadIsDynamic => clause_name!("$head_is_dynamic"),
@@ -430,15 +486,14 @@ impl SystemClauseType {
&SystemClauseType::Maybe => clause_name!("maybe"),
&SystemClauseType::CpuNow => clause_name!("$cpu_now"),
&SystemClauseType::CurrentTime => clause_name!("$current_time"),
&SystemClauseType::ModuleAssertDynamicPredicateToFront => {
clause_name!("$module_asserta")
}
&SystemClauseType::ModuleAssertDynamicPredicateToBack => {
clause_name!("$module_assertz")
}
&SystemClauseType::ModuleHeadIsDynamic => clause_name!("$module_head_is_dynamic"),
// &SystemClauseType::ModuleAssertDynamicPredicateToFront => {
// clause_name!("$module_asserta")
// }
// &SystemClauseType::ModuleAssertDynamicPredicateToBack => {
// clause_name!("$module_assertz")
// }
// &SystemClauseType::ModuleHeadIsDynamic => clause_name!("$module_head_is_dynamic"),
&SystemClauseType::ModuleExists => clause_name!("$module_exists"),
&SystemClauseType::ModuleOf => clause_name!("$module_of"),
&SystemClauseType::NextStream => clause_name!("$next_stream"),
&SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"),
&SystemClauseType::NumberToChars => clause_name!("$number_to_chars"),
@@ -471,10 +526,10 @@ impl SystemClauseType {
&SystemClauseType::SetSeed => clause_name!("$set_seed"),
&SystemClauseType::StreamProperty => clause_name!("$stream_property"),
&SystemClauseType::SetStreamPosition => clause_name!("$set_stream_position"),
&SystemClauseType::StoreGlobalVar => clause_name!("$store_global_var"),
&SystemClauseType::StoreGlobalVarWithOffset => {
clause_name!("$store_global_var_with_offset")
&SystemClauseType::StoreBacktrackableGlobalVar => {
clause_name!("$store_back_trackable_global_var")
}
&SystemClauseType::StoreGlobalVar => clause_name!("$store_global_var"),
&SystemClauseType::InferenceLevel => clause_name!("$inference_level"),
&SystemClauseType::CleanUpBlock => clause_name!("$clean_up_block"),
&SystemClauseType::EraseBall => clause_name!("$erase_ball"),
@@ -483,14 +538,10 @@ impl SystemClauseType {
&SystemClauseType::GetCutPoint => clause_name!("$get_cp"),
&SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"),
&SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"),
&SystemClauseType::ModuleRetractClause => clause_name!("$module_retract_clause"),
&SystemClauseType::NextEP => clause_name!("$nextEP"),
&SystemClauseType::ReadQueryTerm => clause_name!("$read_query_term"),
&SystemClauseType::ReadTerm => clause_name!("$read_term"),
&SystemClauseType::ReadTermFromChars => clause_name!("$read_term_from_chars"),
&SystemClauseType::ResetGlobalVarAtKey => clause_name!("$reset_global_var_at_key"),
&SystemClauseType::ResetGlobalVarAtOffset => clause_name!("$reset_global_var_at_offset"),
&SystemClauseType::RetractClause => clause_name!("$retract_clause"),
&SystemClauseType::ResetBlock => clause_name!("$reset_block"),
&SystemClauseType::ResetContinuationMarker => clause_name!("$reset_cont_marker"),
&SystemClauseType::ReturnFromVerifyAttr => clause_name!("$return_from_verify_attr"),
@@ -504,7 +555,9 @@ impl SystemClauseType {
&SystemClauseType::SocketServerAccept => clause_name!("$socket_server_accept"),
&SystemClauseType::SocketServerClose => clause_name!("$socket_server_close"),
&SystemClauseType::Succeed => clause_name!("$succeed"),
&SystemClauseType::TermAttributedVariables => clause_name!("$term_attributed_variables"),
&SystemClauseType::TermAttributedVariables => {
clause_name!("$term_attributed_variables")
}
&SystemClauseType::TermVariables => clause_name!("$term_variables"),
&SystemClauseType::TruncateLiftedHeapTo => clause_name!("$truncate_lh_to"),
&SystemClauseType::UnifyWithOccursCheck => clause_name!("$unify_with_occurs_check"),
@@ -525,7 +578,9 @@ impl SystemClauseType {
&SystemClauseType::Ed25519Sign => clause_name!("$ed25519_sign"),
&SystemClauseType::Ed25519Verify => clause_name!("$ed25519_verify"),
&SystemClauseType::Ed25519NewKeyPair => clause_name!("$ed25519_new_keypair"),
&SystemClauseType::Ed25519KeyPairPublicKey => clause_name!("$ed25519_keypair_public_key"),
&SystemClauseType::Ed25519KeyPairPublicKey => {
clause_name!("$ed25519_keypair_public_key")
}
&SystemClauseType::Curve25519ScalarMult => clause_name!("$curve25519_scalar_mult"),
&SystemClauseType::LoadHTML => clause_name!("$load_html"),
&SystemClauseType::LoadXML => clause_name!("$load_xml"),
@@ -533,22 +588,38 @@ impl SystemClauseType {
&SystemClauseType::SetEnv => clause_name!("$setenv"),
&SystemClauseType::UnsetEnv => clause_name!("$unsetenv"),
&SystemClauseType::CharsBase64 => clause_name!("$chars_base64"),
&SystemClauseType::LoadLibraryAsStream => clause_name!("$load_library_as_stream"),
&SystemClauseType::DevourWhitespace => clause_name!("$devour_whitespace"),
&SystemClauseType::IsSTOEnabled => clause_name!("$is_sto_enabled"),
&SystemClauseType::SetSTOAsUnify => clause_name!("$set_sto_as_unify"),
&SystemClauseType::SetNSTOAsUnify => clause_name!("$set_nsto_as_unify"),
&SystemClauseType::HomeDirectory => clause_name!("$home_directory"),
&SystemClauseType::SetSTOWithErrorAsUnify => clause_name!("$set_sto_with_error_as_unify"),
}
}
pub fn from(name: &str, arity: usize) -> Option<SystemClauseType> {
pub(crate) fn from(name: &str, arity: usize) -> Option<SystemClauseType> {
match (name, arity) {
("$abolish_clause", 2) => Some(SystemClauseType::AbolishClause),
("$at_end_of_expansion", 0) => Some(SystemClauseType::AtEndOfExpansion),
("$abolish_clause", 3) => Some(SystemClauseType::REPL(REPLCodePtr::AbolishClause)),
("$add_dynamic_predicate", 4) => {
Some(SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate))
}
("$add_multifile_predicate", 4) => {
Some(SystemClauseType::REPL(REPLCodePtr::AddMultifilePredicate))
}
("$add_discontiguous_predicate", 4) => Some(SystemClauseType::REPL(
REPLCodePtr::AddDiscontiguousPredicate,
)),
("$add_goal_expansion_clause", 3) => {
Some(SystemClauseType::REPL(REPLCodePtr::AddGoalExpansionClause))
}
("$add_term_expansion_clause", 2) => {
Some(SystemClauseType::REPL(REPLCodePtr::AddTermExpansionClause))
}
("$atom_chars", 2) => Some(SystemClauseType::AtomChars),
("$atom_codes", 2) => Some(SystemClauseType::AtomCodes),
("$atom_length", 2) => Some(SystemClauseType::AtomLength),
("$abolish_module_clause", 3) => Some(SystemClauseType::AbolishModuleClause),
("$bind_from_register", 2) => Some(SystemClauseType::BindFromRegister),
("$module_asserta", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToFront),
("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack),
("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront),
("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack),
("$call_continuation", 1) => Some(SystemClauseType::CallContinuation),
("$char_code", 2) => Some(SystemClauseType::CharCode),
("$char_type", 2) => Some(SystemClauseType::CharType),
@@ -559,7 +630,6 @@ impl SystemClauseType {
("$copy_term_without_attr_vars", 2) => Some(SystemClauseType::CopyTermWithoutAttrVars),
("$create_partial_string", 3) => Some(SystemClauseType::CreatePartialString),
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)),
("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
("$close", 2) => Some(SystemClauseType::Close),
("$current_hostname", 1) => Some(SystemClauseType::CurrentHostname),
@@ -582,10 +652,7 @@ impl SystemClauseType {
("$peek_char", 2) => Some(SystemClauseType::PeekChar),
("$peek_code", 2) => Some(SystemClauseType::PeekCode),
("$is_partial_string", 1) => Some(SystemClauseType::IsPartialString),
("$expand_term", 2) => Some(SystemClauseType::ExpandTerm),
("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset),
("$get_byte", 2) => Some(SystemClauseType::GetByte),
("$get_char", 2) => Some(SystemClauseType::GetChar),
("$get_n_chars", 3) => Some(SystemClauseType::GetNChars),
@@ -594,18 +661,10 @@ impl SystemClauseType {
("$points_to_cont_reset_marker", 1) => {
Some(SystemClauseType::PointsToContinuationResetMarker)
}
("$put_byte", 2) => {
Some(SystemClauseType::PutByte)
}
("$put_char", 2) => {
Some(SystemClauseType::PutChar)
}
("$put_chars", 2) => {
Some(SystemClauseType::PutChars)
}
("$put_code", 2) => {
Some(SystemClauseType::PutCode)
}
("$put_byte", 2) => Some(SystemClauseType::PutByte),
("$put_char", 2) => Some(SystemClauseType::PutChar),
("$put_chars", 2) => Some(SystemClauseType::PutChars),
("$put_code", 2) => Some(SystemClauseType::PutCode),
("$reset_attr_var_state", 0) => Some(SystemClauseType::ResetAttrVarState),
("$truncate_if_no_lh_growth", 1) => {
Some(SystemClauseType::TruncateIfNoLiftedHeapGrowth)
@@ -615,14 +674,12 @@ impl SystemClauseType {
}
("$get_attr_list", 2) => Some(SystemClauseType::GetAttributedVariableList),
("$get_b_value", 1) => Some(SystemClauseType::GetBValue),
("$get_clause", 2) => Some(SystemClauseType::GetClause),
("$get_module_clause", 3) => Some(SystemClauseType::GetModuleClause),
("$get_lh_from_offset", 2) => Some(SystemClauseType::GetLiftedHeapFromOffset),
("$get_lh_from_offset_diff", 3) => Some(SystemClauseType::GetLiftedHeapFromOffsetDiff),
("$get_double_quotes", 1) => Some(SystemClauseType::GetDoubleQuotes),
("$get_scc_cleaner", 1) => Some(SystemClauseType::GetSCCCleaner),
("$halt", 1) => Some(SystemClauseType::Halt),
("$head_is_dynamic", 1) => Some(SystemClauseType::HeadIsDynamic),
("$head_is_dynamic", 2) => Some(SystemClauseType::HeadIsDynamic),
("$install_scc_cleaner", 2) => Some(SystemClauseType::InstallSCCCleaner),
("$install_inference_counter", 3) => Some(SystemClauseType::InstallInferenceCounter),
("$lh_length", 1) => Some(SystemClauseType::LiftedHeapLength),
@@ -630,10 +687,7 @@ impl SystemClauseType {
("$cpu_now", 1) => Some(SystemClauseType::CpuNow),
("$current_time", 1) => Some(SystemClauseType::CurrentTime),
("$module_exists", 1) => Some(SystemClauseType::ModuleExists),
("$module_of", 2) => Some(SystemClauseType::ModuleOf),
("$module_retract_clause", 5) => Some(SystemClauseType::ModuleRetractClause),
("$module_head_is_dynamic", 2) => Some(SystemClauseType::ModuleHeadIsDynamic),
("$no_such_predicate", 1) => Some(SystemClauseType::NoSuchPredicate),
("$no_such_predicate", 2) => Some(SystemClauseType::NoSuchPredicate),
("$number_to_chars", 2) => Some(SystemClauseType::NumberToChars),
("$number_to_codes", 2) => Some(SystemClauseType::NumberToCodes),
("$op", 3) => Some(SystemClauseType::OpDeclaration),
@@ -665,9 +719,6 @@ impl SystemClauseType {
("$read_term_from_chars", 2) => Some(SystemClauseType::ReadTermFromChars),
("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
("$reset_cont_marker", 0) => Some(SystemClauseType::ResetContinuationMarker),
("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey),
("$reset_global_var_at_offset", 3) => Some(SystemClauseType::ResetGlobalVarAtOffset),
("$retract_clause", 4) => Some(SystemClauseType::RetractClause),
("$return_from_verify_attr", 0) => Some(SystemClauseType::ReturnFromVerifyAttr),
("$set_ball", 1) => Some(SystemClauseType::SetBall),
("$set_cp_by_default", 1) => Some(SystemClauseType::SetCutPointByDefault(temp_v!(1))),
@@ -680,7 +731,9 @@ impl SystemClauseType {
("$socket_server_accept", 7) => Some(SystemClauseType::SocketServerAccept),
("$socket_server_close", 1) => Some(SystemClauseType::SocketServerClose),
("$store_global_var", 2) => Some(SystemClauseType::StoreGlobalVar),
("$store_global_var_with_offset", 2) => Some(SystemClauseType::StoreGlobalVarWithOffset),
("$store_backtrackable_global_var", 2) => {
Some(SystemClauseType::StoreBacktrackableGlobalVar)
}
("$term_attributed_variables", 2) => Some(SystemClauseType::TermAttributedVariables),
("$term_variables", 2) => Some(SystemClauseType::TermVariables),
("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo),
@@ -697,15 +750,36 @@ impl SystemClauseType {
("$working_directory", 2) => Some(SystemClauseType::WorkingDirectory),
("$path_canonical", 2) => Some(SystemClauseType::PathCanonical),
("$file_time", 3) => Some(SystemClauseType::FileTime),
("$use_module", 1) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)),
("$use_module_from_file", 1) =>
Some(SystemClauseType::REPL(REPLCodePtr::UseModuleFromFile)),
("$use_qualified_module", 2) =>
Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule)),
("$use_qualified_module_from_file", 2) =>
Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile)),
("$clause_to_evacuable", 2) => {
Some(SystemClauseType::REPL(REPLCodePtr::ClauseToEvacuable))
}
("$scoped_clause_to_evacuable", 3) => {
Some(SystemClauseType::REPL(REPLCodePtr::ScopedClauseToEvacuable))
}
("$conclude_load", 1) => Some(SystemClauseType::REPL(REPLCodePtr::ConcludeLoad)),
("$use_module", 3) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)),
("$declare_module", 3) => Some(SystemClauseType::REPL(REPLCodePtr::DeclareModule)),
("$load_compiled_library", 3) => {
Some(SystemClauseType::REPL(REPLCodePtr::LoadCompiledLibrary))
}
("$push_load_state_payload", 1) => {
Some(SystemClauseType::REPL(REPLCodePtr::PushLoadStatePayload))
}
("$asserta", 5) => Some(SystemClauseType::REPL(REPLCodePtr::Asserta)),
("$assertz", 5) => Some(SystemClauseType::REPL(REPLCodePtr::Assertz)),
("$retract_clause", 4) => Some(SystemClauseType::REPL(REPLCodePtr::Retract)),
("$is_consistent_with_term_queue", 4) => Some(SystemClauseType::REPL(
REPLCodePtr::IsConsistentWithTermQueue,
)),
("$flush_term_queue", 1) => Some(SystemClauseType::REPL(REPLCodePtr::FlushTermQueue)),
("$remove_module_exports", 2) => {
Some(SystemClauseType::REPL(REPLCodePtr::RemoveModuleExports))
}
("$add_non_counted_backtracking", 3) => Some(SystemClauseType::REPL(
REPLCodePtr::AddNonCountedBacktracking,
)),
("$variant", 2) => Some(SystemClauseType::Variant),
("$wam_instructions", 3) => Some(SystemClauseType::WAMInstructions),
("$wam_instructions", 4) => Some(SystemClauseType::WAMInstructions),
("$write_term", 7) => Some(SystemClauseType::WriteTerm),
("$write_term_to_chars", 7) => Some(SystemClauseType::WriteTermToChars),
("$scryer_prolog_version", 1) => Some(SystemClauseType::ScryerPrologVersion),
@@ -727,13 +801,55 @@ impl SystemClauseType {
("$setenv", 2) => Some(SystemClauseType::SetEnv),
("$unsetenv", 1) => Some(SystemClauseType::UnsetEnv),
("$chars_base64", 4) => Some(SystemClauseType::CharsBase64),
("$load_library_as_stream", 3) => Some(SystemClauseType::LoadLibraryAsStream),
("$push_load_context", 2) => Some(SystemClauseType::REPL(REPLCodePtr::PushLoadContext)),
("$pop_load_state_payload", 1) => {
Some(SystemClauseType::REPL(REPLCodePtr::PopLoadStatePayload))
}
("$pop_load_context", 0) => Some(SystemClauseType::REPL(REPLCodePtr::PopLoadContext)),
("$prolog_lc_source", 1) => {
Some(SystemClauseType::REPL(REPLCodePtr::LoadContextSource))
}
("$prolog_lc_file", 1) => Some(SystemClauseType::REPL(REPLCodePtr::LoadContextFile)),
("$prolog_lc_dir", 1) => {
Some(SystemClauseType::REPL(REPLCodePtr::LoadContextDirectory))
}
("$prolog_lc_module", 1) => {
Some(SystemClauseType::REPL(REPLCodePtr::LoadContextModule))
}
("$prolog_lc_stream", 1) => {
Some(SystemClauseType::REPL(REPLCodePtr::LoadContextStream))
}
("$cpp_meta_predicate_property", 4) => {
Some(SystemClauseType::REPL(REPLCodePtr::MetaPredicateProperty))
}
("$cpp_built_in_property", 2) => {
Some(SystemClauseType::REPL(REPLCodePtr::BuiltInProperty))
}
("$cpp_dynamic_property", 3) => {
Some(SystemClauseType::REPL(REPLCodePtr::DynamicProperty))
}
("$cpp_multifile_property", 3) => {
Some(SystemClauseType::REPL(REPLCodePtr::MultifileProperty))
}
("$cpp_discontiguous_property", 3) => {
Some(SystemClauseType::REPL(REPLCodePtr::DiscontiguousProperty))
}
("$devour_whitespace", 1) => {
Some(SystemClauseType::DevourWhitespace)
}
("$is_sto_enabled", 1) => Some(SystemClauseType::IsSTOEnabled),
("$set_sto_as_unify", 0) => Some(SystemClauseType::SetSTOAsUnify),
("$set_nsto_as_unify", 0) => Some(SystemClauseType::SetNSTOAsUnify),
("$set_sto_with_error_as_unify", 0) => Some(SystemClauseType::SetSTOWithErrorAsUnify),
("$home_directory", 1) => Some(SystemClauseType::HomeDirectory),
_ => None,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum BuiltInClauseType {
pub(crate) enum BuiltInClauseType {
AcyclicTerm,
Arg,
Compare,
@@ -751,10 +867,9 @@ pub enum BuiltInClauseType {
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ClauseType {
pub(crate) enum ClauseType {
BuiltIn(BuiltInClauseType),
CallN,
Hook(CompileTimeHook),
Inlined(InlinedClauseType),
Named(ClauseName, usize, CodeIndex), // name, arity, index.
Op(ClauseName, SharedOpDesc, CodeIndex),
@@ -762,7 +877,7 @@ pub enum ClauseType {
}
impl BuiltInClauseType {
pub fn name(&self) -> ClauseName {
pub(crate) fn name(&self) -> ClauseName {
match self {
&BuiltInClauseType::AcyclicTerm => clause_name!("acyclic_term"),
&BuiltInClauseType::Arg => clause_name!("arg"),
@@ -781,7 +896,7 @@ impl BuiltInClauseType {
}
}
pub fn arity(&self) -> usize {
pub(crate) fn arity(&self) -> usize {
match self {
&BuiltInClauseType::AcyclicTerm => 1,
&BuiltInClauseType::Arg => 3,
@@ -802,23 +917,22 @@ impl BuiltInClauseType {
}
impl ClauseType {
pub fn spec(&self) -> Option<SharedOpDesc> {
pub(crate) fn spec(&self) -> Option<SharedOpDesc> {
match self {
&ClauseType::Op(_, ref spec, _) => Some(spec.clone()),
&ClauseType::Inlined(InlinedClauseType::CompareNumber(..))
| &ClauseType::BuiltIn(BuiltInClauseType::Is(..))
| &ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(_))
| &ClauseType::BuiltIn(BuiltInClauseType::NotEq)
| &ClauseType::BuiltIn(BuiltInClauseType::Eq) => Some(SharedOpDesc::new(700, XFX)),
| &ClauseType::BuiltIn(BuiltInClauseType::Is(..))
| &ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(_))
| &ClauseType::BuiltIn(BuiltInClauseType::NotEq)
| &ClauseType::BuiltIn(BuiltInClauseType::Eq) => Some(SharedOpDesc::new(700, XFX)),
_ => None,
}
}
pub fn name(&self) -> ClauseName {
pub(crate) fn name(&self) -> ClauseName {
match self {
&ClauseType::BuiltIn(ref built_in) => built_in.name(),
&ClauseType::CallN => clause_name!("call"),
&ClauseType::Hook(ref hook) => hook.name(),
&ClauseType::CallN => clause_name!("$call"),
&ClauseType::Inlined(ref inlined) => clause_name!(inlined.name()),
&ClauseType::Op(ref name, ..) => name.clone(),
&ClauseType::Named(ref name, ..) => name.clone(),
@@ -826,7 +940,7 @@ impl ClauseType {
}
}
pub fn from(name: ClauseName, arity: usize, spec: Option<SharedOpDesc>) -> Self {
pub(crate) fn from(name: ClauseName, arity: usize, spec: Option<SharedOpDesc>) -> Self {
CLAUSE_TYPE_FORMS
.borrow()
.get(&(name.as_str(), arity))
@@ -837,7 +951,7 @@ impl ClauseType {
.unwrap_or_else(|| {
if let Some(spec) = spec {
ClauseType::Op(name, spec, CodeIndex::default())
} else if name.as_str() == "call" {
} else if name.as_str() == "$call" {
ClauseType::CallN
} else {
ClauseType::Named(name, arity, CodeIndex::default())

View File

@@ -1,5 +1,7 @@
/// Code generation to WAM-like instructions.
use crate::prolog_parser::ast::*;
use prolog_parser::ast::*;
use prolog_parser::tabled_rc::TabledData;
use prolog_parser::{perm_v, temp_v};
use crate::allocator::*;
use crate::arithmetic::*;
@@ -9,27 +11,21 @@ use crate::forms::*;
use crate::indexing::*;
use crate::instructions::*;
use crate::iterators::*;
use crate::machine::machine_indices::*;
use crate::targets::*;
use crate::indexmap::{IndexMap, IndexSet};
use crate::machine::machine_errors::*;
use indexmap::{IndexMap, IndexSet};
use std::cell::Cell;
use std::collections::VecDeque;
use std::rc::Rc;
use std::vec::Vec;
#[derive(Debug)]
pub struct CodeGenerator<TermMarker> {
marker: TermMarker,
pub var_count: IndexMap<Rc<Var>, usize>,
non_counted_bt: bool,
}
#[derive(Debug)]
pub struct ConjunctInfo<'a> {
pub perm_vs: VariableFixtures<'a>,
pub num_of_chunks: usize,
pub has_deep_cut: bool,
pub(crate) struct ConjunctInfo<'a> {
pub(crate) perm_vs: VariableFixtures<'a>,
pub(crate) num_of_chunks: usize,
pub(crate) has_deep_cut: bool,
}
impl<'a> ConjunctInfo<'a> {
@@ -53,18 +49,14 @@ impl<'a> ConjunctInfo<'a> {
self.has_deep_cut as usize
}
fn mark_unsafe_vars(
&self,
mut unsafe_var_marker: UnsafeVarMarker,
code: &mut Code,
) {
fn mark_unsafe_vars(&self, mut unsafe_var_marker: UnsafeVarMarker, code: &mut Code) {
if code.is_empty() {
return;
}
let mut code_index = 0;
for phase in 0 .. {
for phase in 0.. {
while let Line::Query(ref query_instr) = &code[code_index] {
if !unsafe_var_marker.mark_safe_vars(query_instr) {
unsafe_var_marker.mark_phase(query_instr, phase);
@@ -82,7 +74,7 @@ impl<'a> ConjunctInfo<'a> {
code_index = 0;
for phase in 0 .. {
for phase in 0.. {
while let Line::Query(ref mut query_instr) = &mut code[code_index] {
unsafe_var_marker.mark_unsafe_vars(query_instr, phase);
code_index += 1;
@@ -97,17 +89,121 @@ impl<'a> ConjunctInfo<'a> {
}
}
impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
pub fn new(non_counted_bt: bool) -> Self {
CodeGenerator {
marker: Allocator::new(),
var_count: IndexMap::new(),
non_counted_bt,
#[derive(Clone, Copy, Debug)]
pub(crate) struct CodeGenSettings {
pub global_clock_tick: Option<usize>,
pub is_extensible: bool,
pub non_counted_bt: bool,
}
impl CodeGenSettings {
#[inline]
pub(crate) fn is_dynamic(&self) -> bool {
self.global_clock_tick.is_some()
}
#[inline]
pub(crate) fn internal_try_me_else(&self, offset: usize) -> ChoiceInstruction {
if let Some(global_clock_time) = self.global_clock_tick {
ChoiceInstruction::DynamicInternalElse(
global_clock_time,
Death::Infinity,
if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) },
)
} else {
ChoiceInstruction::TryMeElse(offset)
}
}
pub fn take_vars(self) -> AllocVarDict {
self.marker.take_bindings()
pub(crate) fn try_me_else(&self, offset: usize) -> ChoiceInstruction {
if let Some(global_clock_tick) = self.global_clock_tick {
ChoiceInstruction::DynamicElse(
global_clock_tick,
Death::Infinity,
if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) },
)
} else {
ChoiceInstruction::TryMeElse(offset)
}
}
pub(crate) fn internal_retry_me_else(&self, offset: usize) -> ChoiceInstruction {
if let Some(global_clock_tick) = self.global_clock_tick {
ChoiceInstruction::DynamicInternalElse(
global_clock_tick,
Death::Infinity,
if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) },
)
} else {
ChoiceInstruction::RetryMeElse(offset)
}
}
pub(crate) fn retry_me_else(&self, offset: usize) -> ChoiceInstruction {
if let Some(global_clock_tick) = self.global_clock_tick {
ChoiceInstruction::DynamicElse(
global_clock_tick,
Death::Infinity,
if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) },
)
} else if self.non_counted_bt {
ChoiceInstruction::DefaultRetryMeElse(offset)
} else {
ChoiceInstruction::RetryMeElse(offset)
}
}
pub(crate) fn internal_trust_me(&self) -> ChoiceInstruction {
if let Some(global_clock_tick) = self.global_clock_tick {
ChoiceInstruction::DynamicInternalElse(
global_clock_tick,
Death::Infinity,
NextOrFail::Fail(0),
)
} else if self.non_counted_bt {
ChoiceInstruction::DefaultTrustMe(0)
} else {
ChoiceInstruction::TrustMe(0)
}
}
pub(crate) fn trust_me(&self) -> ChoiceInstruction {
if let Some(global_clock_tick) = self.global_clock_tick {
ChoiceInstruction::DynamicElse(
global_clock_tick,
Death::Infinity,
NextOrFail::Fail(0),
)
} else if self.non_counted_bt {
ChoiceInstruction::DefaultTrustMe(0)
} else {
ChoiceInstruction::TrustMe(0)
}
}
}
#[derive(Debug)]
pub(crate) struct CodeGenerator<TermMarker> {
atom_tbl: TabledData<Atom>,
marker: TermMarker,
pub(crate) var_count: IndexMap<Rc<Var>, usize>,
settings: CodeGenSettings,
pub(crate) skeleton: PredicateSkeleton,
pub(crate) jmp_by_locs: Vec<usize>,
global_jmp_by_locs_offset: usize,
}
impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
pub(crate) fn new(atom_tbl: TabledData<Atom>, settings: CodeGenSettings) -> Self {
CodeGenerator {
atom_tbl,
marker: Allocator::new(),
var_count: IndexMap::new(),
settings,
skeleton: PredicateSkeleton::new(),
jmp_by_locs: vec![],
global_jmp_by_locs_offset: 0,
}
}
fn update_var_count<Iter: Iterator<Item = TermRef<'a>>>(&mut self, iter: Iter) {
@@ -131,7 +227,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
code: &mut Code,
) -> RegType {
let mut target = Vec::new();
self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target);
self.marker
.mark_var(name, Level::Shallow, vr, term_loc, &mut target);
if !target.is_empty() {
code.extend(target.into_iter().map(Line::Query));
@@ -149,9 +246,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
code: &mut Code,
) -> RegType {
match self.marker.bindings().get(&name) {
Some(&VarData::Temp(_, t, _)) if t != 0 => {
RegType::Temp(t)
}
Some(&VarData::Temp(_, t, _)) if t != 0 => RegType::Temp(t),
Some(&VarData::Perm(p)) if p != 0 => {
if let GenContext::Last(_) = term_loc {
self.mark_var_in_non_callable(name.clone(), term_loc, vr, code);
@@ -160,9 +255,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
RegType::Perm(p)
}
}
_ => {
self.mark_var_in_non_callable(name, term_loc, vr, code)
}
_ => self.mark_var_in_non_callable(name, term_loc, vr, code),
}
}
@@ -189,7 +282,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
target: &mut Vec<Target>,
) {
if is_exposed || self.get_var_count(var.as_ref()) > 1 {
self.marker.mark_var(var.clone(), Level::Deep, cell, term_loc, target);
self.marker
.mark_var(var.clone(), Level::Deep, cell, term_loc, target);
} else {
Self::add_or_increment_void_instr(target);
}
@@ -210,7 +304,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
Self::add_or_increment_void_instr(target);
}
&Term::Cons(ref cell, _, _) | &Term::Clause(ref cell, _, _, _) => {
self.marker.mark_non_var(Level::Deep, term_loc, cell, target);
self.marker
.mark_non_var(Level::Deep, term_loc, cell, target);
target.push(Target::clause_arg_to_instr(cell.get()));
}
&Term::Constant(_, ref constant) => {
@@ -222,7 +317,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
};
}
fn compile_target<Target, Iter>(
fn compile_target<Target, Iter>(
&mut self,
iter: Iter,
term_loc: GenContext,
@@ -292,13 +387,14 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
}
}
self.marker.mark_var(var.clone(), lvl, cell, term_loc, &mut target);
self.marker
.mark_var(var.clone(), lvl, cell, term_loc, &mut target);
}
TermRef::Var(lvl @ Level::Shallow, cell, var) => {
self.marker.mark_var(var.clone(), lvl, cell, term_loc, &mut target);
}
_ => {
self.marker
.mark_var(var.clone(), lvl, cell, term_loc, &mut target);
}
_ => {}
};
}
@@ -311,8 +407,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
while let Some((chunk_num, lt_arity, chunked_terms)) = iter.next() {
for (i, chunked_term) in chunked_terms.iter().enumerate() {
let term_loc = match chunked_term {
&ChunkedTerm::HeadClause(..) =>
GenContext::Head,
&ChunkedTerm::HeadClause(..) => GenContext::Head,
&ChunkedTerm::BodyTerm(_) => {
if i < chunked_terms.len() - 1 {
GenContext::Mid(chunk_num)
@@ -337,14 +432,17 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
ConjunctInfo::new(vs, num_of_chunks, has_deep_cut)
}
fn add_conditional_call(code: &mut Code, qt: &QueryTerm, pvs: usize) {
fn add_conditional_call(&mut self, code: &mut Code, qt: &QueryTerm, pvs: usize) {
match qt {
&QueryTerm::Jump(ref vars) => code.push(jmp_call!(vars.len(), 0, pvs)),
&QueryTerm::Jump(ref vars) => {
self.jmp_by_locs.push(code.len());
code.push(jmp_call!(vars.len(), 0, pvs));
}
&QueryTerm::Clause(_, ref ct, ref terms, true) => {
code.push(call_clause_by_default!(ct.clone(), terms.len(), pvs))
code.push(call_clause_by_default!(ct.clone(), terms.len(), pvs));
}
&QueryTerm::Clause(_, ref ct, ref terms, false) => {
code.push(call_clause!(ct.clone(), terms.len(), pvs))
code.push(call_clause!(ct.clone(), terms.len(), pvs));
}
_ => {}
}
@@ -356,15 +454,19 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
match code.last_mut() {
Some(&mut Line::Control(ref mut ctrl)) => match ctrl {
&mut ControlInstruction::CallClause(_, _, _, ref mut last_call, _) => {
*last_call = true
*last_call = true;
}
&mut ControlInstruction::JmpBy(_, _, _, ref mut last_call) => {
*last_call = true
*last_call = true;
}
&mut ControlInstruction::Proceed => {}
_ => dealloc_index += 1,
_ => {
dealloc_index += 1;
}
},
Some(&mut Line::Cut(CutInstruction::Cut(_))) => dealloc_index += 1,
Some(&mut Line::Cut(CutInstruction::Cut(_))) => {
dealloc_index += 1;
}
_ => {}
};
@@ -377,7 +479,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
terms: &'a Vec<Box<Term>>,
term_loc: GenContext,
code: &mut Code,
) -> Result<(), ParserError> {
) -> Result<(), CompilationError> {
match ct {
&InlinedClauseType::CompareNumber(cmp, ..) => {
self.marker.reset_arg(2);
@@ -385,23 +487,17 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
let (mut lcode, at_1) = self.call_arith_eval(terms[0].as_ref(), 1)?;
let (mut rcode, at_2) = self.call_arith_eval(terms[1].as_ref(), 2)?;
let at_1 =
if let &Term::Var(ref vr, ref name) = terms[0].as_ref() {
ArithmeticTerm::Reg(
self.mark_non_callable(name.clone(), 1, term_loc, vr, code)
)
} else {
at_1.unwrap_or(interm!(1))
};
let at_1 = if let &Term::Var(ref vr, ref name) = terms[0].as_ref() {
ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 1, term_loc, vr, code))
} else {
at_1.unwrap_or(interm!(1))
};
let at_2 =
if let &Term::Var(ref vr, ref name) = terms[1].as_ref() {
ArithmeticTerm::Reg(
self.mark_non_callable(name.clone(), 2, term_loc, vr, code)
)
} else {
at_2.unwrap_or(interm!(2))
};
let at_2 = if let &Term::Var(ref vr, ref name) = terms[1].as_ref() {
ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 2, term_loc, vr, code))
} else {
at_2.unwrap_or(interm!(2))
};
code.append(&mut lcode);
code.append(&mut rcode);
@@ -409,9 +505,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
code.push(compare_number_instr!(cmp, at_1, at_2));
}
&InlinedClauseType::IsAtom(..) => match terms[0].as_ref() {
&Term::Constant(_, Constant::Char(_)) |
&Term::Constant(_, Constant::EmptyList) |
&Term::Constant(_, Constant::Atom(..)) => {
&Term::Constant(_, Constant::Char(_))
| &Term::Constant(_, Constant::EmptyList)
| &Term::Constant(_, Constant::Atom(..)) => {
code.push(succeed!());
}
&Term::Var(ref vr, ref name) => {
@@ -476,11 +572,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
}
},
&InlinedClauseType::IsNumber(..) => match terms[0].as_ref() {
&Term::Constant(_, Constant::Float(_)) |
&Term::Constant(_, Constant::Rational(_)) |
&Term::Constant(_, Constant::Integer(_)) |
&Term::Constant(_, Constant::Fixnum(_)) |
&Term::Constant(_, Constant::Usize(_)) => {
&Term::Constant(_, Constant::Float(_))
| &Term::Constant(_, Constant::Rational(_))
| &Term::Constant(_, Constant::Integer(_))
| &Term::Constant(_, Constant::Fixnum(_))
| &Term::Constant(_, Constant::Usize(_)) => {
code.push(succeed!());
}
&Term::Var(ref vr, ref name) => {
@@ -506,9 +602,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
}
},
&InlinedClauseType::IsInteger(..) => match terms[0].as_ref() {
&Term::Constant(_, Constant::Integer(_)) |
&Term::Constant(_, Constant::Fixnum(_)) |
&Term::Constant(_, Constant::Usize(_)) => {
&Term::Constant(_, Constant::Integer(_))
| &Term::Constant(_, Constant::Fixnum(_))
| &Term::Constant(_, Constant::Usize(_)) => {
code.push(succeed!());
}
&Term::Var(ref vr, ref name) => {
@@ -553,7 +649,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
code: &mut Code,
term_loc: GenContext,
use_default_call_policy: bool,
) -> Result<(), ParserError> {
) -> Result<(), CompilationError> {
let (mut acode, at) = self.call_arith_eval(terms[1].as_ref(), 1)?;
code.append(&mut acode);
@@ -563,14 +659,15 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
&Term::Var(ref vr, ref name) => {
let mut target = vec![];
self.marker.mark_var(name.clone(), Level::Shallow, vr, term_loc, &mut target);
self.marker
.mark_var(name.clone(), Level::Shallow, vr, term_loc, &mut target);
if !target.is_empty() {
code.extend(target.into_iter().map(Line::Query));
}
}
&Term::Constant(_, ref c @ Constant::Integer(_)) |
&Term::Constant(_, ref c @ Constant::Fixnum(_)) => {
&Term::Constant(_, ref c @ Constant::Integer(_))
| &Term::Constant(_, ref c @ Constant::Fixnum(_)) => {
code.push(Line::Query(put_constant!(
Level::Shallow,
c.clone(),
@@ -603,14 +700,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
}
}
let at =
if let &Term::Var(ref vr, ref name) = terms[1].as_ref() {
ArithmeticTerm::Reg(
self.mark_non_callable(name.clone(), 2, term_loc, vr, code)
)
} else {
at.unwrap_or(interm!(1))
};
let at = if let &Term::Var(ref vr, ref name) = terms[1].as_ref() {
ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 2, term_loc, vr, code))
} else {
at.unwrap_or(interm!(1))
};
Ok(if use_default_call_policy {
code.push(is_call_by_default!(temp_v!(1), at));
@@ -656,7 +750,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
conjunct_info: &ConjunctInfo<'a>,
code: &mut Code,
is_exposed: bool,
) -> Result<(), ParserError> {
) -> Result<(), CompilationError> {
for (chunk_num, _, terms) in iter.rule_body_iter() {
for (i, term) in terms.iter().enumerate() {
let term_loc = if i + 1 < terms.len() {
@@ -714,7 +808,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
}
}
fn compile_cleanup(code: &mut Code, conjunct_info: &ConjunctInfo, toc: &'a QueryTerm) {
fn compile_cleanup(
&mut self,
code: &mut Code,
conjunct_info: &ConjunctInfo,
toc: &'a QueryTerm,
) {
// add a proceed to bookend any trailing cuts.
match toc {
&QueryTerm::BlockedCut | &QueryTerm::UnblockedCut(..) => code.push(proceed!()),
@@ -726,11 +825,22 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
let dealloc_index = Self::lco(code);
if conjunct_info.allocates() {
let offset = self.global_jmp_by_locs_offset;
if let Some(jmp_by_offset) = self.jmp_by_locs[offset..].last_mut() {
if *jmp_by_offset == dealloc_index {
*jmp_by_offset += 1;
}
}
code.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate));
}
}
pub fn compile_rule<'b: 'a>(&mut self, rule: &'b Rule) -> Result<Code, ParserError> {
pub(crate) fn compile_rule<'b: 'a>(
&mut self,
rule: &'b Rule,
) -> Result<Code, CompilationError> {
let iter = ChunkedIterator::from_rule(rule);
let conjunct_info = self.collect_var_data(iter);
@@ -739,7 +849,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
ref clauses,
} = rule;
let mut code = Vec::new();
let mut code = Code::new();
self.marker.reset_at_head(args);
self.compile_seq_prelude(&conjunct_info, &mut code);
@@ -761,8 +871,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
self.compile_seq(iter, &conjunct_info, &mut code, false)?;
conjunct_info.mark_unsafe_vars(unsafe_var_marker, &mut code);
self.compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1));
Self::compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1));
Ok(code)
}
@@ -787,7 +897,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
UnsafeVarMarker::from_safe_vars(safe_vars)
}
pub fn compile_fact<'b: 'a>(&mut self, term: &'b Term) -> Code {
pub(crate) fn compile_fact<'b: 'a>(&mut self, term: &'b Term) -> Code {
self.update_var_count(post_order_iter(term));
let mut vs = VariableFixtures::new();
@@ -836,26 +946,16 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
}
}
Self::add_conditional_call(code, term, num_perm_vars_left);
self.add_conditional_call(code, term, num_perm_vars_left);
}
pub fn compile_query(&mut self, query: &'a Vec<QueryTerm>) -> Result<Code, ParserError> {
let iter = ChunkedIterator::from_term_sequence(query);
let conjunct_info = self.collect_var_data(iter);
#[inline]
fn increment_jmp_by_locs_by(&mut self, incr: usize) {
let offset = self.global_jmp_by_locs_offset;
let mut code = Vec::new();
self.compile_seq_prelude(&conjunct_info, &mut code);
let iter = ChunkedIterator::from_term_sequence(query);
self.compile_seq(iter, &conjunct_info, &mut code, true)?;
conjunct_info.mark_unsafe_vars(UnsafeVarMarker::new(), &mut code);
if let Some(query_term) = query.last() {
Self::compile_cleanup(&mut code, &conjunct_info, query_term);
for loc in &mut self.jmp_by_locs[offset..] {
*loc += incr;
}
Ok(code)
}
/// Returns the index of the first instantiated argument.
@@ -925,48 +1025,56 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
subseqs
}
fn trust_me(&self) -> ChoiceInstruction {
if self.non_counted_bt {
ChoiceInstruction::DefaultTrustMe
} else {
ChoiceInstruction::TrustMe
}
}
fn retry_me_else(&self, offset: usize) -> ChoiceInstruction {
if self.non_counted_bt {
ChoiceInstruction::DefaultRetryMeElse(offset)
} else {
ChoiceInstruction::RetryMeElse(offset)
}
}
fn compile_pred_subseq<'b: 'a>(
fn compile_pred_subseq<'b: 'a, I: Indexer>(
&mut self,
clauses: &'b [PredicateClause],
optimal_index: usize,
) -> Result<Code, ParserError> {
let mut code_body = Vec::new();
let mut code_offsets = CodeOffsets::new();
) -> Result<Code, CompilationError> {
let mut code = VecDeque::new();
let mut code_offsets = CodeOffsets::new(
self.atom_tbl.clone(),
I::new(),
optimal_index + 1,
);
let num_clauses = clauses.len();
let mut skip_stub_try_me_else = false;
let jmp_by_locs_len = self.jmp_by_locs.len();
for (i, clause) in clauses.iter().enumerate() {
self.marker.reset();
let mut clause_code = match *clause {
PredicateClause::Fact(ref fact, ..) => self.compile_fact(fact),
PredicateClause::Rule(ref rule, ..) => self.compile_rule(rule)?,
let mut clause_index_info = ClauseIndexInfo::new(code.len());
self.global_jmp_by_locs_offset = self.jmp_by_locs.len();
let clause_code = match clause {
&PredicateClause::Fact(ref fact, ..) => self.compile_fact(fact),
&PredicateClause::Rule(ref rule, ..) => self.compile_rule(rule)?,
};
if num_clauses > 1 {
if clauses.len() > 1 {
let choice = match i {
0 => ChoiceInstruction::TryMeElse(clause_code.len() + 1),
_ if i == num_clauses - 1 => self.trust_me(),
_ => self.retry_me_else(clause_code.len() + 1),
0 => self.settings.internal_try_me_else(clause_code.len() + 1),
//ChoiceInstruction::TryMeElse(clause_code.len() + 1),
_ if i == clauses.len() - 1 => self.settings.internal_trust_me(),
_ => self.settings.internal_retry_me_else(clause_code.len() + 1),
};
code_body.push(Line::Choice(choice));
code.push_back(Line::Choice(choice));
} else if self.settings.is_extensible {
/*
generate stub choice instructions for extensible
predicates. if predicates are added to either the
inner or outer thread of choice instructions,
these stubs will be used, and surrounding indexing
instructions modified accordingly.
until then, the v offset of SwitchOnTerm will skip
over them.
*/
code.push_front(Line::Choice(self.settings.internal_try_me_else(0)));
//Line::Choice(ChoiceInstruction::TryMeElse(0)));
skip_stub_try_me_else = !self.settings.is_dynamic(); //true;
}
let arg = match clause.args() {
@@ -976,47 +1084,94 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
},
None => None,
};
if let Some(arg) = arg {
let index = code_body.len();
code_offsets.index_term(arg, index);
let index = code.len();
code_offsets.index_term(arg, index, &mut clause_index_info);
}
code_body.append(&mut clause_code);
if !(clauses.len() == 1 && self.settings.is_extensible) {
self.increment_jmp_by_locs_by(code.len());
}
self.skeleton.clauses.push_back(clause_index_info);
code.extend(clause_code.into_iter());
}
let mut code = Vec::new();
code_offsets.add_indices(&mut code, code_body, optimal_index + 1);
let index_code = code_offsets.compute_indices(skip_stub_try_me_else);
self.global_jmp_by_locs_offset = jmp_by_locs_len;
Ok(code)
if !index_code.is_empty() {
code.push_front(Line::IndexingCode(index_code));
if skip_stub_try_me_else {
// skip the TryMeElse(0) also.
self.increment_jmp_by_locs_by(2);
} else {
self.increment_jmp_by_locs_by(1);
}
} else if clauses.len() == 1 && self.settings.is_extensible {
// the condition is the value of skip_stub_try_me_else, which is
// true if the predicate is not dynamic. This operation must apply
// to dynamic predicates also, though.
// remove the TryMeElse(0).
code.pop_front();
}
Ok(Vec::from(code))
}
pub fn compile_predicate<'b: 'a>(
pub(crate) fn compile_predicate<'b: 'a>(
&mut self,
clauses: &'b Vec<PredicateClause>,
) -> Result<Code, ParserError> {
let mut code = Vec::new();
) -> Result<Code, CompilationError> {
let mut code = Code::new();
let optimal_index = match Self::first_instantiated_index(&clauses) {
Some(index) => index,
None => 0, // Default to first argument indexing.
};
let split_pred = Self::split_predicate(&clauses, optimal_index);
let multi_seq = split_pred.len() > 1;
for (l, r) in split_pred {
let mut code_segment =
self.compile_pred_subseq(&clauses[l..r], optimal_index)?;
let skel_lower_bound = self.skeleton.clauses.len();
let code_segment = if self.settings.is_dynamic() {
self.compile_pred_subseq::<DynamicCodeIndices>(&clauses[l..r], optimal_index)?
} else {
self.compile_pred_subseq::<StaticCodeIndices>(&clauses[l..r], optimal_index)?
};
let clause_start_offset = code.len();
if multi_seq {
let choice = match l {
0 => ChoiceInstruction::TryMeElse(code_segment.len() + 1),
_ if r == clauses.len() => self.trust_me(),
_ => self.retry_me_else(code_segment.len() + 1),
0 => self.settings.try_me_else(code_segment.len() + 1),
_ if r == clauses.len() => self.settings.trust_me(),
_ => self.settings.retry_me_else(code_segment.len() + 1),
};
code.push(Line::Choice(choice));
} else if self.settings.is_extensible {
code.push(Line::Choice(self.settings.try_me_else(0)));
}
code.append(&mut code_segment);
if self.settings.is_extensible {
let segment_is_indexed = to_indexing_line(&code_segment[0]).is_some();
for clause_index_info in self.skeleton.clauses[skel_lower_bound..].iter_mut() {
clause_index_info.clause_start +=
clause_start_offset + 2 * (segment_is_indexed as usize);
clause_index_info.opt_arg_index_key += clause_start_offset + 1;
}
}
self.increment_jmp_by_locs_by(code.len());
self.global_jmp_by_locs_offset = self.jmp_by_locs.len();
code.extend(code_segment.into_iter());
}
Ok(code)

View File

@@ -1,6 +1,7 @@
use crate::indexmap::IndexMap;
use indexmap::IndexMap;
use crate::prolog_parser::ast::*;
use prolog_parser::ast::*;
use prolog_parser::temp_v;
use crate::allocator::*;
use crate::fixtures::*;
@@ -13,7 +14,7 @@ use std::collections::BTreeSet;
use std::rc::Rc;
#[derive(Debug)]
pub struct DebrayAllocator {
pub(crate) struct DebrayAllocator {
bindings: IndexMap<Rc<Var>, VarData>,
arg_c: usize,
temp_lb: usize,
@@ -293,9 +294,7 @@ impl<'a> Allocator<'a> for DebrayAllocator {
(pr, true)
}
r => {
(r, false)
}
r => (r, false),
};
self.mark_reserved_var(var, lvl, cell, term_loc, target, r, is_new_var);

View File

@@ -1,6 +1,6 @@
:- module(bimetatran_tests, [test_bimetatrans/0]).
:- use_module('bimetatrans').
:- use_module(bimetatrans).
:- use_module(library(dcgs)).
:- use_module(library(iso_ext)).

View File

@@ -1,10 +1,10 @@
use crate::prolog_parser::ast::*;
use prolog_parser::ast::*;
use crate::forms::*;
use crate::instructions::*;
use crate::iterators::*;
use crate::indexmap::{IndexMap, IndexSet};
use indexmap::{IndexMap, IndexSet};
use std::cell::Cell;
use std::collections::BTreeSet;
@@ -14,23 +14,23 @@ use std::vec::Vec;
// labeled with chunk numbers.
#[derive(Debug)]
pub enum VarStatus {
pub(crate) enum VarStatus {
Perm(usize),
Temp(usize, TempVarData), // Perm(chunk_num) | Temp(chunk_num, _)
}
pub type OccurrenceSet = BTreeSet<(GenContext, usize)>;
pub(crate) type OccurrenceSet = BTreeSet<(GenContext, usize)>;
// Perm: 0 initially, a stack register once processed.
// Temp: labeled with chunk_num and temp offset (unassigned if 0).
#[derive(Debug)]
pub enum VarData {
pub(crate) enum VarData {
Perm(usize),
Temp(usize, usize, TempVarData),
}
impl VarData {
pub fn as_reg_type(&self) -> RegType {
pub(crate) fn as_reg_type(&self) -> RegType {
match self {
&VarData::Temp(_, r, _) => RegType::Temp(r),
&VarData::Perm(r) => RegType::Perm(r),
@@ -39,15 +39,15 @@ impl VarData {
}
#[derive(Debug)]
pub struct TempVarData {
pub last_term_arity: usize,
pub use_set: OccurrenceSet,
pub no_use_set: BTreeSet<usize>,
pub conflict_set: BTreeSet<usize>,
pub(crate) struct TempVarData {
pub(crate) last_term_arity: usize,
pub(crate) use_set: OccurrenceSet,
pub(crate) no_use_set: BTreeSet<usize>,
pub(crate) conflict_set: BTreeSet<usize>,
}
impl TempVarData {
pub fn new(last_term_arity: usize) -> Self {
pub(crate) fn new(last_term_arity: usize) -> Self {
TempVarData {
last_term_arity: last_term_arity,
use_set: BTreeSet::new(),
@@ -56,7 +56,7 @@ impl TempVarData {
}
}
pub fn uses_reg(&self, reg: usize) -> bool {
pub(crate) fn uses_reg(&self, reg: usize) -> bool {
for &(_, nreg) in self.use_set.iter() {
if reg == nreg {
return true;
@@ -66,7 +66,7 @@ impl TempVarData {
return false;
}
pub fn populate_conflict_set(&mut self) {
pub(crate) fn populate_conflict_set(&mut self) {
if self.last_term_arity > 0 {
let arity = self.last_term_arity;
let mut conflict_set: BTreeSet<usize> = (1..arity).collect();
@@ -83,30 +83,29 @@ impl TempVarData {
type VariableFixture<'a> = (VarStatus, Vec<&'a Cell<VarReg>>);
#[derive(Debug)]
pub struct VariableFixtures<'a>{
pub(crate) struct VariableFixtures<'a> {
perm_vars: IndexMap<Rc<Var>, VariableFixture<'a>>,
last_chunk_temp_vars: IndexSet<Rc<Var>>
last_chunk_temp_vars: IndexSet<Rc<Var>>,
}
impl<'a> VariableFixtures<'a> {
pub fn new() -> Self {
pub(crate) fn new() -> Self {
VariableFixtures {
perm_vars: IndexMap::new(),
last_chunk_temp_vars: IndexSet::new()
last_chunk_temp_vars: IndexSet::new(),
}
}
pub fn insert(&mut self, var: Rc<Var>, vs: VariableFixture<'a>) {
pub(crate) fn insert(&mut self, var: Rc<Var>, vs: VariableFixture<'a>) {
self.perm_vars.insert(var, vs);
}
pub fn insert_last_chunk_temp_var(&mut self, var: Rc<Var>) {
pub(crate) fn insert_last_chunk_temp_var(&mut self, var: Rc<Var>) {
self.last_chunk_temp_vars.insert(var);
}
// computes no_use and conflict sets for all temp vars.
pub fn populate_restricting_sets(&mut self) {
pub(crate) fn populate_restricting_sets(&mut self) {
// three stages:
// 1. move the use sets of each variable to a local IndexMap, use_set
// (iterate mutably, swap mutable refs).
@@ -171,7 +170,7 @@ impl<'a> VariableFixtures<'a> {
};
}
pub fn vars_above_threshold(&self, index: usize) -> usize {
pub(crate) fn vars_above_threshold(&self, index: usize) -> usize {
let mut var_count = 0;
for &(ref var_status, _) in self.values() {
@@ -185,7 +184,7 @@ impl<'a> VariableFixtures<'a> {
var_count
}
pub fn mark_vars_in_chunk<I>(&mut self, iter: I, lt_arity: usize, term_loc: GenContext)
pub(crate) fn mark_vars_in_chunk<I>(&mut self, iter: I, lt_arity: usize, term_loc: GenContext)
where
I: Iterator<Item = TermRef<'a>>,
{
@@ -219,7 +218,7 @@ impl<'a> VariableFixtures<'a> {
}
}
pub fn into_iter(self) -> indexmap::map::IntoIter<Rc<Var>, VariableFixture<'a>> {
pub(crate) fn into_iter(self) -> indexmap::map::IntoIter<Rc<Var>, VariableFixture<'a>> {
self.perm_vars.into_iter()
}
@@ -227,11 +226,11 @@ impl<'a> VariableFixtures<'a> {
self.perm_vars.values()
}
pub fn size(&self) -> usize {
pub(crate) fn size(&self) -> usize {
self.perm_vars.len()
}
pub fn set_perm_vals(&self, has_deep_cuts: bool) {
pub(crate) fn set_perm_vals(&self, has_deep_cuts: bool) {
let mut values_vec: Vec<_> = self
.values()
.filter_map(|ref v| match &v.0 {
@@ -253,43 +252,41 @@ impl<'a> VariableFixtures<'a> {
}
#[derive(Debug)]
pub struct UnsafeVarMarker {
pub unsafe_vars: IndexMap<RegType, usize>,
pub safe_vars: IndexSet<RegType>,
pub(crate) struct UnsafeVarMarker {
pub(crate) unsafe_vars: IndexMap<RegType, usize>,
pub(crate) safe_vars: IndexSet<RegType>,
}
impl UnsafeVarMarker {
pub fn new() -> Self {
pub(crate) fn new() -> Self {
UnsafeVarMarker {
unsafe_vars: IndexMap::new(),
safe_vars: IndexSet::new()
safe_vars: IndexSet::new(),
}
}
pub fn from_safe_vars(safe_vars: IndexSet<RegType>) -> Self {
pub(crate) fn from_safe_vars(safe_vars: IndexSet<RegType>) -> Self {
UnsafeVarMarker {
unsafe_vars: IndexMap::new(),
safe_vars
safe_vars,
}
}
pub fn mark_safe_vars(&mut self, query_instr: &QueryInstruction) -> bool {
pub(crate) fn mark_safe_vars(&mut self, query_instr: &QueryInstruction) -> bool {
match query_instr {
&QueryInstruction::PutVariable(r @ RegType::Temp(_), _)
| &QueryInstruction::SetVariable(r) => {
| &QueryInstruction::SetVariable(r) => {
self.safe_vars.insert(r);
true
}
_ => {
false
}
_ => false,
}
}
pub fn mark_phase(&mut self, query_instr: &QueryInstruction, phase: usize) {
pub(crate) fn mark_phase(&mut self, query_instr: &QueryInstruction, phase: usize) {
match query_instr {
&QueryInstruction::PutValue(r @ RegType::Perm(_), _)
| &QueryInstruction::SetValue(r) => {
| &QueryInstruction::SetValue(r) => {
let p = self.unsafe_vars.entry(r).or_insert(0);
*p = phase;
}
@@ -297,7 +294,7 @@ impl UnsafeVarMarker {
}
}
pub fn mark_unsafe_vars(&mut self, query_instr: &mut QueryInstruction, phase: usize) {
pub(crate) fn mark_unsafe_vars(&mut self, query_instr: &mut QueryInstruction, phase: usize) {
match query_instr {
&mut QueryInstruction::PutValue(RegType::Perm(i), arg) => {
if let Some(p) = self.unsafe_vars.swap_remove(&RegType::Perm(i)) {

View File

@@ -1,55 +1,64 @@
use crate::prolog_parser::ast::*;
use crate::prolog_parser::parser::OpDesc;
use crate::prolog_parser::tabled_rc::*;
use prolog_parser::ast::*;
use prolog_parser::parser::OpDesc;
use prolog_parser::{clause_name, is_infix, is_postfix};
use crate::clause_types::*;
use crate::machine::loader::PredicateQueue;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::ordered_float::OrderedFloat;
use crate::rug::{Integer, Rational};
use ordered_float::OrderedFloat;
use crate::indexmap::IndexMap;
use indexmap::{IndexMap, IndexSet};
use slice_deque::*;
use std::cell::Cell;
use std::collections::VecDeque;
use std::ops::AddAssign;
use std::path::PathBuf;
use std::rc::Rc;
pub type PredicateKey = (ClauseName, usize); // name, arity.
pub(crate) type PredicateKey = (ClauseName, usize); // name, arity.
pub(crate) type Predicate = Vec<PredicateClause>;
// vars of predicate, toplevel offset. Vec<Term> is always a vector
// of vars (we get their adjoining cells this way).
pub type JumpStub = Vec<Term>;
pub(crate) type JumpStub = Vec<Term>;
#[derive(Debug, Clone)]
pub enum TopLevel {
Declaration(Declaration),
Fact(Term, usize, usize), // Term, line_num, col_num
pub(crate) enum TopLevel {
Fact(Term), // Term, line_num, col_num
Predicate(Predicate),
Query(Vec<QueryTerm>),
Rule(Rule, usize, usize), // Rule, line_num, col_num
Rule(Rule), // Rule, line_num, col_num
}
impl TopLevel {
pub fn is_end_of_file_atom(&self) -> bool {
#[derive(Debug, Clone, Copy)]
pub(crate) enum AppendOrPrepend {
Append,
Prepend,
}
impl AppendOrPrepend {
#[inline]
pub(crate) fn is_append(self) -> bool {
match self {
&TopLevel::Fact(Term::Constant(_, Constant::Atom(ref name, _)), ..) => {
return name.as_str() == "end_of_file"
}
_ => false,
AppendOrPrepend::Append => true,
AppendOrPrepend::Prepend => false,
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum Level {
pub(crate) enum Level {
Deep,
Root,
Shallow,
}
impl Level {
pub fn child_level(self) -> Level {
pub(crate) fn child_level(self) -> Level {
match self {
Level::Root => Level::Shallow,
_ => Level::Deep,
@@ -58,7 +67,7 @@ impl Level {
}
#[derive(Debug, Clone)]
pub enum QueryTerm {
pub(crate) enum QueryTerm {
// register, clause type, subterms, use default call policy.
Clause(Cell<RegType>, ClauseType, Vec<Box<Term>>, bool),
BlockedCut, // a cut which is 'blocked by letters', like the P term in P -> Q.
@@ -68,14 +77,14 @@ pub enum QueryTerm {
}
impl QueryTerm {
pub fn set_default_caller(&mut self) {
pub(crate) fn set_default_caller(&mut self) {
match self {
&mut QueryTerm::Clause(_, _, _, ref mut use_default_cp) => *use_default_cp = true,
_ => {}
}
}
pub fn arity(&self) -> usize {
pub(crate) fn arity(&self) -> usize {
match self {
&QueryTerm::Clause(_, _, ref subterms, ..) => subterms.len(),
&QueryTerm::BlockedCut | &QueryTerm::UnblockedCut(..) => 0,
@@ -86,201 +95,88 @@ impl QueryTerm {
}
#[derive(Debug, Clone)]
pub struct Rule {
pub head: (ClauseName, Vec<Box<Term>>, QueryTerm),
pub clauses: Vec<QueryTerm>,
pub(crate) struct Rule {
pub(crate) head: (ClauseName, Vec<Box<Term>>, QueryTerm),
pub(crate) clauses: Vec<QueryTerm>,
}
#[derive(Debug, Clone)]
pub struct Predicate(pub Vec<PredicateClause>);
impl Predicate {
#[inline]
pub fn new() -> Self {
Predicate(vec![])
}
#[inline]
pub fn clauses(self) -> Vec<PredicateClause> {
self.0
}
#[inline]
pub fn predicate_indicator(&self) -> Option<(ClauseName, usize)> {
self.0
.first()
.and_then(|clause| clause.name().map(|name| (name, clause.arity())))
}
}
#[derive(Debug, Clone)]
pub enum ListingSource {
#[derive(Clone, Debug, Hash)]
pub(crate) enum ListingSource {
DynamicallyGenerated,
File(ClauseName, PathBuf), // filename, path
User,
}
impl ListingSource {
pub fn from_file_and_path(filename: ClauseName, path_buf: PathBuf) -> Self {
pub(crate) fn from_file_and_path(filename: ClauseName, path_buf: PathBuf) -> Self {
ListingSource::File(filename, path_buf)
}
pub fn name(&self) -> ClauseName {
match self {
ListingSource::File(ref filename, _) => filename.clone(),
ListingSource::User => clause_name!("[user]")
}
}
pub fn path(&self) -> PathBuf {
match self {
ListingSource::File(_, ref path) => path.clone(),
ListingSource::User => std::env::current_dir().unwrap(),
}
}
}
fn resolved_term_and_module(term: &Term) -> Option<(ClauseName, ClauseName)>
{
match term {
Term::Clause(_, ref name, ref terms, _) => {
if name.as_str() == ":" && terms.len() == 2 {
let module_name = match terms[0].as_ref() {
&Term::Constant(_, Constant::Atom(ref module_name, _)) => {
module_name.clone()
}
_ => {
return Some((name.owning_module(), name.clone()));
}
};
match terms[1].as_ref() {
Term::Clause(_, ref name, ..)
| Term::Constant(_, Constant::Atom(ref name, ..)) => {
return Some((module_name, name.clone()));
}
_ => {
}
}
Some((name.owning_module(), name.clone()))
} else {
Some((name.owning_module(), name.clone()))
}
}
Term::Constant(_, Constant::Atom(ref name, _)) => {
Some((name.owning_module(), name.clone()))
}
_ => {
None
}
}
}
fn resolved_term_arity(term: &Term) -> usize
{
match term {
Term::Clause(_, ref name, ref terms, _) => {
if name.as_str() == ":" && terms.len() == 2 {
match terms[0].as_ref() {
&Term::Constant(_, Constant::Atom(..)) => {
}
_ => {
return 2;
}
}
match terms[1].as_ref() {
Term::Clause(_, _, ref terms, _) => {
terms.len()
}
Term::Constant(_, Constant::Atom(..)) => {
0
}
_ => {
2
}
}
} else {
terms.len()
}
}
_ => {
0
}
}
}
pub trait ClauseConsistency {
fn is_consistent(&self, clauses: &Vec<PredicateClause>) -> bool {
pub(crate) trait ClauseInfo {
fn is_consistent(&self, clauses: &PredicateQueue) -> bool {
match clauses.first() {
Some(ref cl) => {
self.name_and_module() == cl.name_and_module() && self.arity() == cl.arity()
}
None => {
true
Some(cl) => {
self.name() == ClauseInfo::name(cl) && self.arity() == ClauseInfo::arity(cl)
}
None => true,
}
}
fn name_and_module(&self) -> Option<(ClauseName, ClauseName)>;
fn name(&self) -> Option<ClauseName>;
fn arity(&self) -> usize;
}
/* Of course '$current_module$' isn't the name of the current
* module. It'll do if no module is explicitly specified through
* (:)/2.
*/
impl ClauseConsistency for Term {
fn name_and_module(&self) -> Option<(ClauseName, ClauseName)>
{
impl ClauseInfo for PredicateKey {
#[inline]
fn name(&self) -> Option<ClauseName> {
Some(self.0.clone())
}
#[inline]
fn arity(&self) -> usize {
self.1
}
}
impl ClauseInfo for Term {
fn name(&self) -> Option<ClauseName> {
match self {
Term::Clause(_, ref name, ref terms, _) =>
Term::Clause(_, ref name, ref terms, _) => {
match name.as_str() {
":-" => {
match terms.len() {
1 => None, // a declaration.
2 => resolved_term_and_module(&terms[0]),
_ => Some((name.owning_module(), clause_name!(":-"))),
2 => terms[0].name(),
_ => Some(clause_name!(":-")),
}
}
_ => {
resolved_term_and_module(self)
}
},
Term::Constant(_, Constant::Atom(ref name, _)) => {
Some((name.owning_module(), name.clone()))
}
_ => {
None
_ => Some(name.clone()),
}
}
Term::Constant(_, Constant::Atom(ref name, _)) => Some(name.clone()),
_ => None,
}
}
fn arity(&self) -> usize {
match self {
Term::Clause(_, ref name, ref terms, _) =>
match name.as_str() {
":-" => {
match terms.len() {
1 => 0,
2 => resolved_term_arity(&terms[0]),
_ => terms.len(),
}
}
_ => {
resolved_term_arity(self)
}
Term::Clause(_, ref name, ref terms, _) => match name.as_str() {
":-" => match terms.len() {
1 => 0,
2 => terms[0].arity(),
_ => terms.len(),
},
_ => {
0
}
_ => terms.len(),
},
_ => 0,
}
}
}
impl ClauseConsistency for Rule {
fn name_and_module(&self) -> Option<(ClauseName, ClauseName)> {
Some((self.head.0.owning_module(), self.head.0.clone()))
impl ClauseInfo for Rule {
fn name(&self) -> Option<ClauseName> {
Some(self.head.0.clone())
}
fn arity(&self) -> usize {
@@ -288,58 +184,37 @@ impl ClauseConsistency for Rule {
}
}
impl ClauseConsistency for PredicateClause {
fn name_and_module(&self) -> Option<(ClauseName, ClauseName)> {
impl ClauseInfo for PredicateClause {
fn name(&self) -> Option<ClauseName> {
match self {
&PredicateClause::Fact(ref term, ..) => {
term.name_and_module()
.map(|(_, name)| (name.owning_module(), name))
}
&PredicateClause::Rule(ref rule, ..) => {
rule.name_and_module()
}
&PredicateClause::Fact(ref term, ..) => term.name(),
&PredicateClause::Rule(ref rule, ..) => rule.name(),
}
}
fn arity(&self) -> usize {
match self {
&PredicateClause::Fact(ref term, ..) => {
term.arity()
}
&PredicateClause::Rule(ref rule, ..) => {
rule.arity()
}
&PredicateClause::Fact(ref term, ..) => term.arity(),
&PredicateClause::Rule(ref rule, ..) => rule.arity(),
}
}
}
impl ClauseConsistency for Predicate {
fn name_and_module(&self) -> Option<(ClauseName, ClauseName)> {
self.0.first().and_then(|clause| clause.name_and_module())
}
fn arity(&self) -> usize {
self.0.first().map(|clause| clause.arity()).unwrap_or(0)
}
}
pub type CompiledResult = (Predicate, VecDeque<TopLevel>);
// pub(crate) type CompiledResult = (Predicate, VecDeque<TopLevel>);
#[derive(Debug, Clone)]
pub enum PredicateClause {
Fact(Term, usize, usize), // Term, line number, column number.
Rule(Rule, usize, usize), // Term, line number, column number.
pub(crate) enum PredicateClause {
Fact(Term),
Rule(Rule),
}
impl PredicateClause {
// TODO: add this to `Term` in `prolog_parser` like `first_arg`.
pub fn args(&self) -> Option<&[Box<Term>]> {
pub(crate) fn args(&self) -> Option<&[Box<Term>]> {
match *self {
PredicateClause::Fact(ref term, ..) => {
match term {
Term::Clause(_, _, args, _) => Some(&args),
_ => None,
}
PredicateClause::Fact(ref term, ..) => match term {
Term::Clause(_, _, args, _) => Some(&args),
_ => None,
},
PredicateClause::Rule(ref rule, ..) => {
if rule.head.1.is_empty() {
@@ -350,46 +225,16 @@ impl PredicateClause {
}
}
}
pub fn arity(&self) -> usize {
match self {
&PredicateClause::Fact(ref term, ..) => {
term.arity()
}
&PredicateClause::Rule(ref rule, ..) => {
if rule.head.0.as_str() == ":" && rule.head.1.len() == 2 {
match (rule.head.1)[0].as_ref() {
&Term::Constant(_, Constant::Atom(..)) => {
}
_ => {
return 2;
}
}
(rule.head.1)[1].arity()
} else {
rule.head.1.len()
}
}
}
}
pub fn name(&self) -> Option<ClauseName> {
match self {
&PredicateClause::Fact(ref term, ..) => term.name(),
&PredicateClause::Rule(ref rule, ..) => Some(rule.head.0.clone()),
}
}
}
#[derive(Debug, Clone)]
pub enum ModuleSource {
pub(crate) enum ModuleSource {
Library(ClauseName),
File(ClauseName),
}
impl ModuleSource {
pub fn as_functor_stub(&self) -> MachineStub {
pub(crate) fn as_functor_stub(&self) -> MachineStub {
match self {
ModuleSource::Library(ref name) => {
functor!("library", [clause_name(name.clone())])
@@ -401,96 +246,88 @@ impl ModuleSource {
}
}
pub type ScopedPredicateKey = (ClauseName, PredicateKey); // module name, predicate indicator.
// pub(crate) type ScopedPredicateKey = (ClauseName, PredicateKey); // module name, predicate indicator.
/*
#[derive(Debug, Clone)]
pub enum MultiFileIndicator {
pub(crate) enum MultiFileIndicator {
LocalScoped(ClauseName, usize), // name, arity
ModuleScoped(ScopedPredicateKey),
}
*/
#[derive(Clone, Copy, Hash, Debug)]
pub(crate) enum MetaSpec {
Minus,
Plus,
Either,
RequiresExpansionWithArgument(usize),
}
#[derive(Debug, Clone)]
pub enum Declaration {
Dynamic(ClauseName, usize), // name, arity
EndOfFile,
Hook(CompileTimeHook, PredicateClause, VecDeque<TopLevel>),
ModuleInitialization(Vec<QueryTerm>, VecDeque<TopLevel>), // goal
pub(crate) enum Declaration {
Dynamic(ClauseName, usize),
MetaPredicate(ClauseName, ClauseName, Vec<MetaSpec>), // module name, name, meta-specs
Module(ModuleDecl),
MultiFile(MultiFileIndicator),
NonCountedBacktracking(ClauseName, usize), // name, arity
Op(OpDecl),
SetPrologFlag(DoubleQuotes),
UseModule(ModuleSource),
UseQualifiedModule(ModuleSource, Vec<ModuleExport>),
UseQualifiedModule(ModuleSource, IndexSet<ModuleExport>),
}
impl Declaration {
#[inline]
pub fn is_module_decl(&self) -> bool {
if let &Declaration::Module(_) = self {
true
} else {
false
}
}
#[inline]
pub fn is_end_of_file(&self) -> bool {
if let &Declaration::EndOfFile = self {
true
} else {
false
}
}
#[derive(Debug, Clone, Eq, Hash, PartialEq, Ord, PartialOrd)]
pub(crate) struct OpDecl {
pub(crate) prec: usize,
pub(crate) spec: Specifier,
pub(crate) name: ClauseName,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct OpDecl(pub usize, pub Specifier, pub ClauseName);
impl OpDecl {
#[inline]
pub fn name(&self) -> ClauseName {
self.2.clone()
pub(crate) fn new(prec: usize, spec: Specifier, name: ClauseName) -> Self {
Self { prec, spec, name }
}
#[inline]
pub fn remove(&self, op_dir: &mut OpDir) {
self.insert_into_op_dir(clause_name!(""), op_dir, 0);
pub(crate) fn remove(&mut self, op_dir: &mut OpDir) {
let prec = self.prec;
self.prec = 0;
self.insert_into_op_dir(op_dir);
self.prec = prec;
}
#[inline]
pub fn fixity(&self) -> Fixity {
match self.1 {
pub(crate) fn fixity(&self) -> Fixity {
match self.spec {
XFY | XFX | YFX => Fixity::In,
XF | YF => Fixity::Post,
FX | FY => Fixity::Pre,
_ => unreachable!()
_ => unreachable!(),
}
}
pub fn insert_into_op_dir(&self, module: ClauseName, op_dir: &mut OpDir, prec: usize) {
let (spec, name) = (self.1, self.2.clone());
pub(crate) fn insert_into_op_dir(&self, op_dir: &mut OpDir) -> Option<(usize, Specifier)> {
let key = (self.name.clone(), self.fixity());
let fixity = self.fixity();
match op_dir.get(&(name.clone(), fixity)) {
match op_dir.get(&key) {
Some(cell) => {
cell.shared_op_desc().set(prec, spec);
return;
return Some(cell.shared_op_desc().replace((self.prec, self.spec)));
}
None => {}
}
op_dir.insert((name, fixity), OpDirValue::new(spec, prec, module));
op_dir
.insert(key, OpDirValue::new(self.spec, self.prec))
.map(|op_dir_value| op_dir_value.shared_op_desc().get())
}
pub fn submit(
pub(crate) fn submit(
&self,
module: ClauseName,
existing_desc: Option<OpDesc>,
op_dir: &mut OpDir,
) -> Result<(), SessionError> {
let (prec, spec, name) = (self.0, self.1, self.2.clone());
let (spec, name) = (self.spec, self.name.clone());
if is_infix!(spec) {
if let Some(desc) = existing_desc {
@@ -508,11 +345,12 @@ impl OpDecl {
}
}
Ok(self.insert_into_op_dir(module, op_dir, prec))
self.insert_into_op_dir(op_dir);
Ok(())
}
}
pub fn fetch_atom_op_spec(
pub(crate) fn fetch_atom_op_spec(
name: ClauseName,
spec: Option<SharedOpDesc>,
op_dir: &OpDir,
@@ -521,7 +359,7 @@ pub fn fetch_atom_op_spec(
.or_else(|| fetch_op_spec_from_existing(name, 2, spec, op_dir))
}
pub fn fetch_op_spec_from_existing(
pub(crate) fn fetch_op_spec_from_existing(
name: ClauseName,
arity: usize,
spec: Option<SharedOpDesc>,
@@ -539,7 +377,7 @@ pub fn fetch_op_spec_from_existing(
spec.or_else(|| fetch_op_spec(name, arity, op_dir))
}
pub fn fetch_op_spec(
pub(crate) fn fetch_op_spec(
name: ClauseName,
arity: usize,
op_dir: &OpDir,
@@ -547,7 +385,7 @@ pub fn fetch_op_spec(
match arity {
2 => op_dir
.get(&(name, Fixity::In))
.and_then(|OpDirValue(spec, _)| {
.and_then(|OpDirValue(spec)| {
if spec.prec() > 0 {
Some(spec.clone())
} else {
@@ -555,15 +393,15 @@ pub fn fetch_op_spec(
}
}),
1 => {
if let Some(OpDirValue(spec, _)) = op_dir.get(&(name.clone(), Fixity::Pre)) {
if let Some(OpDirValue(spec)) = op_dir.get(&(name.clone(), Fixity::Pre)) {
if spec.prec() > 0 {
return Some(spec.clone());
}
}
op_dir
.get(&(name, Fixity::Post))
.and_then(|OpDirValue(spec, _)| {
.get(&(name.clone(), Fixity::Post))
.and_then(|OpDirValue(spec)| {
if spec.prec() > 0 {
Some(spec.clone())
} else {
@@ -571,46 +409,54 @@ pub fn fetch_op_spec(
}
})
}
_ => {
None
}
_ => None,
}
}
pub type ModuleDir = IndexMap<ClauseName, Module>;
pub(crate) type ModuleDir = IndexMap<ClauseName, Module>;
#[derive(Debug, Clone, PartialEq)]
pub enum ModuleExport {
#[derive(Debug, Clone, Eq, Hash, PartialEq)]
pub(crate) enum ModuleExport {
OpDecl(OpDecl),
PredicateKey(PredicateKey),
}
#[derive(Debug, Clone)]
pub struct ModuleDecl {
pub name: ClauseName,
pub exports: Vec<ModuleExport>,
pub(crate) struct ModuleDecl {
pub(crate) name: ClauseName,
pub(crate) exports: Vec<ModuleExport>,
}
#[derive(Debug)]
pub struct Module {
pub atom_tbl: TabledData<Atom>,
pub module_decl: ModuleDecl,
pub code_dir: CodeDir,
pub op_dir: OpDir,
pub term_dir: TermDir, // this contains multifile predicates.
pub term_expansions: (Predicate, VecDeque<TopLevel>),
pub goal_expansions: (Predicate, VecDeque<TopLevel>),
pub user_term_expansions: (Predicate, VecDeque<TopLevel>), // term expansions inherited from the user scope.
pub user_goal_expansions: (Predicate, VecDeque<TopLevel>), // same for goal_expansions.
pub local_term_expansions: (Predicate, VecDeque<TopLevel>), // expansions local to the module.
pub local_goal_expansions: (Predicate, VecDeque<TopLevel>),
pub inserted_expansions: bool, // has the module been successfully inserted into toplevel??
pub is_impromptu_module: bool,
pub listing_src: ListingSource,
}
pub(crate) struct Module {
pub(crate) module_decl: ModuleDecl,
pub(crate) code_dir: CodeDir,
pub(crate) op_dir: OpDir,
pub(crate) meta_predicates: MetaPredicateDir,
pub(crate) extensible_predicates: ExtensiblePredicates,
pub(crate) local_extensible_predicates: LocalExtensiblePredicates,
pub(crate) is_impromptu_module: bool,
pub(crate) listing_src: ListingSource,
}
// Module's and related types are defined in forms.
impl Module {
pub(crate) fn new(module_decl: ModuleDecl, listing_src: ListingSource) -> Self {
Module {
module_decl,
code_dir: CodeDir::new(),
op_dir: default_op_dir(),
meta_predicates: MetaPredicateDir::new(),
is_impromptu_module: false,
extensible_predicates: ExtensiblePredicates::new(),
local_extensible_predicates: LocalExtensiblePredicates::new(),
listing_src,
}
}
}
#[derive(Debug, Clone)]
pub enum Number {
pub(crate) enum Number {
Float(OrderedFloat<f64>),
Integer(Rc<Integer>),
Rational(Rc<Rational>),
@@ -668,10 +514,9 @@ impl Into<HeapCellValue> for Number {
}
}
impl Number {
#[inline]
pub fn is_positive(&self) -> bool {
pub(crate) fn is_positive(&self) -> bool {
match self {
&Number::Fixnum(n) => n > 0,
&Number::Integer(ref n) => &**n > &0,
@@ -681,7 +526,7 @@ impl Number {
}
#[inline]
pub fn is_negative(&self) -> bool {
pub(crate) fn is_negative(&self) -> bool {
match self {
&Number::Fixnum(n) => n < 0,
&Number::Integer(ref n) => &**n < &0,
@@ -691,7 +536,7 @@ impl Number {
}
#[inline]
pub fn is_zero(&self) -> bool {
pub(crate) fn is_zero(&self) -> bool {
match self {
&Number::Fixnum(n) => n == 0,
&Number::Integer(ref n) => &**n == &0,
@@ -701,17 +546,197 @@ impl Number {
}
#[inline]
pub fn abs(self) -> Self {
pub(crate) fn abs(self) -> Self {
match self {
Number::Fixnum(n) =>
Number::Fixnum(n) => {
if let Some(n) = n.checked_abs() {
Number::from(n)
} else {
Number::from(Integer::from(n).abs())
}
}
Number::Integer(n) => Number::from(Integer::from(n.abs_ref())),
Number::Float(f) => Number::Float(OrderedFloat(f.abs())),
Number::Rational(r) => Number::from(Rational::from(r.abs_ref())),
}
}
}
#[derive(Debug, Clone)]
pub(crate) enum OptArgIndexKey {
Constant(usize, usize, Constant, Vec<Constant>), // index, IndexingCode location, opt arg, alternatives
List(usize, usize), // index, IndexingCode location
None,
Structure(usize, usize, ClauseName, usize), // index, IndexingCode location, name, arity
}
impl OptArgIndexKey {
#[inline]
pub(crate) fn take(&mut self) -> OptArgIndexKey {
std::mem::replace(self, OptArgIndexKey::None)
}
#[inline]
pub(crate) fn arg_num(&self) -> usize {
match &self {
OptArgIndexKey::Constant(arg_num, ..)
| OptArgIndexKey::Structure(arg_num, ..)
| OptArgIndexKey::List(arg_num, _) => {
// these are always at least 1.
*arg_num
}
OptArgIndexKey::None => 0,
}
}
#[inline]
pub(crate) fn is_some(&self) -> bool {
self.switch_on_term_loc().is_some()
}
#[inline]
pub(crate) fn switch_on_term_loc(&self) -> Option<usize> {
match &self {
OptArgIndexKey::Constant(_, loc, ..)
| OptArgIndexKey::Structure(_, loc, ..)
| OptArgIndexKey::List(_, loc) => Some(*loc),
OptArgIndexKey::None => None,
}
}
#[inline]
pub(crate) fn set_switch_on_term_loc(&mut self, value: usize) {
match self {
OptArgIndexKey::Constant(_, ref mut loc, ..)
| OptArgIndexKey::Structure(_, ref mut loc, ..)
| OptArgIndexKey::List(_, ref mut loc) => {
*loc = value;
}
OptArgIndexKey::None => {}
}
}
}
impl AddAssign<usize> for OptArgIndexKey {
#[inline]
fn add_assign(&mut self, n: usize) {
match self {
OptArgIndexKey::Constant(_, ref mut o, ..)
| OptArgIndexKey::List(_, ref mut o)
| OptArgIndexKey::Structure(_, ref mut o, ..) => {
*o += n;
}
OptArgIndexKey::None => {}
}
}
}
#[derive(Clone, Debug)]
pub(crate) struct ClauseIndexInfo {
pub(crate) clause_start: usize,
pub(crate) opt_arg_index_key: OptArgIndexKey,
}
impl ClauseIndexInfo {
#[inline]
pub(crate) fn new(clause_start: usize) -> Self {
Self {
clause_start,
opt_arg_index_key: OptArgIndexKey::None,
// index_locs: vec![],
}
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct PredicateInfo {
pub(crate) is_extensible: bool,
pub(crate) is_discontiguous: bool,
pub(crate) is_dynamic: bool,
pub(crate) is_multifile: bool,
pub(crate) has_clauses: bool,
}
impl Default for PredicateInfo {
#[inline]
fn default() -> Self {
PredicateInfo {
is_extensible: false,
is_discontiguous: false,
is_dynamic: false,
is_multifile: false,
has_clauses: false,
}
}
}
impl PredicateInfo {
#[inline]
pub(crate) fn compile_incrementally(&self) -> bool {
let base = self.is_extensible && self.has_clauses;
base && (self.is_discontiguous || self.is_multifile)
}
#[inline]
pub(crate) fn must_retract_local_clauses(&self) -> bool {
self.is_extensible && self.has_clauses && !self.is_discontiguous
}
}
#[derive(Debug)]
pub(crate) struct PredicateSkeleton {
pub(crate) is_discontiguous: bool,
pub(crate) is_dynamic: bool,
pub(crate) is_multifile: bool,
pub(crate) clauses: SliceDeque<ClauseIndexInfo>,
pub(crate) clause_clause_locs: SliceDeque<usize>,
pub(crate) clause_assert_margin: usize,
}
impl PredicateSkeleton {
#[inline]
pub(crate) fn new() -> Self {
PredicateSkeleton {
is_discontiguous: false,
is_dynamic: false,
is_multifile: false,
clauses: sdeq![],
clause_clause_locs: sdeq![],
clause_assert_margin: 0,
}
}
#[inline]
pub(crate) fn predicate_info(&self) -> PredicateInfo {
PredicateInfo {
is_extensible: true,
is_discontiguous: self.is_discontiguous,
is_dynamic: self.is_dynamic,
is_multifile: self.is_multifile,
has_clauses: !self.clause_clause_locs.is_empty(),
}
}
#[inline]
pub(crate) fn reset(&mut self) {
self.clauses.clear();
self.clause_clause_locs.clear();
self.clause_assert_margin = 0;
}
pub(crate) fn target_pos_of_clause_clause_loc(
&self,
clause_clause_loc: usize,
) -> Option<usize> {
let search_result = self.clause_clause_locs[0..self.clause_assert_margin]
.binary_search_by(|loc| clause_clause_loc.cmp(&loc));
match search_result {
Ok(loc) => Some(loc),
Err(_) => self.clause_clause_locs[self.clause_assert_margin..]
.binary_search_by(|loc| loc.cmp(&clause_clause_loc))
.map(|loc| loc + self.clause_assert_margin)
.ok(),
}
}
}

View File

@@ -1,20 +1,20 @@
use crate::machine::machine_indices::*;
use crate::machine::machine_state::*;
use crate::indexmap::IndexSet;
use indexmap::IndexSet;
use std::cmp::Ordering;
use std::ops::Deref;
use std::vec::Vec;
#[derive(Debug)]
pub struct HCPreOrderIterator<'a> {
pub machine_st: &'a MachineState,
pub state_stack: Vec<Addr>,
pub(crate) struct HCPreOrderIterator<'a> {
pub(crate) machine_st: &'a MachineState,
pub(crate) state_stack: Vec<Addr>,
}
impl<'a> HCPreOrderIterator<'a> {
pub fn new(machine_st: &'a MachineState, a: Addr) -> Self {
pub(crate) fn new(machine_st: &'a MachineState, a: Addr) -> Self {
HCPreOrderIterator {
machine_st,
state_stack: vec![a],
@@ -22,35 +22,28 @@ impl<'a> HCPreOrderIterator<'a> {
}
#[inline]
pub fn machine_st(&self) -> &MachineState {
pub(crate) fn machine_st(&self) -> &MachineState {
&self.machine_st
}
fn follow_heap(&mut self, h: usize) -> Addr {
match &self.machine_st.heap[h] {
&HeapCellValue::NamedStr(arity, _, _) => {
for idx in (1 .. arity + 1).rev() {
for idx in (1..arity + 1).rev() {
self.state_stack.push(Addr::HeapCell(h + idx));
}
Addr::Str(h)
}
&HeapCellValue::Addr(a) => {
self.follow(a)
}
HeapCellValue::PartialString(..) => {
self.follow(Addr::PStrLocation(h, 0))
}
HeapCellValue::Atom(..) | HeapCellValue::DBRef(_)
| HeapCellValue::Integer(_) | HeapCellValue::Rational(_) => {
Addr::Con(h)
}
HeapCellValue::Stream(_) => {
Addr::Stream(h)
}
&HeapCellValue::TcpListener(_) => {
Addr::TcpListener(h)
}
&HeapCellValue::Addr(a) => self.follow(a),
HeapCellValue::PartialString(..) => self.follow(Addr::PStrLocation(h, 0)),
HeapCellValue::Atom(..)
| HeapCellValue::DBRef(_)
| HeapCellValue::Integer(_)
| HeapCellValue::Rational(_) => Addr::Con(h),
HeapCellValue::LoadStatePayload(_) => Addr::LoadStatePayload(h),
HeapCellValue::Stream(_) => Addr::Stream(h),
HeapCellValue::TcpListener(_) => Addr::TcpListener(h),
}
}
@@ -68,10 +61,12 @@ impl<'a> HCPreOrderIterator<'a> {
da
}
Addr::PStrLocation(h, n) => {
if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.machine_st.heap[h] {
if let Some(c) = pstr.range_from(n ..).next() {
if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.machine_st.heap[h]
{
if let Some(c) = pstr.range_from(n..).next() {
if !pstr.at_end(n + c.len_utf8()) {
self.state_stack.push(Addr::PStrLocation(h, n + c.len_utf8()));
self.state_stack
.push(Addr::PStrLocation(h, n + c.len_utf8()));
} else if has_tail {
self.state_stack.push(Addr::HeapCell(h + 1));
} else {
@@ -92,8 +87,9 @@ impl<'a> HCPreOrderIterator<'a> {
self.follow_heap(s) // record terms of structure.
}
Addr::Con(h) => {
if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.machine_st.heap[h] {
if let Some(c) = pstr.range_from(0 ..).next() {
if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.machine_st.heap[h]
{
if let Some(c) = pstr.range_from(0..).next() {
self.state_stack.push(Addr::PStrLocation(h, c.len_utf8()));
self.state_stack.push(Addr::Char(c));
@@ -107,9 +103,7 @@ impl<'a> HCPreOrderIterator<'a> {
Addr::Con(h)
}
}
da => {
da
}
da => da,
}
}
}
@@ -122,7 +116,9 @@ impl<'a> Iterator for HCPreOrderIterator<'a> {
}
}
pub trait MutStackHCIterator<'b> where Self: Iterator
pub(crate) trait MutStackHCIterator<'b>
where
Self: Iterator,
{
type MutStack;
@@ -130,7 +126,7 @@ pub trait MutStackHCIterator<'b> where Self: Iterator
}
#[derive(Debug)]
pub struct HCPostOrderIterator<'a> {
pub(crate) struct HCPostOrderIterator<'a> {
base_iter: HCPreOrderIterator<'a>,
parent_stack: Vec<(usize, Addr)>, // number of children, parent node.
}
@@ -144,7 +140,7 @@ impl<'a> Deref for HCPostOrderIterator<'a> {
}
impl<'a> HCPostOrderIterator<'a> {
pub fn new(base_iter: HCPreOrderIterator<'a>) -> Self {
pub(crate) fn new(base_iter: HCPreOrderIterator<'a>) -> Self {
HCPostOrderIterator {
base_iter,
parent_stack: vec![],
@@ -175,13 +171,18 @@ impl<'a> Iterator for HCPostOrderIterator<'a> {
}
&HeapCellValue::Addr(Addr::PStrLocation(h, n)) => {
match &self.machine_st.heap[h] {
&HeapCellValue::PartialString(ref pstr, _) => {
&HeapCellValue::PartialString(..) => {
// ref pstr, _) => {
/*
let c = pstr.range_from(n ..).next().unwrap();
let next_n = n + c.len_utf8();
if !pstr.at_end(next_n) {
self.parent_stack.push((2, Addr::PStrLocation(h, next_n)));
}
*/
// self.parent_stack.push((2, Addr::PStrLocation(h, next_n)));
// }
self.parent_stack.push((2, Addr::PStrLocation(h, n)));
}
_ => {
unreachable!()
@@ -200,19 +201,19 @@ impl<'a> Iterator for HCPostOrderIterator<'a> {
}
impl MachineState {
pub fn pre_order_iter<'a>(&'a self, a: Addr) -> HCPreOrderIterator<'a> {
pub(crate) fn pre_order_iter<'a>(&'a self, a: Addr) -> HCPreOrderIterator<'a> {
HCPreOrderIterator::new(self, a)
}
pub fn post_order_iter<'a>(&'a self, a: Addr) -> HCPostOrderIterator<'a> {
pub(crate) fn post_order_iter<'a>(&'a self, a: Addr) -> HCPostOrderIterator<'a> {
HCPostOrderIterator::new(HCPreOrderIterator::new(self, a))
}
pub fn acyclic_pre_order_iter<'a>(&'a self, a: Addr,) -> HCAcyclicIterator<'a> {
pub(crate) fn acyclic_pre_order_iter<'a>(&'a self, a: Addr) -> HCAcyclicIterator<'a> {
HCAcyclicIterator::new(HCPreOrderIterator::new(self, a))
}
pub fn zipped_acyclic_pre_order_iter<'a>(
pub(crate) fn zipped_acyclic_pre_order_iter<'a>(
&'a self,
a1: Addr,
a2: Addr,
@@ -233,13 +234,13 @@ impl<'b, 'a: 'b> MutStackHCIterator<'b> for HCPreOrderIterator<'a> {
}
#[derive(Debug)]
pub struct HCAcyclicIterator<'a> {
pub(crate) struct HCAcyclicIterator<'a> {
iter: HCPreOrderIterator<'a>,
seen: IndexSet<Addr>,
}
impl<'a> HCAcyclicIterator<'a> {
pub fn new(iter: HCPreOrderIterator<'a>) -> Self {
pub(crate) fn new(iter: HCPreOrderIterator<'a>) -> Self {
HCAcyclicIterator {
iter,
seen: IndexSet::new(),
@@ -263,8 +264,7 @@ impl<'b, 'a: 'b> MutStackHCIterator<'b> for HCAcyclicIterator<'a> {
}
}
impl<'a> Iterator for HCAcyclicIterator<'a>
{
impl<'a> Iterator for HCAcyclicIterator<'a> {
type Item = Addr;
fn next(&mut self) -> Option<Self::Item> {
@@ -282,11 +282,11 @@ impl<'a> Iterator for HCAcyclicIterator<'a>
}
#[derive(Debug)]
pub struct HCZippedAcyclicIterator<'a> {
pub(crate) struct HCZippedAcyclicIterator<'a> {
i1: HCPreOrderIterator<'a>,
i2: HCPreOrderIterator<'a>,
seen: IndexSet<(Addr, Addr)>,
pub first_to_expire: Ordering,
pub(crate) first_to_expire: Ordering,
}
impl<'b, 'a: 'b> MutStackHCIterator<'b> for HCZippedAcyclicIterator<'a> {
@@ -298,7 +298,7 @@ impl<'b, 'a: 'b> MutStackHCIterator<'b> for HCZippedAcyclicIterator<'a> {
}
impl<'a> HCZippedAcyclicIterator<'a> {
pub fn new(i1: HCPreOrderIterator<'a>, i2: HCPreOrderIterator<'a>) -> Self {
pub(crate) fn new(i1: HCPreOrderIterator<'a>, i2: HCPreOrderIterator<'a>) -> Self {
HCZippedAcyclicIterator {
i1,
i2,
@@ -308,8 +308,7 @@ impl<'a> HCZippedAcyclicIterator<'a> {
}
}
impl<'a> Iterator for HCZippedAcyclicIterator<'a>
{
impl<'a> Iterator for HCZippedAcyclicIterator<'a> {
type Item = (Addr, Addr);
fn next(&mut self) -> Option<Self::Item> {
@@ -334,9 +333,7 @@ impl<'a> Iterator for HCZippedAcyclicIterator<'a>
self.first_to_expire = Ordering::Less;
None
}
_ => {
None
}
_ => None,
}
}
}

View File

@@ -1,4 +1,10 @@
use crate::prolog_parser::ast::*;
use prolog_parser::ast::*;
use prolog_parser::{
alpha_numeric_char, capital_letter_char, clause_name, cut_char, decimal_digit_char,
graphic_token_char, is_fx, is_infix, is_postfix, is_prefix, is_xf, is_xfx, is_xfy, is_yfx,
semicolon_char, sign_char, single_quote_char, small_letter_char, solo_char,
variable_indicator_char,
};
use crate::clause_types::*;
use crate::forms::*;
@@ -7,21 +13,21 @@ use crate::machine::heap::*;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::*;
use crate::machine::streams::*;
use crate::ordered_float::OrderedFloat;
use crate::rug::{Integer, Rational};
use ordered_float::OrderedFloat;
use crate::indexmap::{IndexMap, IndexSet};
use indexmap::{IndexMap, IndexSet};
use std::cell::Cell;
use std::convert::TryFrom;
use std::iter::{FromIterator, once};
use std::iter::{once, FromIterator};
use std::net::{IpAddr, TcpListener};
use std::ops::{Range, RangeFrom};
use std::rc::Rc;
/* contains the location, name, precision and Specifier of the parent op. */
#[derive(Debug, Clone)]
pub enum DirectedOp {
pub(crate) enum DirectedOp {
Left(ClauseName, SharedOpDesc),
Right(ClauseName, SharedOpDesc),
}
@@ -99,10 +105,7 @@ impl<'a> HCPreOrderIterator<'a> {
None => return false,
};
let mut parent_spec = DirectedOp::Left(
clause_name!("-"),
SharedOpDesc::new(200, FY),
);
let mut parent_spec = DirectedOp::Left(clause_name!("-"), SharedOpDesc::new(200, FY));
loop {
match self.machine_st.store(self.machine_st.deref(addr)) {
@@ -154,12 +157,13 @@ fn char_to_string(is_quoted: bool, c: char) -> String {
'\u{07}' if is_quoted => "\\a".to_string(), // UTF-8 alert
'"' if is_quoted => "\\\"".to_string(),
'\\' if is_quoted => "\\\\".to_string(),
'\'' | '\n' | '\r' | '\t' | '\u{0b}' | '\u{0c}' | '\u{08}' | '\u{07}' | '"' | '\\' =>
c.to_string(),
'\u{a0}' ..= '\u{d6}' => c.to_string(),
'\u{d8}' ..= '\u{f6}' => c.to_string(),
'\u{f8}' ..= '\u{74f}' => c.to_string(),
'\x20' ..= '\x7e' => c.to_string(),
'\'' | '\n' | '\r' | '\t' | '\u{0b}' | '\u{0c}' | '\u{08}' | '\u{07}' | '"' | '\\' => {
c.to_string()
}
'\u{a0}'..='\u{d6}' => c.to_string(),
'\u{d8}'..='\u{f6}' => c.to_string(),
'\u{f8}'..='\u{74f}' => c.to_string(),
'\x20'..='\x7e' => c.to_string(),
_ => format!("\\x{:x}\\", c as u32),
}
}
@@ -186,7 +190,7 @@ enum TokenOrRedirect {
HeadTailSeparator,
}
pub trait HCValueOutputter {
pub(crate) trait HCValueOutputter {
type Output;
fn new() -> Self;
@@ -203,7 +207,7 @@ pub trait HCValueOutputter {
}
#[derive(Debug)]
pub struct PrinterOutputter {
pub(crate) struct PrinterOutputter {
contents: String,
}
@@ -271,25 +275,13 @@ fn is_numbered_var(ct: &ClauseType, arity: usize) -> bool {
#[inline]
fn negated_op_needs_bracketing(iter: &HCPreOrderIterator, op: &Option<DirectedOp>) -> bool {
if let Some(ref op) = op {
op.is_negative_sign() &&
iter.leftmost_leaf_has_property(|addr, heap| {
match Number::try_from((addr, heap)) {
Ok(Number::Fixnum(n)) => {
n > 0
}
Ok(Number::Float(f)) => {
f > OrderedFloat(0f64)
}
Ok(Number::Integer(n)) => {
&*n > &0
}
Ok(Number::Rational(n)) => {
&*n > &0
}
_ => {
false
}
}
op.is_negative_sign()
&& iter.leftmost_leaf_has_property(|addr, heap| match Number::try_from((addr, heap)) {
Ok(Number::Fixnum(n)) => n > 0,
Ok(Number::Float(f)) => f > OrderedFloat(0f64),
Ok(Number::Integer(n)) => &*n > &0,
Ok(Number::Rational(n)) => &*n > &0,
_ => false,
})
} else {
false
@@ -298,8 +290,8 @@ fn negated_op_needs_bracketing(iter: &HCPreOrderIterator, op: &Option<DirectedOp
fn numbervar(n: Integer) -> Var {
static CHAR_CODES: [char; 26] = [
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
];
let i = n.mod_u(26) as usize;
@@ -314,7 +306,7 @@ fn numbervar(n: Integer) -> Var {
}
impl MachineState {
pub fn numbervar(&self, offset: &Integer, addr: Addr) -> Option<Var> {
pub(crate) fn numbervar(&self, offset: &Integer, addr: Addr) -> Option<Var> {
let addr = self.store(self.deref(addr));
match Number::try_from((addr, &self.heap)) {
@@ -332,9 +324,7 @@ impl MachineState {
None
}
}
_ => {
None
}
_ => None,
}
}
}
@@ -342,7 +332,7 @@ impl MachineState {
type ReverseHeapVarDict = IndexMap<Addr, Rc<Var>>;
#[derive(Debug)]
pub struct HCPrinter<'a, Outputter> {
pub(crate) struct HCPrinter<'a, Outputter> {
outputter: Outputter,
machine_st: &'a MachineState,
op_dir: &'a OpDir,
@@ -373,7 +363,7 @@ macro_rules! push_space_if_amb {
};
}
pub fn requires_space(atom: &str, op: &str) -> bool {
pub(crate) fn requires_space(atom: &str, op: &str) -> bool {
match atom.chars().last() {
Some(ac) => op
.chars()
@@ -402,19 +392,6 @@ pub fn requires_space(atom: &str, op: &str) -> bool {
}
}
fn reverse_heap_locs<'a>(machine_st: &'a MachineState) -> ReverseHeapVarDict {
machine_st
.heap_locs
.iter()
.map(|(var, var_addr)| {
(
machine_st.store(machine_st.deref(var_addr.clone())),
var.clone(),
)
})
.collect()
}
fn non_quoted_graphic_token<Iter: Iterator<Item = char>>(mut iter: Iter, c: char) -> bool {
if c == '/' {
return match iter.next() {
@@ -444,8 +421,7 @@ fn non_quoted_graphic_token<Iter: Iterator<Item = char>>(mut iter: Iter, c: char
}
}
pub(super)
fn non_quoted_token<Iter: Iterator<Item = char>>(mut iter: Iter) -> bool {
pub(super) fn non_quoted_token<Iter: Iterator<Item = char>>(mut iter: Iter) -> bool {
if let Some(c) = iter.next() {
if small_letter_char!(c) {
iter.all(|c| alpha_numeric_char!(c))
@@ -482,7 +458,7 @@ fn functor_location(addr: &Addr) -> Option<usize> {
}
impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
pub fn new(machine_st: &'a MachineState, op_dir: &'a OpDir, output: Outputter) -> Self {
pub(crate) fn new(machine_st: &'a MachineState, op_dir: &'a OpDir, output: Outputter) -> Self {
HCPrinter {
outputter: output,
machine_st,
@@ -504,34 +480,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
}
}
pub fn from_heap_locs(
machine_st: &'a MachineState,
op_dir: &'a OpDir,
output: Outputter,
) -> Self {
let mut printer = Self::new(machine_st, op_dir, output);
printer.toplevel_spec = Some(DirectedOp::Right(
clause_name!("="),
SharedOpDesc::new(700, XFX),
));
printer.heap_locs = reverse_heap_locs(machine_st);
printer
}
pub fn drop_toplevel_spec(&mut self) {
self.toplevel_spec = None;
}
#[inline]
pub fn see_all_locs(&mut self) {
for key in self.heap_locs.keys().cloned() {
self.printed_vars.insert(key);
}
}
#[inline]
fn ambiguity_check(&self, atom: &str) -> bool {
let tail = self.outputter.range_from(self.last_item_idx..);
@@ -550,7 +498,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
iter.stack().pop();
self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec));
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack
.push(TokenOrRedirect::Atom(clause_name!("...")));
return;
}
@@ -574,7 +523,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
if self.check_max_depth(&mut max_depth) {
iter.stack().pop();
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack
.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec));
return;
@@ -582,7 +532,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
let left_directed_op = DirectedOp::Left(ct.name(), spec.clone());
self.state_stack.push(TokenOrRedirect::CompositeRedirect(max_depth, left_directed_op));
self.state_stack.push(TokenOrRedirect::CompositeRedirect(
max_depth,
left_directed_op,
));
self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec));
} else {
match ct.name().as_str() {
@@ -597,9 +550,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
iter.stack().pop();
iter.stack().pop();
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack
.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec));
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack
.push(TokenOrRedirect::Atom(clause_name!("...")));
return;
}
@@ -607,11 +562,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
let left_directed_op = DirectedOp::Left(ct.name(), spec.clone());
let right_directed_op = DirectedOp::Right(ct.name(), spec.clone());
self.state_stack
.push(TokenOrRedirect::CompositeRedirect(max_depth, left_directed_op));
self.state_stack.push(TokenOrRedirect::CompositeRedirect(
max_depth,
left_directed_op,
));
self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec));
self.state_stack
.push(TokenOrRedirect::CompositeRedirect(max_depth, right_directed_op));
self.state_stack.push(TokenOrRedirect::CompositeRedirect(
max_depth,
right_directed_op,
));
}
}
@@ -621,15 +580,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
mut max_depth: usize,
arity: usize,
name: ClauseName,
) -> bool
{
) -> bool {
if self.check_max_depth(&mut max_depth) {
for _ in 0 .. arity {
for _ in 0..arity {
iter.stack().pop();
}
self.state_stack.push(TokenOrRedirect::Close);
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack
.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack.push(TokenOrRedirect::Open);
self.state_stack.push(TokenOrRedirect::Atom(name));
@@ -639,8 +598,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.state_stack.push(TokenOrRedirect::Close);
for _ in 0 .. arity {
self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
for _ in 0..arity {
self.state_stack
.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack.push(TokenOrRedirect::Comma);
}
@@ -657,12 +617,13 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
iter: &mut HCPreOrderIterator,
mut max_depth: usize,
name: ClauseName,
spec: SharedOpDesc)
{
spec: SharedOpDesc,
) {
if self.check_max_depth(&mut max_depth) {
iter.stack().pop();
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack
.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack.push(TokenOrRedirect::Space);
self.state_stack.push(TokenOrRedirect::Atom(name));
@@ -671,7 +632,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
let op = DirectedOp::Left(name.clone(), spec);
self.state_stack.push(TokenOrRedirect::CompositeRedirect(max_depth, op));
self.state_stack
.push(TokenOrRedirect::CompositeRedirect(max_depth, op));
self.state_stack.push(TokenOrRedirect::Space);
self.state_stack.push(TokenOrRedirect::Atom(name));
}
@@ -682,14 +644,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
mut max_depth: usize,
name: ClauseName,
spec: SharedOpDesc,
)
{
) {
if self.check_max_depth(&mut max_depth) {
iter.stack().pop();
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack
.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack.push(TokenOrRedirect::BarAsOp);
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack
.push(TokenOrRedirect::Atom(clause_name!("...")));
return;
}
@@ -697,25 +660,32 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
let left_directed_op = DirectedOp::Left(name.clone(), spec.clone());
let right_directed_op = DirectedOp::Right(name.clone(), spec.clone());
self.state_stack.push(TokenOrRedirect::CompositeRedirect(max_depth, left_directed_op));
self.state_stack.push(TokenOrRedirect::CompositeRedirect(
max_depth,
left_directed_op,
));
self.state_stack.push(TokenOrRedirect::BarAsOp);
self.state_stack.push(TokenOrRedirect::CompositeRedirect(max_depth, right_directed_op));
self.state_stack.push(TokenOrRedirect::CompositeRedirect(
max_depth,
right_directed_op,
));
}
fn format_curly_braces(&mut self, iter: &mut HCPreOrderIterator, mut max_depth: usize) -> bool
{
fn format_curly_braces(&mut self, iter: &mut HCPreOrderIterator, mut max_depth: usize) -> bool {
if self.check_max_depth(&mut max_depth) {
iter.stack().pop();
self.state_stack.push(TokenOrRedirect::RightCurly);
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack
.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack.push(TokenOrRedirect::LeftCurly);
return false;
}
self.state_stack.push(TokenOrRedirect::RightCurly);
self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack
.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack.push(TokenOrRedirect::LeftCurly);
true
@@ -790,18 +760,12 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
}
match addr {
Addr::Lis(h) | Addr::Str(h) => {
Some(format!("{}", h))
}
Addr::Lis(h) | Addr::Str(h) => Some(format!("{}", h)),
_ => {
if let Some(r) = addr.as_var() {
match r {
Ref::StackCell(fr, sc) => {
Some(format!("_s_{}_{}", fr, sc))
}
Ref::HeapCell(h) | Ref::AttrVar(h) => {
Some(format!("_{}", h))
}
Ref::StackCell(fr, sc) => Some(format!("_s_{}_{}", fr, sc)),
Ref::HeapCell(h) | Ref::AttrVar(h) => Some(format!("_{}", h)),
}
} else {
None
@@ -813,8 +777,12 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
fn record_children_as_non_cyclic(&mut self, addr: &Addr) {
match addr {
&Addr::Lis(l) => {
let c1 = self.machine_st.store(self.machine_st.deref(Addr::HeapCell(l)));
let c2 = self.machine_st.store(self.machine_st.deref(Addr::HeapCell(l + 1)));
let c1 = self
.machine_st
.store(self.machine_st.deref(Addr::HeapCell(l)));
let c2 = self
.machine_st
.store(self.machine_st.deref(Addr::HeapCell(l + 1)));
if let Some(c) = functor_location(&c1) {
self.non_cyclic_terms.insert(c);
@@ -825,18 +793,17 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
}
}
&Addr::Str(s) => {
let arity =
match &self.machine_st.heap[s] {
HeapCellValue::NamedStr(arity, ..) => {
arity
}
_ => {
unreachable!()
}
};
let arity = match &self.machine_st.heap[s] {
HeapCellValue::NamedStr(arity, ..) => arity,
_ => {
unreachable!()
}
};
for i in 1 .. arity + 1 {
let c = self.machine_st.store(self.machine_st.deref(Addr::HeapCell(s + i)));
for i in 1..arity + 1 {
let c = self
.machine_st
.store(self.machine_st.deref(Addr::HeapCell(s + i)));
if let Some(c) = functor_location(&c) {
self.non_cyclic_terms.insert(c);
@@ -851,15 +818,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.non_cyclic_terms.insert(c);
}
}
_ => {
}
_ => {}
}
}
fn check_for_seen(
&mut self,
iter: &mut HCPreOrderIterator,
) -> Option<Addr> {
fn check_for_seen(&mut self, iter: &mut HCPreOrderIterator) -> Option<Addr> {
iter.stack().last().cloned().and_then(|addr| {
let addr = self.machine_st.store(self.machine_st.deref(addr));
@@ -884,9 +847,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
}
None => {
let offset = match functor_location(&addr) {
Some(offset) => {
offset
}
Some(offset) => offset,
None => {
return iter.next();
}
@@ -1024,26 +985,24 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
fn print_rational(&mut self, r: &Rational, add_brackets: bool) {
match self.op_dir.get(&(clause_name!("rdiv"), Fixity::In)) {
Some(OpDirValue(ref spec, _)) => {
Some(OpDirValue(ref spec)) => {
if add_brackets {
self.state_stack.push(TokenOrRedirect::Close);
}
let rdiv_ct = clause_name!("rdiv");
let left_directed_op =
if spec.prec() > 0 {
Some(DirectedOp::Left(rdiv_ct.clone(), spec.clone()))
} else {
None
};
let left_directed_op = if spec.prec() > 0 {
Some(DirectedOp::Left(rdiv_ct.clone(), spec.clone()))
} else {
None
};
let right_directed_op =
if spec.prec() > 0 {
Some(DirectedOp::Right(rdiv_ct.clone(), spec.clone()))
} else {
None
};
let right_directed_op = if spec.prec() > 0 {
Some(DirectedOp::Right(rdiv_ct.clone(), spec.clone()))
} else {
None
};
if spec.prec() > 0 {
self.state_stack.push(TokenOrRedirect::Number(
@@ -1051,10 +1010,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
left_directed_op,
));
self.state_stack.push(TokenOrRedirect::Op(
rdiv_ct,
spec.clone(),
));
self.state_stack
.push(TokenOrRedirect::Op(rdiv_ct, spec.clone()));
self.state_stack.push(TokenOrRedirect::Number(
Number::from(r.numer()),
@@ -1063,17 +1020,13 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} else {
self.state_stack.push(TokenOrRedirect::Close);
self.state_stack.push(TokenOrRedirect::Number(
Number::from(r.denom()),
None,
));
self.state_stack
.push(TokenOrRedirect::Number(Number::from(r.denom()), None));
self.state_stack.push(TokenOrRedirect::Comma);
self.state_stack.push(TokenOrRedirect::Number(
Number::from(r.numer()),
None,
));
self.state_stack
.push(TokenOrRedirect::Number(Number::from(r.numer()), None));
self.state_stack.push(TokenOrRedirect::Open);
self.state_stack.push(TokenOrRedirect::Atom(rdiv_ct));
@@ -1087,8 +1040,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
}
}
fn print_char(&mut self, is_quoted: bool, c: char)
{
fn print_char(&mut self, is_quoted: bool, c: char) {
if non_quoted_token(once(c)) {
let c = char_to_string(false, c);
@@ -1115,46 +1067,37 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
fn print_proper_string(&mut self, buf: String, max_depth: usize) {
self.push_char('"');
let buf =
if max_depth == 0 {
String::from_iter(buf.chars().map(|c| {
char_to_string(self.quoted, c)
}))
} else {
let mut char_count = 0;
let mut buf =
String::from_iter(buf.chars().take(max_depth).map(|c| {
char_count += 1;
char_to_string(self.quoted, c)
}));
let buf = if max_depth == 0 {
String::from_iter(buf.chars().map(|c| char_to_string(self.quoted, c)))
} else {
let mut char_count = 0;
let mut buf = String::from_iter(buf.chars().take(max_depth).map(|c| {
char_count += 1;
char_to_string(self.quoted, c)
}));
if char_count == max_depth {
buf += " ...";
}
if char_count == max_depth {
buf += " ...";
}
buf
};
buf
};
self.append_str(&buf);
self.push_char('"');
}
fn print_list_like(
&mut self,
iter: &mut HCPreOrderIterator,
addr: Addr,
mut max_depth: usize,
) {
fn print_list_like(&mut self, iter: &mut HCPreOrderIterator, addr: Addr, mut max_depth: usize) {
if self.check_max_depth(&mut max_depth) {
iter.stack().pop();
iter.stack().pop();
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack
.push(TokenOrRedirect::Atom(clause_name!("...")));
return;
}
let mut heap_pstr_iter =
self.machine_st.heap_pstr_iter(addr);
let mut heap_pstr_iter = self.machine_st.heap_pstr_iter(addr);
let buf = heap_pstr_iter.to_string();
@@ -1179,12 +1122,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
let buf_len = buf.len();
let buf_iter: Box<dyn Iterator<Item=char>> =
if self.max_depth == 0 {
Box::new(buf.chars())
} else {
Box::new(buf.chars().take(max_depth))
};
let buf_iter: Box<dyn Iterator<Item = char>> = if self.max_depth == 0 {
Box::new(buf.chars())
} else {
Box::new(buf.chars().take(max_depth))
};
let mut byte_len = 0;
@@ -1202,14 +1144,16 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
byte_len += c.len_utf8();
}
for _ in 0 .. char_count {
for _ in 0..char_count {
self.state_stack.push(TokenOrRedirect::Close);
}
if self.max_depth > 0 && buf_len > byte_len {
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack
.push(TokenOrRedirect::Atom(clause_name!("...")));
} else {
self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack
.push(TokenOrRedirect::FunctorRedirect(max_depth));
iter.stack().push(end_addr);
}
} else {
@@ -1227,15 +1171,17 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
byte_len += c.len_utf8();
}
self.state_stack.push(TokenOrRedirect::CloseList(Rc::new(
Cell::new((switch, 0))
)));
self.state_stack
.push(TokenOrRedirect::CloseList(Rc::new(Cell::new((switch, 0)))));
if self.max_depth > 0 && buf_len > byte_len {
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
} else {
self.outputter.truncate(self.outputter.len() - ','.len_utf8());
self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack
.push(TokenOrRedirect::Atom(clause_name!("...")));
} else {
self.outputter
.truncate(self.outputter.len() - ','.len_utf8());
self.state_stack
.push(TokenOrRedirect::FunctorRedirect(max_depth));
iter.stack().push(end_addr);
}
@@ -1263,8 +1209,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
let cell = Rc::new(Cell::new((true, 0)));
self.state_stack.push(TokenOrRedirect::CloseList(cell.clone()));
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack
.push(TokenOrRedirect::CloseList(cell.clone()));
self.state_stack
.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack.push(TokenOrRedirect::OpenList(cell));
return;
@@ -1272,11 +1220,14 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
let cell = Rc::new(Cell::new((true, max_depth)));
self.state_stack.push(TokenOrRedirect::CloseList(cell.clone()));
self.state_stack
.push(TokenOrRedirect::CloseList(cell.clone()));
self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack
.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack.push(TokenOrRedirect::HeadTailSeparator); // bar
self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack
.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack.push(TokenOrRedirect::OpenList(cell));
}
@@ -1293,23 +1244,24 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
max_depth: usize,
) {
let add_brackets = if !self.ignore_ops {
negated_operand || if let Some(ref op) = op {
if self.numbervars && arity == 1 && name.as_str() == "$VAR" {
!iter.immediate_leaf_has_property(|addr, heap| {
match heap.index_addr(&addr).as_ref() {
&HeapCellValue::Integer(ref n) => &**n >= &0,
&HeapCellValue::Addr(Addr::Fixnum(n)) => n >= 0,
&HeapCellValue::Addr(Addr::Float(f)) => f >= OrderedFloat(0f64),
&HeapCellValue::Rational(ref r) => &**r >= &0,
_ => false
}
}) && needs_bracketing(&spec, op)
negated_operand
|| if let Some(ref op) = op {
if self.numbervars && arity == 1 && name.as_str() == "$VAR" {
!iter.immediate_leaf_has_property(|addr, heap| {
match heap.index_addr(&addr).as_ref() {
&HeapCellValue::Integer(ref n) => &**n >= &0,
&HeapCellValue::Addr(Addr::Fixnum(n)) => n >= 0,
&HeapCellValue::Addr(Addr::Float(f)) => f >= OrderedFloat(0f64),
&HeapCellValue::Rational(ref r) => &**r >= &0,
_ => false,
}
}) && needs_bracketing(&spec, op)
} else {
needs_bracketing(&spec, op)
}
} else {
needs_bracketing(&spec, op)
is_functor_redirect && spec.prec() >= 1000
}
} else {
is_functor_redirect && spec.prec() >= 1000
}
} else {
false
};
@@ -1339,15 +1291,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
tcp_listener: &TcpListener,
max_depth: usize,
) {
let (ip, port) =
if let Some(addr) = tcp_listener.local_addr().ok() {
(addr.ip(), Number::from(addr.port() as isize))
} else {
let disconnected_atom = clause_name!("$disconnected_tcp_listener");
self.state_stack.push(TokenOrRedirect::Atom(disconnected_atom));
let (ip, port) = if let Some(addr) = tcp_listener.local_addr().ok() {
(addr.ip(), Number::from(addr.port() as isize))
} else {
let disconnected_atom = clause_name!("$disconnected_tcp_listener");
self.state_stack
.push(TokenOrRedirect::Atom(disconnected_atom));
return;
};
return;
};
if self.format_struct(iter, max_depth, 1, clause_name!("$tcp_listener")) {
let atom = self.state_stack.pop().unwrap();
@@ -1364,22 +1316,16 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
}
}
fn print_stream(
&mut self,
iter: &mut HCPreOrderIterator,
stream: &Stream,
max_depth: usize,
) {
if let Some(alias) = &stream.options.alias {
fn print_stream(&mut self, iter: &mut HCPreOrderIterator, stream: &Stream, max_depth: usize) {
if let Some(alias) = &stream.options().alias {
self.print_atom(alias);
} else {
if self.format_struct(iter, max_depth, 1, clause_name!("$stream")) {
let atom =
if stream.is_stdout() || stream.is_stdin() {
TokenOrRedirect::Atom(clause_name!("user"))
} else {
TokenOrRedirect::RawPtr(stream.as_ptr())
};
let atom = if stream.is_stdout() || stream.is_stdin() {
TokenOrRedirect::Atom(clause_name!("user"))
} else {
TokenOrRedirect::RawPtr(stream.as_ptr())
};
let stream_root = self.state_stack.pop().unwrap();
@@ -1409,7 +1355,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
match self.machine_st.heap.index_addr(&addr).as_ref() {
&HeapCellValue::NamedStr(arity, ref name, ref spec) => {
let spec = fetch_op_spec_from_existing(name.clone(), arity, spec.clone(), self.op_dir);
let spec =
fetch_op_spec_from_existing(name.clone(), arity, spec.clone(), self.op_dir);
if let Some(spec) = spec {
self.handle_op_as_struct(
@@ -1524,7 +1471,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
}
}
pub fn print(mut self, addr: Addr) -> Outputter {
pub(crate) fn print(mut self, addr: Addr) -> Outputter {
let mut iter = self.machine_st.pre_order_iter(addr);
loop {

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,18 @@
use crate::prolog_parser::ast::*;
use prolog_parser::ast::*;
use prolog_parser::clause_name;
use crate::clause_types::*;
use crate::forms::*;
use crate::indexing::IndexingCodePtr;
use crate::machine::heap::*;
use crate::machine::machine_errors::MachineStub;
use crate::machine::machine_indices::*;
use crate::rug::Integer;
use crate::indexmap::IndexMap;
use indexmap::IndexMap;
use slice_deque::SliceDeque;
use std::collections::VecDeque;
use std::rc::Rc;
fn reg_type_into_functor(r: RegType) -> MachineStub {
@@ -32,9 +35,7 @@ impl Level {
impl ArithmeticTerm {
fn into_functor(&self) -> MachineStub {
match self {
&ArithmeticTerm::Reg(r) => {
reg_type_into_functor(r)
}
&ArithmeticTerm::Reg(r) => reg_type_into_functor(r),
&ArithmeticTerm::Interm(i) => {
functor!("intermediate", [integer(i)])
}
@@ -45,39 +46,132 @@ impl ArithmeticTerm {
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum NextOrFail {
Next(usize),
Fail(usize),
}
impl NextOrFail {
#[inline]
pub fn is_next(&self) -> bool {
if let NextOrFail::Next(_) = self {
true
} else {
false
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) enum Death {
Finite(usize),
Infinity,
}
#[derive(Debug)]
pub enum ChoiceInstruction {
pub(crate) enum ChoiceInstruction {
DynamicElse(usize, Death, NextOrFail),
DynamicInternalElse(usize, Death, NextOrFail),
DefaultRetryMeElse(usize),
DefaultTrustMe,
DefaultTrustMe(usize),
RetryMeElse(usize),
TrustMe,
TrustMe(usize),
TryMeElse(usize),
}
impl ChoiceInstruction {
pub fn to_functor(&self) -> MachineStub {
pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
match self {
&ChoiceInstruction::DynamicElse(birth, death, next_or_fail) => {
match (death, next_or_fail) {
(Death::Infinity, NextOrFail::Next(i)) => {
functor!(
"dynamic_else",
[integer(birth), atom("inf"), integer(i)]
)
}
(Death::Infinity, NextOrFail::Fail(i)) => {
let next_functor = functor!("fail", [integer(i)]);
functor!(
"dynamic_else",
[integer(birth), atom("inf"), aux(h, 0)],
[next_functor]
)
}
(Death::Finite(d), NextOrFail::Fail(i)) => {
let next_functor = functor!("fail", [integer(i)]);
functor!(
"dynamic_else",
[integer(birth), integer(d), aux(h, 0)],
[next_functor]
)
}
(Death::Finite(d), NextOrFail::Next(i)) => {
functor!(
"dynamic_else",
[integer(birth), integer(d), integer(i)]
)
}
}
}
&ChoiceInstruction::DynamicInternalElse(birth, death, next_or_fail) => {
match (death, next_or_fail) {
(Death::Infinity, NextOrFail::Next(i)) => {
functor!(
"dynamic_internal_else",
[integer(birth), atom("inf"), integer(i)]
)
}
(Death::Infinity, NextOrFail::Fail(i)) => {
let next_functor = functor!("fail", [integer(i)]);
functor!(
"dynamic_internal_else",
[integer(birth), atom("inf"), aux(h, 0)],
[next_functor]
)
}
(Death::Finite(d), NextOrFail::Fail(i)) => {
let next_functor = functor!("fail", [integer(i)]);
functor!(
"dynamic_internal_else",
[integer(birth), integer(d), aux(h, 0)],
[next_functor]
)
}
(Death::Finite(d), NextOrFail::Next(i)) => {
functor!(
"dynamic_internal_else",
[integer(birth), integer(d), integer(i)]
)
}
}
}
&ChoiceInstruction::TryMeElse(offset) => {
functor!("try_me_else", [integer(offset)])
}
&ChoiceInstruction::RetryMeElse(offset) => {
functor!("retry_me_else", [integer(offset)])
}
&ChoiceInstruction::TrustMe => {
functor!("trust_me")
&ChoiceInstruction::TrustMe(offset) => {
functor!("trust_me", [integer(offset)])
}
&ChoiceInstruction::DefaultRetryMeElse(offset) => {
functor!("default_retry_me_else", [integer(offset)])
}
&ChoiceInstruction::DefaultTrustMe => {
functor!("default_trust_me")
&ChoiceInstruction::DefaultTrustMe(offset) => {
functor!("default_trust_me", [integer(offset)])
}
}
}
}
#[derive(Debug)]
pub enum CutInstruction {
pub(crate) enum CutInstruction {
Cut(RegType),
GetLevel(RegType),
GetLevelAndUnify(RegType),
@@ -85,7 +179,7 @@ pub enum CutInstruction {
}
impl CutInstruction {
pub fn to_functor(&self, h: usize) -> MachineStub {
pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
match self {
&CutInstruction::Cut(r) => {
let rt_stub = reg_type_into_functor(r);
@@ -106,21 +200,15 @@ impl CutInstruction {
}
}
#[derive(Debug)]
pub enum IndexedChoiceInstruction {
#[derive(Clone, Copy, Debug)]
pub(crate) enum IndexedChoiceInstruction {
Retry(usize),
Trust(usize),
Try(usize),
}
impl From<IndexedChoiceInstruction> for Line {
fn from(i: IndexedChoiceInstruction) -> Self {
Line::IndexedChoice(i)
}
}
impl IndexedChoiceInstruction {
pub fn offset(&self) -> usize {
pub(crate) fn offset(&self) -> usize {
match self {
&IndexedChoiceInstruction::Retry(offset) => offset,
&IndexedChoiceInstruction::Trust(offset) => offset,
@@ -128,7 +216,7 @@ impl IndexedChoiceInstruction {
}
}
pub fn to_functor(&self) -> MachineStub {
pub(crate) fn to_functor(&self) -> MachineStub {
match self {
&IndexedChoiceInstruction::Try(offset) => {
functor!("try", [integer(offset)])
@@ -145,43 +233,110 @@ impl IndexedChoiceInstruction {
/// A `Line` is an instruction (cf. page 98 of wambook).
#[derive(Debug)]
pub enum Line {
pub(crate) enum IndexingLine {
Indexing(IndexingInstruction),
IndexedChoice(SliceDeque<IndexedChoiceInstruction>),
DynamicIndexedChoice(SliceDeque<usize>),
}
impl From<IndexingInstruction> for IndexingLine {
#[inline]
fn from(instr: IndexingInstruction) -> Self {
IndexingLine::Indexing(instr)
}
}
impl From<SliceDeque<IndexedChoiceInstruction>> for IndexingLine {
#[inline]
fn from(instrs: SliceDeque<IndexedChoiceInstruction>) -> Self {
IndexingLine::IndexedChoice(instrs)
}
}
#[derive(Debug)]
pub(crate) enum Line {
Arithmetic(ArithmeticInstruction),
Choice(ChoiceInstruction),
Control(ControlInstruction),
Cut(CutInstruction),
Fact(FactInstruction),
Indexing(IndexingInstruction),
IndexingCode(Vec<IndexingLine>),
IndexedChoice(IndexedChoiceInstruction),
DynamicIndexedChoice(usize),
Query(QueryInstruction),
}
impl Line {
pub fn is_head_instr(&self) -> bool {
#[inline]
pub(crate) fn is_head_instr(&self) -> bool {
match self {
&Line::Cut(_) => true,
&Line::Fact(_) => true,
&Line::Query(_) => true,
_ => false,
}
}
pub fn to_functor(&self, h: usize) -> MachineStub {
pub(crate) fn enqueue_functors(&self, mut h: usize, functors: &mut Vec<MachineStub>) {
match self {
&Line::Arithmetic(ref arith_instr) => arith_instr.to_functor(h),
&Line::Choice(ref choice_instr) => choice_instr.to_functor(),
&Line::Control(ref control_instr) => control_instr.to_functor(),
&Line::Cut(ref cut_instr) => cut_instr.to_functor(h),
&Line::Fact(ref fact_instr) => fact_instr.to_functor(h),
&Line::Indexing(ref indexing_instr) => indexing_instr.to_functor(),
&Line::IndexedChoice(ref indexed_choice_instr) => indexed_choice_instr.to_functor(),
&Line::Query(ref query_instr) => query_instr.to_functor(h),
&Line::Arithmetic(ref arith_instr) => functors.push(arith_instr.to_functor(h)),
&Line::Choice(ref choice_instr) => functors.push(choice_instr.to_functor(h)),
&Line::Control(ref control_instr) => functors.push(control_instr.to_functor()),
&Line::Cut(ref cut_instr) => functors.push(cut_instr.to_functor(h)),
&Line::Fact(ref fact_instr) => functors.push(fact_instr.to_functor(h)),
&Line::IndexingCode(ref indexing_instrs) => {
for indexing_instr in indexing_instrs {
match indexing_instr {
IndexingLine::Indexing(indexing_instr) => {
let section = indexing_instr.to_functor(h);
h += section.len();
functors.push(section);
}
IndexingLine::IndexedChoice(indexed_choice_instrs) => {
for indexed_choice_instr in indexed_choice_instrs {
let section = indexed_choice_instr.to_functor();
h += section.len();
functors.push(section);
}
}
IndexingLine::DynamicIndexedChoice(indexed_choice_instrs) => {
for indexed_choice_instr in indexed_choice_instrs {
let section = functor!("dynamic", [integer(*indexed_choice_instr)]);
h += section.len();
functors.push(section);
}
}
}
}
}
&Line::IndexedChoice(ref indexed_choice_instr) => {
functors.push(indexed_choice_instr.to_functor())
}
&Line::DynamicIndexedChoice(ref indexed_choice_instr) => {
functors.push(functor!("dynamic", [integer(*indexed_choice_instr)]));
}
&Line::Query(ref query_instr) => functors.push(query_instr.to_functor(h)),
}
}
}
#[inline]
pub(crate) fn to_indexing_line_mut(line: &mut Line) -> Option<&mut Vec<IndexingLine>> {
match line {
Line::IndexingCode(ref mut indexing_code) => Some(indexing_code),
_ => None,
}
}
#[inline]
pub(crate) fn to_indexing_line(line: &Line) -> Option<&Vec<IndexingLine>> {
match line {
Line::IndexingCode(ref indexing_code) => Some(indexing_code),
_ => None,
}
}
#[derive(Debug, Clone)]
pub enum ArithmeticInstruction {
pub(crate) enum ArithmeticInstruction {
Add(ArithmeticTerm, ArithmeticTerm, usize),
Sub(ArithmeticTerm, ArithmeticTerm, usize),
Mul(ArithmeticTerm, ArithmeticTerm, usize),
@@ -231,11 +386,7 @@ fn arith_instr_unary_functor(
) -> MachineStub {
let at_stub = at.into_functor();
functor!(
name,
[aux(h, 0), integer(t)],
[at_stub]
)
functor!(name, [aux(h, 0), integer(t)], [at_stub])
}
fn arith_instr_bin_functor(
@@ -256,7 +407,7 @@ fn arith_instr_bin_functor(
}
impl ArithmeticInstruction {
pub fn to_functor(&self, h: usize) -> MachineStub {
pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
match self {
&ArithmeticInstruction::Add(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "add", at_1, at_2, t)
@@ -318,39 +469,17 @@ impl ArithmeticInstruction {
&ArithmeticInstruction::Gcd(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "gcd", at_1, at_2, t)
}
&ArithmeticInstruction::Sign(ref at, t) => {
arith_instr_unary_functor(h, "sign", at, t)
}
&ArithmeticInstruction::Cos(ref at, t) => {
arith_instr_unary_functor(h, "cos", at, t)
}
&ArithmeticInstruction::Sin(ref at, t) => {
arith_instr_unary_functor(h, "sin", at, t)
}
&ArithmeticInstruction::Tan(ref at, t) => {
arith_instr_unary_functor(h, "tan", at, t)
}
&ArithmeticInstruction::Log(ref at, t) => {
arith_instr_unary_functor(h, "log", at, t)
}
&ArithmeticInstruction::Exp(ref at, t) => {
arith_instr_unary_functor(h, "exp", at, t)
}
&ArithmeticInstruction::ACos(ref at, t) => {
arith_instr_unary_functor(h, "acos", at, t)
}
&ArithmeticInstruction::ASin(ref at, t) => {
arith_instr_unary_functor(h, "asin", at, t)
}
&ArithmeticInstruction::ATan(ref at, t) => {
arith_instr_unary_functor(h, "atan", at, t)
}
&ArithmeticInstruction::Sqrt(ref at, t) => {
arith_instr_unary_functor(h, "sqrt", at, t)
}
&ArithmeticInstruction::Abs(ref at, t) => {
arith_instr_unary_functor(h, "abs", at, t)
}
&ArithmeticInstruction::Sign(ref at, t) => arith_instr_unary_functor(h, "sign", at, t),
&ArithmeticInstruction::Cos(ref at, t) => arith_instr_unary_functor(h, "cos", at, t),
&ArithmeticInstruction::Sin(ref at, t) => arith_instr_unary_functor(h, "sin", at, t),
&ArithmeticInstruction::Tan(ref at, t) => arith_instr_unary_functor(h, "tan", at, t),
&ArithmeticInstruction::Log(ref at, t) => arith_instr_unary_functor(h, "log", at, t),
&ArithmeticInstruction::Exp(ref at, t) => arith_instr_unary_functor(h, "exp", at, t),
&ArithmeticInstruction::ACos(ref at, t) => arith_instr_unary_functor(h, "acos", at, t),
&ArithmeticInstruction::ASin(ref at, t) => arith_instr_unary_functor(h, "asin", at, t),
&ArithmeticInstruction::ATan(ref at, t) => arith_instr_unary_functor(h, "atan", at, t),
&ArithmeticInstruction::Sqrt(ref at, t) => arith_instr_unary_functor(h, "sqrt", at, t),
&ArithmeticInstruction::Abs(ref at, t) => arith_instr_unary_functor(h, "abs", at, t),
&ArithmeticInstruction::Float(ref at, t) => {
arith_instr_unary_functor(h, "float", at, t)
}
@@ -366,12 +495,8 @@ impl ArithmeticInstruction {
&ArithmeticInstruction::Floor(ref at, t) => {
arith_instr_unary_functor(h, "floor", at, t)
}
&ArithmeticInstruction::Neg(ref at, t) => {
arith_instr_unary_functor(h, "-", at, t)
}
&ArithmeticInstruction::Plus(ref at, t) => {
arith_instr_unary_functor(h, "+", at, t)
}
&ArithmeticInstruction::Neg(ref at, t) => arith_instr_unary_functor(h, "-", at, t),
&ArithmeticInstruction::Plus(ref at, t) => arith_instr_unary_functor(h, "+", at, t),
&ArithmeticInstruction::BitwiseComplement(ref at, t) => {
arith_instr_unary_functor(h, "\\", at, t)
}
@@ -380,28 +505,28 @@ impl ArithmeticInstruction {
}
#[derive(Debug)]
pub enum ControlInstruction {
pub(crate) enum ControlInstruction {
Allocate(usize), // num_frames.
// name, arity, perm_vars after threshold, last call, use default call policy.
CallClause(ClauseType, usize, usize, bool, bool),
Deallocate,
JmpBy(usize, usize, usize, bool), // arity, global_offset, perm_vars after threshold, last call.
RevJmpBy(usize), // notice the lack of context change as in
// JmpBy. RevJmpBy is used only to patch extensible
// predicates together.
Proceed,
}
impl ControlInstruction {
pub fn perm_vars(&self) -> Option<usize> {
pub(crate) fn perm_vars(&self) -> Option<usize> {
match self {
ControlInstruction::CallClause(_, _, num_cells, ..) =>
Some(*num_cells),
ControlInstruction::JmpBy(_, _, num_cells, ..) =>
Some(*num_cells),
_ =>
None
ControlInstruction::CallClause(_, _, num_cells, ..) => Some(*num_cells),
ControlInstruction::JmpBy(_, _, num_cells, ..) => Some(*num_cells),
_ => None,
}
}
pub fn to_functor(&self) -> MachineStub {
pub(crate) fn to_functor(&self) -> MachineStub {
match self {
&ControlInstruction::Allocate(num_frames) => {
functor!("allocate", [integer(num_frames)])
@@ -418,6 +543,9 @@ impl ControlInstruction {
&ControlInstruction::JmpBy(_, offset, ..) => {
functor!("jmp_by", [integer(offset)])
}
&ControlInstruction::RevJmpBy(offset) => {
functor!("rev_jmp_by", [integer(offset)])
}
&ControlInstruction::Proceed => {
functor!("proceed")
}
@@ -427,42 +555,101 @@ impl ControlInstruction {
/// `IndexingInstruction` cf. page 110 of wambook.
#[derive(Debug)]
pub enum IndexingInstruction {
pub(crate) enum IndexingInstruction {
// The first index is the optimal argument being indexed.
SwitchOnTerm(usize, usize, usize, usize, usize),
SwitchOnConstant(usize, usize, IndexMap<Constant, usize>),
SwitchOnStructure(usize, usize, IndexMap<(ClauseName, usize), usize>),
}
impl From<IndexingInstruction> for Line {
fn from(i: IndexingInstruction) -> Self {
Line::Indexing(i)
}
SwitchOnTerm(
usize,
IndexingCodePtr,
IndexingCodePtr,
IndexingCodePtr,
IndexingCodePtr,
),
SwitchOnConstant(IndexMap<Constant, IndexingCodePtr>),
SwitchOnStructure(IndexMap<(ClauseName, usize), IndexingCodePtr>),
}
impl IndexingInstruction {
pub fn to_functor(&self) -> MachineStub {
pub(crate) fn to_functor(&self, mut h: usize) -> MachineStub {
match self {
&IndexingInstruction::SwitchOnTerm(arg, vars, constants, lists, structures) => {
functor!(
"switch_on_term",
[integer(arg),
integer(vars),
integer(constants),
integer(lists),
integer(structures)]
[
integer(arg),
indexing_code_ptr(h, vars),
indexing_code_ptr(h, constants),
indexing_code_ptr(h, lists),
indexing_code_ptr(h, structures)
]
)
}
&IndexingInstruction::SwitchOnConstant(arg, constants, _) => {
&IndexingInstruction::SwitchOnConstant(ref constants) => {
let mut key_value_list_stub = vec![];
let orig_h = h;
h += 2; // skip the 2-cell "switch_on_constant" functor.
for (c, ptr) in constants.iter() {
let key_value_pair = functor!(
":",
SharedOpDesc::new(600, XFY),
[constant(c), indexing_code_ptr(h + 3, *ptr)]
);
key_value_list_stub.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
key_value_list_stub.push(HeapCellValue::Addr(Addr::Str(h + 3)));
key_value_list_stub.push(HeapCellValue::Addr(Addr::HeapCell(
h + 3 + key_value_pair.len(),
)));
h += key_value_pair.len() + 3;
key_value_list_stub.extend(key_value_pair.into_iter());
}
key_value_list_stub.push(HeapCellValue::Addr(Addr::EmptyList));
functor!(
"switch_on_constant",
[integer(arg), integer(constants)]
[aux(orig_h, 0)],
[key_value_list_stub]
)
}
&IndexingInstruction::SwitchOnStructure(arg, structures, _) => {
&IndexingInstruction::SwitchOnStructure(ref structures) => {
let mut key_value_list_stub = vec![];
let orig_h = h;
h += 2; // skip the 2-cell "switch_on_constant" functor.
for ((name, arity), ptr) in structures.iter() {
let predicate_indicator_stub = functor!(
"/",
SharedOpDesc::new(400, YFX),
[clause_name(name.clone()), integer(*arity)]
);
let key_value_pair = functor!(
":",
SharedOpDesc::new(600, XFY),
[aux(h + 3, 0), indexing_code_ptr(h + 3, *ptr)],
[predicate_indicator_stub]
);
key_value_list_stub.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
key_value_list_stub.push(HeapCellValue::Addr(Addr::Str(h + 3)));
key_value_list_stub.push(HeapCellValue::Addr(Addr::HeapCell(
h + 3 + key_value_pair.len(),
)));
h += key_value_pair.len() + 3;
key_value_list_stub.extend(key_value_pair.into_iter());
}
key_value_list_stub.push(HeapCellValue::Addr(Addr::EmptyList));
functor!(
"switch_on_structure",
[integer(arg), integer(structures)]
[aux(orig_h, 0)],
[key_value_list_stub]
)
}
}
@@ -470,7 +657,7 @@ impl IndexingInstruction {
}
#[derive(Debug, Clone)]
pub enum FactInstruction {
pub(crate) enum FactInstruction {
GetConstant(Level, Constant, RegType),
GetList(Level, RegType),
GetPartialString(Level, String, RegType, bool),
@@ -485,11 +672,11 @@ pub enum FactInstruction {
}
impl FactInstruction {
pub fn to_functor(&self, h: usize) -> MachineStub {
pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
match self {
&FactInstruction::GetConstant(lvl, ref c, r) => {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
let rt_stub = reg_type_into_functor(r);
functor!(
"get_constant",
@@ -499,17 +686,13 @@ impl FactInstruction {
}
&FactInstruction::GetList(lvl, r) => {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
let rt_stub = reg_type_into_functor(r);
functor!(
"get_list",
[aux(h, 0), aux(h, 1)],
[lvl_stub, rt_stub]
)
functor!("get_list", [aux(h, 0), aux(h, 1)], [lvl_stub, rt_stub])
}
&FactInstruction::GetPartialString(lvl, ref s, r, has_tail) => {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
let rt_stub = reg_type_into_functor(r);
functor!(
"get_partial_string",
@@ -529,20 +712,12 @@ impl FactInstruction {
&FactInstruction::GetValue(r, arg) => {
let rt_stub = reg_type_into_functor(r);
functor!(
"get_value",
[aux(h, 0), integer(arg)],
[rt_stub]
)
functor!("get_value", [aux(h, 0), integer(arg)], [rt_stub])
}
&FactInstruction::GetVariable(r, arg) => {
let rt_stub = reg_type_into_functor(r);
functor!(
"get_variable",
[aux(h, 0), integer(arg)],
[rt_stub]
)
functor!("get_variable", [aux(h, 0), integer(arg)], [rt_stub])
}
&FactInstruction::UnifyConstant(ref c) => {
functor!("unify_constant", [constant(h, c)], [])
@@ -550,29 +725,17 @@ impl FactInstruction {
&FactInstruction::UnifyLocalValue(r) => {
let rt_stub = reg_type_into_functor(r);
functor!(
"unify_local_value",
[aux(h, 0)],
[rt_stub]
)
functor!("unify_local_value", [aux(h, 0)], [rt_stub])
}
&FactInstruction::UnifyVariable(r) => {
let rt_stub = reg_type_into_functor(r);
functor!(
"unify_variable",
[aux(h, 0)],
[rt_stub]
)
functor!("unify_variable", [aux(h, 0)], [rt_stub])
}
&FactInstruction::UnifyValue(r) => {
let rt_stub = reg_type_into_functor(r);
functor!(
"unify_value",
[aux(h, 0)],
[rt_stub]
)
functor!("unify_value", [aux(h, 0)], [rt_stub])
}
&FactInstruction::UnifyVoid(vars) => {
functor!("unify_void", [integer(vars)])
@@ -582,7 +745,7 @@ impl FactInstruction {
}
#[derive(Debug, Clone)]
pub enum QueryInstruction {
pub(crate) enum QueryInstruction {
GetVariable(RegType, usize),
PutConstant(Level, Constant, RegType),
PutList(Level, RegType),
@@ -599,15 +762,14 @@ pub enum QueryInstruction {
}
impl QueryInstruction {
pub fn to_functor(&self, h: usize) -> MachineStub {
pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
match self {
&QueryInstruction::PutUnsafeValue(norm, arg) => functor!(
"put_unsafe_value",
[integer(norm), integer(arg)]
),
&QueryInstruction::PutUnsafeValue(norm, arg) => {
functor!("put_unsafe_value", [integer(norm), integer(arg)])
}
&QueryInstruction::PutConstant(lvl, ref c, r) => {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
let rt_stub = reg_type_into_functor(r);
functor!(
"put_constant",
@@ -617,17 +779,13 @@ impl QueryInstruction {
}
&QueryInstruction::PutList(lvl, r) => {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
let rt_stub = reg_type_into_functor(r);
functor!(
"put_list",
[aux(h, 0), aux(h, 1)],
[lvl_stub, rt_stub]
)
functor!("put_list", [aux(h, 0), aux(h, 1)], [lvl_stub, rt_stub])
}
&QueryInstruction::PutPartialString(lvl, ref s, r, has_tail) => {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
let rt_stub = reg_type_into_functor(r);
functor!(
"put_partial_string",
@@ -647,29 +805,17 @@ impl QueryInstruction {
&QueryInstruction::PutValue(r, arg) => {
let rt_stub = reg_type_into_functor(r);
functor!(
"put_value",
[aux(h, 0), integer(arg)],
[rt_stub]
)
functor!("put_value", [aux(h, 0), integer(arg)], [rt_stub])
}
&QueryInstruction::GetVariable(r, arg) => {
let rt_stub = reg_type_into_functor(r);
functor!(
"get_variable",
[aux(h, 0), integer(arg)],
[rt_stub]
)
functor!("get_variable", [aux(h, 0), integer(arg)], [rt_stub])
}
&QueryInstruction::PutVariable(r, arg) => {
let rt_stub = reg_type_into_functor(r);
functor!(
"put_variable",
[aux(h, 0), integer(arg)],
[rt_stub]
)
functor!("put_variable", [aux(h, 0), integer(arg)], [rt_stub])
}
&QueryInstruction::SetConstant(ref c) => {
functor!("set_constant", [constant(h, c)], [])
@@ -677,29 +823,17 @@ impl QueryInstruction {
&QueryInstruction::SetLocalValue(r) => {
let rt_stub = reg_type_into_functor(r);
functor!(
"set_local_value",
[aux(h, 0)],
[rt_stub]
)
functor!("set_local_value", [aux(h, 0)], [rt_stub])
}
&QueryInstruction::SetVariable(r) => {
let rt_stub = reg_type_into_functor(r);
functor!(
"set_variable",
[aux(h, 0)],
[rt_stub]
)
functor!("set_variable", [aux(h, 0)], [rt_stub])
}
&QueryInstruction::SetValue(r) => {
let rt_stub = reg_type_into_functor(r);
functor!(
"set_value",
[aux(h, 0)],
[rt_stub]
)
functor!("set_value", [aux(h, 0)], [rt_stub])
}
&QueryInstruction::SetVoid(vars) => {
functor!("set_void", [integer(vars)])
@@ -708,10 +842,6 @@ impl QueryInstruction {
}
}
pub type CompiledFact = Vec<FactInstruction>;
pub(crate) type CompiledFact = Vec<FactInstruction>;
pub type ThirdLevelIndex = Vec<IndexedChoiceInstruction>;
pub type Code = Vec<Line>;
pub type CodeDeque = VecDeque<Line>;
pub(crate) type Code = Vec<Line>;

View File

@@ -1,4 +1,5 @@
use crate::prolog_parser::ast::*;
use prolog_parser::ast::*;
use prolog_parser::rc_atom;
use crate::clause_types::*;
use crate::forms::*;
@@ -12,7 +13,7 @@ use std::rc::Rc;
use std::vec::Vec;
#[derive(Debug, Clone)]
pub enum TermRef<'a> {
pub(crate) enum TermRef<'a> {
AnonVar(Level),
Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
Constant(Level, &'a Cell<RegType>, &'a Constant),
@@ -22,20 +23,20 @@ pub enum TermRef<'a> {
}
impl<'a> TermRef<'a> {
pub fn level(self) -> Level {
pub(crate) fn level(self) -> Level {
match self {
TermRef::AnonVar(lvl)
| TermRef::Cons(lvl, ..)
| TermRef::Constant(lvl, ..)
| TermRef::Var(lvl, ..)
| TermRef::Clause(lvl, ..) => lvl,
| TermRef::PartialString(lvl, ..) => lvl,
| TermRef::Cons(lvl, ..)
| TermRef::Constant(lvl, ..)
| TermRef::Var(lvl, ..)
| TermRef::Clause(lvl, ..) => lvl,
TermRef::PartialString(lvl, ..) => lvl,
}
}
}
#[derive(Debug)]
pub enum TermIterState<'a> {
pub(crate) enum TermIterState<'a> {
AnonVar(Level),
Constant(Level, &'a Cell<RegType>, &'a Constant),
Clause(
@@ -51,23 +52,16 @@ pub enum TermIterState<'a> {
Var(Level, &'a Cell<VarReg>, Rc<Var>),
}
fn is_partial_string<'a>(
head: &'a Term,
mut tail: &'a Term,
) -> Option<(String, Option<&'a Term>)>
{
let mut string =
match head {
&Term::Constant(_, Constant::Atom(ref atom, _)) if atom.is_char() => {
atom.as_str().chars().next().unwrap().to_string()
}
&Term::Constant(_, Constant::Char(c)) => {
c.to_string()
}
_ => {
return None;
}
};
fn is_partial_string<'a>(head: &'a Term, mut tail: &'a Term) -> Option<(String, Option<&'a Term>)> {
let mut string = match head {
&Term::Constant(_, Constant::Atom(ref atom, _)) if atom.is_char() => {
atom.as_str().chars().next().unwrap().to_string()
}
&Term::Constant(_, Constant::Char(c)) => c.to_string(),
_ => {
return None;
}
};
while let Term::Cons(_, ref head, ref succ) = tail {
match head.as_ref() {
@@ -103,11 +97,9 @@ fn is_partial_string<'a>(
}
impl<'a> TermIterState<'a> {
pub fn subterm_to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> {
pub(crate) fn subterm_to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> {
match term {
&Term::AnonVar => {
TermIterState::AnonVar(lvl)
}
&Term::AnonVar => TermIterState::AnonVar(lvl),
&Term::Clause(ref cell, ref name, ref subterms, ref spec) => {
let ct = if let Some(spec) = spec {
ClauseType::Op(name.clone(), spec.clone(), CodeIndex::default())
@@ -120,18 +112,14 @@ impl<'a> TermIterState<'a> {
&Term::Cons(ref cell, ref head, ref tail) => {
TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref())
}
&Term::Constant(ref cell, ref constant) => {
TermIterState::Constant(lvl, cell, constant)
}
&Term::Var(ref cell, ref var) => {
TermIterState::Var(lvl, cell, var.clone())
}
&Term::Constant(ref cell, ref constant) => TermIterState::Constant(lvl, cell, constant),
&Term::Var(ref cell, ref var) => TermIterState::Var(lvl, cell, var.clone()),
}
}
}
#[derive(Debug)]
pub struct QueryIterator<'a> {
pub(crate) struct QueryIterator<'a> {
state_stack: Vec<TermIterState<'a>>,
}
@@ -175,8 +163,7 @@ impl<'a> QueryIterator<'a> {
state_stack: vec![],
}
}
&Term::Var(ref cell, ref var) =>
TermIterState::Var(Level::Root, cell, (*var).clone()),
&Term::Var(ref cell, ref var) => TermIterState::Var(Level::Root, cell, (*var).clone()),
};
QueryIterator {
@@ -265,18 +252,15 @@ impl<'a> Iterator for QueryIterator<'a> {
}
TermIterState::InitialCons(lvl, cell, head, tail) => {
if let Some((string, tail)) = is_partial_string(head, tail) {
self.state_stack.push(TermIterState::PartialString(
lvl,
cell,
string,
tail,
));
self.state_stack
.push(TermIterState::PartialString(lvl, cell, string, tail));
if let Some(tail) = tail {
self.push_subterm(lvl.child_level(), tail);
}
} else {
self.state_stack.push(TermIterState::FinalCons(lvl, cell, head, tail));
self.state_stack
.push(TermIterState::FinalCons(lvl, cell, head, tail));
self.push_subterm(lvl.child_level(), tail);
self.push_subterm(lvl.child_level(), head);
@@ -302,17 +286,18 @@ impl<'a> Iterator for QueryIterator<'a> {
}
#[derive(Debug)]
pub struct FactIterator<'a> {
pub(crate) struct FactIterator<'a> {
state_queue: VecDeque<TermIterState<'a>>,
iterable_root: bool,
}
impl<'a> FactIterator<'a> {
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
self.state_queue.push_back(TermIterState::subterm_to_state(lvl, term));
self.state_queue
.push_back(TermIterState::subterm_to_state(lvl, term));
}
pub fn from_rule_head_clause(terms: &'a Vec<Box<Term>>) -> Self {
pub(crate) fn from_rule_head_clause(terms: &'a Vec<Box<Term>>) -> Self {
let state_queue = terms
.iter()
.map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt.as_ref()))
@@ -393,8 +378,7 @@ impl<'a> Iterator for FactIterator<'a> {
TermIterState::Var(lvl, cell, var) => {
return Some(TermRef::Var(lvl, cell, var));
}
_ => {
}
_ => {}
}
}
@@ -402,26 +386,26 @@ impl<'a> Iterator for FactIterator<'a> {
}
}
pub fn post_order_iter(term: &Term) -> QueryIterator {
pub(crate) fn post_order_iter(term: &Term) -> QueryIterator {
QueryIterator::from_term(term)
}
pub fn breadth_first_iter(term: &Term, iterable_root: bool) -> FactIterator {
pub(crate) fn breadth_first_iter(term: &Term, iterable_root: bool) -> FactIterator {
FactIterator::new(term, iterable_root)
}
#[derive(Debug)]
pub enum ChunkedTerm<'a> {
pub(crate) enum ChunkedTerm<'a> {
HeadClause(ClauseName, &'a Vec<Box<Term>>),
BodyTerm(&'a QueryTerm),
}
pub fn query_term_post_order_iter<'a>(query_term: &'a QueryTerm) -> QueryIterator<'a> {
pub(crate) fn query_term_post_order_iter<'a>(query_term: &'a QueryTerm) -> QueryIterator<'a> {
QueryIterator::new(query_term)
}
impl<'a> ChunkedTerm<'a> {
pub fn post_order_iter(&self) -> QueryIterator<'a> {
pub(crate) fn post_order_iter(&self) -> QueryIterator<'a> {
match self {
&ChunkedTerm::BodyTerm(ref qt) => QueryIterator::new(qt),
&ChunkedTerm::HeadClause(_, terms) => QueryIterator::from_rule_head_clause(terms),
@@ -441,8 +425,8 @@ fn contains_cut_var<'a, Iter: Iterator<Item = &'a Term>>(terms: Iter) -> bool {
false
}
pub struct ChunkedIterator<'a> {
pub chunk_num: usize,
pub(crate) struct ChunkedIterator<'a> {
pub(crate) chunk_num: usize,
iter: Box<dyn Iterator<Item = ChunkedTerm<'a>> + 'a>,
deep_cut_encountered: bool,
cut_var_in_head: bool,
@@ -464,7 +448,7 @@ type ChunkedIteratorItem<'a> = (usize, usize, Vec<ChunkedTerm<'a>>);
type RuleBodyIteratorItem<'a> = (usize, usize, Vec<&'a QueryTerm>);
impl<'a> ChunkedIterator<'a> {
pub fn rule_body_iter(self) -> Box<dyn Iterator<Item = RuleBodyIteratorItem<'a>> + 'a> {
pub(crate) fn rule_body_iter(self) -> Box<dyn Iterator<Item = RuleBodyIteratorItem<'a>> + 'a> {
Box::new(self.filter_map(|(cn, lt_arity, terms)| {
let filtered_terms: Vec<_> = terms
.into_iter()
@@ -481,17 +465,17 @@ impl<'a> ChunkedIterator<'a> {
}
}))
}
pub fn from_term_sequence(terms: &'a [QueryTerm]) -> Self {
ChunkedIterator {
chunk_num: 0,
iter: Box::new(terms.iter().map(|t| ChunkedTerm::BodyTerm(t))),
deep_cut_encountered: false,
cut_var_in_head: false,
/*
pub(crate) fn from_term_sequence(terms: &'a [QueryTerm]) -> Self {
ChunkedIterator {
chunk_num: 0,
iter: Box::new(terms.iter().map(|t| ChunkedTerm::BodyTerm(t))),
deep_cut_encountered: false,
cut_var_in_head: false,
}
}
}
pub fn from_rule_body(p1: &'a QueryTerm, clauses: &'a Vec<QueryTerm>) -> Self {
*/
pub(crate) fn from_rule_body(p1: &'a QueryTerm, clauses: &'a Vec<QueryTerm>) -> Self {
let inner_iter = Box::new(once(ChunkedTerm::BodyTerm(p1)));
let iter = inner_iter.chain(clauses.iter().map(|t| ChunkedTerm::BodyTerm(t)));
@@ -503,7 +487,7 @@ impl<'a> ChunkedIterator<'a> {
}
}
pub fn from_rule(rule: &'a Rule) -> Self {
pub(crate) fn from_rule(rule: &'a Rule) -> Self {
let &Rule {
head: (ref name, ref args, ref p1),
ref clauses,
@@ -521,7 +505,7 @@ impl<'a> ChunkedIterator<'a> {
}
}
pub fn encountered_deep_cut(&self) -> bool {
pub(crate) fn encountered_deep_cut(&self) -> bool {
self.deep_cut_encountered
}

25
src/lib.rs Normal file
View File

@@ -0,0 +1,25 @@
#[cfg(feature = "num-rug-adapter")]
use num_rug_adapter as rug;
#[cfg(feature = "rug")]
use rug;
#[macro_use]
mod macros;
mod allocator;
mod arithmetic;
mod clause_types;
mod codegen;
mod debray_allocator;
mod fixtures;
mod forms;
mod heap_iter;
mod heap_print;
mod indexing;
mod instructions;
mod iterators;
pub mod machine;
pub mod read;
mod targets;
mod write;
use machine::*;

View File

@@ -63,11 +63,8 @@ Assocs are Key-Value associations implemented as a balanced binary tree
@author R.A.O'Keefe, L.Damas, V.S.Costa and Jan Wielemaker
*/
/*
:- meta_predicate
map_assoc(1, ?),
map_assoc(2, ?, ?).
*/
:- meta_predicate map_assoc(1, ?).
:- meta_predicate map_assoc(2, ?, ?).
%! empty_assoc(?Assoc) is semidet.
%

View File

@@ -1,4 +1,5 @@
:- module(atts, [op(1199, fx, attribute), call_residue_vars/2,
:- module(atts, [op(1199, fx, attribute),
call_residue_vars/2,
term_attributed_variables/2,
'$absent_attr'/2, '$copy_attr_list'/2, '$get_attr'/2,
'$put_attr'/2, '$absent_from_list'/2,
@@ -19,9 +20,7 @@
).
'$default_attr_list'([PG | PGs], Module, AttrVar) -->
( { '$module_of'(Module, PG) } -> [Module:put_atts(AttrVar, PG)]
; { true }
),
[Module:put_atts(AttrVar, PG)],
'$default_attr_list'(PGs, Module, AttrVar).
'$default_attr_list'([], _, _) --> [].
@@ -66,7 +65,8 @@
'$del_attr_step'(Ls1, V, Attr) :-
( nonvar(Ls1) -> Ls1 = [_ | Ls2], '$del_attr_buried'(Ls1, Ls2, V, Attr)
; true ).
; true
).
%% assumptions: Ls0 is a list, Ls1 is its tail;
%% the head of Ls0 can be ignored.
@@ -75,8 +75,8 @@
; Ls1 = [Att | Ls2] ->
( Att \= Attr -> '$del_attr_buried'(Ls1, Ls2, V, Attr)
; '$enqueue_attr_var'(V),
'$del_attr_non_head'(Ls0), %% set tail of Ls0 = tail of Ls1. can be undone by backtracking.
'$del_attr_step'(Ls1, V, Attr)
'$del_attr_non_head'(Ls0), %% set tail of Ls0 = tail of Ls1. can be undone by backtracking.
'$del_attr_step'(Ls1, V, Attr)
)
).
@@ -88,66 +88,66 @@ user:term_expansion(Term0, Terms) :-
nonvar(Term0),
Term0 = (:- attribute Atts),
nonvar(Atts),
phrase(expand_terms(Atts), Terms).
loader:prolog_load_context(module, Module),
phrase(expand_terms(Atts, Module), Terms).
expand_terms(Atts) -->
expand_terms(Atts, Module) -->
put_attrs_var_check,
put_attrs(Atts),
put_attrs(Atts, Module),
get_attrs_var_check,
get_attrs(Atts).
get_attrs(Atts, Module).
put_attrs_var_check -->
{ numbervars([Var, Attr], 0, _) },
[(put_atts(Var, Attr) :- nonvar(Var), throw(error(type_error(variable, Var), put_atts/2))),
(put_atts(Var, Attr) :- var(Attr), throw(error(instantiation_error, put_atts/2)))].
get_attrs_var_check -->
{ numbervars([Var, Ls, Attr], 0, _) },
[(get_atts(Var, Attr) :- nonvar(Var), throw(error(type_error(variable, Var), get_atts/2))),
(get_atts(Var, Attr) :- var(Attr), !, '$get_attr_list'(Var, Ls), nonvar(Ls),
'$copy_attr_list'(Ls, Attr))].
put_attrs(Name/Arity) -->
put_attr(Name, Arity),
{ numbervars([Var, Attr], 0, _) },
[(put_atts(Var, Attr) :- lists:maplist(put_atts(Var), Attr), !)].
put_attrs((Name/Arity, Atts)) -->
put_attrs(Name/Arity, Module) -->
put_attr(Name, Arity, Module),
[(put_atts(Var, Attr) :- lists:maplist(Module:put_atts(Var), Attr), !)].
put_attrs((Name/Arity, Atts), Module) -->
{ nonvar(Atts) },
put_attr(Name, Arity),
put_attrs(Atts).
put_attr(Name, Arity, Module),
put_attrs(Atts, Module).
get_attrs(Name/Arity) -->
get_attr(Name, Arity).
get_attrs((Name/Arity, Atts)) -->
get_attrs(Name/Arity, Module) -->
get_attr(Name, Arity, Module).
get_attrs((Name/Arity, Atts), Module) -->
{ nonvar(Atts) },
get_attr(Name, Arity),
get_attrs(Atts).
get_attr(Name, Arity, Module),
get_attrs(Atts, Module).
put_attr(Name, Arity) -->
{ functor(Attr, Name, Arity),
numbervars(Attr, 0, Arity),
V = '$VAR'(Arity) },
[(put_atts(V, +Attr) :- !, functor(Attr, Head, Arity),
functor(AttrForm, Head, Arity),
'$get_attr_list'(V, Ls),
'$del_attr'(Ls, V, AttrForm),
'$put_attr'(V, Attr)),
(put_atts(V, Attr) :- !, functor(Attr, Head, Arity),
functor(AttrForm, Head, Arity),
'$get_attr_list'(V, Ls),
'$del_attr'(Ls, V, AttrForm),
'$put_attr'(V, Attr)),
(put_atts(V, -Attr) :- !, functor(Attr, _, _),
'$get_attr_list'(V, Ls),
'$del_attr'(Ls, V, Attr))].
put_attr(Name, Arity, Module) -->
{ functor(Attr, Name, Arity) },
[(put_atts(V, +Attr) :-
!,
functor(Attr, Head, Arity),
functor(AttrForm, Head, Arity),
'$get_attr_list'(V, Ls),
'$del_attr'(Ls, V, Module:AttrForm),
'$put_attr'(V, Module:Attr)),
(put_atts(V, Attr) :-
!,
functor(Attr, Head, Arity),
functor(AttrForm, Head, Arity),
'$get_attr_list'(V, Ls),
'$del_attr'(Ls, V, Module:AttrForm),
'$put_attr'(V, Module:Attr)),
(put_atts(V, -Attr) :-
!,
functor(Attr, _, _),
'$get_attr_list'(V, Ls),
'$del_attr'(Ls, V, Module:Attr))].
get_attr(Name, Arity) -->
{ functor(Attr, Name, Arity),
numbervars(Attr, 0, Arity),
V = '$VAR'(Arity) },
[(get_atts(V, +Attr) :- !, functor(Attr, _, _), '$get_attr'(V, Attr)),
(get_atts(V, Attr) :- !, functor(Attr, _, _), '$get_attr'(V, Attr)),
(get_atts(V, -Attr) :- !, functor(Attr, _, _), '$absent_attr'(V, Attr))].
get_attr(Name, Arity, Module) -->
{ functor(Attr, Name, Arity) },
[(get_atts(V, +Attr) :- !, functor(Attr, _, _), '$get_attr'(V, Module:Attr)),
(get_atts(V, Attr) :- !, functor(Attr, _, _), '$get_attr'(V, Module:Attr)),
(get_atts(V, -Attr) :- !, functor(Attr, _, _), '$absent_attr'(V, Module:Attr))].
user:goal_expansion(Term, M:put_atts(Var, Attr)) :-
nonvar(Term),
@@ -156,6 +156,8 @@ user:goal_expansion(Term, M:get_atts(Var, Attr)) :-
nonvar(Term),
Term = get_atts(Var, M, Attr).
:- meta_predicate call_residue_vars(0, ?).
call_residue_vars(Goal, Vars) :-
'$get_attr_var_queue_delim'(B),
call(Goal),

File diff suppressed because it is too large Load Diff

View File

@@ -53,7 +53,7 @@ extend_var_list(Vars, VarList, NewVarList, VarType) :-
extend_var_list_(Vars, 0, VarList, NewVarList0, VarType),
append(VarList, NewVarList0, NewVarList).
extend_var_list_([], _, VarList, [], _).
extend_var_list_([], _, _, [], _).
extend_var_list_([V|Vs], N, VarList, NewVarList, VarType) :-
( var_list_contains_variable(VarList, V) ->
extend_var_list_(Vs, N, VarList, NewVarList, VarType)

View File

@@ -17,8 +17,8 @@
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- module(clpb, [op(300, fy, ~),
op(500, yfx, #),
sat/1,
op(500, yfx, #),
sat/1,
taut/2,
labeling/1,
sat_count/2,

View File

@@ -3068,12 +3068,10 @@ is_false(var(X)) :- nonvar(X).
:- dynamic(goal_expansion/1).
% goal expansion is disabled for now, until #445 is resolved
%
% user:goal_expansion(Goal0, Goal) :-
% \+ goal_expansion(false),
% clpz_expandable(Goal0),
% clpz_expansion(Goal0, Goal).
user:goal_expansion(Goal0, Goal) :-
\+ goal_expansion(false),
clpz_expandable(Goal0),
clpz_expansion(Goal0, Goal).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -5884,10 +5882,12 @@ difference_arcs([V|Vs], FL0) -->
writeln(T) :- write(T), nl.
:- meta_predicate must_succeed(0).
must_succeed(G) :-
(G -> true
;write(failed-G), halt
).
( G -> true
; throw(failed-G)
).
enumerate([], _) --> [].
enumerate([N|Ns], V) -->
@@ -6047,6 +6047,8 @@ remove_attr(Var, Attr) :-
functor(Term, Attr, 1),
put_atts(Var, -Term).
:- meta_predicate with_local_attributes(?, 0, ?).
with_local_attributes(Vars, Goal, Result) :-
catch((Goal,
maplist(del_all_attrs, Vars),
@@ -7578,20 +7580,6 @@ attribute_goals(X) -->
attributes_goals(Ps),
{ del_attr(X, clpz) }.
clpz_aux:attribute_goals(_) --> [].
clpz_gcc_vs:attribute_goals(_) --> [].
clpz_gcc_num:attribute_goals(_) --> [].
clpz_gcc_occurred:attribute_goals(_) --> [].
clpz_relation:attribute_goals(_) --> [].
attribute_goal(Var, Goal) :-
phrase(attribute_goals(Var), Goals),
list_goal(Goals, Goal).
attributes_goals([]) --> [].
attributes_goals([propagator(P, State)|As]) -->
( { ground(State) } -> []
@@ -7654,7 +7642,9 @@ attribute_goal_(pelement(N,Is,V)) --> [element(N, Is, V)].
attribute_goal_(pgcc(Vs, Pairs, _)) --> [global_cardinality(Vs, Pairs)].
attribute_goal_(pgcc_single(_,_)) --> [].
attribute_goal_(pgcc_check_single(_)) --> [].
attribute_goal_(pgcc_check(_)) --> [].
attribute_goal_(pgcc_check(Pairs)) -->
{ pairs_values(Pairs, Nums),
maplist(gcc_done, Nums) }.
attribute_goal_(pcircuit(Vs)) --> [circuit(Vs)].
attribute_goal_(pserialized(_,_,_,_,O)) --> original_goal(O).
attribute_goal_(rel_tuple(R, Tuple)) -->
@@ -7763,11 +7753,10 @@ zo_t(1, true).
Generated predicates
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
generated_clauses(Cs) :-
make_parse_clpz(Cs1),
make_parse_reified(Cs2),
make_matches(Cs3),
append([Cs1,Cs2,Cs3], Cs).
term_expansion(make_parse_clpz, Clauses) :- make_parse_clpz(Clauses).
term_expansion(make_parse_reified, Clauses) :- make_parse_reified(Clauses).
term_expansion(make_matches, Clauses) :- make_matches(Clauses).
:- initialization((generated_clauses(Cs),
maplist(assertz, Cs))).
make_parse_clpz.
make_parse_reified.
make_matches.

View File

@@ -1,5 +1,7 @@
:- module(cont, [reset/3, shift/1]).
:- meta_predicate reset(0, ?, ?).
reset(Goal, Ball, Cont) :-
call(Goal),
'$reset_cont_marker',
@@ -11,7 +13,7 @@ shift(Ball) :-
get_chunks(E, P, L),
( L == [] ->
Cont = cont(true)
; Cont = cont(call_continuation(L))
; Cont = cont(cont:call_continuation(L))
),
'$write_cont_and_term'(_, _, Cont, Ball),
'$unwind_environments'.

View File

@@ -5,41 +5,86 @@
:- use_module(library(error)).
:- use_module(library(lists), [append/3]).
:- use_module(library(loader), [strip_module/3]).
:- meta_predicate phrase(2, ?).
:- meta_predicate phrase(2, ?, ?).
phrase(GRBody, S0) :-
phrase(GRBody, S0, []).
phrase(GRBody, S0, S) :-
( var(GRBody) -> throw(error(instantiation_error, phrase/3))
; dcg_constr(GRBody) -> phrase_(GRBody, S0, S)
; functor(GRBody, _, _) -> call(GRBody, S0, S)
( var(GRBody) ->
throw(error(instantiation_error, phrase/3))
; strip_module(GRBody, Module, GRBody0),
dcg_constr(GRBody0) ->
( var(Module) ->
phrase_(GRBody0, S0, S)
; phrase_(Module:GRBody0, S0, S)
)
; functor(GRBody, _, _) ->
call(GRBody, S0, S)
; throw(error(type_error(callable, GRBody), phrase/3))
).
phrase_([], S, S).
phrase_(!, S, S).
phrase_(_:[], S, S) :- !.
phrase_(_:!, S, S) :- !.
phrase_((A, B), S0, S) :-
phrase(A, S0, S1), phrase(B, S1, S).
phrase_(M:(A, B), S0, S) :-
!,
phrase(M:A, S0, S1), phrase(M:B, S1, S).
phrase_((A -> B ; C), S0, S) :-
!,
( phrase(A, S0, S1) ->
phrase(B, S1, S)
; phrase(C, S0, S)
).
phrase_(M:(A -> B ; C), S0, S) :-
!,
( phrase(M:A, S0, S1) ->
phrase(M:B, S1, S)
; phrase(M:C, S0, S)
).
phrase_((A ; B), S0, S) :-
( phrase(A, S0, S) ; phrase(B, S0, S) ).
phrase_(M:(A ; B), S0, S) :-
!,
( phrase(M:A, S0, S) ; phrase(M:B, S0, S) ).
phrase_((A | B), S0, S) :-
( phrase(A, S0, S) ; phrase(B, S0, S) ).
phrase_(M:(A | B), S0, S) :-
!,
( phrase(M:A, S0, S) ; phrase(M:B, S0, S) ).
phrase_({G}, S0, S) :-
( call(G), S0 = S ).
phrase_(M:{G}, S0, S) :-
!,
( call(M:G), S0 = S ).
phrase_(call(G), S0, S) :-
call(G, S0, S).
phrase_(M:call(G), S0, S) :-
!,
call(M:G, S0, S).
phrase_((A -> B), S0, S) :-
phrase((A -> B ; fail), S0, S).
phrase_(M:(A -> B), S0, S) :-
!,
phrase((M:A -> M:B ; fail), S0, S).
phrase_(phrase(NonTerminal), S0, S) :-
phrase(NonTerminal, S0, S).
phrase_(M:phrase(NonTerminal), S0, S) :-
!,
phrase(M:NonTerminal, S0, S).
phrase_([T|Ts], S0, S) :-
append([T|Ts], S, S0).
phrase_(_:[T|Ts], S0, S) :-
append([T|Ts], S, S0).
% The same version of the below two dcg_rule clauses, but with module scoping.
dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :-

View File

@@ -11,6 +11,10 @@
:- use_module(library(format), [portray_clause/1]).
:- meta_predicate *(0).
:- meta_predicate $(0).
:- meta_predicate $-(0).
$-(G_0) :-
catch(G_0, Ex, ( portray_clause(exception:Ex:G_0), throw(Ex) ) ).

View File

@@ -2,13 +2,23 @@
:- use_module(library(error)).
wam_instructions(Clause, Listing) :-
( nonvar(Clause) ->
Clause = Name / Arity,
must_be(atom, Name),
must_be(integer, Arity),
( Arity >= 0 -> '$wam_instructions'(Name, Arity, Listing)
; throw(error(domain_error(not_less_than_zero, Arity), wam_instructions/2))
( Clause = Name / Arity ->
fetch_instructions(user, Name, Arity, Listing)
; Clause = Module : (Name / Arity) ->
fetch_instructions(Module, Name, Arity, Listing)
)
; throw(error(instantiation_error, wam_instructions/2))
).
fetch_instructions(Module, Name, Arity, Listing) :-
must_be(atom, Module),
must_be(atom, Name),
must_be(integer, Arity),
( Arity >= 0 ->
'$wam_instructions'(Module, Name, Arity, Listing)
; throw(error(domain_error(not_less_than_zero, Arity), wam_instructions/2))
).

View File

@@ -8,8 +8,8 @@
put_dif_att(Var, X, Y) :-
( get_atts(Var, +dif(Z)) ->
sort([X \== Y | Z], NewZ),
put_atts(Var, +dif(NewZ))
sort([X \== Y | Z], NewZ),
put_atts(Var, +dif(NewZ))
; put_atts(Var, +dif([X \== Y]))
).
@@ -21,8 +21,8 @@ dif_set_variables([Var|Vars], X, Y) :-
append_goals([], _).
append_goals([Var|Vars], Goals) :-
( get_atts(Var, +dif(VarGoals)) ->
append(Goals, VarGoals, NewGoals0),
sort(NewGoals0, NewGoals)
append(Goals, VarGoals, NewGoals0),
sort(NewGoals0, NewGoals)
; NewGoals = Goals
),
put_atts(Var, +dif(NewGoals)),
@@ -30,8 +30,8 @@ append_goals([Var|Vars], Goals) :-
verify_attributes(Var, Value, Goals) :-
( get_atts(Var, +dif(Goals)) ->
term_variables(Value, ValueVars),
append_goals(ValueVars, Goals)
term_variables(Value, ValueVars),
append_goals(ValueVars, Goals)
; Goals = []
).
@@ -50,7 +50,7 @@ dif(X, Y) :-
gather_dif_goals([]) --> [].
gather_dif_goals([(X \== Y) | Goals]) -->
( { X \= Y } -> []
; [dif(X, Y)]
; [dif:dif(X, Y)]
),
gather_dif_goals(Goals).

View File

@@ -44,10 +44,10 @@ must_be_(var, Term) :-
).
must_be_(integer, Term) :- check_(integer, integer, Term).
must_be_(atom, Term) :- check_(atom, atom, Term).
must_be_(character, T) :- check_(character, character, T).
must_be_(list, Term) :- check_(ilist, list, Term).
must_be_(type, Term) :- check_(type, type, Term).
must_be_(boolean, Term) :- check_(boolean, boolean, Term).
must_be_(character, T) :- check_(error:character, character, T).
must_be_(list, Term) :- check_(error:ilist, list, Term).
must_be_(type, Term) :- check_(error:type, type, Term).
must_be_(boolean, Term) :- check_(error:boolean, boolean, Term).
check_(Pred, Type, Term) :-
( var(Term) -> instantiation_error(must_be/2)

View File

@@ -1,5 +1,5 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Written March 2020 by Markus Triska (triska@metalevel.at)
Written 2020, 2021 by Markus Triska (triska@metalevel.at)
Part of Scryer Prolog.
This library provides the nonterminal format_//2 to describe
@@ -141,7 +141,7 @@ element_gluevar(glue(_,V), N, N) --> [V].
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Our key datastructure is a list of cells and newlines.
A cell has the shape from_to(From,To,Elements), where
A cell has the shape cell(From,To,Elements), where
From and To denote the positions of surrounding tab stops.
Elements is a list of elements that occur in a cell,
@@ -263,6 +263,11 @@ cells([~,'`',Char,t|Fs], Args, Tab, Es, VNs) --> !,
cells(Fs, Args, Tab, [glue(Char,_)|Es], VNs).
cells([~,t|Fs], Args, Tab, Es, VNs) --> !,
cells(Fs, Args, Tab, [glue(' ',_)|Es], VNs).
cells([~,'|'|Fs], Args, Tab0, Es, VNs) --> !,
{ phrase(elements_gluevars(Es, 0, Width), _),
Tab is Tab0 + Width },
cell(Tab0, Tab, Es),
cells(Fs, Args, Tab, [], VNs).
cells([~|Fs0], Args0, Tab, Es, VNs) -->
{ numeric_argument(Fs0, Num, ['|'|Fs], Args0, Args) },
!,
@@ -381,15 +386,15 @@ format(Stream, Fs, Args) :-
flush_output(Stream).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
?- phrase(cells("hello", [], 0, []), Cs).
?- phrase(format:cells("hello", [], 0, [], []), Cs).
?- phrase(cells("hello~10|", [], 0, []), Cs).
?- phrase(cells("~ta~t~10|", [], 0, []), Cs).
?- phrase(format:cells("hello~10|", [], 0, [], []), Cs).
?- phrase(format:cells("~ta~t~10|", [], 0, [], []), Cs).
?- phrase(format_("~`at~50|", []), Ls).
?- phrase(cells("~`at~50|", [], 0, []), Cs),
phrase(format_cells(Cs), Ls).
?- phrase(format:cells("~`at~50|", [], 0, [], []), Cs),
phrase(format:format_cells(Cs), Ls).
?- phrase(format:cells("~ta~t~tb~tc~21|", [], 0, [], []), Cs).
Cs = [cell(0,21,[glue(' ',_A),chars("a"),glue(' ',_B),glue(' ',_C),chars("b"),glue(' ',_D),chars("c ...")])]
?- phrase(format:cells("~ta~t~4|", [], 0, [], []), Cs).

View File

@@ -3,6 +3,8 @@
:- use_module(library(atts)).
:- use_module(library(dcgs)).
:- meta_predicate freeze(?, 0).
:- attribute frozen/1.
verify_attributes(Var, Other, Goals) :-

View File

@@ -10,7 +10,7 @@
Usage
==========
The main predicate of the library is http_listen/2, which needs a port number
(usually 80) and a list of handlers. A handler is a compund term with the functor
(usually 80) and a list of handlers. A handler is a compound term with the functor
as one HTTP method (in lowercase) and followed by a Route Match and a predicate
which will handle the call.
@@ -58,6 +58,8 @@
url_decode//1
]).
:- meta_predicate http_listen(?, 2).
:- use_module(library(sockets)).
:- use_module(library(dcgs)).
:- use_module(library(format)).
@@ -68,8 +70,17 @@
:- use_module(library(time)).
:- use_module(library(crypto)).
% Module prefix workaround with meta_predicate
http_listen(Port, Module:Handlers0) :-
maplist(module_qualification(Module), Handlers0, Handlers),
http_listen_(Port, Handlers).
module_qualification(M, H0, H) :-
H0 =.. [Method, Path, Goal],
H =.. [Method, Path, M:Goal].
% Server initialization
http_listen(Port, Handlers) :-
http_listen_(Port, Handlers) :-
must_be(integer, Port),
must_be(list, Handlers),
once(socket_server_open(Port, Socket)),
@@ -99,7 +110,7 @@ accept_loop(Socket, Handlers) :-
HttpResponse = http_response(_, _, _),
(call(Handler, HttpRequest, HttpResponse) ->
send_response(Stream, HttpResponse)
; format(Stream, "HTTP/1.0 500 Internal Server Error\r\n\r\n")
; format(Stream, "HTTP/1.0 500 Internal Server Error\r\n\r\n", [])
)
)
; format(Stream, "HTTP/1.0 404 Not Found\r\n\r\n", [])

View File

@@ -3,47 +3,53 @@
%% ?- use_module(library(iso_ext)).
:- module(iso_ext, [bb_b_put/2, bb_get/2, bb_put/2, call_cleanup/2,
call_with_inference_limit/3, forall/2,
partial_string/1, partial_string/3,
partial_string_tail/2, setup_call_cleanup/3,
call_nth/2, variant/2]).
:- module(iso_ext, [bb_b_put/2,
bb_get/2,
bb_put/2,
call_cleanup/2,
call_with_inference_limit/3,
forall/2,
partial_string/1,
partial_string/3,
partial_string_tail/2,
setup_call_cleanup/3,
call_nth/2,
variant/2,
copy_term_nat/2]).
:- use_module(library(error), [can_be/2, domain_error/3, type_error/3]).
:- meta_predicate call_cleanup(0, 0).
:- meta_predicate setup_call_cleanup(0, 0, 0).
:- use_module(library(error), [can_be/2,domain_error/3]).
forall(Generate, Test) :-
\+ (Generate, \+ Test).
%% (non-)backtrackable global variables.
bb_put(Key, Value) :- atom(Key), !, '$store_global_var'(Key, Value).
bb_put(Key, _) :- throw(error(type_error(atom, Key), bb_put/2)).
bb_put(Key, Value) :-
( atom(Key) ->
'$store_global_var'(Key, Value)
; type_error(atom, Key, bb_put/2)
).
%% backtrackable global variables.
bb_b_put(Key, NewValue) :-
( '$bb_get_with_offset'(Key, OldValue, OldOffset) ->
call_cleanup((store_global_var_with_offset(Key, NewValue) ; false),
reset_global_var_at_offset(Key, OldValue, OldOffset))
; call_cleanup((store_global_var_with_offset(Key, NewValue) ; false),
reset_global_var_at_key(Key))
bb_b_put(Key, Value) :-
( atom(Key) ->
'$store_backtrackable_global_var'(Key, Value)
; type_error(atom, Key, bb_b_put/2)
).
store_global_var_with_offset(Key, Value) :- '$store_global_var_with_offset'(Key, Value).
bb_get(Key, Value) :-
( atom(Key) ->
'$fetch_global_var'(Key, Value)
; type_error(atom, Key, bb_get/2)
).
store_global_var(Key, Value) :- '$store_global_var'(Key, Value).
reset_global_var_at_key(Key) :- '$reset_global_var_at_key'(Key).
reset_global_var_at_offset(Key, Value, Offset) :- '$reset_global_var_at_offset'(Key, Value, Offset).
'$bb_get_with_offset'(Key, OldValue, Offset) :-
atom(Key), !, '$fetch_global_var_with_offset'(Key, OldValue, Offset).
'$bb_get_with_offset'(Key, _, _) :-
throw(error(type_error(atom, Key), bb_b_put/2)).
bb_get(Key, Value) :- atom(Key), !, '$fetch_global_var'(Key, Value).
bb_get(Key, _) :- throw(error(type_error(atom, Key), bb_get/2)).
call_cleanup(G, C) :- setup_call_cleanup(true, G, C).
@@ -103,10 +109,10 @@ run_cleaners_without_handling(Cp) :-
% call_with_inference_limit
:- non_counted_backtracking end_block/4.
end_block(_, Bb, NBb, L) :-
end_block(_, Bb, NBb, _L) :-
'$clean_up_block'(NBb),
'$reset_block'(Bb).
end_block(B, Bb, NBb, L) :-
end_block(B, _Bb, NBb, L) :-
'$install_inference_counter'(B, L, _),
'$reset_block'(NBb),
'$fail'.
@@ -117,6 +123,8 @@ handle_ile(B, E, _) :-
'$remove_call_policy_check'(B),
'$call_with_default_policy'(throw(E)).
:- meta_predicate call_with_inference_limit(0, ?, ?).
call_with_inference_limit(G, L, R) :-
'$get_current_block'(Bb),
'$get_b_value'(B),
@@ -195,3 +203,7 @@ call_nth_nesting(ID) :-
),
asserta(i_call_nth_nesting(ID, 0)),
asserta(i_call_nth_counter(ID)).
copy_term_nat(Source, Dest) :-
'$copy_term_without_attr_vars'(Source, Dest).

230
src/lib/lambda.pl Normal file
View File

@@ -0,0 +1,230 @@
/*
Author: Ulrich Neumerkel
E-mail: ulrich@complang.tuwien.ac.at
Copyright (C): 2009 Ulrich Neumerkel. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY Ulrich Neumerkel ``AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Ulrich Neumerkel OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation
are those of the authors and should not be interpreted as representing
official policies, either expressed or implied, of Ulrich Neumerkel.
*/
:- module(lambda, [
(^)/3, (^)/4, (^)/5, (^)/6, (^)/7, (^)/8, (^)/9, (^)/10,
(\)/1, (\)/2, (\)/3, (\)/4, (\)/5, (\)/6, (\)/7, (\)/8,
(+\)/2, (+\)/3, (+\)/4, (+\)/5, (+\)/6, (+\)/7, (+\)/8,
(+\)/9, op(201,xfx,+\)]).
:- use_module(library(iso_ext)).
/** <module> Lambda expressions
This library provides lambda expressions to simplify higher order
programming based on call/N.
Lambda expressions are represented by ordinary Prolog terms.
There are two kinds of lambda expressions:
Free+\X1^X2^ ..^XN^Goal
\X1^X2^ ..^XN^Goal
The second is a shorthand for t+\X1^X2^..^XN^Goal.
Xi are the parameters.
Goal is a goal or continuation. Syntax note: Operators within Goal
require parentheses due to the low precedence of the ^ operator.
Free contains variables that are valid outside the scope of the lambda
expression. They are thus free variables within.
All other variables of Goal are considered local variables. They must
not appear outside the lambda expression. This restriction is
currently not checked. Violations may lead to unexpected bindings.
In the following example the parentheses around X>3 are necessary.
==
?- use_module(library(lambda)).
?- use_module(library(lists)).
?- maplist(\X^(X>3),[4,5,9]).
true.
==
In the following X is a variable that is shared by both instances of
the lambda expression. The second query illustrates the cooperation of
continuations and lambdas. The lambda expression is in this case a
continuation expecting a further argument.
==
?- use_module(library(dif)).
true.
?- Xs = [A,B], maplist(X+\Y^dif(X,Y), Xs).
Xs = [A,B], dif:dif(X,A), dif:dif(X,B).
?- Xs = [A,B], maplist(X+\dif(X), Xs).
Xs = [A,B], dif:dif(X,A), dif:dif(X,B).
==
The following queries are all equivalent. To see this, use
the fact f(x,y).
==
?- call(f,A1,A2).
?- call(\X^f(X),A1,A2).
?- call(\X^Y^f(X,Y), A1,A2).
?- call(\X^(X+\Y^f(X,Y)), A1,A2).
?- call(call(f, A1),A2).
?- call(f(A1),A2).
?- f(A1,A2).
A1 = x, A2 = y.
==
Further discussions
http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/ISO-Hiord
@tbd Static expansion similar to apply_macros.
@author Ulrich Neumerkel
*/
:- meta_predicate ^(?,0,?).
:- meta_predicate ^(?,1,?,?).
:- meta_predicate ^(?,2,?,?,?).
:- meta_predicate ^(?,3,?,?,?,?).
:- meta_predicate ^(?,4,?,?,?,?,?).
:- meta_predicate ^(?,5,?,?,?,?,?,?).
:- meta_predicate ^(?,6,?,?,?,?,?,?,?).
:- meta_predicate ^(?,7,?,?,?,?,?,?,?,?).
:- meta_predicate \(0).
:- meta_predicate \(1,?).
:- meta_predicate \(2,?,?).
:- meta_predicate \(3,?,?,?).
:- meta_predicate \(4,?,?,?,?).
:- meta_predicate \(5,?,?,?,?,?).
:- meta_predicate \(6,?,?,?,?,?,?).
:- meta_predicate \(7,?,?,?,?,?,?,?).
:- meta_predicate +\(?,0).
:- meta_predicate +\(?,1,?).
:- meta_predicate +\(?,2,?,?).
:- meta_predicate +\(?,3,?,?,?).
:- meta_predicate +\(?,4,?,?,?,?).
:- meta_predicate +\(?,5,?,?,?,?,?).
:- meta_predicate +\(?,6,?,?,?,?,?,?).
:- meta_predicate +\(?,7,?,?,?,?,?,?,?).
:- meta_predicate no_hat_call(0).
^(V1,C_0,V1) :-
no_hat_call(C_0).
^(V1,C_1,V1,V2) :-
call(C_1,V2).
^(V1,C_2,V1,V2,V3) :-
call(C_2,V2,V3).
^(V1,C_3,V1,V2,V3,V4) :-
call(C_3,V2,V3,V4).
^(V1,C_4,V1,V2,V3,V4,V5) :-
call(C_4,V2,V3,V4,V5).
^(V1,C_5,V1,V2,V3,V4,V5,V6) :-
call(C_5,V2,V3,V4,V5,V6).
^(V1,C_6,V1,V2,V3,V4,V5,V6,V7) :-
call(C_6,V2,V3,V4,V5,V6,V7).
^(V1,C_7,V1,V2,V3,V4,V5,V6,V7,V8) :-
call(C_7,V2,V3,V4,V5,V6,V7,V8).
\(FC_0) :-
copy_term_nat(FC_0,C_0),
no_hat_call(C_0).
\(FC_1,V1) :-
copy_term_nat(FC_1,C_1),
call(C_1,V1).
\(FC_2,V1,V2) :-
copy_term_nat(FC_2,C_2),
call(C_2,V1,V2).
\(FC_3,V1,V2,V3) :-
copy_term_nat(FC_3,C_3),
call(C_3,V1,V2,V3).
\(FC_4,V1,V2,V3,V4) :-
copy_term_nat(FC_4,C_4),
call(C_4,V1,V2,V3,V4).
\(FC_5,V1,V2,V3,V4,V5) :-
copy_term_nat(FC_5,C_5),
call(C_5,V1,V2,V3,V4,V5).
\(FC_6,V1,V2,V3,V4,V5,V6) :-
copy_term_nat(FC_6,C_6),
call(C_6,V1,V2,V3,V4,V5,V6).
\(FC_7,V1,V2,V3,V4,V5,V6,V7) :-
copy_term_nat(FC_7,C_7),
call(C_7,V1,V2,V3,V4,V5,V6,V7).
+\(GV,FC_0) :-
copy_term_nat(GV+FC_0,GV+C_0),
no_hat_call(C_0).
+\(GV,FC_1,V1) :-
copy_term_nat(GV+FC_1,GV+C_1),
call(C_1,V1).
+\(GV,FC_2,V1,V2) :-
copy_term_nat(GV+FC_2,GV+C_2),
call(C_2,V1,V2).
+\(GV,FC_3,V1,V2,V3) :-
copy_term_nat(GV+FC_3,GV+C_3),
call(C_3,V1,V2,V3).
+\(GV,FC_4,V1,V2,V3,V4) :-
copy_term_nat(GV+FC_4,GV+C_4),
call(C_4,V1,V2,V3,V4).
+\(GV,FC_5,V1,V2,V3,V4,V5) :-
copy_term_nat(GV+FC_5,GV+C_5),
call(C_5,V1,V2,V3,V4,V5).
+\(GV,FC_6,V1,V2,V3,V4,V5,V6) :-
copy_term_nat(GV+FC_6,GV+C_6),
call(C_6,V1,V2,V3,V4,V5,V6).
+\(GV,FC_7,V1,V2,V3,V4,V5,V6,V7) :-
copy_term_nat(GV+FC_7,GV+C_7),
call(C_7,V1,V2,V3,V4,V5,V6,V7).
%% no_hat_call(:Goal_0)
%
% Like call, but issues an error for a goal (^)/2. Such goals are
% likely the result of an insufficient number of arguments.
no_hat_call(MGoal_0) :-
strip_module(MGoal_0, _, Goal_0),
( nonvar(Goal_0),
Goal_0 = (_^_)
-> throw(
error(
existence_error(lambda_parameter,MGoal_0),
_))
; call(MGoal_0)
).
% I would like to replace this by:
% V1^Goal :- throw(error(existence_error(lambda_parameter,V1^Goal),_)).

View File

@@ -1,15 +1,29 @@
:- module(lists, [member/2, select/3, append/2, append/3, foldl/4, foldl/5,
memberchk/2, reverse/2, length/2, maplist/2,
maplist/3, maplist/4, maplist/5, maplist/6,
maplist/7, maplist/8, maplist/9, same_length/2, nth0/3,
sum_list/2, transpose/2, list_to_set/2, list_max/2, list_min/2]).
memberchk/2, reverse/2, length/2, maplist/2,
maplist/3, maplist/4, maplist/5, maplist/6,
maplist/7, maplist/8, maplist/9, same_length/2, nth0/3,
sum_list/2, transpose/2, list_to_set/2, list_max/2, list_min/2]).
:- use_module(library(error)).
:- meta_predicate maplist(1, ?).
:- meta_predicate maplist(2, ?, ?).
:- meta_predicate maplist(3, ?, ?, ?).
:- meta_predicate maplist(4, ?, ?, ?, ?).
:- meta_predicate maplist(5, ?, ?, ?, ?, ?).
:- meta_predicate maplist(6, ?, ?, ?, ?, ?, ?).
:- meta_predicate maplist(7, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate maplist(8, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate foldl(3, ?, ?, ?).
:- meta_predicate foldl(4, ?, ?, ?, ?).
length(Xs, N) :-
var(N), !,
var(N),
!,
'$skip_max_list'(M, -1, Xs, Xs0),
( Xs0 == [] -> N = M
; var(Xs0) -> length_addendum(Xs0, N, M)).
@@ -66,7 +80,6 @@ reverse([], [], YsRev, YsRev).
reverse([_|Xs], [Y1|Ys], YsPreludeRev, Xss) :-
reverse(Xs, Ys, [Y1|YsPreludeRev], Xss).
maplist(_, []).
maplist(Cont1, [E1|E1s]) :-
call(Cont1, E1),
@@ -87,21 +100,25 @@ maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s]) :-
call(Cont, E1, E2, E3, E4),
maplist(Cont, E1s, E2s, E3s, E4s).
maplist(_, [], [], [], [], []).
maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s]) :-
call(Cont, E1, E2, E3, E4, E5),
maplist(Cont, E1s, E2s, E3s, E4s, E5s).
maplist(_, [], [], [], [], [], []).
maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s]) :-
call(Cont, E1, E2, E3, E4, E5, E6),
maplist(Cont, E1s, E2s, E3s, E4s, E5s, E6s).
maplist(_, [], [], [], [], [], [], []).
maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7s]) :-
call(Cont, E1, E2, E3, E4, E5, E6, E7),
maplist(Cont, E1s, E2s, E3s, E4s, E5s, E6s, E7s).
maplist(_, [], [], [], [], [], [], [], []).
maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7s], [E8|E8s]) :-
call(Cont, E1, E2, E3, E4, E5, E6, E7, E8),
@@ -109,7 +126,7 @@ maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7
sum_list(Ls, S) :-
foldl(sum_, Ls, 0, S).
foldl(lists:sum_, Ls, 0, S).
sum_(L, S0, S) :- S is S0 + L.
@@ -132,6 +149,7 @@ foldl_([L|Ls], G_3, A0, A) :-
foldl(Goal_4, Xs, Ys, A0, A) :-
foldl_(Xs, Ys, Goal_4, A0, A).
foldl_([], [], _, A, A).
foldl_([X|Xs], [Y|Ys], G_4, A0, A) :-
call(G_4, X, Y, A0, A1),
@@ -142,17 +160,17 @@ transpose(Ls, Ts) :-
lists_transpose([], []).
lists_transpose([L|Ls], Ts) :-
maplist(same_length(L), Ls),
foldl(transpose_, L, Ts, [L|Ls], _).
maplist(lists:same_length(L), Ls),
foldl(lists:transpose_, L, Ts, [L|Ls], _).
transpose_(_, Fs, Lists0, Lists) :-
maplist(list_first_rest, Lists0, Fs, Lists).
maplist(lists:list_first_rest, Lists0, Fs, Lists).
list_first_rest([L|Ls], L, Ls).
list_to_set(Ls0, Ls) :-
maplist(with_var, Ls0, LVs0),
maplist(lists:with_var, Ls0, LVs0),
keysort(LVs0, LVs),
same_elements(LVs),
pick_firsts(LVs0, Ls).
@@ -170,7 +188,7 @@ with_var(E, E-_).
same_elements([]).
same_elements([EV|EVs]) :-
foldl(unify_same, EVs, EV, _).
foldl(lists:unify_same, EVs, EV, _).
unify_same(E-V, Prev-Var, E-V) :-
( Prev == E ->
@@ -203,13 +221,13 @@ nth0_search(N0, N, [_|Es], E) :-
list_max([N|Ns], Max) :-
foldl(list_max_, Ns, N, Max).
foldl(lists:list_max_, Ns, N, Max).
list_max_(N, Max0, Max) :-
Max is max(N, Max0).
list_min([N|Ns], Min) :-
foldl(list_min_, Ns, N, Min).
foldl(lists:list_min_, Ns, N, Min).
list_min_(N, Min0, Min) :-
Min is min(N, Min0).

View File

@@ -0,0 +1,129 @@
:- op(400, yfx, /).
% module resolution operator.
:- op(600, xfy, :).
:- op(1199, fx, meta_predicate).
/* this is an implementation specific declarative operator used to implement call_with_inference_limit/3
and setup_call_cleanup/3. switches to the default trust_me and retry_me_else. Indexing choice
instructions are unchanged. */
:- op(700, fx, non_counted_backtracking).
% arithmetic operators.
:- op(700, xfx, is).
:- op(500, yfx, +).
:- op(500, yfx, -).
:- op(400, yfx, *).
:- op(200, xfy, **).
:- op(200, xfy, ^).
:- op(500, yfx, /\).
:- op(500, yfx, \/).
:- op(500, yfx, xor).
:- op(400, yfx, div).
:- op(400, yfx, //).
:- op(400, yfx, rdiv).
:- op(400, yfx, <<).
:- op(400, yfx, >>).
:- op(400, yfx, mod).
:- op(400, yfx, rem).
:- op(200, fy, +).
:- op(200, fy, -).
:- op(200, fy, \).
% arithmetic comparison operators.
:- op(700, xfx, >).
:- op(700, xfx, <).
:- op(700, xfx, =\=).
:- op(700, xfx, =:=).
:- op(700, xfx, >=).
:- op(700, xfx, =<).
% term comparison.
:- op(700, xfx, ==).
:- op(700, xfx, \==).
:- op(700, xfx, @=<).
:- op(700, xfx, @>=).
:- op(700, xfx, @<).
:- op(700, xfx, @>).
% conditional operators.
:- op(1050, xfy, ->).
:- op(1100, xfy, ;).
% control.
:- op(700, xfx, =).
:- op(700, xfx, =..).
:- op(700, xfx, \=).
:- op(900, fy, \+).
:- op(1200, xfx, -->).
% meta_predicate declarations for call/{1, 66}.
:- meta_predicate call(0).
:- meta_predicate call(1, ?).
:- meta_predicate call(2, ?, ?).
:- meta_predicate call(3, ?, ?, ?).
:- meta_predicate call(4, ?, ?, ?, ?).
:- meta_predicate call(5, ?, ?, ?, ?, ?).
:- meta_predicate call(6, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(7, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(8, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(9, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(10, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(11, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(12, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(13, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(14, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(15, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(16, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(17, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(18, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(19, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(20, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(21, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(22, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(23, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(24, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(25, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(26, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(27, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(28, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(29, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(30, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(31, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(32, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(33, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(34, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(35, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(36, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(37, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(38, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(39, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(40, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(41, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(42, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(43, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(44, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(45, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(46, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(47, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(48, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(49, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(50, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(51, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(52, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(53, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(54, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(55, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(56, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(57, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(58, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(59, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(60, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(60, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(61, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(62, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(63, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(64, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(65, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).

View File

@@ -5,6 +5,8 @@
map_list_to_pairs/3]).
:- meta_predicate map_list_to_pairs(0, ?, ?).
pairs_keys_values([], [], []).
pairs_keys_values([A-B|ABs], [A|As], [B|Bs]) :-
pairs_keys_values(ABs, As, Bs).

View File

@@ -7,6 +7,9 @@
:- use_module(library(iso_ext), [setup_call_cleanup/3, partial_string/3]).
:- use_module(library(lists), [member/2]).
:- meta_predicate phrase_from_file(2, ?).
:- meta_predicate phrase_from_file(2, ?, ?).
phrase_from_file(NT, File) :-
phrase_from_file(NT, File, []).

View File

@@ -4,6 +4,8 @@
:- use_module(library(dif)).
:- meta_predicate if_(0, 0, 0).
if_(If_1, Then_0, Else_0) :-
call(If_1, T),
( T == true -> call(Then_0)
@@ -26,6 +28,8 @@ dif(X, Y, T) :-
non(true, false).
non(false, true).
:- meta_predicate tfilter(1, ?, ?).
tfilter(C_2, Es, Fs) :-
i_tfilter(Es, C_2, Fs).
@@ -34,6 +38,8 @@ i_tfilter([E|Es], C_2, Fs0) :-
if_(call(C_2, E), Fs0 = [E|Fs], Fs0 = Fs),
i_tfilter(Es, C_2, Fs).
:- meta_predicate tpartition(1, ?, ?).
tpartition(P_2, Xs, Ts, Fs) :-
i_tpartition(Xs, P_2, Ts, Fs).
@@ -44,12 +50,18 @@ i_tpartition([X|Xs], P_2, Ts0, Fs0) :-
, ( Fs0 = [X|Fs], Ts0 = Ts ) ),
i_tpartition(Xs, P_2, Ts, Fs).
:- meta_predicate ','(0, 0, ?).
','(A_1, B_1, T) :-
if_(A_1, call(B_1, T), T = false).
:- meta_predicate ';'(0, 0, ?).
';'(A_1, B_1, T) :-
if_(A_1, T = true, call(B_1, T)).
:- meta_predicate cond_t(0, 0, ?).
cond_t(If_1, Then_0, T) :-
if_(If_1, ( Then_0, T = true ), T = false ).
@@ -60,8 +72,12 @@ i_memberd_t([], _, false).
i_memberd_t([X|Xs], E, T) :-
if_( X = E, T = true, i_memberd_t(Xs, E, T) ).
:- meta_predicate tmember(1, ?).
tmember(P_2, [X|Xs]) :-
if_( call(P_2, X), true, tmember(P_2, Xs) ).
:- meta_predicate tmember_t(1, ?).
tmember_t(P_2, [X|Xs], T) :-
if_( call(P_2, X), T = true, tmember_t(P_2, Xs, T) ).

View File

@@ -15,7 +15,7 @@ parse_socket_options_(Option, OptionPair) :-
parse_socket_options(Options, OptionValues, Stub) :-
DefaultOptions = [alias-[], eof_action-eof_code, reposition-false, tls-false, type-text],
builtins:parse_options_list(Options, parse_socket_options_, DefaultOptions, OptionValues, Stub).
builtins:parse_options_list(Options, sockets:parse_socket_options_, DefaultOptions, OptionValues, Stub).
socket_client_open(Addr, Stream, Options) :-
( var(Addr) ->

View File

@@ -11,9 +11,9 @@
:- use_module(library(tabling/double_linked_list)).
:- use_module(library(tabling/table_data_structure)).
:- use_module(library(tabling/batched_worklist)).
:- use_module(library(tabling/wrapper)).
:- use_module(library(tabling/global_worklist)).
:- use_module(library(tabling/table_link_manager)).
:- use_module(library(tabling/wrapper)).
:- use_module(library(cont)).
:- use_module(library(lists)).
@@ -66,6 +66,9 @@ table_and_status_for_variant(V,T,S) :-
table_for_variant(V,T),
tbd_table_status(T,S).
:- meta_predicate start_tabling(?, 0).
start_tabling(Wrapper,Worker) :-
put_new_trie_table_link,
put_new_global_worklist,

View File

@@ -53,6 +53,8 @@
:- attribute executing_all_work/1, worklist_presence/1, wkl_answer_cluster/1, wkl_suspension_cluster/1, wkl_answer_cluster_pointer_flag/1.
verify_attributes(_, _, []).
/** <module> Tabling Worklist management
A batched worklist: a worklist that clusters suspensions and answers as

View File

@@ -13,6 +13,8 @@
:- attribute table_global_worklist/1.
verify_attributes(_, _, []).
put_new_global_worklist :-
( bb_get(table_global_worklist_initialized, _) ->
true

View File

@@ -61,6 +61,8 @@
:- attribute table_status/1, newly_created_table_identifiers/1.
verify_attributes(_, _, []).
% This file defines the table datastructure.
%
% The table datastructure contains the following sub-structures:

View File

@@ -51,6 +51,8 @@
:- attribute trie_table_link/1.
verify_attributes(_, _, []).
% This file defines a call pattern trie.
%
% This data structure keeps the relation between a variant and the

View File

@@ -47,6 +47,8 @@
:- attribute maybe_just/1, children/1.
verify_attributes(_, _, []).
% Implementation of a prefix tree, a.k.a. trie %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View File

@@ -40,6 +40,8 @@
:- use_module(library(dcgs)).
:- use_module(library(error)).
:- multifile(tabled/2).
%%:- multifile
%% system:term_expansion/2,
%% tabled/2.
@@ -75,7 +77,7 @@ wrappers(Name/Arity) -->
atom_concat(Name, ' tabled', WrapName),
Head =.. [Name|Args],
WrappedHead =.. [WrapName|Args],
'$module_of'(Module, Name) %prolog_load_context(module, Module)
prolog_load_context(module, Module)
},
[ ( Head :-
start_tabling(Module:Head, WrappedHead)
@@ -109,10 +111,10 @@ rename_term(Name, WrapName) :-
user:term_expansion(Term0, Clauses) :-
nonvar(Term0),
nonvar(Term0),
Term0 = (:- table Preds),
phrase(wrappers(Preds), Clauses).
user:term_expansion(Clause, NewClause) :-
nonvar(Clause),
'$module_of'(Module, Clause),
nonvar(Clause),
prolog_load_context(module, Module),
rename(Clause, NewClause, Module).

View File

@@ -82,6 +82,8 @@ sleep(T) :-
% '$cpu_now' can be replaced by statistics/2 once that is implemented.
:- meta_predicate time(0).
time(Goal) :-
'$cpu_now'(T0),
setup_call_cleanup(true,

107
src/lib/uuid.pl Normal file
View File

@@ -0,0 +1,107 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Written in February 2021 by Adrián Arroyo (adrian.arroyocalle@gmail.com)
Part of Scryer-Prolog
This library provides reasoning about UUID (only version 4 right now).
There are three predicates:
* uuidv4/1, to generate a new UUIDv4
* uuidv4_string/1, to generate a new UUIDv4 in string hex representation
* uuid_string/2, to converte between UUID list of bytes and UUID hex representation
Examples:
?- uuidv4(X).
X = [42,147,248,242,117,196,79,2,129,159|...].
?- uuidv4_string(X).
X = "428499fc-76e3-4240- ...".
?- uuidv4(X), uuid_string(X, S).
X = [173,12,244,152,139,118,64,139,137,4|...], S = "ad0cf498-8b76-408b- ...".
?- uuid_string(X, "61ae692e-eaf6-4199-8dd3-9f01db70a20b").
X = [97,174,105,46,234,246,65,153,141,211|...].
I place this code in the public domain. Use it in any way you want.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- module(uuid, [
uuidv4/1,
uuidv4_string/1,
uuid_string/2
]).
:- use_module(library(crypto)).
:- use_module(library(dcgs)).
:- use_module(library(lists)).
/*
An UUID is made of 16 bytes, composed of 5 sections:
time_low - 4
time_mid - 2
time_hi_and_version - 2
clock_seq_hi_and_res_clock_seq_low - 2
node - 6
UUID v4 can be generated from a set of 16 random bytes: https://www.rfc-archive.org/getrfc.php?rfc=4122#gsc.tab=0 (section 4.4)
*/
uuidv4(Uuid) :-
crypto_n_random_bytes(16, Bytes),
Bytes = [B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, B11, B12, B13, B14, B15, B16],
byte_bits(B9, BitsClockSeqHi0),
BitsClockSeqHi0 = [_X7, _X6, X5, X4, X3, X2, X1, X0],
NewBitsClockSeqHi0 = [1, 0, X5, X4, X3, X2, X1, X0],
byte_bits(NewClockSeqHi0, NewBitsClockSeqHi0),
byte_bits(B7, BitsTimeHi),
BitsTimeHi = [_Y7, _Y6, _Y5, _Y4, Y3, Y2, Y1, Y0],
NewBitsTimeHi = [0, 1, 0, 0, Y3, Y2, Y1, Y0],
byte_bits(NewTimeHi, NewBitsTimeHi),
Uuid = [B1, B2, B3, B4, B5, B6, NewTimeHi, B8, NewClockSeqHi0, B10, B11, B12, B13, B14, B15, B16].
uuidv4_string(String) :- uuidv4(Uuid), uuid_string(Uuid, String).
uuid_string(Uuid, String) :-
Uuid = [B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, B11, B12, B13, B14, B15, B16],
phrase(uuid_([S1, S2, S3, S4, S5]), String),
hex_bytes(S1, [B1, B2, B3, B4]),
hex_bytes(S2, [B5, B6]),
hex_bytes(S3, [B7, B8]),
hex_bytes(S4, [B9, B10]),
hex_bytes(S5, [B11, B12, B13, B14, B15, B16]).
uuid_([S1, S2, S3, S4, S5]) -->
{
length(S1, 8),
length(S2, 4),
length(S3, 4),
length(S4, 4),
length(S5, 12)
},
S1,
"-",
S2,
"-",
S3,
"-",
S4,
"-",
S5.
byte_bits(Byte, Bits) :-
\+ var(Byte),
byte_bits_(Byte, Bits),
length(Bits, 8),!.
byte_bits(Byte, Bits) :-
\+ var(Bits),
length(Bits, 8),
byte_bits__(Byte, Bits),!.
byte_bits_(0, [0]).
byte_bits_(1, [1]).
byte_bits_(Byte, Bits) :-
R is Byte // 2,
M is Byte mod 2,
byte_bits_(R, Bits0),
append(Bits0, [M], Bits).
byte_bits__(0, []).
byte_bits__(Byte, Bits) :-
length(Bits, N),
Bits = [Bit|Bits0],
byte_bits__(Byte0, Bits0),
Byte is Byte0 + Bit*(2 ^ (N-1)).

1404
src/loader.pl Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,6 @@
:- module('$atts', []).
driver(Vars, Values) :-
iterate(Vars, Values, ListOfListsOfGoalLists),
!,
@@ -13,9 +14,9 @@ iterate([Var|VarBindings], [Value|ValueBindings], [ListOfGoalLists | ListsCubed]
iterate(VarBindings, ValueBindings, ListsCubed).
iterate([], [], []).
gather_modules(Attrs, []) :- var(Attrs), !.
gather_modules([Attr|Attrs], [Module|Modules]) :-
'$module_of'(Module, Attr), % write the owning module of Attr to Module.
gather_modules([Module:_|Attrs], [Module|Modules]) :-
gather_modules(Attrs, Modules).
call_verify_attributes(Attrs, _, _, []) :-
@@ -26,27 +27,30 @@ call_verify_attributes([Attr|Attrs], Var, Value, ListOfGoalLists) :-
sort(Modules0, Modules),
verify_attrs(Modules, Var, Value, ListOfGoalLists).
verify_attrs([Module|Modules], Var, Value, [Goals|ListOfGoalLists]) :-
verify_attrs([Module|Modules], Var, Value, [Module-Goals|ListOfGoalLists]) :-
catch(Module:verify_attributes(Var, Value, Goals),
error(evaluation_error((Module:verify_attributes)/3), verify_attributes/3),
Goals = []),
verify_attrs(Modules, Var, Value, ListOfGoalLists).
verify_attrs([], _, _, []).
call_goals([ListOfGoalLists | ListsCubed]) :-
call_goals_0(ListOfGoalLists),
call_goals(ListsCubed).
call_goals([]).
call_goals_0([GoalList | GoalLists]) :-
( var(GoalList), throw(error(instantiation_error, call_goals_0/1))
call_goals_0([Module-GoalList | GoalLists]) :-
( var(GoalList),
throw(error(instantiation_error, call_goals_0/1))
; true
),
call_goals_1(GoalList),
call_goals_1(GoalList, Module),
call_goals_0(GoalLists).
call_goals_0([]).
call_goals_1([Goal | Goals]) :-
call(Goal),
call_goals_1(Goals).
call_goals_1([]).
call_goals_1([Goal | Goals], Module) :-
call(Module:Goal),
call_goals_1(Goals, Module).
call_goals_1([], _).

View File

@@ -1,14 +1,12 @@
use crate::heap_iter::*;
use crate::machine::*;
use prolog_parser::temp_v;
use crate::indexmap::IndexSet;
use indexmap::IndexSet;
use std::cmp::Ordering;
use std::vec::IntoIter;
pub static VERIFY_ATTRS: &str = include_str!("attributed_variables.pl");
pub static PROJECT_ATTRS: &str = include_str!("project_attributes.pl");
pub(super) type Bindings = Vec<(usize, Addr)>;
#[derive(Debug)]
@@ -23,8 +21,7 @@ pub(super) struct AttrVarInitializer {
}
impl AttrVarInitializer {
pub(super)
fn new(verify_attrs_loc: usize, project_attrs_loc: usize) -> Self {
pub(super) fn new(verify_attrs_loc: usize, project_attrs_loc: usize) -> Self {
AttrVarInitializer {
attribute_goals: vec![],
attr_var_queue: vec![],
@@ -37,24 +34,21 @@ impl AttrVarInitializer {
}
#[inline]
pub(super)
fn reset(&mut self) {
self.attribute_goals.clear();
pub(super) fn reset(&mut self) {
self.attribute_goals.clear();
self.attr_var_queue.clear();
self.bindings.clear();
}
#[inline]
pub(super)
fn backtrack(&mut self, queue_b: usize, bindings_b: usize) {
pub(super) fn backtrack(&mut self, queue_b: usize, bindings_b: usize) {
self.attr_var_queue.truncate(queue_b);
self.bindings.truncate(bindings_b);
}
}
impl MachineState {
pub(super)
fn push_attr_var_binding(&mut self, h: usize, addr: Addr) {
pub(super) fn push_attr_var_binding(&mut self, h: usize, addr: Addr) {
if self.attr_var_init.bindings.is_empty() {
self.attr_var_init.instigating_p = self.p.local();
@@ -82,7 +76,7 @@ impl MachineState {
let iter = self
.attr_var_init
.bindings
.drain(0 ..)
.drain(0..)
.map(|(_, addr)| HeapCellValue::Addr(addr));
let value_list_addr = Addr::HeapCell(self.heap.to_list(iter));
@@ -100,8 +94,7 @@ impl MachineState {
self[temp_v!(2)] = value_list_addr;
}
pub(super)
fn gather_attr_vars_created_since(&self, b: usize) -> IntoIter<Addr> {
pub(super) fn gather_attr_vars_created_since(&self, b: usize) -> IntoIter<Addr> {
let mut attr_vars: Vec<_> = self.attr_var_init.attr_var_queue[b..]
.iter()
.filter_map(|h| match self.store(self.deref(Addr::HeapCell(*h))) {
@@ -110,29 +103,25 @@ impl MachineState {
})
.collect();
attr_vars.sort_unstable_by(|a1, a2| {
self.compare_term_test(a1, a2).unwrap_or(Ordering::Less)
});
attr_vars
.sort_unstable_by(|a1, a2| self.compare_term_test(a1, a2).unwrap_or(Ordering::Less));
self.term_dedup(&mut attr_vars);
attr_vars.into_iter()
}
pub(super)
fn verify_attr_interrupt(&mut self, p: usize) {
pub(super) fn verify_attr_interrupt(&mut self, p: usize) {
self.allocate(self.num_of_args + 2);
let e = self.e;
self.stack.index_and_frame_mut(e).prelude.interrupt_cp = self.attr_var_init.cp;
for i in 1 .. self.num_of_args + 1 {
self.stack.index_and_frame_mut(e)[i] = self[RegType::Temp(i)].clone();
for i in 1..self.num_of_args + 1 {
self.stack.index_and_frame_mut(e)[i] = self[RegType::Temp(i)];
}
self.stack.index_and_frame_mut(e)[self.num_of_args + 1] =
Addr::CutPoint(self.b0);
self.stack.index_and_frame_mut(e)[self.num_of_args + 2] =
Addr::Usize(self.num_of_args);
self.stack.index_and_frame_mut(e)[self.num_of_args + 1] = Addr::CutPoint(self.b0);
self.stack.index_and_frame_mut(e)[self.num_of_args + 2] = Addr::Usize(self.num_of_args);
self.verify_attributes();
@@ -141,9 +130,8 @@ impl MachineState {
self.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
}
pub(super)
fn attr_vars_of_term(&self, addr: Addr) -> Vec<Addr> {
let mut seen_set = IndexSet::new();
pub(super) fn attr_vars_of_term(&self, addr: Addr) -> Vec<Addr> {
let mut seen_set = IndexSet::new();
let mut seen_vars = vec![];
let mut iter = self.acyclic_pre_order_iter(addr);

View File

@@ -1,161 +1,54 @@
use crate::clause_types::*;
use crate::codegen::*;
use crate::debray_allocator::*;
use crate::forms::*;
use crate::instructions::*;
use crate::machine::compile::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::indexmap::IndexSet;
use std::collections::VecDeque;
use std::mem;
#[derive(Debug)]
pub struct CodeRepo {
pub(super) cached_query: Code,
pub(super) goal_expanders: Code,
pub(super) term_expanders: Code,
pub(crate) struct CodeRepo {
pub(super) code: Code,
pub(super) in_situ_code: Code,
pub(super) term_dir: TermDir,
}
impl CodeRepo {
#[inline]
pub(super) fn new() -> Self {
CodeRepo {
cached_query: vec![],
goal_expanders: Code::new(),
term_expanders: Code::new(),
code: Code::new(),
in_situ_code: Code::new(),
term_dir: TermDir::new(),
CodeRepo { code: Code::new() }
}
#[inline]
pub(super) fn lookup_local_instr<'a>(&'a self, p: LocalCodePtr) -> RefOrOwned<'a, Line> {
match p {
LocalCodePtr::Halt => {
// exit with the interrupt exit code.
std::process::exit(1);
}
LocalCodePtr::DirEntry(p) => RefOrOwned::Borrowed(&self.code[p as usize]),
LocalCodePtr::IndexingBuf(p, o, i) => match &self.code[p] {
&Line::IndexingCode(ref indexing_lines) => match &indexing_lines[o] {
&IndexingLine::IndexedChoice(ref indexed_choice_instrs) => {
RefOrOwned::Owned(Line::IndexedChoice(indexed_choice_instrs[i]))
}
&IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => {
RefOrOwned::Owned(Line::DynamicIndexedChoice(indexed_choice_instrs[i]))
}
_ => {
unreachable!()
}
},
_ => {
unreachable!()
}
},
}
}
#[inline]
pub fn term_dir_entry_len(&self, key: PredicateKey) -> (usize, usize) {
self.term_dir
.get(&key)
.map(|entry| ((entry.0).0.len(), entry.1.len()))
.unwrap_or((0, 0))
}
#[inline]
pub fn truncate_terms(
&mut self,
key: PredicateKey,
len: usize,
queue_len: usize,
) -> (Predicate, VecDeque<TopLevel>) {
self.term_dir
.get_mut(&key)
.map(|entry| {
let terms =
if len < (entry.0).0.len() {
(entry.0).0.drain(len ..).collect()
} else {
vec![]
};
let queue =
if queue_len < entry.1.len() {
entry.1.drain(queue_len ..).collect()
} else {
VecDeque::new()
};
(Predicate(terms), queue)
})
.unwrap_or((Predicate::new(), VecDeque::new()))
}
pub(crate)
fn add_in_situ_result(
&mut self,
result: &CompiledResult,
in_situ_code_dir: &mut InSituCodeDir,
in_situ_module_dir: &mut ModuleStubDir,
non_counted_bt_preds: &IndexSet<PredicateKey>,
) -> Result<(), SessionError> {
let (ref decl, ref queue) = result;
let (name, arity) = decl
.0
.first()
.and_then(|cl| {
let arity = cl.arity();
cl.name().map(|name| (name, arity))
})
.ok_or(SessionError::NamelessEntry)?;
let non_counted_bt = non_counted_bt_preds.contains(&(name.clone(), arity));
let module_name = name.owning_module();
let p = self.in_situ_code.len();
match in_situ_module_dir.get_mut(&module_name) {
Some(ref mut module_stub) if name.has_table(&module_stub.atom_tbl) => {
module_stub.in_situ_code_dir.insert((name, arity), p);
}
_ => {
in_situ_code_dir.insert((name, arity), p);
}
}
let mut cg = CodeGenerator::<DebrayAllocator>::new(non_counted_bt);
let mut decl_code = cg.compile_predicate(&decl.0)?;
compile_appendix(&mut decl_code, queue, non_counted_bt)?;
Ok(self.in_situ_code.extend(decl_code.into_iter()))
}
#[inline]
pub(super)
fn size_of_cached_query(&self) -> usize {
self.cached_query.len()
}
#[inline]
pub(super)
fn take_in_situ_code(&mut self) -> Code {
mem::replace(&mut self.in_situ_code, Code::new())
}
pub(super)
fn lookup_instr<'a>(
pub(super) fn lookup_instr<'a>(
&'a self,
last_call: bool,
p: &CodePtr,
) -> Option<RefOrOwned<'a, Line>> {
match p {
&CodePtr::Local(LocalCodePtr::UserGoalExpansion(p)) => {
if p < self.goal_expanders.len() {
Some(RefOrOwned::Borrowed(&self.goal_expanders[p]))
} else {
None
}
&CodePtr::Local(local) => {
return Some(self.lookup_local_instr(local));
}
&CodePtr::Local(LocalCodePtr::UserTermExpansion(p)) => {
if p < self.term_expanders.len() {
Some(RefOrOwned::Borrowed(&self.term_expanders[p]))
} else {
None
}
}
&CodePtr::Local(LocalCodePtr::TopLevel(_, p)) => {
if p < self.cached_query.len() {
Some(RefOrOwned::Borrowed(&self.cached_query[p]))
} else {
None
}
}
&CodePtr::Local(LocalCodePtr::InSituDirEntry(p)) => {
Some(RefOrOwned::Borrowed(&self.in_situ_code[p]))
}
&CodePtr::Local(LocalCodePtr::DirEntry(p)) => Some(RefOrOwned::Borrowed(&self.code[p])),
&CodePtr::REPL(..) => None,
&CodePtr::BuiltInClause(ref built_in, _) => {
let call_clause = call_clause!(
@@ -164,14 +57,121 @@ impl CodeRepo {
0,
last_call
);
Some(RefOrOwned::Owned(call_clause))
}
&CodePtr::CallN(arity, _, last_call) => {
let call_clause = call_clause!(ClauseType::CallN, arity, 0, last_call);
Some(RefOrOwned::Owned(call_clause))
}
&CodePtr::VerifyAttrInterrupt(p) => Some(RefOrOwned::Borrowed(&self.code[p])),
&CodePtr::DynamicTransaction(..) => None,
}
}
pub(super) fn find_living_dynamic_else(
&self,
mut p: usize,
cc: usize,
) -> Option<(usize, usize)> {
loop {
match &self.code[p] {
&Line::Choice(ChoiceInstruction::DynamicElse(
birth,
death,
NextOrFail::Next(i),
)) => {
if birth < cc && Death::Finite(cc) <= death {
return Some((p, i));
} else if i > 0 {
p += i;
} else {
return None;
}
}
&Line::Choice(ChoiceInstruction::DynamicElse(
birth,
death,
NextOrFail::Fail(_),
)) => {
if birth < cc && Death::Finite(cc) <= death {
return Some((p, 0));
} else {
return None;
}
}
&Line::Choice(ChoiceInstruction::DynamicInternalElse(
birth,
death,
NextOrFail::Next(i),
)) => {
if birth < cc && Death::Finite(cc) <= death {
return Some((p, i));
} else if i > 0 {
p += i;
} else {
return None;
}
}
&Line::Choice(ChoiceInstruction::DynamicInternalElse(
birth,
death,
NextOrFail::Fail(_),
)) => {
if birth < cc && Death::Finite(cc) <= death {
return Some((p, 0));
} else {
return None;
}
}
&Line::Control(ControlInstruction::RevJmpBy(i)) => {
p -= i;
}
_ => {
unreachable!();
}
}
}
}
pub(super) fn find_living_dynamic(
&self,
p: LocalCodePtr,
cc: usize,
) -> Option<(usize, usize, usize, bool)> {
let (p, oi, mut ii) = match p {
LocalCodePtr::IndexingBuf(p, oi, ii) => (p, oi, ii),
_ => unreachable!(),
};
let indexed_choice_instrs = match &self.code[p] {
Line::IndexingCode(ref indexing_code) => match &indexing_code[oi] {
IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => {
indexed_choice_instrs
}
_ => unreachable!(),
},
_ => unreachable!(),
};
loop {
match &indexed_choice_instrs.get(ii) {
Some(&offset) => match &self.code[p + offset - 1] {
&Line::Choice(ChoiceInstruction::DynamicInternalElse(
birth,
death,
next_or_fail,
)) => {
if birth < cc && Death::Finite(cc) <= death {
return Some((offset, oi, ii, next_or_fail.is_next()));
} else {
ii += 1;
}
}
_ => unreachable!(),
},
None => return None,
}
}
}
}

View File

@@ -1,90 +1,71 @@
use crate::instructions::*;
use std::collections::VecDeque;
use indexmap::IndexSet;
fn scan_for_trust_me(
code: &Code,
jmp_offsets: &mut VecDeque<usize>,
before_idx: usize,
after_idx: &mut usize,
) {
// record the location of the line after the TrustMe capping the
// choice instruction sequence to after_idx.
loop {
match &code[*after_idx] {
&Line::Choice(ChoiceInstruction::DefaultRetryMeElse(offset)) |
&Line::Choice(ChoiceInstruction::RetryMeElse(offset)) |
&Line::IndexedChoice(IndexedChoiceInstruction::Retry(offset)) => {
*after_idx += offset;
fn capture_offset(line: &Line, index: usize, stack: &mut Vec<usize>) -> bool {
match line {
&Line::Choice(ChoiceInstruction::TryMeElse(offset)) if offset > 0 => {
stack.push(index + offset);
}
&Line::Choice(ChoiceInstruction::DefaultRetryMeElse(offset))
| &Line::Choice(ChoiceInstruction::RetryMeElse(offset))
if offset > 0 =>
{
stack.push(index + offset);
}
&Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(offset)))
if offset > 0 => {
stack.push(index + offset);
}
&Line::Choice(ChoiceInstruction::DefaultTrustMe) |
&Line::Choice(ChoiceInstruction::TrustMe) |
&Line::IndexedChoice(IndexedChoiceInstruction::Trust(..)) => {
break;
&Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(offset)))
if offset > 0 => {
stack.push(index + offset);
}
_ => {
*after_idx += 1;
&Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => {
stack.push(index + offset);
}
&Line::Control(ControlInstruction::JmpBy(_, offset, _, true)) => {
stack.push(index + offset);
return true;
}
&Line::Control(ControlInstruction::Proceed)
| &Line::Control(ControlInstruction::CallClause(_, _, _, true, _)) => {
return true;
}
&Line::Control(ControlInstruction::RevJmpBy(offset)) => {
if offset > 0 {
stack.push(index - offset);
} else {
return true;
}
}
}
_ => {}
};
// search the code in the range for JmpBy instructions and record their
// offsets for future scanning.
for (idx, instr) in code[before_idx .. *after_idx].iter().enumerate() {
match instr {
&Line::Control(ControlInstruction::JmpBy(_, offset, ..)) => {
jmp_offsets.push_back(before_idx + idx + offset)
}
_ => {
}
}
}
*after_idx += 1;
}
fn capture_next_range(code: &Code, queue: &mut VecDeque<usize>, last_idx: &mut usize) {
loop {
match &code[*last_idx] {
&Line::Choice(ChoiceInstruction::TryMeElse(offset)) |
&Line::IndexedChoice(IndexedChoiceInstruction::Try(offset)) => {
let before_idx = *last_idx;
*last_idx += offset;
scan_for_trust_me(code, queue, before_idx, last_idx);
}
&Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => {
queue.push_back(*last_idx + offset);
*last_idx += 1;
}
&Line::Control(ControlInstruction::JmpBy(_, offset, _, true)) => {
queue.push_back(*last_idx + offset);
break;
}
&Line::Control(ControlInstruction::Proceed) |
&Line::Control(ControlInstruction::CallClause(_, _, _, true, _)) =>
break,
_ =>
*last_idx += 1,
};
}
false
}
/* This function walks the code of a single predicate, supposed to
* begin in code at the offset p. Each instruction is passed to the
* walker function.
*/
pub fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Line))
{
let mut queue = VecDeque::from(vec![p]);
pub(crate) fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Line)) {
let mut stack = vec![p];
let mut visited_indices = IndexSet::new();
while let Some(first_idx) = queue.pop_front() {
let mut last_idx = first_idx;
while let Some(first_index) = stack.pop() {
if visited_indices.contains(&first_index) {
continue;
} else {
visited_indices.insert(first_index);
}
capture_next_range(code, &mut queue, &mut last_idx);
for instr in &code[first_idx .. last_idx + 1] {
for (index, instr) in code[first_index..].iter().enumerate() {
walker(instr);
if capture_offset(instr, first_index + index, &mut stack) {
break;
}
}
}
}
@@ -92,7 +73,8 @@ pub fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Line))
/* A function for code walking that might result in modification to
* the code. Otherwise identical to walk_code.
*/
pub fn walk_code_mut(code: &mut Code, p: usize, mut walker: impl FnMut(&mut Line))
/*
pub(crate) fn walk_code_mut(code: &mut Code, p: usize, mut walker: impl FnMut(&mut Line))
{
let mut queue = VecDeque::from(vec![p]);
@@ -106,3 +88,4 @@ pub fn walk_code_mut(code: &mut Code, p: usize, mut walker: impl FnMut(&mut Line
}
}
}
*/

File diff suppressed because it is too large Load Diff

View File

@@ -7,13 +7,12 @@ use std::ops::IndexMut;
type Trail = Vec<(Ref, HeapCellValue)>;
#[derive(Debug, Clone, Copy)]
pub enum AttrVarPolicy {
pub(crate) enum AttrVarPolicy {
DeepCopy,
StripAttributes
StripAttributes,
}
pub(crate)
trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
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;
@@ -21,8 +20,7 @@ trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
fn threshold(&self) -> usize;
}
pub(crate)
fn copy_term<T: CopierTarget>(target: T, addr: Addr, attr_var_policy: AttrVarPolicy) {
pub(crate) fn copy_term<T: CopierTarget>(target: T, addr: Addr, attr_var_policy: AttrVarPolicy) {
let mut copy_term_state = CopyTermState::new(target, attr_var_policy);
copy_term_state.copy_term_impl(addr);
}
@@ -43,7 +41,7 @@ impl<T: CopierTarget> CopyTermState<T> {
scan: 0,
old_h: target.threshold(),
target,
attr_var_policy
attr_var_policy,
}
}
@@ -59,14 +57,11 @@ impl<T: CopierTarget> CopyTermState<T> {
HeapCellValue::Addr(Addr::Lis(threshold)),
);
self.trail.push((
Ref::HeapCell(addr),
trail_item,
));
self.trail.push((Ref::HeapCell(addr), trail_item));
}
fn copy_list(&mut self, addr: usize) {
for offset in 0 .. 2 {
for offset in 0..2 {
if let Addr::Lis(h) = self.target[addr + offset].as_addr(addr + offset) {
if h >= self.old_h {
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(h));
@@ -81,12 +76,14 @@ impl<T: CopierTarget> CopyTermState<T> {
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(threshold));
for i in 0 .. 2 {
for i in 0..2 {
let hcv = self.target[addr + i].context_free_clone();
self.target.push(hcv);
}
let cdr = self.target.store(self.target.deref(Addr::HeapCell(addr + 1)));
let cdr = self
.target
.store(self.target.deref(Addr::HeapCell(addr + 1)));
if !cdr.is_ref() {
self.trail_list_cell(addr + 1, threshold);
@@ -113,34 +110,27 @@ impl<T: CopierTarget> CopyTermState<T> {
let threshold = self.target.threshold();
*self.value_at_scan() =
HeapCellValue::Addr(Addr::PStrLocation(threshold, n));
*self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(threshold, n));
self.scan += 1;
let (pstr, has_tail) =
match &self.target[addr] {
&HeapCellValue::PartialString(ref pstr, has_tail) => {
(pstr.clone_from_offset(0), has_tail)
}
_ => {
unreachable!()
}
};
let (pstr, has_tail) = match &self.target[addr] {
&HeapCellValue::PartialString(ref pstr, has_tail) => {
(pstr.clone_from_offset(0), has_tail)
}
_ => {
unreachable!()
}
};
self.target.push(HeapCellValue::PartialString(pstr, has_tail));
self.target
.push(HeapCellValue::PartialString(pstr, has_tail));
let replacement = HeapCellValue::Addr(Addr::PStrLocation(threshold, n));
let trail_item = mem::replace(
&mut self.target[addr],
replacement,
);
let trail_item = mem::replace(&mut self.target[addr], replacement);
self.trail.push((
Ref::HeapCell(addr),
trail_item,
));
self.trail.push((Ref::HeapCell(addr), trail_item));
if has_tail {
let tail_addr = self.target[addr + 1].as_addr(addr + 1);
@@ -154,10 +144,8 @@ impl<T: CopierTarget> CopyTermState<T> {
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier));
self.target[h] = HeapCellValue::Addr(Addr::HeapCell(frontier));
self.trail.push((
Ref::HeapCell(h),
HeapCellValue::Addr(Addr::HeapCell(h)),
));
self.trail
.push((Ref::HeapCell(h), HeapCellValue::Addr(Addr::HeapCell(h))));
}
Addr::StackCell(fr, sc) => {
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier));
@@ -178,13 +166,12 @@ impl<T: CopierTarget> CopyTermState<T> {
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(threshold));
self.target[h] = HeapCellValue::Addr(Addr::HeapCell(threshold));
self.trail.push((
Ref::AttrVar(h),
HeapCellValue::Addr(Addr::AttrVar(h)),
));
self.trail
.push((Ref::AttrVar(h), HeapCellValue::Addr(Addr::AttrVar(h))));
if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
self.target.push(HeapCellValue::Addr(Addr::AttrVar(threshold)));
self.target
.push(HeapCellValue::Addr(Addr::AttrVar(threshold)));
let list_val = self.target[h + 1].context_free_clone();
self.target.push(list_val);
@@ -226,12 +213,10 @@ impl<T: CopierTarget> CopyTermState<T> {
HeapCellValue::Addr(Addr::Str(threshold)),
);
self.trail.push((
Ref::HeapCell(addr),
trail_item,
));
self.trail.push((Ref::HeapCell(addr), trail_item));
self.target.push(HeapCellValue::NamedStr(arity, name, fixity));
self.target
.push(HeapCellValue::NamedStr(arity, name, fixity));
for i in 0..arity {
let hcv = self.target[addr + 1 + i].context_free_clone();
@@ -255,43 +240,41 @@ impl<T: CopierTarget> CopyTermState<T> {
while self.scan < self.target.threshold() {
match self.value_at_scan() {
&mut HeapCellValue::Addr(addr) => {
match addr {
Addr::Con(h) => {
let addr = self.target[h].as_addr(h);
&mut HeapCellValue::Addr(addr) => match addr {
Addr::Con(h) => {
let addr = self.target[h].as_addr(h);
if addr == Addr::Con(h) {
*self.value_at_scan() = self.target[h].context_free_clone();
} else {
*self.value_at_scan() = HeapCellValue::Addr(addr);
}
}
Addr::Lis(h) => {
if h >= self.old_h {
self.scan += 1;
} else {
self.copy_list(h);
}
}
addr @ Addr::AttrVar(_) |
addr @ Addr::HeapCell(_) |
addr @ Addr::StackCell(..) => {
self.copy_var(addr);
}
Addr::Str(addr) => {
self.copy_structure(addr);
}
Addr::PStrLocation(addr, n) => {
self.copy_partial_string(addr, n);
}
Addr::Stream(h) => {
if addr == Addr::Con(h) {
*self.value_at_scan() = self.target[h].context_free_clone();
}
_ => {
self.scan += 1;
} else {
*self.value_at_scan() = HeapCellValue::Addr(addr);
}
}
}
Addr::Lis(h) => {
if h >= self.old_h {
self.scan += 1;
} else {
self.copy_list(h);
}
}
addr @ Addr::AttrVar(_)
| addr @ Addr::HeapCell(_)
| addr @ Addr::StackCell(..) => {
self.copy_var(addr);
}
Addr::Str(addr) => {
self.copy_structure(addr);
}
Addr::PStrLocation(addr, n) => {
self.copy_partial_string(addr, n);
}
Addr::Stream(h) => {
*self.value_at_scan() = self.target[h].context_free_clone();
}
_ => {
self.scan += 1;
}
},
_ => {
self.scan += 1;
}
@@ -304,10 +287,10 @@ impl<T: CopierTarget> CopyTermState<T> {
fn unwind_trail(&mut self) {
for (r, value) in self.trail.drain(0..) {
match r {
Ref::AttrVar(h) | Ref::HeapCell(h) =>
self.target[h] = value,
Ref::StackCell(fr, sc) =>
self.target.stack().index_and_frame_mut(fr)[sc] = value.as_addr(0),
Ref::AttrVar(h) | Ref::HeapCell(h) => self.target[h] = value,
Ref::StackCell(fr, sc) => {
self.target.stack().index_and_frame_mut(fr)[sc] = value.as_addr(0)
}
}
}
}

View File

@@ -1,396 +0,0 @@
use crate::prolog_parser::ast::*;
use crate::heap_print::*;
use crate::machine::*;
use crate::machine::compile::*;
use crate::machine::machine_errors::*;
use crate::machine::streams::*;
use std::convert::TryFrom;
impl Machine {
pub(super) fn atom_tbl_of(&self, name: &ClauseName) -> TabledData<Atom> {
match name {
&ClauseName::User(ref rc) => rc.table.clone(),
_ => self.indices.atom_tbl(),
}
}
fn compile_into_machine(
&mut self,
src: Stream,
name: ClauseName,
arity: usize,
) -> EvalSession {
match name.owning_module().as_str() {
"user" => match self.indices.code_dir.get(&(name.clone(), arity)).cloned() {
Some(idx) => {
let module = idx.0.borrow().1.clone();
match module.as_str() {
"user" => compile_user_module(self, src, true, ListingSource::User),
_ => compile_into_module(self, module, src, name)
}
}
None => compile_user_module(self, src, true, ListingSource::User),
},
_ => compile_into_module(self, name.owning_module(), src, name),
}
}
fn get_predicate_key(&self, name: RegType, arity: RegType) -> PredicateKey {
let name = self.machine_st[name].clone();
let arity = self.machine_st[arity].clone();
let name = match self.machine_st.store(self.machine_st.deref(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(h) => {
match &self.machine_st.heap[h] {
HeapCellValue::Integer(ref arity) => {
arity.to_usize().unwrap()
}
HeapCellValue::Addr(Addr::Fixnum(arity)) => {
usize::try_from(*arity).unwrap()
}
_ => {
unreachable!()
}
}
}
Addr::Fixnum(arity) => {
usize::try_from(arity).unwrap()
}
Addr::Usize(n) => {
n
}
_ => {
unreachable!()
}
};
(name, arity)
}
fn print_new_dynamic_clause(
&self,
addrs: VecDeque<Addr>,
name: ClauseName,
arity: usize,
) -> String {
let mut output = PrinterOutputter::new();
output.append(format!(":- dynamic({}/{}). ", name.as_str(), arity).as_str());
for addr in addrs {
let mut printer = HCPrinter::new(&self.machine_st, &self.indices.op_dir, output);
printer.quoted = true;
output = printer.print(addr);
output.append(". ");
}
output.result()
}
fn make_undefined(&mut self, name: ClauseName, arity: usize) {
let module_name = name.owning_module();
match self.indices.modules.get(&module_name) {
Some(ref module) => {
if let Some(idx) = module.code_dir.get(&(name.clone(), arity)) {
set_code_index!(idx, IndexPtr::DynamicUndefined, module_name);
}
}
None => {
}
}
if let Some(idx) = self.indices.code_dir.get(&(name, arity)) {
set_code_index!(idx, IndexPtr::DynamicUndefined, clause_name!("user"));
}
}
fn make_undefined_in_module(&mut self, module_name: ClauseName, name: ClauseName, arity: usize) {
if let Some(idx) = self.indices.code_dir.get(&(name, arity)) {
if idx.module_name() == module_name {
set_code_index!(idx, IndexPtr::DynamicUndefined, clause_name!("user"));
}
}
}
fn abolish_dynamic_clause(&mut self, name: RegType, arity: RegType) {
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);
}
fn abolish_dynamic_clause_in_module(&mut self, name: RegType, arity: RegType, module: RegType) {
let (name, arity) = self.get_predicate_key(name, arity);
let module_addr = self.machine_st[module].clone();
let module_name = match self.machine_st.store(self.machine_st.deref(module_addr)) {
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!(),
};
self.make_undefined_in_module(module_name.clone(), name.clone(), arity);
self.indices.remove_code_index((name.clone(), arity));
self.indices.remove_clause_subsection(module_name, name, arity);
}
fn handle_eval_result_from_dynamic_compile(
&mut self,
pred_str: String,
name: ClauseName,
arity: usize,
src: ClauseName,
) {
let machine_st = mem::replace(&mut self.machine_st, MachineState::new());
let result = self.compile_into_machine(
Stream::from(pred_str),
name,
arity,
);
self.machine_st = machine_st;
if let EvalSession::Error(err) = result {
let h = self.machine_st.heap.h();
let stub = MachineError::functor_stub(src, 1);
let err = MachineError::session_error(h, err);
let err = self.machine_st.error_form(err, stub);
self.machine_st.throw_exception(err);
}
}
fn recompile_dynamic_predicate_impl(
&mut self,
place: DynamicAssertPlace,
name: ClauseName,
arity: usize,
) {
let stub = MachineError::functor_stub(place.predicate_name(), 1);
let pred_str = match self.machine_st.try_from_list(temp_v!(2), stub) {
Ok(addrs) => {
let mut addrs = VecDeque::from(addrs);
let added_clause = self.machine_st[temp_v!(1)].clone();
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);
}
};
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(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!(),
};
if let &mut ClauseName::User(ref mut rc) = name {
rc.table = atom_tbl;
}
true
}
fn recompile_dynamic_predicate_in_module(&mut self, place: DynamicAssertPlace) {
let (mut name, arity) = self.get_predicate_key(temp_v!(3), temp_v!(4));
let module_addr = self.machine_st[temp_v!(5)].clone();
if self.set_module_atom_tbl(module_addr, &mut name) {
self.recompile_dynamic_predicate_impl(place, name, arity);
}
}
fn recompile_dynamic_predicate(&mut self, place: DynamicAssertPlace) {
let (name, arity) = self.get_predicate_key(temp_v!(3), temp_v!(4));
self.recompile_dynamic_predicate_impl(place, name, arity);
}
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(h) =>
match &self.machine_st.heap[h] {
HeapCellValue::Integer(ref arity) => {
arity.to_usize().unwrap()
}
HeapCellValue::Addr(Addr::Fixnum(arity)) => {
usize::try_from(*arity).unwrap()
}
_ => {
unreachable!()
}
}
Addr::Fixnum(arity) => {
usize::try_from(arity).unwrap()
}
_ => {
unreachable!()
}
};
let (mut name, arity) = self.get_predicate_key(temp_v!(1), temp_v!(2));
let module_addr = self.machine_st[temp_v!(5)].clone();
if self.set_module_atom_tbl(module_addr, &mut name) {
let stub = MachineError::functor_stub(clause_name!("retract"), 1);
let pred_str = match self.machine_st.try_from_list(temp_v!(4), stub) {
Ok(addrs) => {
let mut addrs = VecDeque::from(addrs);
addrs.remove(index);
if addrs.is_empty() {
self.make_undefined(name.clone(), arity);
}
self.print_new_dynamic_clause(addrs, name.clone(), arity)
}
Err(err) => {
return self.machine_st.throw_exception(err);
}
};
self.handle_eval_result_from_dynamic_compile(
pred_str,
name,
arity,
clause_name!("retract"),
);
}
}
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(h) => {
match &self.machine_st.heap[h] {
HeapCellValue::Integer(ref arity) => {
arity.to_usize().unwrap()
}
HeapCellValue::Addr(Addr::Fixnum(arity)) => {
usize::try_from(*arity).unwrap()
}
_ => {
unreachable!()
}
}
}
Addr::Usize(n) => {
n
}
Addr::Fixnum(n) => {
usize::try_from(n).unwrap()
}
_ => {
unreachable!()
}
};
let (name, arity) = self.get_predicate_key(temp_v!(1), temp_v!(2));
let stub = MachineError::functor_stub(clause_name!("retract"), 1);
let pred_str = match self.machine_st.try_from_list(temp_v!(4), stub) {
Ok(addrs) => {
let mut addrs = VecDeque::from(addrs);
addrs.remove(index);
if addrs.is_empty() {
self.make_undefined(name.clone(), arity);
}
self.print_new_dynamic_clause(addrs, name.clone(), arity)
}
Err(err) => {
return self.machine_st.throw_exception(err);
}
};
self.handle_eval_result_from_dynamic_compile(
pred_str,
name,
arity,
clause_name!("retract"),
);
}
pub(super) fn dynamic_transaction(
&mut self,
trans_type: DynamicTransactionType,
p: LocalCodePtr,
) {
match trans_type {
DynamicTransactionType::Abolish => {
self.abolish_dynamic_clause(temp_v!(1), temp_v!(2))
}
DynamicTransactionType::Assert(place) => {
self.recompile_dynamic_predicate(place)
}
DynamicTransactionType::ModuleAbolish => {
self.abolish_dynamic_clause_in_module(temp_v!(1), temp_v!(2), temp_v!(3))
}
DynamicTransactionType::ModuleAssert(place) => {
self.recompile_dynamic_predicate_in_module(place)
}
DynamicTransactionType::ModuleRetract => {
self.retract_from_dynamic_predicate_in_module()
}
DynamicTransactionType::Retract => {
self.retract_from_dynamic_predicate()
}
}
self.machine_st.p = CodePtr::Local(p);
}
}

View File

@@ -1,6 +1,6 @@
use core::marker::PhantomData;
use crate::prolog_parser::ast::Constant;
use prolog_parser::ast::Constant;
use crate::machine::machine_indices::*;
use crate::machine::partial_string::*;
@@ -42,16 +42,17 @@ impl<T: RawBlockTraits> Drop for HeapTemplate<T> {
}
#[derive(Debug)]
pub(crate)
struct HeapIntoIter<T: RawBlockTraits> {
pub(crate) struct HeapIntoIter<T: RawBlockTraits> {
offset: usize,
buf: RawBlock<T>,
}
impl<T: RawBlockTraits> Drop for HeapIntoIter<T> {
fn drop(&mut self) {
let mut heap =
HeapTemplate { buf: self.buf.take(), _marker: PhantomData };
let mut heap = HeapTemplate {
buf: self.buf.take(),
_marker: PhantomData,
};
heap.truncate(self.offset / mem::size_of::<HeapCellValue>());
heap.buf.deallocate();
@@ -66,9 +67,7 @@ impl<T: RawBlockTraits> Iterator for HeapIntoIter<T> {
self.offset += mem::size_of::<HeapCellValue>();
if ptr < self.buf.top as usize {
unsafe {
Some(ptr::read(ptr as *const HeapCellValue))
}
unsafe { Some(ptr::read(ptr as *const HeapCellValue)) }
} else {
None
}
@@ -76,15 +75,13 @@ impl<T: RawBlockTraits> Iterator for HeapIntoIter<T> {
}
#[derive(Debug)]
pub(crate)
struct HeapIter<'a, T: RawBlockTraits> {
pub(crate) struct HeapIter<'a, T: RawBlockTraits> {
offset: usize,
buf: &'a RawBlock<T>,
}
impl<'a, T: RawBlockTraits> HeapIter<'a, T> {
pub(crate)
fn new(buf: &'a RawBlock<T>, offset: usize) -> Self {
pub(crate) fn new(buf: &'a RawBlock<T>, offset: usize) -> Self {
HeapIter { buf, offset }
}
}
@@ -97,9 +94,7 @@ impl<'a, T: RawBlockTraits> Iterator for HeapIter<'a, T> {
self.offset += mem::size_of::<HeapCellValue>();
if ptr < self.buf.top as usize {
unsafe {
Some(&*(ptr as *const _))
}
unsafe { Some(&*(ptr as *const _)) }
} else {
None
}
@@ -107,23 +102,20 @@ impl<'a, T: RawBlockTraits> Iterator for HeapIter<'a, T> {
}
#[allow(dead_code)]
pub(crate)
fn print_heap_terms<'a, I: Iterator<Item = &'a HeapCellValue>>(heap: I, h: usize) {
pub(crate) fn print_heap_terms<'a, I: Iterator<Item = &'a HeapCellValue>>(heap: I, h: usize) {
for (index, term) in heap.enumerate() {
println!("{} : {}", h + index, term);
}
}
#[derive(Debug)]
pub(crate)
struct HeapIterMut<'a, T: RawBlockTraits> {
pub(crate) struct HeapIterMut<'a, T: RawBlockTraits> {
offset: usize,
buf: &'a mut RawBlock<T>,
}
impl<'a, T: RawBlockTraits> HeapIterMut<'a, T> {
pub(crate)
fn new(buf: &'a mut RawBlock<T>, offset: usize) -> Self {
pub(crate) fn new(buf: &'a mut RawBlock<T>, offset: usize) -> Self {
HeapIterMut { buf, offset }
}
}
@@ -136,9 +128,7 @@ impl<'a, T: RawBlockTraits> Iterator for HeapIterMut<'a, T> {
self.offset += mem::size_of::<HeapCellValue>();
if ptr < self.buf.top as usize {
unsafe {
Some(&mut *(ptr as *mut _))
}
unsafe { Some(&mut *(ptr as *mut _)) }
} else {
None
}
@@ -147,48 +137,33 @@ impl<'a, T: RawBlockTraits> Iterator for HeapIterMut<'a, T> {
impl<T: RawBlockTraits> HeapTemplate<T> {
#[inline]
pub(crate)
fn new() -> Self {
HeapTemplate { buf: RawBlock::new(), _marker: PhantomData }
}
#[inline]
pub(crate)
fn clone(&self, h: usize) -> HeapCellValue {
match &self[h] {
&HeapCellValue::Addr(addr) => {
HeapCellValue::Addr(addr)
}
&HeapCellValue::Atom(ref name, ref op) => {
HeapCellValue::Atom(name.clone(), op.clone())
}
&HeapCellValue::DBRef(ref db_ref) => {
HeapCellValue::DBRef(db_ref.clone())
}
&HeapCellValue::Integer(ref n) => {
HeapCellValue::Integer(n.clone())
}
&HeapCellValue::NamedStr(arity, ref name, ref op) => {
HeapCellValue::NamedStr(arity, name.clone(), op.clone())
}
&HeapCellValue::PartialString(..) => {
HeapCellValue::Addr(Addr::PStrLocation(h, 0))
}
&HeapCellValue::Rational(ref r) => {
HeapCellValue::Rational(r.clone())
}
&HeapCellValue::Stream(_) => {
HeapCellValue::Addr(Addr::Stream(h))
}
&HeapCellValue::TcpListener(_) => {
HeapCellValue::Addr(Addr::TcpListener(h))
}
pub(crate) fn new() -> Self {
HeapTemplate {
buf: RawBlock::new(),
_marker: PhantomData,
}
}
#[inline]
pub(crate)
fn put_complete_string(&mut self, s: &str) -> Addr {
pub(crate) fn clone(&self, h: usize) -> HeapCellValue {
match &self[h] {
&HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr),
&HeapCellValue::Atom(ref name, ref op) => HeapCellValue::Atom(name.clone(), op.clone()),
&HeapCellValue::DBRef(ref db_ref) => HeapCellValue::DBRef(db_ref.clone()),
&HeapCellValue::Integer(ref n) => HeapCellValue::Integer(n.clone()),
&HeapCellValue::LoadStatePayload(_) => HeapCellValue::Addr(Addr::LoadStatePayload(h)),
&HeapCellValue::NamedStr(arity, ref name, ref op) => {
HeapCellValue::NamedStr(arity, name.clone(), op.clone())
}
&HeapCellValue::PartialString(..) => HeapCellValue::Addr(Addr::PStrLocation(h, 0)),
&HeapCellValue::Rational(ref r) => HeapCellValue::Rational(r.clone()),
&HeapCellValue::Stream(_) => HeapCellValue::Addr(Addr::Stream(h)),
&HeapCellValue::TcpListener(_) => HeapCellValue::Addr(Addr::TcpListener(h)),
}
}
#[inline]
pub(crate) fn put_complete_string(&mut self, s: &str) -> Addr {
if s.is_empty() {
return Addr::EmptyList;
}
@@ -211,30 +186,15 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
}
#[inline]
pub(crate)
fn put_constant(&mut self, c: Constant) -> Addr {
pub(crate) fn put_constant(&mut self, c: Constant) -> Addr {
match c {
Constant::Atom(name, op) => {
Addr::Con(self.push(HeapCellValue::Atom(name, op)))
}
Constant::Char(c) => {
Addr::Char(c)
}
Constant::EmptyList => {
Addr::EmptyList
}
Constant::Fixnum(n) => {
Addr::Fixnum(n)
}
Constant::Integer(n) => {
Addr::Con(self.push(HeapCellValue::Integer(n)))
}
Constant::Rational(r) => {
Addr::Con(self.push(HeapCellValue::Rational(r)))
}
Constant::Float(f) => {
Addr::Float(f)
}
Constant::Atom(name, op) => Addr::Con(self.push(HeapCellValue::Atom(name, op))),
Constant::Char(c) => Addr::Char(c),
Constant::EmptyList => Addr::EmptyList,
Constant::Fixnum(n) => Addr::Fixnum(n),
Constant::Integer(n) => Addr::Con(self.push(HeapCellValue::Integer(n))),
Constant::Rational(r) => Addr::Con(self.push(HeapCellValue::Rational(r))),
Constant::Float(f) => Addr::Float(f),
Constant::String(s) => {
if s.is_empty() {
Addr::EmptyList
@@ -242,15 +202,17 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
self.put_complete_string(&s)
}
}
Constant::Usize(n) => {
Addr::Usize(n)
}
Constant::Usize(n) => Addr::Usize(n),
}
}
#[inline]
pub(crate)
fn pop(&mut self) {
pub(crate) fn is_empty(&self) -> bool {
self.h() == 0
}
#[inline]
pub(crate) fn pop(&mut self) {
let h = self.h();
if h > 0 {
@@ -259,8 +221,7 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
}
#[inline]
pub(crate)
fn push(&mut self, val: HeapCellValue) -> usize {
pub(crate) fn push(&mut self, val: HeapCellValue) -> usize {
let h = self.h();
unsafe {
@@ -273,8 +234,7 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
}
#[inline]
pub(crate)
fn atom_at(&self, h: usize) -> bool {
pub(crate) fn atom_at(&self, h: usize) -> bool {
if let HeapCellValue::Atom(..) = &self[h] {
true
} else {
@@ -283,21 +243,15 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
}
#[inline]
pub(crate)
fn to_unifiable(&mut self, non_heap_value: HeapCellValue) -> Addr {
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))
}
HeapCellValue::Addr(addr) => addr,
val @ HeapCellValue::Atom(..)
| val @ HeapCellValue::Integer(_)
| val @ HeapCellValue::DBRef(_)
| val @ HeapCellValue::Rational(_) => Addr::Con(self.push(val)),
val @ HeapCellValue::LoadStatePayload(_) => Addr::LoadStatePayload(self.push(val)),
val @ HeapCellValue::NamedStr(..) => Addr::Str(self.push(val)),
HeapCellValue::PartialString(pstr, has_tail) => {
let h = self.push(HeapCellValue::PartialString(pstr, has_tail));
@@ -307,20 +261,14 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
Addr::Con(h)
}
val @ HeapCellValue::Stream(..) => {
Addr::Stream(self.push(val))
}
val @ HeapCellValue::TcpListener(..) => {
Addr::TcpListener(self.push(val))
}
val @ HeapCellValue::Stream(..) => Addr::Stream(self.push(val)),
val @ HeapCellValue::TcpListener(..) => Addr::TcpListener(self.push(val)),
}
}
#[inline]
pub(crate)
fn allocate_pstr(&mut self, src: &str) -> Addr {
self.write_pstr(src)
.unwrap_or_else(|| Addr::EmptyList)
pub(crate) fn allocate_pstr(&mut self, src: &str) -> Addr {
self.write_pstr(src).unwrap_or_else(|| Addr::EmptyList)
}
#[inline]
@@ -341,23 +289,20 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
let h = self.h();
let (pstr, rest_src) =
match PartialString::new(src) {
Some(tuple) => {
tuple
let (pstr, rest_src) = match PartialString::new(src) {
Some(tuple) => tuple,
None => {
if src.len() > '\u{0}'.len_utf8() {
src = &src['\u{0}'.len_utf8()..];
continue;
} else if orig_h == h {
return None;
} else {
self[h - 1] = HeapCellValue::Addr(Addr::HeapCell(h - 1));
return Some(Addr::PStrLocation(orig_h, 0));
}
None => {
if src.len() > '\u{0}'.len_utf8() {
src = &src['\u{0}'.len_utf8() ..];
continue;
} else if orig_h == h {
return None;
} else {
self[h - 1] = HeapCellValue::Addr(Addr::HeapCell(h - 1));
return Some(Addr::PStrLocation(orig_h, 0));
}
}
};
}
};
self.push(HeapCellValue::PartialString(pstr, true));
@@ -372,17 +317,7 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
}
#[inline]
pub(crate)
fn take(&mut self) -> Self {
HeapTemplate {
buf: self.buf.take(),
_marker: PhantomData,
}
}
#[inline]
pub(crate)
fn truncate(&mut self, h: usize) {
pub(crate) fn truncate(&mut self, h: usize) {
let new_top = h * mem::size_of::<HeapCellValue>() + self.buf.base as usize;
let mut h = new_top;
@@ -398,30 +333,27 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
}
#[inline]
pub(crate)
fn h(&self) -> usize {
pub(crate) fn h(&self) -> usize {
(self.buf.top as usize - self.buf.base as usize) / mem::size_of::<HeapCellValue>()
}
pub(crate)
fn append(&mut self, vals: Vec<HeapCellValue>) {
pub(crate) fn append(&mut self, vals: Vec<HeapCellValue>) {
for val in vals {
self.push(val);
}
}
pub(crate)
fn clear(&mut self) {
pub(crate) fn clear(&mut self) {
if !self.buf.base.is_null() {
self.truncate(0);
self.buf.top = self.buf.base;
}
}
pub(crate)
fn to_list<Iter, SrcT>(&mut self, values: Iter) -> usize
where Iter: Iterator<Item = SrcT>,
SrcT: Into<HeapCellValue>
pub(crate) fn to_list<Iter, SrcT>(&mut self, values: Iter) -> usize
where
Iter: Iterator<Item = SrcT>,
SrcT: Into<HeapCellValue>,
{
let head_addr = self.h();
let mut h = head_addr;
@@ -439,35 +371,33 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
}
/* Create an iterator starting from the passed offset. */
pub(crate)
fn iter_from<'a>(&'a self, offset: usize) -> HeapIter<'a, T> {
pub(crate) fn iter_from<'a>(&'a self, offset: usize) -> HeapIter<'a, T> {
HeapIter::new(&self.buf, offset * mem::size_of::<HeapCellValue>())
}
pub(crate)
fn iter_mut_from<'a>(&'a mut self, offset: usize) -> HeapIterMut<'a, T> {
pub(crate) fn iter_mut_from<'a>(&'a mut self, offset: usize) -> HeapIterMut<'a, T> {
HeapIterMut::new(&mut self.buf, offset * mem::size_of::<HeapCellValue>())
}
pub(crate)
fn into_iter(mut self) -> HeapIntoIter<T> {
HeapIntoIter { buf: self.buf.take(), offset: 0 }
pub(crate) fn into_iter(mut self) -> HeapIntoIter<T> {
HeapIntoIter {
buf: self.buf.take(),
offset: 0,
}
}
pub(crate)
fn extend<Iter: Iterator<Item = HeapCellValue>>(&mut self, iter: Iter) {
pub(crate) fn extend<Iter: Iterator<Item = HeapCellValue>>(&mut self, iter: Iter) {
for hcv in iter {
self.push(hcv);
}
}
pub(crate)
fn to_local_code_ptr(&self, addr: &Addr) -> Option<LocalCodePtr> {
pub(crate) fn to_local_code_ptr(&self, addr: &Addr) -> Option<LocalCodePtr> {
let extract_integer = |s: usize| -> Option<usize> {
match &self[s] {
&HeapCellValue::Addr(Addr::Fixnum(n)) => usize::try_from(n).ok(),
&HeapCellValue::Integer(ref n) => n.to_usize(),
_ => None
_ => None,
}
};
@@ -476,12 +406,8 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
match &self[*s] {
HeapCellValue::NamedStr(arity, ref name, _) => {
match (name.as_str(), *arity) {
("dir_entry", 1) => {
extract_integer(s+1).map(LocalCodePtr::DirEntry)
}
("in_situ_dir_entry", 1) => {
extract_integer(s+1).map(LocalCodePtr::InSituDirEntry)
}
("dir_entry", 1) => extract_integer(s + 1).map(LocalCodePtr::DirEntry),
/*
("top_level", 2) => {
if let Some(chunk_num) = extract_integer(s+1) {
if let Some(p) = extract_integer(s+2) {
@@ -491,32 +417,24 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
None
}
("user_goal_expansion", 1) => {
extract_integer(s+1).map(LocalCodePtr::UserGoalExpansion)
}
("user_term_expansion", 1) => {
extract_integer(s+1).map(LocalCodePtr::UserTermExpansion)
}
_ => None
*/
_ => None,
}
}
_ => unreachable!()
_ => unreachable!(),
}
}
_ => None
_ => None,
}
}
#[inline]
pub
fn index_addr<'a>(&'a self, addr: &Addr) -> RefOrOwned<'a, HeapCellValue> {
pub(crate) fn index_addr<'a>(&'a self, addr: &Addr) -> RefOrOwned<'a, HeapCellValue> {
match addr {
&Addr::Con(h) | &Addr::Str(h) | &Addr::Stream(h) | &Addr::TcpListener(h) => {
RefOrOwned::Borrowed(&self[h])
}
addr => {
RefOrOwned::Owned(HeapCellValue::Addr(*addr))
}
addr => RefOrOwned::Owned(HeapCellValue::Addr(*addr)),
}
}
}

1201
src/machine/load_state.rs Normal file

File diff suppressed because it is too large Load Diff

2261
src/machine/loader.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,12 @@
use crate::prolog_parser::ast::*;
use prolog_parser::ast::*;
use prolog_parser::{clause_name, temp_v};
use crate::forms::{ModuleSource, Number, PredicateKey};
use crate::forms::{ModuleSource, Number}; //, PredicateKey};
use crate::machine::heap::*;
use crate::machine::loader::CompilationTarget;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::*;
use crate::machine::PredicateKey;
use crate::rug::Integer;
use std::rc::Rc;
@@ -23,74 +26,59 @@ pub(crate) struct MachineError {
from: ErrorProvenance,
}
pub(crate)
trait TypeError {
pub(crate) 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)]
);
let stub = functor!("type_error", [atom(valid_type.as_str()), addr(self)]);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received
from: ErrorProvenance::Received,
}
}
}
impl TypeError for HeapCellValue {
fn type_error(self, _: usize, valid_type: ValidType) -> MachineError {
let stub = functor!(
"type_error",
[atom(valid_type.as_str()), value(self)]
);
let stub = functor!("type_error", [atom(valid_type.as_str()), value(self)]);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received
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]
);
let stub = functor!("type_error", [atom(valid_type.as_str()), aux(h, 0)], [self]);
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed
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)]
);
let stub = functor!("type_error", [atom(valid_type.as_str()), number(self)]);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received
from: ErrorProvenance::Received,
}
}
}
pub(crate)
trait PermissionError {
pub(crate) trait PermissionError {
fn permission_error(self, h: usize, index_str: &'static str, perm: Permission) -> MachineError;
}
@@ -104,7 +92,7 @@ impl PermissionError for Addr {
MachineError {
stub,
location: None,
from: ErrorProvenance::Received
from: ErrorProvenance::Received,
}
}
}
@@ -120,22 +108,18 @@ impl PermissionError for MachineStub {
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed
from: ErrorProvenance::Constructed,
}
}
}
pub(super)
trait DomainError {
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)]
);
let stub = functor!("domain_error", [atom(error.as_str()), addr(self)]);
MachineError {
stub,
@@ -147,10 +131,7 @@ impl DomainError for Addr {
impl DomainError for Number {
fn domain_error(self, error: DomainErrorType) -> MachineError {
let stub = functor!(
"domain_error",
[atom(error.as_str()), number(self)]
);
let stub = functor!("domain_error", [atom(error.as_str()), number(self)]);
MachineError {
stub,
@@ -161,8 +142,7 @@ impl DomainError for Number {
}
impl MachineError {
pub(super)
fn functor_stub(name: ClauseName, arity: usize) -> MachineStub {
pub(super) fn functor_stub(name: ClauseName, arity: usize) -> MachineStub {
functor!(
"/",
SharedOpDesc::new(400, YFX),
@@ -171,8 +151,7 @@ impl MachineError {
}
#[inline]
pub(super)
fn interrupt_error() -> Self {
pub(super) fn interrupt_error() -> Self {
let stub = functor!("$interrupt_thrown");
MachineError {
@@ -182,8 +161,7 @@ impl MachineError {
}
}
pub(super)
fn evaluation_error(eval_error: EvalError) -> Self {
pub(super) fn evaluation_error(eval_error: EvalError) -> Self {
let stub = functor!("evaluation_error", [atom(eval_error.as_str())]);
MachineError {
@@ -193,13 +171,11 @@ impl MachineError {
}
}
pub(super)
fn type_error<T: TypeError>(h: usize, valid_type: ValidType, culprit: T) -> Self {
pub(super) fn type_error<T: TypeError>(h: usize, valid_type: ValidType, culprit: T) -> Self {
culprit.type_error(h, valid_type)
}
pub(super)
fn module_resolution_error(
pub(super) fn module_resolution_error(
h: usize,
mod_name: ClauseName,
name: ClauseName,
@@ -218,11 +194,7 @@ impl MachineError {
[res_stub]
);
let stub = functor!(
"evaluation_error",
[aux(h, 0)],
[ind_stub]
);
let stub = functor!("evaluation_error", [aux(h, 0)], [ind_stub]);
MachineError {
stub,
@@ -231,14 +203,10 @@ impl MachineError {
}
}
pub(super)
fn existence_error(h: usize, err: ExistenceError) -> Self {
pub(super) fn existence_error(h: usize, err: ExistenceError) -> Self {
match err {
ExistenceError::Module(name) => {
let stub = functor!(
"existence_error",
[atom("source_sink"), clause_name(name)]
);
let stub = functor!("existence_error", [atom("source_sink"), clause_name(name)]);
MachineError {
stub,
@@ -253,11 +221,7 @@ impl MachineError {
[clause_name(name), integer(arity)]
);
let stub = functor!(
"existence_error",
[atom("procedure"), aux(h, 0)],
[culprit]
);
let stub = functor!("existence_error", [atom("procedure"), aux(h, 0)], [culprit]);
MachineError {
stub,
@@ -281,10 +245,7 @@ impl MachineError {
}
}
ExistenceError::SourceSink(culprit) => {
let stub = functor!(
"existence_error",
[atom("source_sink"), addr(culprit)]
);
let stub = functor!("existence_error", [atom("source_sink"), addr(culprit)]);
MachineError {
stub,
@@ -293,10 +254,7 @@ impl MachineError {
}
}
ExistenceError::Stream(culprit) => {
let stub = functor!(
"existence_error",
[atom("stream"), addr(culprit)]
);
let stub = functor!("existence_error", [atom("stream"), addr(culprit)]);
MachineError {
stub,
@@ -307,25 +265,18 @@ impl MachineError {
}
}
pub(super)
fn permission_error<T: PermissionError>(
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,
)
culprit.permission_error(h, index_str, err)
}
fn arithmetic_error(h: usize, err: ArithmeticError) -> Self {
match err {
ArithmeticError::UninstantiatedVar => {
Self::instantiation_error()
}
ArithmeticError::UninstantiatedVar => Self::instantiation_error(),
ArithmeticError::NonEvaluableFunctor(name, arity) => {
let culprit = functor!(
"/",
@@ -339,13 +290,11 @@ impl MachineError {
}
#[inline]
pub(super)
fn domain_error<T: DomainError>(error: DomainErrorType, culprit: T) -> Self {
pub(super) fn domain_error<T: DomainError>(error: DomainErrorType, culprit: T) -> Self {
culprit.domain_error(error)
}
pub(super)
fn instantiation_error() -> Self {
pub(super) fn instantiation_error() -> Self {
let stub = functor!("instantiation_error");
MachineError {
@@ -355,24 +304,10 @@ impl MachineError {
}
}
pub(super)
fn uninstantiation_error(culprit: Addr) -> Self {
let stub = functor!(
"uninstantiation_error",
[addr(culprit)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
pub(super)
fn session_error(h: usize, err: SessionError) -> Self {
pub(super) fn session_error(h: usize, err: SessionError) -> Self {
match err {
SessionError::CannotOverwriteBuiltIn(pred_str) |
// SessionError::CannotOverwriteBuiltIn(pred_str) |
/*
SessionError::CannotOverwriteImport(pred_str) => {
Self::permission_error(
h,
@@ -381,64 +316,69 @@ impl MachineError {
functor!(clause_name(pred_str)),
)
}
SessionError::ExistenceError(err) => {
Self::existence_error(h, err)
}
SessionError::InvalidFileName(filename) => {
Self::existence_error(h, ExistenceError::Module(filename))
}
SessionError::ModuleDoesNotContainExport(..) => {
Self::permission_error(
h,
Permission::Access,
"private_procedure",
functor!("module_does_not_contain_claimed_export"),
)
}
SessionError::NamelessEntry => {
Self::permission_error(
h,
Permission::Create,
"static_procedure",
functor!("nameless_procedure")
)
}
*/
SessionError::ExistenceError(err) => Self::existence_error(h, err),
// SessionError::InvalidFileName(filename) => {
// Self::existence_error(h, ExistenceError::Module(filename))
// }
SessionError::ModuleDoesNotContainExport(..) => Self::permission_error(
h,
Permission::Access,
"private_procedure",
functor!("module_does_not_contain_claimed_export"),
),
SessionError::ModuleCannotImportSelf(module_name) => Self::permission_error(
h,
Permission::Modify,
"module",
functor!("module_cannot_import_self", [clause_name(module_name)]),
),
SessionError::NamelessEntry => Self::permission_error(
h,
Permission::Create,
"static_procedure",
functor!("nameless_procedure"),
),
SessionError::OpIsInfixAndPostFix(op) => {
Self::permission_error(h, Permission::Create, "operator", functor!(clause_name(op)))
}
SessionError::CompilationError(err) => Self::syntax_error(h, err),
SessionError::PredicateNotMultifileOrDiscontiguous(compilation_target, key) => {
let functor_stub = Self::functor_stub(key.0, key.1);
let stub = functor!(
":",
SharedOpDesc::new(600, XFY),
[clause_name(compilation_target.module_name()), aux(h + 4, 0)],
[functor_stub]
);
Self::permission_error(
h,
Permission::Create,
"operator",
functor!(clause_name(op)),
)
}
SessionError::ParserError(err) => {
Self::syntax_error(h, err)
}
SessionError::QueryCannotBeDefinedAsFact => {
Self::permission_error(
h,
Permission::Create,
"static_procedure",
functor!("query_cannot_be_defined_as_fact")
Permission::Modify,
"not_declared_multifile_or_discontiguous",
stub,
)
}
SessionError::QueryCannotBeDefinedAsFact => Self::permission_error(
h,
Permission::Create,
"static_procedure",
functor!("query_cannot_be_defined_as_fact"),
),
}
}
pub(super)
fn syntax_error(h: usize, err: ParserError) -> Self {
if let ParserError::Arithmetic(err) = err {
pub(super) fn syntax_error<E: Into<CompilationError>>(h: usize, err: E) -> Self {
let err = err.into();
if let CompilationError::Arithmetic(err) = err {
return Self::arithmetic_error(h, err);
}
let location = err.line_and_col_num();
let stub = functor!(err.as_str());
let stub = err.as_functor(h);
let stub = functor!(
"syntax_error",
[aux(h, 0)],
[stub]
);
let stub = functor!("syntax_error", [aux(h, 0)], [stub]);
MachineError {
stub,
@@ -447,8 +387,7 @@ impl MachineError {
}
}
pub(super)
fn representation_error(flag: RepFlag) -> Self {
pub(super) fn representation_error(flag: RepFlag) -> Self {
let stub = functor!("representation_error", [atom(flag.as_str())]);
MachineError {
@@ -475,8 +414,85 @@ impl MachineError {
}
}
#[derive(Debug)]
pub(crate) enum CompilationError {
Arithmetic(ArithmeticError),
ParserError(ParserError),
// BadPendingByte,
CannotParseCyclicTerm,
// ExpandedTermsListNotAList,
ExpectedRel,
// ExpectedTopLevelTerm,
InadmissibleFact,
InadmissibleQueryTerm,
InconsistentEntry,
// InvalidDoubleQuotesDecl,
// InvalidHook,
InvalidMetaPredicateDecl,
InvalidModuleDecl,
InvalidModuleExport,
InvalidRuleHead,
InvalidUseModuleDecl,
InvalidModuleResolution(ClauseName),
UnreadableTerm,
}
impl From<ArithmeticError> for CompilationError {
#[inline]
fn from(err: ArithmeticError) -> CompilationError {
CompilationError::Arithmetic(err)
}
}
impl From<ParserError> for CompilationError {
#[inline]
fn from(err: ParserError) -> CompilationError {
CompilationError::ParserError(err)
}
}
impl CompilationError {
pub(crate) fn line_and_col_num(&self) -> Option<(usize, usize)> {
match self {
&CompilationError::ParserError(ref err) => err.line_and_col_num(),
_ => None,
}
}
pub(crate) fn as_functor(&self, _h: usize) -> MachineStub {
match self {
&CompilationError::Arithmetic(..) => functor!("arithmetic_error"),
// &CompilationError::BadPendingByte =>
// functor!("bad_pending_byte"),
&CompilationError::CannotParseCyclicTerm => functor!("cannot_parse_cyclic_term"),
// &CompilationError::ExpandedTermsListNotAList =>
// functor!("expanded_terms_list_is_not_a_list"),
&CompilationError::ExpectedRel => functor!("expected_relation"),
// &CompilationError::ExpectedTopLevelTerm =>
// functor!("expected_atom_or_cons_or_clause"),
&CompilationError::InadmissibleFact => functor!("inadmissible_fact"),
&CompilationError::InadmissibleQueryTerm => functor!("inadmissible_query_term"),
&CompilationError::InconsistentEntry => functor!("inconsistent_entry"),
// &CompilationError::InvalidDoubleQuotesDecl =>
// functor!("invalid_double_quotes_declaration"),
// &CompilationError::InvalidHook =>
// functor!("invalid_hook"),
&CompilationError::InvalidMetaPredicateDecl => functor!("invalid_meta_predicate_decl"),
&CompilationError::InvalidModuleDecl => functor!("invalid_module_declaration"),
&CompilationError::InvalidModuleExport => functor!("invalid_module_export"),
&CompilationError::InvalidModuleResolution(ref module_name) => {
functor!("no_such_module", [clause_name(module_name.clone())])
}
&CompilationError::InvalidRuleHead => functor!("invalid_head_of_rule"),
&CompilationError::InvalidUseModuleDecl => functor!("invalid_use_module_declaration"),
&CompilationError::ParserError(ref err) => functor!(err.as_str()),
&CompilationError::UnreadableTerm => functor!("unreadable_term"),
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum Permission {
pub(crate) enum Permission {
Access,
Create,
InputStream,
@@ -488,7 +504,7 @@ pub enum Permission {
impl Permission {
#[inline]
pub fn as_str(self) -> &'static str {
pub(crate) fn as_str(self) -> &'static str {
match self {
Permission::Access => "access",
Permission::Create => "create",
@@ -503,7 +519,7 @@ impl Permission {
// from 7.12.2 b) of 13211-1:1995
#[derive(Debug, Clone, Copy)]
pub enum ValidType {
pub(crate) enum ValidType {
Atom,
Atomic,
// Boolean,
@@ -525,7 +541,7 @@ pub enum ValidType {
}
impl ValidType {
pub fn as_str(self) -> &'static str {
pub(crate) fn as_str(self) -> &'static str {
match self {
ValidType::Atom => "atom",
ValidType::Atomic => "atomic",
@@ -550,7 +566,7 @@ impl ValidType {
}
#[derive(Debug, Clone, Copy)]
pub enum DomainErrorType {
pub(crate) enum DomainErrorType {
IOMode,
NotLessThanZero,
Order,
@@ -560,7 +576,7 @@ pub enum DomainErrorType {
}
impl DomainErrorType {
pub fn as_str(self) -> &'static str {
pub(crate) fn as_str(self) -> &'static str {
match self {
DomainErrorType::IOMode => "io_mode",
DomainErrorType::NotLessThanZero => "not_less_than_zero",
@@ -574,22 +590,24 @@ impl DomainErrorType {
// from 7.12.2 f) of 13211-1:1995
#[derive(Debug, Clone, Copy)]
pub enum RepFlag {
pub(crate) enum RepFlag {
Character,
CharacterCode,
InCharacterCode,
MaxArity,
// MaxInteger,
// MinInteger
// MinInteger,
Term,
}
impl RepFlag {
pub fn as_str(self) -> &'static str {
pub(crate) fn as_str(self) -> &'static str {
match self {
RepFlag::Character => "character",
RepFlag::CharacterCode => "character_code",
RepFlag::InCharacterCode => "in_character_code",
RepFlag::MaxArity => "max_arity",
RepFlag::Term => "term",
// RepFlag::MaxInteger => "max_integer",
// RepFlag::MinInteger => "min_integer"
}
@@ -598,7 +616,7 @@ impl RepFlag {
// from 7.12.2 g) of 13211-1:1995
#[derive(Debug, Clone, Copy)]
pub enum EvalError {
pub(crate) enum EvalError {
FloatOverflow,
Undefined,
// Underflow,
@@ -606,7 +624,7 @@ pub enum EvalError {
}
impl EvalError {
pub fn as_str(self) -> &'static str {
pub(crate) fn as_str(self) -> &'static str {
match self {
EvalError::FloatOverflow => "float_overflow",
EvalError::Undefined => "undefined",
@@ -621,16 +639,15 @@ impl EvalError {
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.
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).
}
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()));
@@ -640,7 +657,9 @@ impl MachineState {
return Err(self.error_form(MachineError::instantiation_error(), stub))
}
CycleSearchResult::NotList => {
return Err(self.error_form(MachineError::type_error(0, ValidType::List, list), stub))
return Err(
self.error_form(MachineError::type_error(0, ValidType::List, list), stub)
)
}
_ => {}
};
@@ -672,7 +691,8 @@ impl MachineState {
new_l = l;
}
HeapCellValue::NamedStr(2, ref name, Some(_))
if name.as_str() == "-" => {
if name.as_str() == "-" =>
{
break;
}
HeapCellValue::Addr(Addr::HeapCell(_)) => {
@@ -699,11 +719,10 @@ 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()) {
@@ -720,8 +739,7 @@ impl MachineState {
}
#[inline]
pub(crate)
fn type_error<T: TypeError>(
pub(crate) fn type_error<T: TypeError>(
&self,
valid_type: ValidType,
culprit: T,
@@ -729,33 +747,25 @@ impl MachineState {
arity: usize,
) -> MachineStub {
let stub = MachineError::functor_stub(caller, arity);
let err = MachineError::type_error(
self.heap.h(),
valid_type,
culprit,
);
let err = MachineError::type_error(self.heap.h(), valid_type, culprit);
return self.error_form(err, stub);
}
#[inline]
pub(crate)
fn representation_error(
pub(crate) fn representation_error(
&self,
rep_flag: RepFlag,
caller: ClauseName,
arity: usize,
) -> MachineStub {
let stub = MachineError::functor_stub(caller, arity);
let err = MachineError::representation_error(
rep_flag,
);
let err = MachineError::representation_error(rep_flag);
return self.error_form(err, stub);
}
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();
@@ -780,8 +790,7 @@ impl MachineState {
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;
@@ -797,7 +806,7 @@ impl MachineState {
}
#[derive(Debug)]
pub enum ExistenceError {
pub(crate) enum ExistenceError {
Module(ClauseName),
ModuleSource(ModuleSource),
Procedure(ClauseName, usize),
@@ -806,38 +815,57 @@ pub enum ExistenceError {
}
#[derive(Debug)]
pub enum SessionError {
CannotOverwriteBuiltIn(ClauseName),
CannotOverwriteImport(ClauseName),
pub(crate) enum SessionError {
CompilationError(CompilationError),
// CannotOverwriteBuiltIn(ClauseName),
// CannotOverwriteImport(ClauseName),
ExistenceError(ExistenceError),
InvalidFileName(ClauseName),
// InvalidFileName(ClauseName),
ModuleDoesNotContainExport(ClauseName, PredicateKey),
ModuleCannotImportSelf(ClauseName),
NamelessEntry,
OpIsInfixAndPostFix(ClauseName),
PredicateNotMultifileOrDiscontiguous(CompilationTarget, PredicateKey),
QueryCannotBeDefinedAsFact,
ParserError(ParserError),
}
#[derive(Debug)]
pub enum EvalSession {
EntrySuccess,
pub(crate) enum EvalSession {
// EntrySuccess,
Error(SessionError),
}
impl From<SessionError> for EvalSession {
#[inline]
fn from(err: SessionError) -> Self {
EvalSession::Error(err)
}
}
impl From<std::io::Error> for SessionError {
#[inline]
fn from(err: std::io::Error) -> SessionError {
SessionError::from(ParserError::from(err))
}
}
impl From<ParserError> for SessionError {
#[inline]
fn from(err: ParserError) -> Self {
SessionError::ParserError(err)
SessionError::CompilationError(CompilationError::from(err))
}
}
impl From<CompilationError> for SessionError {
#[inline]
fn from(err: CompilationError) -> Self {
SessionError::CompilationError(err)
}
}
impl From<ParserError> for EvalSession {
#[inline]
fn from(err: ParserError) -> Self {
EvalSession::from(SessionError::ParserError(err))
EvalSession::from(SessionError::from(err))
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,371 +0,0 @@
use crate::prolog_parser::ast::*;
use crate::prolog_parser::tabled_rc::*;
use crate::forms::*;
use crate::machine::code_repo::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use std::collections::VecDeque;
use std::mem;
// Module's and related types are defined in forms.
impl Module {
pub fn new(
module_decl: ModuleDecl,
atom_tbl: TabledData<Atom>,
listing_src: ListingSource,
) -> Self
{
Module {
atom_tbl,
module_decl,
term_dir: TermDir::new(),
user_term_expansions: (Predicate::new(), VecDeque::from(vec![])),
user_goal_expansions: (Predicate::new(), VecDeque::from(vec![])),
term_expansions: (Predicate::new(), VecDeque::from(vec![])),
goal_expansions: (Predicate::new(), VecDeque::from(vec![])),
local_term_expansions: (Predicate::new(), VecDeque::from(vec![])),
local_goal_expansions: (Predicate::new(), VecDeque::from(vec![])),
code_dir: CodeDir::new(),
op_dir: default_op_dir(),
inserted_expansions: false,
is_impromptu_module: false,
listing_src,
}
}
pub fn dump_expansions(
&self,
code_repo: &mut CodeRepo,
) -> Result<(), ParserError> {
{
let te = code_repo
.term_dir
.entry((clause_name!("term_expansion"), 2))
.or_insert((Predicate::new(), VecDeque::from(vec![])));
(te.0)
.0
.extend((self.user_term_expansions.0).0.iter().cloned());
te.1.extend(self.user_term_expansions.1.iter().cloned());
}
{
let ge = code_repo
.term_dir
.entry((clause_name!("goal_expansion"), 2))
.or_insert((Predicate::new(), VecDeque::from(vec![])));
(ge.0)
.0
.extend((self.user_goal_expansions.0).0.iter().cloned());
ge.1.extend(self.user_goal_expansions.1.iter().cloned());
}
code_repo.compile_hook(CompileTimeHook::TermExpansion)?;
code_repo.compile_hook(CompileTimeHook::GoalExpansion)?;
Ok(())
}
pub fn add_expansion_record(
&mut self,
hook: CompileTimeHook,
clause: PredicateClause,
queue: VecDeque<TopLevel>,
) {
match hook {
CompileTimeHook::TermExpansion | CompileTimeHook::UserTermExpansion => {
(self.term_expansions.0).0.push(clause);
self.term_expansions.1.extend(queue.into_iter());
}
CompileTimeHook::GoalExpansion | CompileTimeHook::UserGoalExpansion => {
(self.goal_expansions.0).0.push(clause);
self.goal_expansions.1.extend(queue.into_iter());
}
}
}
pub fn add_local_expansion(
&mut self,
hook: CompileTimeHook,
clause: PredicateClause,
queue: VecDeque<TopLevel>,
) {
match hook {
CompileTimeHook::TermExpansion => {
(self.local_term_expansions.0).0.push(clause);
self.local_term_expansions.1.extend(queue.into_iter());
}
CompileTimeHook::GoalExpansion => {
(self.local_goal_expansions.0).0.push(clause);
self.local_goal_expansions.1.extend(queue.into_iter());
}
_ => {}
}
}
pub fn take_local_expansions(&mut self) -> Vec<(Predicate, VecDeque<TopLevel>)>
{
let term_expansions =
mem::replace(&mut self.local_term_expansions, (Predicate::new(), VecDeque::new()));
let goal_expansions =
mem::replace(&mut self.local_goal_expansions, (Predicate::new(), VecDeque::new()));
vec![term_expansions, goal_expansions]
}
}
pub trait SubModuleUser {
fn atom_tbl(&self) -> TabledData<Atom>;
fn op_dir(&mut self) -> &mut OpDir;
fn remove_code_index(&mut self, _: PredicateKey);
fn get_code_index(&self, _: PredicateKey, _: ClauseName) -> Option<CodeIndex>;
fn insert_dir_entry(&mut self, _: ClauseName, _: usize, _: CodeIndex);
fn get_op_module_name(&mut self, name: ClauseName, fixity: Fixity) -> Option<ClauseName> {
self.op_dir()
.get(&(name, fixity))
.map(|op_val| op_val.owning_module())
}
fn remove_module(&mut self, mod_name: ClauseName, module: &Module) {
for export in module.module_decl.exports.iter().cloned() {
match export {
ModuleExport::PredicateKey((name, arity)) => {
let name = name.defrock_brackets();
match self.get_code_index((name.clone(), arity), mod_name.clone()) {
Some(CodeIndex(ref code_idx)) => {
if &code_idx.borrow().1 != &module.module_decl.name {
continue;
}
self.remove_code_index((name.clone(), arity));
// remove or respecify ops.
if arity == 2 {
if let Some(mod_name) = self.get_op_module_name(name.clone(), Fixity::In) {
if mod_name == module.module_decl.name {
self.op_dir().remove(&(name.clone(), Fixity::In));
}
}
} else if arity == 1 {
if let Some(mod_name) = self.get_op_module_name(name.clone(), Fixity::Pre) {
if mod_name == module.module_decl.name {
self.op_dir().remove(&(name.clone(), Fixity::Pre));
}
}
if let Some(mod_name) = self.get_op_module_name(name.clone(), Fixity::Post)
{
if mod_name == module.module_decl.name {
self.op_dir().remove(&(name.clone(), Fixity::Post));
}
}
}
}
_ => {}
};
},
ModuleExport::OpDecl(op_decl) => {
let op_dir = self.op_dir();
op_dir.remove(&(op_decl.name(), op_decl.fixity()));
}
}
}
}
// returns true on successful import.
fn import_decl(&mut self, name: ClauseName, arity: usize, submodule: &Module) -> bool {
let name = name.defrock_brackets();
if let Some(code_data) = submodule.code_dir.get(&(name.clone(), arity)) {
let name = name.with_table(submodule.atom_tbl.clone());
let atom_tbl = self.atom_tbl();
atom_tbl.borrow_mut().insert(name.to_rc());
self.insert_dir_entry(name, arity, code_data.clone());
true
} else {
submodule.is_impromptu_module
}
}
fn use_qualified_module(
&mut self,
_: &mut CodeRepo,
_: MachineFlags,
_: &Module,
_: &Vec<ModuleExport>,
) -> Result<(), SessionError>;
fn use_module(
&mut self,
_: &mut CodeRepo,
_: MachineFlags,
_: &Module
) -> Result<(), SessionError>;
}
pub fn use_qualified_module<User>(
user: &mut User,
submodule: &Module,
exports: &Vec<ModuleExport>,
) -> Result<(), SessionError>
where
User: SubModuleUser,
{
for export in exports.iter().cloned() {
match export {
ModuleExport::PredicateKey((name, arity)) => {
if !submodule
.module_decl
.exports
.contains(&ModuleExport::PredicateKey((name.clone(), arity)))
{
continue;
}
if !user.import_decl(name.clone(), arity, submodule) {
let submodule_name = submodule.module_decl.name.clone();
return Err(SessionError::ModuleDoesNotContainExport(
submodule_name,
(name, arity)
));
}
},
ModuleExport::OpDecl(op_decl) => {
if !submodule
.module_decl
.exports
.contains(&ModuleExport::OpDecl(op_decl.clone()))
{
continue;
}
let op_dir = user.op_dir();
let prec = op_decl.0;
op_decl.insert_into_op_dir(
submodule.module_decl.name.clone(),
op_dir,
prec,
);
}
}
}
Ok(())
}
pub fn use_module<User: SubModuleUser>(
user: &mut User,
submodule: &Module,
) -> Result<(), SessionError> {
for export in submodule.module_decl.exports.iter().cloned() {
match export {
ModuleExport::PredicateKey((name, arity)) => {
if !user.import_decl(name.clone(), arity, submodule) {
let submodule_name = submodule.module_decl.name.clone();
return Err(SessionError::ModuleDoesNotContainExport(
submodule_name,
(name, arity)
));
}
}
ModuleExport::OpDecl(op_decl) => {
let op_dir = user.op_dir();
let prec = op_decl.0;
op_decl.insert_into_op_dir(
submodule.module_decl.name.clone(),
op_dir,
prec,
);
}
}
}
Ok(())
}
impl SubModuleUser for Module {
fn atom_tbl(&self) -> TabledData<Atom> {
self.atom_tbl.clone()
}
fn op_dir(&mut self) -> &mut OpDir {
&mut self.op_dir
}
fn get_code_index(&self, key: PredicateKey, _: ClauseName) -> Option<CodeIndex> {
self.code_dir.get(&key).cloned()
}
fn remove_code_index(&mut self, key: PredicateKey) {
self.code_dir.remove(&key);
}
fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: CodeIndex) {
self.code_dir.insert((name, arity), idx);
}
fn use_qualified_module(
&mut self,
_: &mut CodeRepo,
_: MachineFlags,
submodule: &Module,
exports: &Vec<ModuleExport>,
) -> Result<(), SessionError> {
use_qualified_module(self, submodule, exports)?;
(self.user_term_expansions.0)
.0
.extend((submodule.term_expansions.0).0.iter().cloned());
self.user_term_expansions
.1
.extend(submodule.term_expansions.1.iter().cloned());
(self.user_goal_expansions.0)
.0
.extend((submodule.goal_expansions.0).0.iter().cloned());
self.user_goal_expansions
.1
.extend(submodule.goal_expansions.1.iter().cloned());
Ok(())
}
fn use_module(
&mut self,
_: &mut CodeRepo,
_: MachineFlags,
submodule: &Module,
) -> Result<(), SessionError> {
use_module(self, submodule)?;
(self.user_term_expansions.0)
.0
.extend((submodule.term_expansions.0).0.iter().cloned());
self.user_term_expansions
.1
.extend(submodule.term_expansions.1.iter().cloned());
(self.user_goal_expansions.0)
.0
.extend((submodule.goal_expansions.0).0.iter().cloned());
self.user_goal_expansions
.1
.extend(submodule.goal_expansions.1.iter().cloned());
Ok(())
}
}

View File

@@ -1,14 +1,20 @@
use crate::machine::machine_indices::*;
use crate::machine::*;
use core::marker::PhantomData;
use std::alloc;
use std::cmp::Ordering;
use std::mem;
use std::ptr;
use std::ops::RangeFrom;
use std::ptr;
use std::slice;
use std::str;
use indexmap::IndexSet;
#[derive(Debug)]
pub struct PartialString {
pub(crate) struct PartialString {
buf: *const u8,
len: usize,
_marker: PhantomData<[u8]>,
@@ -48,7 +54,7 @@ fn scan_for_terminator<Iter: Iterator<Item = char>>(iter: Iter) -> usize {
}
#[derive(Debug)]
pub struct PStrIter {
pub(crate) struct PStrIter {
buf: *const u8,
len: usize,
}
@@ -85,17 +91,14 @@ impl Iterator for PStrIter {
impl PartialString {
#[inline]
pub(super)
fn new(src: &str) -> Option<(Self, &str)> {
pub(super) fn new(src: &str) -> Option<(Self, &str)> {
let pstr = PartialString {
buf: ptr::null_mut(),
len: 0,
_marker: PhantomData,
};
unsafe {
pstr.append_chars(src)
}
unsafe { pstr.append_chars(src) }
}
unsafe fn append_chars(mut self, src: &str) -> Option<(Self, &str)> {
@@ -109,29 +112,23 @@ impl PartialString {
self.buf = alloc::alloc(layout) as *const _;
self.len = terminator_idx + '\u{0}'.len_utf8();
ptr::copy(
src.as_ptr(),
self.buf as *mut _,
terminator_idx,
);
ptr::copy(src.as_ptr(), self.buf as *mut _, terminator_idx);
self.write_terminator_at(terminator_idx);
Some(if terminator_idx != src.as_bytes().len() {
(self, &src[terminator_idx ..])
(self, &src[terminator_idx..])
} else {
(self, "")
})
}
pub(super)
fn clone_from_offset(&self, n: usize) -> Self {
let len =
if self.len - '\u{0}'.len_utf8() > n {
self.len - n - '\u{0}'.len_utf8()
} else {
0
};
pub(super) fn clone_from_offset(&self, n: usize) -> Self {
let len = if self.len - '\u{0}'.len_utf8() > n {
self.len - n - '\u{0}'.len_utf8()
} else {
0
};
let mut pstr = PartialString {
buf: ptr::null_mut(),
@@ -162,18 +159,14 @@ impl PartialString {
}
#[inline]
pub(super)
fn write_terminator_at(&mut self, index: usize) {
pub(super) fn write_terminator_at(&mut self, index: usize) {
unsafe {
ptr::write(
(self.buf as usize + index) as *mut u8,
0u8,
);
ptr::write((self.buf as usize + index) as *mut u8, 0u8);
}
}
#[inline]
pub fn range_from(&self, index: RangeFrom<usize>) -> PStrIter {
pub(crate) fn range_from(&self, index: RangeFrom<usize>) -> PStrIter {
if self.len >= '\u{0}'.len_utf8() {
PStrIter::from(self.buf, self.len - '\u{0}'.len_utf8(), index.start)
} else {
@@ -182,21 +175,285 @@ impl PartialString {
}
#[inline]
pub fn at_end(&self, end_n: usize) -> bool {
pub(crate) fn at_end(&self, end_n: usize) -> bool {
end_n + 1 == self.len
}
#[inline]
pub fn as_str_from(&self, n: usize) -> &str {
pub(crate) fn as_str_from(&self, n: usize) -> &str {
unsafe {
let slice = slice::from_raw_parts(
self.buf,
self.len - '\u{0}'.len_utf8(),
);
let slice = slice::from_raw_parts(self.buf, self.len - '\u{0}'.len_utf8());
let s = str::from_utf8(slice).unwrap();
&s[n ..]
&s[n..]
}
}
}
#[derive(Debug)]
pub(crate) struct HeapPStrIter<'a> {
focus: Addr,
machine_st: &'a MachineState,
seen: IndexSet<Addr>,
}
impl<'a> HeapPStrIter<'a> {
#[inline]
pub(super) fn new(machine_st: &'a MachineState, focus: Addr) -> Self {
HeapPStrIter {
focus,
machine_st,
seen: IndexSet::new(),
}
}
#[inline]
pub(crate) fn focus(&self) -> Addr {
self.machine_st.store(self.machine_st.deref(self.focus))
}
#[inline]
pub(crate) fn to_string(&mut self) -> String {
let mut buf = String::new();
while let Some(iteratee) = self.next() {
match iteratee {
PStrIteratee::Char(c) => {
buf.push(c);
}
PStrIteratee::PStrSegment(h, n) => match &self.machine_st.heap[h] {
HeapCellValue::PartialString(ref pstr, _) => {
buf += pstr.as_str_from(n);
}
_ => {
unreachable!()
}
},
}
}
buf
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum PStrIteratee {
Char(char),
PStrSegment(usize, usize),
}
impl<'a> Iterator for HeapPStrIter<'a> {
type Item = PStrIteratee;
fn next(&mut self) -> Option<Self::Item> {
let addr = self.machine_st.store(self.machine_st.deref(self.focus));
if !self.seen.contains(&addr) {
self.seen.insert(addr);
} else {
return None;
}
match addr {
Addr::PStrLocation(h, n) => {
if let &HeapCellValue::PartialString(_, has_tail) = &self.machine_st.heap[h] {
self.focus = if has_tail {
Addr::HeapCell(h + 1)
} else {
Addr::EmptyList
};
return Some(PStrIteratee::PStrSegment(h, n));
} else {
unreachable!()
}
}
Addr::Lis(l) => {
let addr = self
.machine_st
.store(self.machine_st.deref(Addr::HeapCell(l)));
let opt_c = match addr {
Addr::Con(h) if self.machine_st.heap.atom_at(h) => {
if let HeapCellValue::Atom(ref atom, _) = &self.machine_st.heap[h] {
if atom.is_char() {
Some(atom.as_str().chars().next().unwrap())
} else {
None
}
} else {
unreachable!()
}
}
Addr::Char(c) => Some(c),
_ => None,
};
if let Some(c) = opt_c {
self.focus = Addr::HeapCell(l + 1);
return Some(PStrIteratee::Char(c));
} else {
return None;
}
}
Addr::EmptyList => {
self.focus = Addr::EmptyList;
return None;
}
_ => {
return None;
}
}
}
}
#[inline]
pub(super) fn compare_pstr_prefixes<'a>(
i1: &mut HeapPStrIter<'a>,
i2: &mut HeapPStrIter<'a>,
) -> Option<Ordering> {
let mut r1 = i1.next();
let mut r2 = i2.next();
loop {
if let Some(r1i) = r1 {
if let Some(r2i) = r2 {
match (r1i, r2i) {
(PStrIteratee::Char(c1), PStrIteratee::Char(c2)) => {
if c1 != c2 {
return c1.partial_cmp(&c2);
}
}
(PStrIteratee::Char(c1), PStrIteratee::PStrSegment(h, n)) => {
if let &HeapCellValue::PartialString(ref pstr, _) = &i2.machine_st.heap[h] {
if let Some(c2) = pstr.as_str_from(n).chars().next() {
if c1 != c2 {
return c1.partial_cmp(&c2);
} else {
r1 = i1.next();
r2 = Some(PStrIteratee::PStrSegment(h, n + c2.len_utf8()));
continue;
}
} else {
r2 = i2.next();
continue;
}
} else {
unreachable!()
}
}
(PStrIteratee::PStrSegment(h, n), PStrIteratee::Char(c2)) => {
if let &HeapCellValue::PartialString(ref pstr, _) = &i1.machine_st.heap[h] {
if let Some(c1) = pstr.as_str_from(n).chars().next() {
if c1 != c2 {
return c2.partial_cmp(&c1);
} else {
r1 = i1.next();
r2 = Some(PStrIteratee::PStrSegment(h, n + c1.len_utf8()));
continue;
}
} else {
r1 = i1.next();
continue;
}
} else {
unreachable!()
}
}
(PStrIteratee::PStrSegment(h1, n1), PStrIteratee::PStrSegment(h2, n2)) => {
match (&i1.machine_st.heap[h1], &i2.machine_st.heap[h2]) {
(
&HeapCellValue::PartialString(ref pstr1, _),
&HeapCellValue::PartialString(ref pstr2, _),
) => {
let str1 = pstr1.as_str_from(n1);
let str2 = pstr2.as_str_from(n2);
if str1.starts_with(str2) {
r1 = Some(PStrIteratee::PStrSegment(h1, n1 + str2.len()));
r2 = i2.next();
continue;
} else if str2.starts_with(str1) {
r1 = i1.next();
r2 = Some(PStrIteratee::PStrSegment(h2, n2 + str1.len()));
continue;
} else {
return str1.partial_cmp(str2);
}
}
_ => {
unreachable!()
}
}
}
}
r1 = i1.next();
r2 = i2.next();
continue;
}
}
return match (i1.focus(), i2.focus()) {
(Addr::EmptyList, Addr::EmptyList) => Some(Ordering::Equal),
(Addr::EmptyList, _) => Some(Ordering::Less),
(_, Addr::EmptyList) => Some(Ordering::Greater),
_ => None,
};
}
}
#[inline]
pub(super) fn compare_pstr_to_string<'a>(
heap_pstr_iter: &mut HeapPStrIter<'a>,
s: &String,
) -> Option<usize> {
let mut s_offset = 0;
while let Some(iteratee) = heap_pstr_iter.next() {
match iteratee {
PStrIteratee::Char(c1) => {
if let Some(c2) = s[s_offset..].chars().next() {
if c1 != c2 {
return None;
} else {
s_offset += c1.len_utf8();
}
} else {
return Some(s_offset);
}
}
PStrIteratee::PStrSegment(h, n) => match heap_pstr_iter.machine_st.heap[h] {
HeapCellValue::PartialString(ref pstr, _) => {
let t = pstr.as_str_from(n);
if s[s_offset..].starts_with(t) {
s_offset += t.len();
} else if t.starts_with(&s[s_offset..]) {
heap_pstr_iter.focus = Addr::PStrLocation(h, n + s[s_offset..].len());
s_offset += s[s_offset..].len();
return Some(s_offset);
} else {
return None;
}
}
_ => {
unreachable!()
}
},
}
if s[s_offset..].is_empty() {
return Some(s_offset);
}
}
Some(s_offset)
}

921
src/machine/preprocessor.rs Normal file
View File

@@ -0,0 +1,921 @@
use prolog_parser::ast::*;
use prolog_parser::tabled_rc::*;
use prolog_parser::{atom, clause_name, rc_atom};
use crate::forms::*;
use crate::iterators::*;
use crate::machine::load_state::*;
use crate::machine::machine_errors::*;
use crate::machine::*;
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: ClauseName) -> Term
where
I: DoubleEndedIterator<Item = Term>,
{
for prec in terms.rev() {
term = Term::Clause(
Cell::default(),
sym.clone(),
vec![Box::new(prec), Box::new(term)],
None,
);
}
term
}
pub(crate) fn to_op_decl(
prec: usize,
spec: &str,
name: ClauseName,
) -> Result<OpDecl, CompilationError> {
match spec {
"xfx" => Ok(OpDecl::new(prec, XFX, name)),
"xfy" => Ok(OpDecl::new(prec, XFY, name)),
"yfx" => Ok(OpDecl::new(prec, YFX, name)),
"fx" => Ok(OpDecl::new(prec, FX, name)),
"fy" => Ok(OpDecl::new(prec, FY, name)),
"xf" => Ok(OpDecl::new(prec, XF, name)),
"yf" => Ok(OpDecl::new(prec, YF, name)),
_ => Err(CompilationError::InconsistentEntry),
}
}
fn setup_op_decl(
mut terms: Vec<Box<Term>>,
atom_tbl: TabledData<Atom>,
) -> Result<OpDecl, CompilationError> {
let name = match *terms.pop().unwrap() {
Term::Constant(_, Constant::Atom(name, _)) => name,
Term::Constant(_, Constant::Char(c)) => clause_name!(c.to_string(), atom_tbl),
_ => return Err(CompilationError::InconsistentEntry),
};
let spec = match *terms.pop().unwrap() {
Term::Constant(_, Constant::Atom(name, _)) => name,
Term::Constant(_, Constant::Char(c)) => clause_name!(c.to_string(), atom_tbl),
_ => return Err(CompilationError::InconsistentEntry),
};
let prec = match *terms.pop().unwrap() {
Term::Constant(_, Constant::Fixnum(bi)) => match usize::try_from(bi) {
Ok(n) if n <= 1200 => n,
_ => return Err(CompilationError::InconsistentEntry),
},
_ => return Err(CompilationError::InconsistentEntry),
};
to_op_decl(prec, spec.as_str(), name)
}
fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, CompilationError> {
match term {
Term::Clause(_, ref slash, ref mut terms, Some(_))
if (slash.as_str() == "/" || slash.as_str() == "//") && terms.len() == 2 =>
{
let arity = *terms.pop().unwrap();
let name = *terms.pop().unwrap();
let arity = arity
.into_constant()
.and_then(|c| match c {
Constant::Integer(n) => n.to_usize(),
Constant::Fixnum(n) => usize::try_from(n).ok(),
_ => None,
})
.ok_or(CompilationError::InvalidModuleExport)?;
let name = name
.into_constant()
.and_then(|c| c.to_atom())
.ok_or(CompilationError::InvalidModuleExport)?;
if slash.as_str() == "/" {
Ok((name, arity))
} else {
Ok((name, arity + 2))
}
}
_ => Err(CompilationError::InvalidModuleExport),
}
}
/*
fn setup_scoped_predicate_indicator(term: &mut Term) -> Result<ScopedPredicateKey, CompilationError>
{
match term {
Term::Clause(_, ref name, ref mut terms, Some(_))
if name.as_str() == ":" && terms.len() == 2 =>
{
let mut predicate_indicator = *terms.pop().unwrap();
let module_name = *terms.pop().unwrap();
let module_name = module_name
.to_constant()
.and_then(|c| c.to_atom())
.ok_or(CompilationError::InvalidModuleExport)?;
let key = setup_predicate_indicator(&mut predicate_indicator)?;
Ok((module_name, key))
}
_ => Err(CompilationError::InvalidModuleExport),
}
}
*/
fn setup_module_export(
mut term: Term,
atom_tbl: TabledData<Atom>,
) -> Result<ModuleExport, CompilationError> {
setup_predicate_indicator(&mut term)
.map(ModuleExport::PredicateKey)
.or_else(|_| {
if let Term::Clause(_, name, terms, _) = term {
if terms.len() == 3 && name.as_str() == "op" {
Ok(ModuleExport::OpDecl(setup_op_decl(terms, atom_tbl)?))
} else {
Err(CompilationError::InvalidModuleDecl)
}
} else {
Err(CompilationError::InvalidModuleDecl)
}
})
}
pub(super) fn setup_module_export_list(
mut export_list: Term,
atom_tbl: TabledData<Atom>,
) -> Result<Vec<ModuleExport>, CompilationError> {
let mut exports = vec![];
while let Term::Cons(_, t1, t2) = export_list {
let module_export = setup_module_export(*t1, atom_tbl.clone())?;
exports.push(module_export);
export_list = *t2;
}
if let Term::Constant(_, Constant::EmptyList) = export_list {
Ok(exports)
} else {
Err(CompilationError::InvalidModuleDecl)
}
}
fn setup_module_decl(
mut terms: Vec<Box<Term>>,
atom_tbl: TabledData<Atom>,
) -> Result<ModuleDecl, CompilationError> {
let export_list = *terms.pop().unwrap();
let name = terms
.pop()
.unwrap()
.into_constant()
.and_then(|c| c.to_atom())
.ok_or(CompilationError::InvalidModuleDecl)?;
let exports = setup_module_export_list(export_list, atom_tbl)?;
Ok(ModuleDecl { name, exports })
}
fn setup_use_module_decl(mut terms: Vec<Box<Term>>) -> Result<ModuleSource, CompilationError> {
match *terms.pop().unwrap() {
Term::Clause(_, ref name, ref mut terms, None)
if name.as_str() == "library" && terms.len() == 1 =>
{
terms
.pop()
.unwrap()
.into_constant()
.and_then(|c| c.to_atom())
.map(|c| ModuleSource::Library(c))
.ok_or(CompilationError::InvalidUseModuleDecl)
}
Term::Constant(_, Constant::Atom(ref name, _)) => Ok(ModuleSource::File(name.clone())),
_ => Err(CompilationError::InvalidUseModuleDecl),
}
}
/*
fn setup_double_quotes(mut terms: Vec<Box<Term>>) -> Result<DoubleQuotes, CompilationError> {
let dbl_quotes = *terms.pop().unwrap();
match terms[0].as_ref() {
Term::Constant(_, Constant::Atom(ref name, _))
if name.as_str() == "double_quotes" => {
match dbl_quotes {
Term::Constant(_, Constant::Atom(name, _)) => {
match name.as_str() {
"atom" => Ok(DoubleQuotes::Atom),
"chars" => Ok(DoubleQuotes::Chars),
"codes" => Ok(DoubleQuotes::Codes),
_ => Err(CompilationError::InvalidDoubleQuotesDecl),
}
}
_ => {
Err(CompilationError::InvalidDoubleQuotesDecl)
}
}
},
_ => {
Err(CompilationError::InvalidDoubleQuotesDecl)
}
}
}
*/
type UseModuleExport = (ModuleSource, IndexSet<ModuleExport>);
fn setup_qualified_import(
mut terms: Vec<Box<Term>>,
atom_tbl: TabledData<Atom>,
) -> Result<UseModuleExport, CompilationError> {
let mut export_list = *terms.pop().unwrap();
let module_src = match *terms.pop().unwrap() {
Term::Clause(_, ref name, ref mut terms, None)
if name.as_str() == "library" && terms.len() == 1 =>
{
terms
.pop()
.unwrap()
.into_constant()
.and_then(|c| c.to_atom())
.map(|c| ModuleSource::Library(c))
.ok_or(CompilationError::InvalidUseModuleDecl)
}
Term::Constant(_, Constant::Atom(ref name, _)) => Ok(ModuleSource::File(name.clone())),
_ => Err(CompilationError::InvalidUseModuleDecl),
}?;
let mut exports = IndexSet::new();
while let Term::Cons(_, t1, t2) = export_list {
exports.insert(setup_module_export(*t1, atom_tbl.clone())?);
export_list = *t2;
}
if let Term::Constant(_, Constant::EmptyList) = export_list {
Ok((module_src, exports))
} else {
Err(CompilationError::InvalidModuleDecl)
}
}
/*
* setup_meta_predicate tries to extract meta-predicate information
* from an appropriately formed declaration
*
* :- meta_predicate maplist(:, ?, ?).
*
* indicating that, for each QueryTerm call to maplist/3, the first
* argument is to be expanded with the call resolution ((:)/2)
* operator, the first argument of which is the name of the host
* module, as an atom. For example,
*
* p(X) :- maplist(X, [a,b,c], Result).
*
* If p/2 is defined in a module named "mod", the call is expanded to
*
* maplist(mod:X, [a,b,c], Result).
*
* before the predicate is compiled to WAM instructions.
*
* If the term bound to X -- the predicate to be called -- is
* qualified with (:)/2 already, the innermost qualifier is used for
* call resolution.
*
* The three arguments returned by a successful call are the module name,
* predicate name, and the list of meta-specs, one for each predicate argument.
*
* The module name might be used to specify intra-module meta-predicates whose
* module is not yet defined. There are several examples of this
* contained in src/lib/ops_and_meta_predicates.pl, which is loaded before
* src/lib/builtins.pl.
*
* Meta-specs have three forms:
*
* (:) (the argument should be expanded with (:)/2 as described above)
* + (mode declarations under the mode syntax, which currently have no effect)
* -
* ?
*/
fn setup_meta_predicate<'a>(
mut terms: Vec<Box<Term>>,
load_state: &LoadState<'a>,
) -> Result<(ClauseName, ClauseName, Vec<MetaSpec>), CompilationError> {
fn get_name_and_meta_specs(
name: ClauseName,
terms: &mut [Box<Term>],
) -> Result<(ClauseName, Vec<MetaSpec>), CompilationError> {
let mut meta_specs = vec![];
for meta_spec in terms.into_iter() {
match &**meta_spec {
Term::Constant(_, Constant::Atom(meta_spec, _)) => {
let meta_spec = match meta_spec.as_str() {
"+" => MetaSpec::Plus,
"-" => MetaSpec::Minus,
"?" => MetaSpec::Either,
_ => return Err(CompilationError::InvalidMetaPredicateDecl),
};
meta_specs.push(meta_spec);
}
Term::Constant(_, Constant::Fixnum(n)) => match usize::try_from(*n) {
Ok(n) if n <= MAX_ARITY => {
meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n));
}
_ => {
return Err(CompilationError::InvalidMetaPredicateDecl);
}
},
_ => {
return Err(CompilationError::InvalidMetaPredicateDecl);
}
}
}
Ok((name, meta_specs))
}
match *terms.pop().unwrap() {
Term::Clause(_, name, mut terms, _) if name.as_str() == ":" && terms.len() == 2 => {
let spec = *terms.pop().unwrap();
let module_name = *terms.pop().unwrap();
match module_name {
Term::Constant(_, Constant::Atom(module_name, _)) => match spec {
Term::Clause(_, name, mut terms, _) => {
let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?;
Ok((module_name, name, meta_specs))
}
_ => Err(CompilationError::InvalidMetaPredicateDecl),
},
_ => Err(CompilationError::InvalidMetaPredicateDecl),
}
}
Term::Clause(_, name, mut terms, _) => {
let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?;
Ok((
load_state.compilation_target.module_name(),
name,
meta_specs,
))
}
_ => Err(CompilationError::InvalidMetaPredicateDecl),
}
}
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: ClauseName) {
for term in terms.iter_mut() {
match term {
&mut Term::Constant(_, Constant::Atom(ref mut var, _)) if var.as_str() == "!" => {
*var = name.clone()
}
_ => {}
}
}
}
fn mark_cut_variable(term: &mut Term) -> bool {
let cut_var_found = match term {
&mut Term::Constant(_, Constant::Atom(ref var, _)) if var.as_str() == "!" => true,
_ => false,
};
if cut_var_found {
*term = Term::Var(Cell::default(), rc_atom!("!"));
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(_, ref name, ref subterms, _)) = terms.last() {
if name.as_str() != "->" || subterms.len() != 2 {
return;
}
} else {
return;
}
if let Some(Term::Clause(_, _, mut subterms, _)) = terms.pop() {
let mut conq_terms = VecDeque::from(unfold_by_str(*subterms.pop().unwrap(), ","));
let mut pre_cut_terms = VecDeque::from(unfold_by_str(*subterms.pop().unwrap(), ","));
conq_terms.push_front(Term::Constant(
Cell::default(),
Constant::Atom(clause_name!("blocked_!"), None),
));
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,
clause_name!(","),
));
}
}
pub(super) fn setup_declaration<'a>(
load_state: &LoadState<'a>,
mut terms: Vec<Box<Term>>,
) -> Result<Declaration, CompilationError> {
let term = *terms.pop().unwrap();
let atom_tbl = load_state.wam.machine_st.atom_tbl.clone();
match term {
Term::Clause(_, name, mut terms, _) => match (name.as_str(), terms.len()) {
("dynamic", 1) => {
let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?;
Ok(Declaration::Dynamic(name, arity))
}
("module", 2) => Ok(Declaration::Module(setup_module_decl(terms, atom_tbl)?)),
("op", 3) => Ok(Declaration::Op(setup_op_decl(terms, atom_tbl)?)),
("non_counted_backtracking", 1) => {
let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?;
Ok(Declaration::NonCountedBacktracking(name, arity))
}
("use_module", 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)),
("use_module", 2) => {
let (name, exports) = setup_qualified_import(terms, atom_tbl)?;
Ok(Declaration::UseQualifiedModule(name, exports))
}
("meta_predicate", 1) => {
let (module_name, name, meta_specs) = setup_meta_predicate(terms, load_state)?;
Ok(Declaration::MetaPredicate(module_name, name, meta_specs))
}
_ => Err(CompilationError::InconsistentEntry),
},
_ => Err(CompilationError::InconsistentEntry),
}
}
#[inline]
fn clause_to_query_term<'a>(
load_state: &mut LoadState<'a>,
name: ClauseName,
terms: Vec<Box<Term>>,
fixity: Option<SharedOpDesc>,
) -> QueryTerm {
let ct = load_state.get_clause_type(name, terms.len(), fixity);
QueryTerm::Clause(Cell::default(), ct, terms, false)
}
#[inline]
fn qualified_clause_to_query_term<'a>(
load_state: &mut LoadState<'a>,
module_name: ClauseName,
name: ClauseName,
terms: Vec<Box<Term>>,
fixity: Option<SharedOpDesc>,
) -> QueryTerm {
let ct = load_state.get_qualified_clause_type(module_name, name, terms.len(), fixity);
QueryTerm::Clause(Cell::default(), ct, terms, false)
}
#[derive(Debug)]
pub(crate) struct Preprocessor {
flags: MachineFlags,
queue: VecDeque<VecDeque<Term>>,
}
impl Preprocessor {
pub(super) fn new(flags: MachineFlags) -> Self {
Preprocessor {
flags,
queue: VecDeque::new(),
}
}
fn setup_fact(&mut self, term: Term) -> Result<Term, CompilationError> {
match term {
Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => Ok(term),
_ => Err(CompilationError::InadmissibleFact),
}
}
fn compute_head(&self, 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_atom!("!"));
vars.into_iter()
.map(|v| Term::Var(Cell::default(), v))
.collect()
}
fn fabricate_rule_body(&self, vars: &Vec<Term>, body_term: Term) -> Term {
let vars_of_head = vars.iter().cloned().map(Box::new).collect();
let head_term = Term::Clause(Cell::default(), clause_name!(""), vars_of_head, None);
let rule = vec![Box::new(head_term), Box::new(body_term)];
let turnstile = clause_name!(":-");
Term::Clause(Cell::default(), turnstile, rule, None)
}
// 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 fabricate_rule(&self, 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 = self.compute_head(&body_term);
let rule = self.fabricate_rule_body(&vars, body_term);
(vars, VecDeque::from(vec![rule]))
}
fn fabricate_disjunct(&self, body_term: Term) -> (JumpStub, VecDeque<Term>) {
let vars = self.compute_head(&body_term);
let results = unfold_by_str(body_term, ";")
.into_iter()
.map(|term| {
let mut subterms = unfold_by_str(term, ",");
mark_cut_variables(&mut subterms);
check_for_internal_if_then(&mut subterms);
let term = subterms.pop().unwrap();
let clause = fold_by_str(subterms.into_iter(), term, clause_name!(","));
self.fabricate_rule_body(&vars, clause)
})
.collect();
(vars, results)
}
fn fabricate_if_then(&self, prec: Term, conq: Term) -> (JumpStub, VecDeque<Term>) {
let mut prec_seq = unfold_by_str(prec, ",");
let comma_sym = clause_name!(",");
let cut_sym = atom!("!");
prec_seq.push(Term::Constant(Cell::default(), cut_sym));
mark_cut_variables_as(&mut prec_seq, clause_name!("blocked_!"));
let mut conq_seq = unfold_by_str(conq, ",");
mark_cut_variables(&mut conq_seq);
prec_seq.extend(conq_seq.into_iter());
let back_term = Box::new(prec_seq.pop().unwrap());
let front_term = Box::new(prec_seq.pop().unwrap());
let body_term = Term::Clause(
Cell::default(),
comma_sym.clone(),
vec![front_term, back_term],
None,
);
self.fabricate_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym))
}
fn to_query_term<'a>(
&mut self,
load_state: &mut LoadState<'a>,
term: Term,
) -> Result<QueryTerm, CompilationError> {
match term {
Term::Constant(_, Constant::Atom(name, fixity)) => {
if name.as_str() == "!" || name.as_str() == "blocked_!" {
Ok(QueryTerm::BlockedCut)
} else {
Ok(clause_to_query_term(load_state, name, vec![], fixity))
}
}
Term::Constant(_, Constant::Char('!')) => Ok(QueryTerm::BlockedCut),
Term::Var(_, ref v) if v.as_str() == "!" => {
Ok(QueryTerm::UnblockedCut(Cell::default()))
}
Term::Clause(r, name, mut terms, fixity) => match (name.as_str(), terms.len()) {
(";", 2) => {
let term = Term::Clause(r, name.clone(), terms, fixity);
let (stub, clauses) = self.fabricate_disjunct(term);
self.queue.push_back(clauses);
Ok(QueryTerm::Jump(stub))
}
("->", 2) => {
let conq = *terms.pop().unwrap();
let prec = *terms.pop().unwrap();
let (stub, clauses) = self.fabricate_if_then(prec, conq);
self.queue.push_back(clauses);
Ok(QueryTerm::Jump(stub))
}
("\\+", 1) => {
terms.push(Box::new(Term::Constant(
Cell::default(),
Constant::Atom(clause_name!("$fail"), None),
)));
let conq =
Term::Constant(Cell::default(), Constant::Atom(clause_name!("true"), None));
let prec = Term::Clause(Cell::default(), clause_name!("->"), terms, None);
let terms = vec![Box::new(prec), Box::new(conq)];
let term = Term::Clause(Cell::default(), clause_name!(";"), terms, None);
let (stub, clauses) = self.fabricate_disjunct(term);
debug_assert!(clauses.len() > 0);
self.queue.push_back(clauses);
Ok(QueryTerm::Jump(stub))
}
("$get_level", 1) => {
if let Term::Var(_, ref var) = *terms[0] {
Ok(QueryTerm::GetLevelAndUnify(Cell::default(), var.clone()))
} else {
Err(CompilationError::InadmissibleQueryTerm)
}
}
(":", 2) => {
let predicate_name = *terms.pop().unwrap();
let module_name = *terms.pop().unwrap();
match (module_name, predicate_name) {
(
Term::Constant(_, Constant::Atom(module_name, _)),
Term::Constant(_, Constant::Atom(predicate_name, fixity)),
) => Ok(qualified_clause_to_query_term(
load_state,
module_name,
predicate_name,
vec![],
fixity,
)),
(
Term::Constant(_, Constant::Atom(module_name, _)),
Term::Clause(_, name, terms, fixity),
) => Ok(qualified_clause_to_query_term(
load_state,
module_name,
name,
terms,
fixity,
)),
(module_name, predicate_name) => {
terms.push(Box::new(module_name));
terms.push(Box::new(predicate_name));
Ok(clause_to_query_term(load_state, name, terms, fixity))
}
}
}
_ => Ok(clause_to_query_term(load_state, name, terms, fixity)),
},
Term::Var(..) => Ok(QueryTerm::Clause(
Cell::default(),
ClauseType::CallN,
vec![Box::new(term)],
false,
)),
_ => Err(CompilationError::InadmissibleQueryTerm),
}
}
fn pre_query_term<'a>(
&mut self,
load_state: &mut LoadState<'a>,
term: Term,
) -> Result<QueryTerm, CompilationError> {
match term {
Term::Clause(r, name, mut subterms, fixity) => {
if subterms.len() == 1 && name.as_str() == "$call_with_default_policy" {
self.to_query_term(load_state, *subterms.pop().unwrap())
.map(|mut query_term| {
query_term.set_default_caller();
query_term
})
} else {
let clause = Term::Clause(r, name, subterms, fixity);
self.to_query_term(load_state, clause)
}
}
_ => self.to_query_term(load_state, term),
}
}
fn setup_query<'a>(
&mut self,
load_state: &mut LoadState<'a>,
terms: Vec<Box<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, op_spec) = term {
if name.as_str() == "," && terms.len() == 2 {
let term = Term::Clause(cell, name, terms, op_spec);
let mut subterms = unfold_by_str(term, ",");
while let Some(subterm) = subterms.pop() {
work_queue.push_front(Box::new(subterm));
}
continue;
} else {
term = Term::Clause(cell, name, terms, op_spec);
}
}
if let CutContext::HasCutVariable = cut_context {
mark_cut_variable(&mut term);
}
query_terms.push(self.pre_query_term(load_state, term)?);
}
Ok(query_terms)
}
fn setup_rule<'a>(
&mut self,
load_state: &mut LoadState<'a>,
mut terms: Vec<Box<Term>>,
cut_context: CutContext,
) -> Result<Rule, CompilationError> {
let post_head_terms: Vec<_> = terms.drain(1..).collect();
let mut query_terms = self.setup_query(load_state, post_head_terms, cut_context)?;
let clauses = query_terms.drain(1..).collect();
let qt = query_terms.pop().unwrap();
match *terms.pop().unwrap() {
Term::Clause(_, name, terms, _) => Ok(Rule {
head: (name, terms, qt),
clauses,
}),
Term::Constant(_, Constant::Atom(name, _)) => Ok(Rule {
head: (name, vec![], qt),
clauses,
}),
_ => Err(CompilationError::InvalidRuleHead),
}
}
fn try_term_to_query<'a>(
&mut self,
load_state: &mut LoadState<'a>,
terms: Vec<Box<Term>>,
cut_context: CutContext,
) -> Result<TopLevel, CompilationError> {
Ok(TopLevel::Query(self.setup_query(
load_state,
terms,
cut_context,
)?))
}
pub(super) fn try_term_to_tl<'a>(
&mut self,
load_state: &mut LoadState<'a>,
term: Term,
cut_context: CutContext,
) -> Result<TopLevel, CompilationError> {
match term {
Term::Clause(r, name, terms, fixity) => {
if name.as_str() == "?-" {
self.try_term_to_query(load_state, terms, cut_context)
} else if name.as_str() == ":-" && terms.len() == 2 {
Ok(TopLevel::Rule(self.setup_rule(
load_state,
terms,
cut_context,
)?))
} else {
let term = Term::Clause(r, name, terms, fixity);
Ok(TopLevel::Fact(self.setup_fact(term)?))
}
}
term => Ok(TopLevel::Fact(self.setup_fact(term)?)),
}
}
fn try_terms_to_tls<'a, I: IntoIterator<Item = Term>>(
&mut self,
load_state: &mut LoadState<'a>,
terms: I,
cut_context: CutContext,
) -> Result<VecDeque<TopLevel>, CompilationError> {
let mut results = VecDeque::new();
for term in terms.into_iter() {
results.push_back(self.try_term_to_tl(load_state, term, cut_context)?);
}
Ok(results)
}
pub(super) fn parse_queue<'a>(
&mut self,
load_state: &mut LoadState<'a>,
) -> Result<VecDeque<TopLevel>, CompilationError> {
let mut queue = VecDeque::new();
while let Some(terms) = self.queue.pop_front() {
let clauses = merge_clauses(&mut self.try_terms_to_tls(
load_state,
terms,
CutContext::HasCutVariable,
)?)?;
queue.push_back(clauses);
}
Ok(queue)
}
}

View File

@@ -1,11 +1,11 @@
:- module('$project_atts', [copy_term/3]).
'$attribute_goals_driver'(QueryVars, AttrVars) :-
gather_modules(AttrVars, Modules0, _),
driver(QueryVars, AttrVars) :-
gather_attr_modules(AttrVars, Modules0),
sort(Modules0, Modules),
call_project_attributes(Modules, QueryVars, AttrVars),
call_attribute_goals(Modules, call_query_var_goals, QueryVars),
call_attribute_goals(Modules, call_attr_var_goals, AttrVars).
call_attribute_goals(Modules, '$project_atts':call_query_var_goals, QueryVars),
call_attribute_goals(Modules, '$project_atts':call_attr_var_goals, AttrVars).
enqueue_goals(Goals0) :-
nonvar(Goals0),
@@ -36,7 +36,7 @@ call_project_attributes([Module|Modules], QueryVars, AttrVars) :-
call_project_attributes(Modules, QueryVars, AttrVars).
call_attribute_goals([], _, _).
call_attribute_goals([Module | Modules], GoalCaller, AttrVars) :-
call_attribute_goals([Module|Modules], GoalCaller, AttrVars) :-
call(GoalCaller, AttrVars, Module, Goals),
enqueue_goals(Goals),
call_attribute_goals(Modules, GoalCaller, AttrVars).
@@ -51,13 +51,13 @@ call_attribute_goals([Module | Modules], GoalCaller, AttrVars) :-
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,
( '$print_attribute_goals_exception'(Module, E),
atts:'$default_attr_list'(Module, AttrVar, Goals, RGoals)
))
( 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)
),
@@ -66,25 +66,14 @@ call_query_var_goals([AttrVar|AttrVars], Module, Goals) :-
call_attr_var_goals([], _, []).
call_attr_var_goals([AttrVar|AttrVars], Module, Goals) :-
( catch(Module:attribute_goals(AttrVar, Goals, RGoals),
E,
'$print_attribute_goals_exception'(Module, E)
)
E,
'$project_atts':'$print_attribute_goals_exception'(Module, E)
)
-> true
; true
),
call_attr_var_goals(AttrVars, Module, RGoals).
gather_modules([], [], _).
gather_modules([AttrVar|AttrVars], Modules, Modules0) :-
'$get_attr_list'(AttrVar, Attrs),
gather_modules_for_attrs(Attrs, Modules, Modules0),
gather_modules(AttrVars, Modules0, _).
gather_modules_for_attrs(Attrs, Modules, Modules) :-
var(Attrs), !.
gather_modules_for_attrs([Attr|Attrs], [Module|Modules], Modules0) :-
'$module_of'(Module, Attr),
gather_modules_for_attrs(Attrs, Modules, Modules0).
module_prefixed_goals([], _, Gs, Gs).
module_prefixed_goals([G|Gs], Module, [MG|MGs], TailGs) :-
@@ -100,11 +89,25 @@ 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], Modules) :-
'$get_attr_list'(AttrVar, Attrs),
copy_attribute_modules(Attrs, Modules, Modules0),
gather_attr_modules(AttrVars, Modules0).
copy_attribute_modules(Attrs, Ls, Ls) :-
var(Attrs), !.
copy_attribute_modules([Module:_|Attrs], [Module|Modules0], Modules1) :-
copy_attribute_modules(Attrs, Modules0, Modules1).
copy_term(Source, Dest, Goals) :-
'$term_attributed_variables'(Source, Vars),
gather_modules(Vars, Modules0, _),
'$term_attributed_variables'(Source, AttrVars),
gather_attr_modules(AttrVars, Modules0),
sort(Modules0, Modules),
call_attribute_goals_with_module_prefix(Modules, call_query_var_goals, Vars, Goals0),
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]).

View File

@@ -23,9 +23,7 @@ impl RawBlockTraits for StackTraits {
#[inline]
fn base_offset(base: *const u8) -> *const u8 {
unsafe {
base.offset(Self::align() as isize)
}
unsafe { base.offset(Self::align() as isize) }
}
}
@@ -37,7 +35,7 @@ const fn prelude_size<Prelude>() -> usize {
}
#[derive(Debug)]
pub struct Stack {
pub(crate) struct Stack {
buf: RawBlock<StackTraits>,
_marker: PhantomData<Addr>,
}
@@ -50,25 +48,25 @@ impl Drop for Stack {
}
#[derive(Debug, Clone, Copy)]
pub struct FramePrelude {
pub num_cells: usize,
pub(crate) struct FramePrelude {
pub(crate) num_cells: usize,
}
#[derive(Debug)]
pub struct AndFramePrelude {
pub univ_prelude: FramePrelude,
pub e: usize,
pub cp: LocalCodePtr,
pub interrupt_cp: LocalCodePtr,
pub(crate) struct AndFramePrelude {
pub(crate) univ_prelude: FramePrelude,
pub(crate) e: usize,
pub(crate) cp: LocalCodePtr,
pub(crate) interrupt_cp: LocalCodePtr,
}
#[derive(Debug)]
pub struct AndFrame {
pub prelude: AndFramePrelude,
pub(crate) struct AndFrame {
pub(crate) prelude: AndFramePrelude,
}
impl AndFrame {
pub fn size_of(num_cells: usize) -> usize {
pub(crate) fn size_of(num_cells: usize) -> usize {
prelude_size::<AndFramePrelude>() + num_cells * mem::size_of::<Addr>()
}
}
@@ -104,23 +102,23 @@ impl IndexMut<usize> for AndFrame {
}
#[derive(Debug)]
pub struct OrFramePrelude {
pub univ_prelude: FramePrelude,
pub e: usize,
pub cp: LocalCodePtr,
pub b: usize,
pub bp: LocalCodePtr,
pub tr: usize,
pub pstr_tr: usize,
pub h: usize,
pub b0: usize,
pub attr_var_init_queue_b: usize,
pub attr_var_init_bindings_b: usize,
pub(crate) struct OrFramePrelude {
pub(crate) univ_prelude: FramePrelude,
pub(crate) e: usize,
pub(crate) cp: LocalCodePtr,
pub(crate) b: usize,
pub(crate) bp: LocalCodePtr,
pub(crate) tr: usize,
pub(crate) pstr_tr: usize,
pub(crate) h: usize,
pub(crate) b0: usize,
pub(crate) attr_var_init_queue_b: usize,
pub(crate) attr_var_init_bindings_b: usize,
}
#[derive(Debug)]
pub struct OrFrame {
pub prelude: OrFramePrelude,
pub(crate) struct OrFrame {
pub(crate) prelude: OrFramePrelude,
}
impl Index<usize> for OrFrame {
@@ -156,24 +154,27 @@ impl IndexMut<usize> for OrFrame {
}
impl OrFrame {
pub fn size_of(num_cells: usize) -> usize {
pub(crate) fn size_of(num_cells: usize) -> usize {
prelude_size::<OrFramePrelude>() + num_cells * mem::size_of::<Addr>()
}
}
impl Stack {
pub fn new() -> Self {
Stack { buf: RawBlock::new(), _marker: PhantomData }
pub(crate) fn new() -> Self {
Stack {
buf: RawBlock::new(),
_marker: PhantomData,
}
}
pub fn allocate_and_frame(&mut self, num_cells: usize) -> usize {
pub(crate) fn allocate_and_frame(&mut self, num_cells: usize) -> usize {
let frame_size = AndFrame::size_of(num_cells);
unsafe {
let new_top = self.buf.new_block(frame_size);
let e = self.buf.top as usize - self.buf.base as usize;
for idx in 0 .. num_cells {
for idx in 0..num_cells {
let offset = prelude_size::<AndFramePrelude>() + idx * mem::size_of::<Addr>();
ptr::write(
(self.buf.top as usize + offset) as *mut Addr,
@@ -190,14 +191,14 @@ impl Stack {
}
}
pub fn allocate_or_frame(&mut self, num_cells: usize) -> usize {
pub(crate) fn allocate_or_frame(&mut self, num_cells: usize) -> usize {
let frame_size = OrFrame::size_of(num_cells);
unsafe {
let new_top = self.buf.new_block(frame_size);
let b = self.buf.top as usize - self.buf.base as usize;
for idx in 0 .. num_cells {
for idx in 0..num_cells {
let offset = prelude_size::<OrFramePrelude>() + idx * mem::size_of::<Addr>();
ptr::write(
(self.buf.top as usize + offset) as *mut Addr,
@@ -215,7 +216,7 @@ impl Stack {
}
#[inline]
pub fn index_and_frame(&self, e: usize) -> &AndFrame {
pub(crate) fn index_and_frame(&self, e: usize) -> &AndFrame {
unsafe {
let ptr = self.buf.base as usize + e;
&*(ptr as *const AndFrame)
@@ -223,7 +224,7 @@ impl Stack {
}
#[inline]
pub fn index_and_frame_mut(&mut self, e: usize) -> &mut AndFrame {
pub(crate) fn index_and_frame_mut(&mut self, e: usize) -> &mut AndFrame {
unsafe {
let ptr = self.buf.base as usize + e;
&mut *(ptr as *mut AndFrame)
@@ -231,7 +232,7 @@ impl Stack {
}
#[inline]
pub fn index_or_frame(&self, b: usize) -> &OrFrame {
pub(crate) fn index_or_frame(&self, b: usize) -> &OrFrame {
unsafe {
let ptr = self.buf.base as usize + b;
&*(ptr as *const OrFrame)
@@ -239,19 +240,15 @@ impl Stack {
}
#[inline]
pub fn index_or_frame_mut(&mut self, b: usize) -> &mut OrFrame {
pub(crate) fn index_or_frame_mut(&mut self, b: usize) -> &mut OrFrame {
unsafe {
let ptr = self.buf.base as usize + b;
&mut *(ptr as *mut OrFrame)
}
}
pub fn take(&mut self) -> Self {
Stack { buf: self.buf.take(), _marker: PhantomData }
}
#[inline]
pub fn truncate(&mut self, b: usize) {
pub(crate) fn truncate(&mut self, b: usize) {
if b == 0 {
self.inner_truncate(mem::align_of::<Addr>());
} else {
@@ -268,7 +265,7 @@ impl Stack {
}
}
pub fn drop_in_place(&mut self) {
pub(crate) fn drop_in_place(&mut self) {
self.truncate(mem::align_of::<Addr>());
debug_assert!(if self.buf.top.is_null() {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,394 +0,0 @@
use crate::prolog_parser::ast::*;
use crate::prolog_parser::parser::*;
use crate::machine::machine_indices::HeapCellValue;
use crate::machine::*;
use crate::rug::ops::Pow;
use crate::rug::Integer;
use std::cell::Cell;
use std::collections::VecDeque;
use std::iter::Rev;
use std::vec::IntoIter;
pub fn fold_by_str<I>(terms: I, mut term: Term, sym: ClauseName) -> Term
where
I: DoubleEndedIterator<Item = Term>,
{
for prec in terms.rev() {
term = Term::Clause(
Cell::default(),
sym.clone(),
vec![Box::new(prec), Box::new(term)],
None,
);
}
term
}
fn extract_from_list(
head: Box<Term>,
tail: Box<Term>,
) -> Result<Rev<IntoIter<Term>>, ParserError>
{
let mut terms = vec![*head];
let mut tail = *tail;
while let Term::Cons(_, head, next_tail) = tail {
terms.push(*head);
tail = *next_tail;
}
if let Term::Constant(_, Constant::EmptyList) = tail {
Ok(terms.into_iter().rev())
} else {
Err(ParserError::ExpectedTopLevelTerm)
}
}
#[derive(Debug)]
pub struct TermStream<'a> {
stack: Vec<Term>,
pub(crate) wam: &'a mut Machine,
parser: Parser<'a, Stream>,
pub(crate) flags: MachineFlags,
term_expansion_lens: (usize, usize),
goal_expansion_lens: (usize, usize),
top_level_terms: Vec<(Term, usize, usize)>, // term, line_num, col_num.
}
#[derive(Debug)]
pub struct ExpansionAdditionResult {
term_expansion_additions: (Predicate, VecDeque<TopLevel>),
goal_expansion_additions: (Predicate, VecDeque<TopLevel>),
}
impl ExpansionAdditionResult {
pub fn take_term_expansions(&mut self) -> (Predicate, VecDeque<TopLevel>) {
let tes = mem::replace(&mut self.term_expansion_additions.0, Predicate::new());
let teqs = mem::replace(&mut self.term_expansion_additions.1, VecDeque::from(vec![]));
(tes, teqs)
}
pub fn take_goal_expansions(&mut self) -> (Predicate, VecDeque<TopLevel>) {
let ges = mem::replace(&mut self.goal_expansion_additions.0, Predicate::new());
let geqs = mem::replace(&mut self.goal_expansion_additions.1, VecDeque::from(vec![]));
(ges, geqs)
}
}
impl<'a> Drop for TermStream<'a> {
fn drop(&mut self) {
self.wam.indices.in_situ_code_dir.clear();
self.wam.indices.in_situ_module_dir.clear();
self.wam.code_repo.in_situ_code.clear();
discard_result!(self.rollback_expansion_code());
}
}
impl<'a> TermStream<'a> {
pub fn new(
src: &'a mut ParsingStream<Stream>,
atom_tbl: TabledData<Atom>,
flags: MachineFlags,
wam: &'a mut Machine,
) -> Self {
TermStream {
stack: Vec::new(),
term_expansion_lens: wam
.code_repo
.term_dir_entry_len((clause_name!("term_expansion"), 2)),
goal_expansion_lens: wam
.code_repo
.term_dir_entry_len((clause_name!("goal_expansion"), 2)),
wam,
parser: Parser::new(src, atom_tbl, flags),
flags,
top_level_terms: vec![],
}
}
#[inline]
pub fn top_level_terms(&mut self) -> Vec<(Term, usize, usize)> {
mem::replace(&mut self.top_level_terms, vec![])
}
#[inline]
pub fn incr_expansion_lens(&mut self, hook: CompileTimeHook, len: usize, queue_len: usize) {
match hook {
CompileTimeHook::UserTermExpansion => {
self.term_expansion_lens.0 += len;
self.term_expansion_lens.1 += queue_len;
}
CompileTimeHook::UserGoalExpansion => {
self.goal_expansion_lens.0 += len;
self.goal_expansion_lens.1 += queue_len;
}
_ => {}
}
}
#[inline]
pub fn line_num(&self) -> usize {
self.parser.line_num()
}
#[inline]
pub fn col_num(&self) -> usize {
self.parser.col_num()
}
#[inline]
pub fn update_expansion_lens(&mut self) {
let te_key = (clause_name!("term_expansion"), 2);
let ge_key = (clause_name!("goal_expansion"), 2);
let (tes_len, tes_q_len) = self.wam.code_repo.term_dir_entry_len(te_key);
self.term_expansion_lens.0 = tes_len;
self.term_expansion_lens.1 = tes_q_len;
let (ges_len, ges_q_len) = self.wam.code_repo.term_dir_entry_len(ge_key);
self.goal_expansion_lens.0 = ges_len;
self.goal_expansion_lens.1 = ges_q_len;
}
#[inline]
pub fn set_atom_tbl(&mut self, atom_tbl: TabledData<Atom>) {
self.parser.set_atom_tbl(atom_tbl);
}
#[inline]
pub fn eof(&mut self) -> Result<bool, ParserError> {
self.parser.devour_whitespace()?; // eliminate dangling comments before checking for EOF.
Ok(self.stack.is_empty() && self.parser.eof()?)
}
pub fn rollback_expansion_code(&mut self) -> Result<ExpansionAdditionResult, ParserError> {
let te_len = self.term_expansion_lens.0;
let te_queue_len = self.term_expansion_lens.1;
let ge_len = self.goal_expansion_lens.0;
let ge_queue_len = self.goal_expansion_lens.1;
let term_expansion_additions = self.wam.code_repo.truncate_terms(
(clause_name!("term_expansion"), 2),
te_len,
te_queue_len,
);
let goal_expansion_additions = self.wam.code_repo.truncate_terms(
(clause_name!("goal_expansion"), 2),
ge_len,
ge_queue_len,
);
self.wam
.code_repo
.compile_hook(CompileTimeHook::TermExpansion)?;
self.wam
.code_repo
.compile_hook(CompileTimeHook::GoalExpansion)?;
Ok(ExpansionAdditionResult {
term_expansion_additions,
goal_expansion_additions,
})
}
fn enqueue_term(&mut self, term: Term) -> Result<(), ParserError> {
match term {
Term::Cons(_, head, tail) => {
let iter = extract_from_list(head, tail)?;
Ok(self.stack.extend(iter))
}
Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => {
Ok(self.stack.push(term))
}
_ => {
Err(ParserError::ExpectedTopLevelTerm)
}
}
}
fn parse_expansion_output(
&self,
term_string: &str,
op_dir: &OpDir,
) -> Result<Term, ParserError> {
let mut stream = parsing_stream(term_string.trim().as_bytes())?;
let mut parser = Parser::new(&mut stream, self.parser.get_atom_tbl(), self.flags);
parser.read_term(composite_op!(
false,
&self.wam.indices.op_dir,
op_dir
))
}
pub fn expand_term(&mut self, term: Term, op_dir: &OpDir) -> Result<Term, ParserError> {
let mut machine_st = MachineState::new();
self.stack.push(term);
while let Some(term) = self.stack.pop() {
match machine_st.try_expand_term(self.wam, &term, CompileTimeHook::TermExpansion) {
Some(term_string) => {
let term = self.parse_expansion_output(term_string.as_str(), op_dir)?;
self.enqueue_term(term)?;
}
None => {
return Ok(term);
}
};
}
unreachable!()
}
pub fn read_term(&mut self, op_dir: &OpDir) -> Result<Term, ParserError> {
loop {
if let Some(term) = self.stack.pop() {
return Ok(self.expand_term(term, op_dir)?);
}
self.parser.reset();
let line_num = self.line_num();
let col_num = self.col_num();
let term = self.parser.read_term(composite_op!(
false,
&self.wam.indices.op_dir,
op_dir
))?;
// preserve a copy of the original unexpanded term for warning scans,
// if that stage is reached.
self.top_level_terms.push((term.clone(), line_num, col_num));
self.stack.push(term);
}
}
pub(super)
fn expand_goals(
&mut self,
machine_st: &mut MachineState,
op_dir: &OpDir,
mut terms: VecDeque<Term>,
) -> Result<Vec<Term>, ParserError> {
let mut results = vec![];
while let Some(term) = terms.pop_front() {
match machine_st.try_expand_term(self.wam, &term, CompileTimeHook::GoalExpansion) {
Some(term_string) => {
let term = self.parse_expansion_output(term_string.as_str(), op_dir)?;
match term {
Term::Cons(_, head, tail) => {
for term in extract_from_list(head, tail)? {
terms.push_front(term);
}
}
term => terms.push_front(term),
};
}
None => results.push(term),
}
}
Ok(results)
}
}
impl MachineState {
pub(super)
fn print_with_locs(&self, addr: Addr, op_dir: &OpDir) -> PrinterOutputter {
let output = PrinterOutputter::new();
let mut printer = HCPrinter::from_heap_locs(&self, op_dir, output);
let mut max_var_length = 0;
for var in self.heap_locs.keys() {
max_var_length = std::cmp::max(var.len(), max_var_length);
}
printer.quoted = true;
printer.numbervars = true;
// the purpose of the offset is to avoid clashes with variable
// names that might occur after the addresses in the expanded
// term are substituted with the variable names in the
// pre-expansion term. This formula ensures that all generated
// "numbervars"- style variable names will be longer than the
// keys of the var_dict, and therefore not equal to any of
// them.
printer.numbervars_offset = Integer::from(10).pow(max_var_length as u32) * 26;
printer.print_strings_as_strs = true;
printer.drop_toplevel_spec();
printer.see_all_locs();
let mut output = printer.print(addr);
output.push_char('.');
output
}
// reset the machine, but keep the heap contents as they were.
// this prevents clashes between underscored variable names in the
// same query.
fn reset_with_heap_preservation(&mut self) {
let heap = self.heap.take();
self.reset();
self.heap = heap;
}
fn try_expand_term(
&mut self,
wam: &mut Machine,
term: &Term,
hook: CompileTimeHook,
) -> Option<String> {
let term_write_result = write_term_to_heap(term, self);
let h = self.heap.h();
self[temp_v!(1)] = Addr::HeapCell(term_write_result.heap_loc);
self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
self[temp_v!(2)] = Addr::HeapCell(h);
let code = vec![call_clause!(ClauseType::Hook(hook), 2, 0, true)];
wam.code_repo.cached_query = code;
self.cp = LocalCodePtr::TopLevel(0, 0);
self.at_end_of_expansion = false;
self.flags.double_quotes = DoubleQuotes::Chars;
self.query_stepper(
&mut wam.indices,
&mut MachinePolicies::default(),
&mut wam.code_repo,
&mut readline::input_stream(),
&mut Stream::stdout(),
);
if self.fail || self.at_end_of_expansion {
self.reset_with_heap_preservation();
None
} else {
let TermWriteResult { var_dict, .. } = term_write_result;
self.heap_locs = var_dict;
let output = self.print_with_locs(Addr::HeapCell(h), &wam.indices.op_dir);
self.reset_with_heap_preservation();
Some(output.result())
}
}
}

148
src/machine/term_stream.rs Normal file
View File

@@ -0,0 +1,148 @@
use prolog_parser::ast::*;
use prolog_parser::parser::*;
use crate::machine::machine_errors::CompilationError;
use crate::machine::*;
use indexmap::IndexSet;
use std::collections::VecDeque;
use std::fmt;
pub(crate) trait TermStream: Sized {
type Evacuable;
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError>;
fn eof(&mut self) -> Result<bool, CompilationError>;
fn listing_src(&self) -> &ListingSource;
fn evacuate<'a>(loader: Loader<'a, Self>) -> Result<Self::Evacuable, SessionError>;
}
#[derive(Debug)]
pub(super) struct BootstrappingTermStream<'a> {
listing_src: ListingSource,
parser: Parser<'a, Stream>,
}
impl<'a> BootstrappingTermStream<'a> {
#[inline]
pub(super) fn from_prolog_stream(
stream: &'a mut PrologStream,
atom_tbl: TabledData<Atom>,
flags: MachineFlags,
listing_src: ListingSource,
) -> Self {
let parser = Parser::new(stream, atom_tbl, flags);
Self {
parser,
listing_src,
}
}
}
impl<'a> TermStream for BootstrappingTermStream<'a> {
type Evacuable = CompilationTarget;
#[inline]
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError> {
self.parser.reset();
self.parser
.read_term(op_dir)
.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()?)
}
#[inline]
fn listing_src(&self) -> &ListingSource {
&self.listing_src
}
fn evacuate(mut loader: Loader<Self>) -> Result<Self::Evacuable, SessionError> {
if !loader.predicates.is_empty() {
loader.compile_and_submit()?;
}
loader
.load_state
.retraction_info
.reset(loader.load_state.wam.code_repo.code.len());
loader.load_state.remove_module_op_exports();
Ok(loader.load_state.compilation_target.take())
}
}
pub(crate) struct LiveTermStream {
pub(super) term_queue: VecDeque<Term>,
pub(super) listing_src: ListingSource,
}
impl LiveTermStream {
#[inline]
pub(super) fn new(listing_src: ListingSource) -> Self {
Self {
term_queue: VecDeque::new(),
listing_src,
}
}
}
pub(crate) struct LoadStatePayload {
pub(super) term_stream: LiveTermStream,
pub(super) compilation_target: CompilationTarget,
pub(super) retraction_info: RetractionInfo,
pub(super) module_op_exports: Vec<(OpDecl, Option<(usize, Specifier)>)>,
pub(super) non_counted_bt_preds: IndexSet<PredicateKey>,
pub(super) predicates: PredicateQueue,
pub(super) clause_clauses: Vec<(Term, Term)>,
}
impl fmt::Debug for LoadStatePayload {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "LoadStatePayload")
}
}
impl LoadStatePayload {
pub(super) fn new(wam: &Machine) -> Self {
Self {
term_stream: LiveTermStream::new(ListingSource::User),
compilation_target: CompilationTarget::default(),
retraction_info: RetractionInfo::new(wam.code_repo.code.len()),
module_op_exports: vec![],
non_counted_bt_preds: IndexSet::new(),
predicates: predicate_queue![],
clause_clauses: vec![],
}
}
}
impl TermStream for LiveTermStream {
type Evacuable = LoadStatePayload;
#[inline]
fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
Ok(self.term_queue.pop_front().unwrap())
}
#[inline]
fn eof(&mut self) -> Result<bool, CompilationError> {
return Ok(self.term_queue.is_empty());
}
#[inline]
fn listing_src(&self) -> &ListingSource {
&self.listing_src
}
#[inline]
fn evacuate(loader: Loader<Self>) -> Result<LoadStatePayload, SessionError> {
Ok(loader.to_load_state_payload())
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -68,10 +68,18 @@ macro_rules! functor {
});
($name:expr, [$($dt:ident($($value:expr),*)),+]) => ({
{
let arity = count_tt!($($dt) +);
use crate::machine::heap::*;
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None),
$(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ]
let arity = count_tt!($($dt) +);
#[allow(unused_variables, unused_mut)]
let mut addendum = Heap::new();
let mut result =
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None),
$(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ];
result.extend(addendum.into_iter());
result
}
});
($name:expr, $fixity:expr) => (
@@ -112,13 +120,29 @@ macro_rules! functor_term {
(number($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
$e.into()
);
(integer($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
(integer($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
HeapCellValue::Integer(Rc::new(Integer::from($e)))
);
(clause_name($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
(indexing_code_ptr($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
let stub =
match $e {
IndexingCodePtr::DynamicExternal(o) => functor!("dynamic_external", [integer(o)]),
IndexingCodePtr::External(o) => functor!("external", [integer(o)]),
IndexingCodePtr::Internal(o) => functor!("internal", [integer(o)]),
IndexingCodePtr::Fail => vec![HeapCellValue::Atom(clause_name!("fail"), None)],
};
let len: usize = $aux_lens.iter().sum();
let h = len + $arity + 1 + $addendum.h() + $h;
$addendum.extend(stub.into_iter());
HeapCellValue::Addr(Addr::HeapCell(h))
});
(clause_name($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
HeapCellValue::Atom($e, None)
);
(atom($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
(atom($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
HeapCellValue::Atom(clause_name!($e), None)
);
(value($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
@@ -312,14 +336,6 @@ macro_rules! jmp_call {
};
}
macro_rules! try_eval_session {
($e:expr) => {
match $e {
Ok(result) => result,
Err(e) => return EvalSession::from(e),
}
};
}
macro_rules! return_from_clause {
($lco:expr, $machine_st:expr) => {{
if let CodePtr::VerifyAttrInterrupt(_) = $machine_st.p {
@@ -342,39 +358,22 @@ macro_rules! dir_entry {
};
}
macro_rules! set_code_index {
($idx:expr, $ip:expr, $mod_name:expr) => {{
let mut idx = $idx.0.borrow_mut();
idx.0 = $ip;
idx.1 = $mod_name.clone();
}};
}
macro_rules! index_store {
($atom_tbl:expr, $code_dir:expr, $op_dir:expr, $modules:expr) => {
($code_dir:expr, $op_dir:expr, $modules:expr) => {
IndexStore {
atom_tbl: $atom_tbl,
code_dir: $code_dir,
module_dir: ModuleDir::new(),
dynamic_code_dir: DynamicCodeDir::new(),
extensible_predicates: ExtensiblePredicates::new(),
local_extensible_predicates: LocalExtensiblePredicates::new(),
global_variables: GlobalVarDir::new(),
in_situ_code_dir: InSituCodeDir::new(),
in_situ_module_dir: ModuleStubDir::new(),
op_dir: $op_dir,
meta_predicates: MetaPredicateDir::new(),
modules: $modules,
stream_aliases: StreamAliasDir::new(),
op_dir: $op_dir,
streams: StreamDir::new(),
stream_aliases: StreamAliasDir::new(),
}
};
}
macro_rules! default_index_store {
($atom_tbl:expr) => {
index_store!($atom_tbl, CodeDir::new(), default_op_dir(), IndexMap::new())
};
}
macro_rules! put_constant {
($lvl:expr, $cons:expr, $r:expr) => {
QueryInstruction::PutConstant($lvl, $cons, $r)
@@ -387,6 +386,7 @@ macro_rules! get_level_and_unify {
};
}
/*
macro_rules! unwind_protect {
($e: expr, $protected: expr) => {
match $e {
@@ -398,7 +398,8 @@ macro_rules! unwind_protect {
}
};
}
*/
/*
macro_rules! discard_result {
($f: expr) => {
match $f {
@@ -406,7 +407,7 @@ macro_rules! discard_result {
}
};
}
*/
macro_rules! ar_reg {
($r: expr) => {
ArithmeticTerm::Reg($r)
@@ -414,7 +415,7 @@ macro_rules! ar_reg {
}
macro_rules! atom_from {
($self:expr, $indices:expr, $e:expr) => {
($self:expr, $e:expr) => {
match $e {
Addr::Con(h) if $self.heap.atom_at(h) => {
match &$self.heap[h] {
@@ -427,7 +428,7 @@ macro_rules! atom_from {
}
}
Addr::Char(c) => {
clause_name!(c.to_string(), $indices.atom_tbl.clone())
clause_name!(c.to_string(), $self.atom_tbl)
}
_ => {
unreachable!()
@@ -435,3 +436,15 @@ macro_rules! atom_from {
}
}
}
macro_rules! try_or_fail {
($s:expr, $e:expr) => {{
match $e {
Ok(val) => val,
Err(msg) => {
$s.throw_exception(msg);
return;
}
}
}};
}

View File

@@ -1,72 +0,0 @@
extern crate blake2;
extern crate chrono;
extern crate cpu_time;
extern crate crossterm;
extern crate divrem;
#[macro_use]
extern crate downcast;
extern crate git_version;
extern crate hostname;
extern crate indexmap;
#[macro_use]
extern crate lazy_static;
extern crate libc;
extern crate native_tls;
extern crate nix;
extern crate openssl;
extern crate ordered_float;
#[macro_use]
extern crate prolog_parser;
#[macro_use]
extern crate ref_thread_local;
extern crate ring;
extern crate ripemd160;
#[cfg(feature = "rug")]
extern crate rug;
#[cfg(feature = "num-rug-adapter")]
extern crate num_rug_adapter as rug;
extern crate rustyline;
extern crate sha3;
extern crate unicode_reader;
use crate::nix::sys::signal;
#[macro_use]
mod macros;
mod allocator;
mod arithmetic;
mod codegen;
mod clause_types;
mod debray_allocator;
mod fixtures;
mod forms;
mod heap_iter;
mod heap_print;
mod indexing;
mod instructions;
mod iterators;
mod machine;
mod read;
mod targets;
mod write;
use machine::*;
use machine::streams::*;
use read::*;
use std::sync::atomic::Ordering;
extern fn handle_sigint(signal: libc::c_int) {
let signal = signal::Signal::from_c_int(signal).unwrap();
if signal == signal::Signal::SIGINT {
INTERRUPT.store(true, Ordering::Relaxed);
}
}
fn main() {
let handler = signal::SigHandler::Handler(handle_sigint);
unsafe { signal::signal(signal::Signal::SIGINT, handler) }.unwrap();
let mut wam = Machine::new(readline::input_stream(), Stream::stdout());
wam.run_top_level();
}

View File

@@ -1,6 +1,6 @@
use crate::prolog_parser::ast::*;
use crate::prolog_parser::parser::*;
use crate::prolog_parser::tabled_rc::TabledData;
use prolog_parser::ast::*;
use prolog_parser::parser::*;
use prolog_parser::tabled_rc::TabledData;
use crate::forms::*;
use crate::iterators::*;
@@ -12,19 +12,19 @@ use std::collections::VecDeque;
type SubtermDeque = VecDeque<(usize, usize)>;
pub type PrologStream = ParsingStream<Stream>;
pub(crate) type PrologStream = ParsingStream<Stream>;
pub mod readline {
use crate::machine::streams::Stream;
use crate::rustyline::error::ReadlineError;
use crate::rustyline::{Cmd, Editor, KeyEvent};
use rustyline::error::ReadlineError;
use rustyline::{Cmd, Config, Editor, KeyEvent};
use std::io::{Cursor, Error, ErrorKind, Read};
static mut PROMPT: bool = false;
const HISTORY_FILE: &'static str = ".scryer_history";
pub fn set_prompt(value: bool) {
pub(crate) fn set_prompt(value: bool) {
unsafe {
PROMPT = value;
}
@@ -33,7 +33,11 @@ pub mod readline {
#[inline]
fn get_prompt() -> &'static str {
unsafe {
if PROMPT { "?- " } else { "" }
if PROMPT {
"?- "
} else {
""
}
}
}
@@ -45,8 +49,10 @@ pub mod readline {
impl ReadlineStream {
#[inline]
pub fn new(pending_input: String) -> Self {
let mut rl = Editor::<()>::new();
pub(crate) fn new(pending_input: String) -> Self {
let config = Config::builder().check_cursor_position(true).build();
let mut rl = Editor::<()>::with_config(config); //Editor::<()>::new();
if let Some(mut path) = dirs_next::home_dir() {
path.push(HISTORY_FILE);
if path.exists() {
@@ -57,11 +63,14 @@ pub mod readline {
}
rl.bind_sequence(KeyEvent::from('\t'), Cmd::Insert(1, "\t".to_string()));
ReadlineStream { rl, pending_input: Cursor::new(pending_input) }
ReadlineStream {
rl,
pending_input: Cursor::new(pending_input),
}
}
#[inline]
pub fn input_stream(pending_input: String) -> Stream {
pub(crate) fn input_stream(pending_input: String) -> Stream {
Stream::from(Self::new(pending_input))
}
@@ -85,12 +94,8 @@ pub mod readline {
self.pending_input.read(buf)
}
Err(ReadlineError::Eof) => {
Ok(0)
}
Err(e) => {
Err(Error::new(ErrorKind::InvalidInput, e))
}
Err(ReadlineError::Eof) => Ok(0),
Err(e) => Err(Error::new(ErrorKind::InvalidInput, e)),
}
}
@@ -109,7 +114,7 @@ pub mod readline {
}
}
pub fn peek_byte(&mut self) -> std::io::Result<u8> {
pub(crate) fn peek_byte(&mut self) -> std::io::Result<u8> {
set_prompt(false);
loop {
@@ -117,26 +122,20 @@ pub mod readline {
Some(b) => {
return Ok(b);
}
None => {
match self.call_readline(&mut []) {
Err(e) => {
return Err(e);
}
Ok(0) => {
return Err(Error::new(
ErrorKind::UnexpectedEof,
"end of file",
));
}
_ => {
}
None => match self.call_readline(&mut []) {
Err(e) => {
return Err(e);
}
}
Ok(0) => {
return Err(Error::new(ErrorKind::UnexpectedEof, "end of file"));
}
_ => {}
},
}
}
}
pub fn peek_char(&mut self) -> std::io::Result<char> {
pub(crate) fn peek_char(&mut self) -> std::io::Result<char> {
set_prompt(false);
loop {
@@ -144,21 +143,15 @@ pub mod readline {
Some(c) => {
return Ok(c);
}
None => {
match self.call_readline(&mut []) {
Err(e) => {
return Err(e);
}
Ok(0) => {
return Err(Error::new(
ErrorKind::UnexpectedEof,
"end of file",
));
}
_ => {
}
None => match self.call_readline(&mut []) {
Err(e) => {
return Err(e);
}
}
Ok(0) => {
return Err(Error::new(ErrorKind::UnexpectedEof, "end of file"));
}
_ => {}
},
}
}
}
@@ -167,12 +160,8 @@ pub mod readline {
impl Read for ReadlineStream {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
match self.pending_input.read(buf) {
Ok(0) => {
self.call_readline(buf)
}
result => {
result
}
Ok(0) => self.call_readline(buf),
result => result,
}
}
}
@@ -185,7 +174,27 @@ pub mod readline {
}
impl MachineState {
pub fn read(
pub(crate) fn devour_whitespace(
&mut self,
mut inner: Stream,
atom_tbl: TabledData<Atom>,
) -> Result<bool, ParserError> {
let mut stream = parsing_stream(inner.clone())?;
let mut parser = Parser::new(&mut stream, atom_tbl, self.flags);
parser.devour_whitespace()?;
inner.add_lines_read(parser.num_lines_read());
let result = parser.eof();
let buf = stream.take_buf();
inner.pause_stream(buf)?;
result
}
pub(crate) fn read(
&mut self,
mut inner: Stream,
atom_tbl: TabledData<Atom>,
@@ -193,11 +202,18 @@ impl MachineState {
) -> Result<TermWriteResult, ParserError> {
let mut stream = parsing_stream(inner.clone())?;
let term = {
let (term, num_lines_read) = {
let prior_num_lines_read = inner.lines_read();
let mut parser = Parser::new(&mut stream, atom_tbl, self.flags);
parser.read_term(composite_op!(op_dir))?
parser.add_lines_read(prior_num_lines_read);
let term = parser.read_term(&CompositeOpDir::new(op_dir, None))?;
(term, parser.num_lines_read() - prior_num_lines_read)
};
inner.add_lines_read(num_lines_read);
// 'pausing' the stream saves the pending top buffer
// created by the parsing stream, which was created in this
// scope and is about to be destroyed in it.
@@ -210,8 +226,7 @@ impl MachineState {
}
#[inline]
pub(crate)
fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult {
pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult {
let term_writer = TermWriter::new(machine_st);
term_writer.write_term_to_heap(term)
}
@@ -224,7 +239,7 @@ struct TermWriter<'a> {
}
#[derive(Debug)]
pub struct TermWriteResult {
pub(crate) struct TermWriteResult {
pub(crate) heap_loc: usize,
pub(crate) var_dict: HeapVarDict,
}
@@ -242,8 +257,7 @@ impl<'a> TermWriter<'a> {
#[inline]
fn modify_head_of_queue(&mut self, term: &TermRef<'a>, h: usize) {
if let Some((arity, site_h)) = self.queue.pop_front() {
self.machine_st.heap[site_h] =
HeapCellValue::Addr(self.term_as_addr(term, h));
self.machine_st.heap[site_h] = HeapCellValue::Addr(self.term_as_addr(term, h));
if arity > 1 {
self.queue.push_front((arity - 1, site_h + 1));
@@ -254,26 +268,18 @@ impl<'a> TermWriter<'a> {
#[inline]
fn push_stub_addr(&mut self) {
let h = self.machine_st.heap.h();
self.machine_st.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
self.machine_st
.heap
.push(HeapCellValue::Addr(Addr::HeapCell(h)));
}
fn term_as_addr(&mut self, term: &TermRef<'a>, h: usize) -> Addr {
match term {
&TermRef::AnonVar(_) | &TermRef::Var(..) => {
Addr::HeapCell(h)
}
&TermRef::Cons(..) => {
Addr::HeapCell(h)
}
&TermRef::Constant(_, _, c) => {
self.machine_st.heap.put_constant(c.clone())
}
&TermRef::Clause(..) => {
Addr::Str(h)
}
&TermRef::PartialString(..) => {
Addr::PStrLocation(h, 0)
}
&TermRef::AnonVar(_) | &TermRef::Var(..) => Addr::HeapCell(h),
&TermRef::Cons(..) => Addr::HeapCell(h),
&TermRef::Constant(_, _, c) => self.machine_st.heap.put_constant(c.clone()),
&TermRef::Clause(..) => Addr::Str(h),
&TermRef::PartialString(..) => Addr::PStrLocation(h, 0),
}
}
@@ -286,7 +292,9 @@ impl<'a> TermWriter<'a> {
match &term {
&TermRef::Cons(lvl, ..) => {
self.queue.push_back((2, h + 1));
self.machine_st.heap.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
self.machine_st
.heap
.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
self.push_stub_addr();
self.push_stub_addr();
@@ -355,13 +363,15 @@ impl<'a> TermWriter<'a> {
continue;
}
_ => {
}
_ => {}
};
self.modify_head_of_queue(&term, h);
}
TermWriteResult { heap_loc, var_dict: self.var_dict }
TermWriteResult {
heap_loc,
var_dict: self.var_dict,
}
}
}

View File

@@ -1,11 +1,11 @@
use crate::prolog_parser::ast::*;
use prolog_parser::ast::*;
use crate::clause_types::*;
use crate::forms::*;
use crate::instructions::*;
use crate::iterators::*;
pub trait CompilationTarget<'a> {
pub(crate) trait CompilationTarget<'a> {
type Iterator: Iterator<Item = TermRef<'a>>;
fn iter(_: &'a Term) -> Self::Iterator;

6
src/tests/hello_world.pl Normal file
View File

@@ -0,0 +1,6 @@
:- use_module(library(debug)).
:- use_module(library(format)).
hello_world :- write('Hello World!'), nl.
:- initialization(hello_world).

View File

@@ -1,26 +1,46 @@
:- module('$toplevel', ['$repl'/1, consult/1, use_module/1, use_module/2,
argv/1]).
:- module('$toplevel', [argv/1,
copy_term/3]).
:- use_module(library(charsio)).
:- use_module(library(files)).
:- use_module(library(iso_ext)).
:- use_module(library(lists)).
:- use_module(library(si)).
:- use_module(library('$project_atts')).
:- use_module(library('$atts')).
load_scryerrc :-
( '$home_directory'(HomeDir) ->
append(HomeDir, "/.scryerrc", ScryerrcFile),
( file_exists(ScryerrcFile) ->
% convert ScryerrcFile to atom. somehow, I dunno how.
append(ScryerrcFile, "'.", ScryerrcFile0),
read_term_from_chars(['\'' | ScryerrcFile0], ScryerrcFileAtom),
catch(use_module(ScryerrcFileAtom), E, print_exception(E))
; true
)
; true
).
:- dynamic(argv/1).
'$repl'([_|Args0]) :-
\+ argv(_),
( append(Args1, ["--"|Args2], Args0) ->
asserta(argv(Args2)),
asserta('$toplevel':argv(Args2)),
Args = Args1
; asserta(argv([])),
; asserta('$toplevel':argv([])),
Args = Args0
),
load_scryerrc,
delegate_task(Args, []),
repl.
'$repl'(_) :-
( \+ argv(_) -> asserta(argv([]))
( \+ argv(_) -> asserta('$toplevel':argv([]))
; true
),
load_scryerrc,
repl.
delegate_task([], []).
@@ -85,9 +105,9 @@ run_goals([g(Gs0)|Goals]) :-
),
read_term_from_chars(Gs1, Goal),
( catch(
Goal,
user:Goal,
Exception,
(write(Gs0), write(' causes: '), write(Exception), nl) % halt?
(write(Goal), write(' causes: '), write(Exception), nl) % halt?
)
; write('Warning: initialization failed for '),
write(Gs0), nl
@@ -104,14 +124,22 @@ repl :-
repl :-
repl.
%% Enable op declarations with lists of operands, i.e.,
%% :- op(900, fy, [$,@]).
user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
expand_op_list([Op | OtherOps], Pred, Spec, OpResults).
expand_op_list([], _, _, []).
expand_op_list([Op | OtherOps], Pred, Spec, [(:- op(Pred, Spec, Op)) | OtherResults]) :-
expand_op_list(OtherOps, Pred, Spec, OtherResults).
read_and_match :-
'$read_query_term'(_, Term, _, _, VarList),
instruction_match(Term, VarList).
% make compile_batch, a system routine, callable.
compile_batch :- '$compile_batch'.
instruction_match(Term, VarList) :-
( var(Term) ->
throw(error(instantiation_error, repl/0))
@@ -119,38 +147,43 @@ instruction_match(Term, VarList) :-
!,
( atom(Item) ->
( Item == user ->
catch(compile_batch, E, print_exception_with_check(E))
; consult(Item)
catch(load(user_input), E, print_exception_with_check(E))
;
submit_query_and_print_results(consult(Item), [])
)
;
catch(throw(error(type_error(atom, Item), repl/0)),
catch(type_error(atom, Item, repl/0),
E,
print_exception_with_check(E))
)
; Term = end_of_file ->
halt
; submit_query_and_print_results(Term, VarList)
;
submit_query_and_print_results(Term, VarList)
).
:- use_module(library(iso_ext)).
% auxiliary predicates, so that using them in setup_call_cleanup/3 works
get_b_value(B) :- '$get_b_value'(B).
clear_attribute_goals :- '$clear_attribute_goals'.
submit_query_and_print_results_(Term, VarList) :-
'$get_b_value'(B),
call(Term),
write_eqs_and_read_input(B, VarList),
!.
submit_query_and_print_results_(_, _) :-
% clear attribute goal lists, which may be populated by
% copy_term/3 prior to failure.
'$clear_attribute_goals',
write('false.'),
nl.
submit_query_and_print_results(Term0, VarList) :-
( expand_goals(Term0, Term) -> true
; Term0 = Term
),
expand_goal(call(Term0), user, Term),
!,
setup_call_cleanup(bb_put('$first_answer', true),
( get_b_value(B), call(Term), write_eqs_and_read_input(B, VarList),
!
; % clear attribute goal lists, which may be populated by
% copy_term/3 prior to failure.
clear_attribute_goals, write('false.'), nl
),
submit_query_and_print_results_(Term, VarList),
bb_put('$first_answer', false)).
needs_bracketing(Value, Op) :-
catch((functor(Value, F, _),
current_op(EqPrec, EqSpec, Op),
@@ -254,12 +287,12 @@ write_eqs_and_read_input(B, VarList) :-
( B0 == B ->
( Goals == [] ->
write('true.'), nl
; thread_goals(Goals, ThreadedGoals, (',')),
; loader:thread_goals(Goals, ThreadedGoals, (',')),
write_eq(ThreadedGoals, NewVarList0, 20),
write('.'),
nl
)
; thread_goals(Goals, ThreadedGoals, (',')),
; loader:thread_goals(Goals, ThreadedGoals, (',')),
write_eq(ThreadedGoals, NewVarList0, 20),
read_input(ThreadedGoals, NewVarList0)
).
@@ -353,133 +386,3 @@ print_exception_with_check(E) :-
% is expected to be printed instead.
; print_exception(E)
).
module_export(Source, PI) :-
( nonvar(PI) ->
( PI = Name / Arity ->
( var(Name) -> throw(error(instantiation_error, Source))
; integer(Arity) ->
( \+ atom(Name) -> throw(error(type_error(atom, Name), Source))
; Arity < 0 -> throw(error(domain_error(not_less_than_zero, Arity), Source))
; true
)
; throw(error(type_error(integer, Arity), Source))
)
; PI = op(Prec, Spec, Name) ->
( integer(Prec) ->
( \+ atom(Name) ->
throw(error(type_error(atom, Name), Source))
; Prec < 0 ->
throw(error(domain_error(not_less_than_zero, Prec), Source))
; Prec > 1200 ->
throw(error(domain_error(operator_precision, Prec), Source))
; memberchk(Spec, [xfy, yfx, xfx, fx, fy, yf, xf])
; throw(error(domain_error(operator_specification, Spec), Source))
)
; throw(error(type_error(integer, Prec), Source))
)
; throw(error(type_error(module_export, PI), Source))
)
; throw(error(instantiation_error, Source))
).
consult(Item) :-
( atom(Item) -> use_module(Item)
; throw(error(type_error(atom, Item), consult/1))
).
use_module(Module) :-
( nonvar(Module) ->
( Module = library(Filename) ->
write_term_to_chars(Filename, [], FilenameString),
'$use_module'(FilenameString)
; atom(Module) ->
'$use_module_from_file'(Module)
; throw(error(invalid_module_specifier, use_module/1))
)
; throw(error(instantiation_error, use_module/1))
).
use_module(Module, QualifiedExports) :-
( nonvar(Module) ->
( list_si(QualifiedExports) ->
maplist('$module_export'(use_module/2), QualifiedExports) ->
( Module = library(Filename) ->
write_term_to_chars(Filename, [], FilenameString),
'$use_qualified_module'(FilenameString, QualifiedExports)
; atom(Module) ->
'$use_qualified_module_from_file'(Module, QualifiedExports)
; throw(error(invalid_module_specifier, use_module/2))
)
; throw(error(type_error(list, QualifiedExports), use_module/2))
)
; throw(error(instantiation_error, use_module/2))
).
% expand goals in initialization directives.
user:term_expansion(Term0, (:- initialization(ExpandedGoals))) :-
nonvar(Term0),
Term0 = (:- initialization(Goals)),
expand_goals(Goals, ExpandedGoals),
Goals \== ExpandedGoals.
module_expand_goal(UnexpandedGoals, ExpandedGoals) :-
( '$module_of'(Module, UnexpandedGoals),
'$module_exists'(Module),
Module:goal_expansion(UnexpandedGoals, ExpandedGoals),
UnexpandedGoals \== ExpandedGoals ->
true
; user:goal_expansion(UnexpandedGoals, ExpandedGoals)
).
expand_goals(UnexpandedGoals, ExpandedGoals) :-
nonvar(UnexpandedGoals),
var(ExpandedGoals),
( module_expand_goal(UnexpandedGoals, Goals) ->
true
; Goals = UnexpandedGoals
),
( Goals = (Goal0, Goals0) ->
( expand_goals(Goal0, Goal1) ->
expand_goals(Goals0, Goals1),
thread_goals(Goal1, ExpandedGoals, Goals1, (','))
; expand_goals(Goals0, Goals1),
ExpandedGoals = (Goal0, Goals1)
)
; Goals = (Goals0 -> Goals1) ->
expand_goals(Goals0, ExpandedGoals0),
expand_goals(Goals1, ExpandedGoals1),
ExpandedGoals = (ExpandedGoals0 -> ExpandedGoals1)
; Goals = (Goals0 ; Goals1) ->
expand_goals(Goals0, ExpandedGoals0),
expand_goals(Goals1, ExpandedGoals1),
ExpandedGoals = (ExpandedGoals0 ; ExpandedGoals1)
; Goals = (\+ Goals0) ->
expand_goals(Goals0, Goals1),
ExpandedGoals = (\+ Goals1)
; thread_goals(Goals, ExpandedGoals, (','))
; Goals = ExpandedGoals
).
thread_goals(Goals0, Goals1, Hole, Functor) :-
nonvar(Goals0),
( Goals0 = [G | Gs] ->
( Gs == [] ->
Goals1 =.. [Functor, G, Hole]
; Goals1 =.. [Functor, G, Goals2],
thread_goals(Gs, Goals2, Hole, Functor)
)
; Goals1 =.. [Functor, Goals0, Hole]
).
thread_goals(Goals0, Goals1, Functor) :-
nonvar(Goals0),
( Goals0 = [G | Gs] ->
( Gs = [] ->
Goals1 = G
; Goals1 =.. [Functor, G, Goals2],
thread_goals(Gs, Goals2, Functor)
)
; Goals1 = Goals0
).

View File

@@ -1,6 +1,8 @@
use crate::clause_types::*;
use crate::forms::*;
use crate::indexing::IndexingCodePtr;
use crate::instructions::*;
use crate::machine::loader::CompilationTarget;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
@@ -10,14 +12,8 @@ impl fmt::Display for LocalCodePtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
LocalCodePtr::DirEntry(p) => write!(f, "LocalCodePtr::DirEntry({})", p),
LocalCodePtr::InSituDirEntry(p) => write!(f, "LocalCodePtr::InSituDirEntry({})", p),
LocalCodePtr::TopLevel(cn, p) => write!(f, "LocalCodePtr::TopLevel({}, {})", cn, p),
LocalCodePtr::UserGoalExpansion(p) => {
write!(f, "LocalCodePtr::UserGoalExpansion({})", p)
}
LocalCodePtr::UserTermExpansion(p) => {
write!(f, "LocalCodePtr::UserTermExpansion({})", p)
}
LocalCodePtr::Halt => write!(f, "LocalCodePtr::Halt"),
LocalCodePtr::IndexingBuf(p, o, i) => write!(f, "LocalCodePtr::IndexingBuf({}, {}, {})", p, o, i),
}
}
}
@@ -25,16 +21,72 @@ impl fmt::Display for LocalCodePtr {
impl fmt::Display for REPLCodePtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
REPLCodePtr::CompileBatch =>
write!(f, "REPLCodePtr::CompileBatch"),
REPLCodePtr::AddDiscontiguousPredicate =>
write!(f, "REPLCodePtr::AddDiscontiguousPredicate"),
REPLCodePtr::AddDynamicPredicate =>
write!(f, "REPLCodePtr::AddDynamicPredicate"),
REPLCodePtr::AddMultifilePredicate =>
write!(f, "REPLCodePtr::AddMultifilePredicate"),
REPLCodePtr::AddGoalExpansionClause =>
write!(f, "REPLCodePtr::AddGoalExpansionClause"),
REPLCodePtr::AddTermExpansionClause =>
write!(f, "REPLCodePtr::AddTermExpansionClause"),
REPLCodePtr::AbolishClause =>
write!(f, "REPLCodePtr::AbolishClause"),
REPLCodePtr::Assertz =>
write!(f, "REPLCodePtr::Assertz"),
REPLCodePtr::Asserta =>
write!(f, "REPLCodePtr::Asserta"),
REPLCodePtr::Retract =>
write!(f, "REPLCodePtr::Retract"),
REPLCodePtr::ClauseToEvacuable =>
write!(f, "REPLCodePtr::ClauseToEvacuable"),
REPLCodePtr::ScopedClauseToEvacuable =>
write!(f, "REPLCodePtr::ScopedClauseToEvacuable"),
REPLCodePtr::ConcludeLoad =>
write!(f, "REPLCodePtr::ConcludeLoad"),
REPLCodePtr::DeclareModule =>
write!(f, "REPLCodePtr::DeclareModule"),
REPLCodePtr::LoadCompiledLibrary =>
write!(f, "REPLCodePtr::LoadCompiledLibrary"),
REPLCodePtr::LoadContextSource =>
write!(f, "REPLCodePtr::LoadContextSource"),
REPLCodePtr::LoadContextFile =>
write!(f, "REPLCodePtr::LoadContextFile"),
REPLCodePtr::LoadContextDirectory =>
write!(f, "REPLCodePtr::LoadContextDirectory"),
REPLCodePtr::LoadContextModule =>
write!(f, "REPLCodePtr::LoadContextModule"),
REPLCodePtr::LoadContextStream =>
write!(f, "REPLCodePtr::LoadContextStream"),
REPLCodePtr::PopLoadContext =>
write!(f, "REPLCodePtr::PopLoadContext"),
REPLCodePtr::PopLoadStatePayload =>
write!(f, "REPLCodePtr::PopLoadStatePayload"),
REPLCodePtr::PushLoadContext =>
write!(f, "REPLCodePtr::PushLoadContext"),
REPLCodePtr::PushLoadStatePayload =>
write!(f, "REPLCodePtr::PushLoadStatePayload"),
REPLCodePtr::UseModule =>
write!(f, "REPLCodePtr::UseModule"),
REPLCodePtr::UseQualifiedModule =>
write!(f, "REPLCodePtr::UseQualifiedModule"),
REPLCodePtr::UseModuleFromFile =>
write!(f, "REPLCodePtr::UseModuleFromFile"),
REPLCodePtr::UseQualifiedModuleFromFile =>
write!(f, "REPLCodePtr::UseQualifiedModuleFromFile")
REPLCodePtr::MetaPredicateProperty =>
write!(f, "REPLCodePtr::MetaPredicateProperty"),
REPLCodePtr::BuiltInProperty =>
write!(f, "REPLCodePtr::BuiltInProperty"),
REPLCodePtr::DynamicProperty =>
write!(f, "REPLCodePtr::DynamicProperty"),
REPLCodePtr::MultifileProperty =>
write!(f, "REPLCodePtr::MultifileProperty"),
REPLCodePtr::DiscontiguousProperty =>
write!(f, "REPLCodePtr::DiscontiguousProperty"),
REPLCodePtr::IsConsistentWithTermQueue =>
write!(f, "REPLCodePtr::IsConsistentWithTermQueue"),
REPLCodePtr::FlushTermQueue =>
write!(f, "REPLCodePtr::FlushTermQueue"),
REPLCodePtr::RemoveModuleExports =>
write!(f, "REPLCodePtr::RemoveModuleExports"),
REPLCodePtr::AddNonCountedBacktracking =>
write!(f, "REPLCodePtr::AddNonCountedBacktracking"),
}
}
}
@@ -44,10 +96,16 @@ impl fmt::Display for IndexPtr {
match self {
&IndexPtr::DynamicUndefined => write!(f, "undefined"),
&IndexPtr::Undefined => write!(f, "undefined"),
&IndexPtr::Index(i) => write!(f, "{}", i),
&IndexPtr::InSituDirEntry(i) => write!(f, "in_situ({})", i),
&IndexPtr::UserTermExpansion => write!(f, "user:term_expansion"),
&IndexPtr::UserGoalExpansion => write!(f, "user:goal_expansion"),
&IndexPtr::DynamicIndex(i) | &IndexPtr::Index(i) => write!(f, "{}", i),
}
}
}
impl fmt::Display for CompilationTarget {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
CompilationTarget::User => write!(f, "user"),
CompilationTarget::Module(ref module_name) => write!(f, "{}", module_name),
}
}
}
@@ -68,17 +126,27 @@ impl fmt::Display for FactInstruction {
&FactInstruction::GetStructure(ref ct, ref arity, ref r) => {
write!(f, "get_structure {}/{}, {}", ct.name(), arity, r)
}
&FactInstruction::GetValue(ref x, ref a) => write!(f, "get_value {}, A{}", x, a),
&FactInstruction::GetValue(ref x, ref a) => {
write!(f, "get_value {}, A{}", x, a)
}
&FactInstruction::GetVariable(ref x, ref a) => {
write!(f, "fact:get_variable {}, A{}", x, a)
}
&FactInstruction::UnifyConstant(ref constant) => {
write!(f, "unify_constant {}", constant)
}
&FactInstruction::UnifyVariable(ref r) => write!(f, "unify_variable {}", r),
&FactInstruction::UnifyLocalValue(ref r) => write!(f, "unify_local_value {}", r),
&FactInstruction::UnifyValue(ref r) => write!(f, "unify_value {}", r),
&FactInstruction::UnifyVoid(n) => write!(f, "unify_void {}", n),
&FactInstruction::UnifyVariable(ref r) => {
write!(f, "unify_variable {}", r)
}
&FactInstruction::UnifyLocalValue(ref r) => {
write!(f, "unify_local_value {}", r)
}
&FactInstruction::UnifyValue(ref r) => {
write!(f, "unify_value {}", r)
}
&FactInstruction::UnifyVoid(n) => {
write!(f, "unify_void {}", n)
}
}
}
}
@@ -141,12 +209,16 @@ impl fmt::Display for CompareTermQT {
impl fmt::Display for ClauseType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&ClauseType::System(SystemClauseType::SetCutPoint(r)) => write!(f, "$set_cp({})", r),
&ClauseType::Named(ref name, _, ref idx) | &ClauseType::Op(ref name, _, ref idx) => {
let idx = idx.0.borrow();
write!(f, "{}:{}/{}", idx.1, name, idx.0)
&ClauseType::System(SystemClauseType::SetCutPoint(r)) => {
write!(f, "$set_cp({})", r)
}
&ClauseType::Named(ref name, _, ref idx) | &ClauseType::Op(ref name, _, ref idx) => {
let idx = idx.0.get();
write!(f, "{}/{}", name, idx)
}
ref ct => {
write!(f, "{}", ct.name())
}
ref ct => write!(f, "{}", ct.name()),
}
}
}
@@ -158,6 +230,7 @@ impl fmt::Display for HeapCellValue {
&HeapCellValue::Atom(ref atom, _) => write!(f, "{}", atom.as_str()),
&HeapCellValue::DBRef(ref db_ref) => write!(f, "{}", db_ref),
&HeapCellValue::Integer(ref n) => write!(f, "{}", n),
&HeapCellValue::LoadStatePayload(_) => write!(f, "LoadStatePayload"),
&HeapCellValue::Rational(ref n) => write!(f, "{}", n),
&HeapCellValue::NamedStr(arity, ref name, Some(ref cell)) => write!(
f,
@@ -209,6 +282,7 @@ impl fmt::Display for Addr {
&Addr::CutPoint(cp) => write!(f, "Addr::CutPoint({})", cp),
&Addr::Con(ref c) => write!(f, "Addr::Con({})", c),
&Addr::Lis(l) => write!(f, "Addr::Lis({})", l),
&Addr::LoadStatePayload(s) => write!(f, "Addr::LoadStatePayload({})", s),
&Addr::AttrVar(h) => write!(f, "Addr::AttrVar({})", h),
&Addr::HeapCell(h) => write!(f, "Addr::HeapCell({})", h),
&Addr::StackCell(fr, sc) => write!(f, "Addr::StackCell({}, {})", fr, sc),
@@ -244,6 +318,9 @@ impl fmt::Display for ControlInstruction {
&ControlInstruction::JmpBy(arity, offset, pvs, true) => {
write!(f, "jmp_by_execute {}/{}, {}", offset, arity, pvs)
}
&ControlInstruction::RevJmpBy(offset) => {
write!(f, "rev_jmp_by {}", offset)
}
&ControlInstruction::Proceed => write!(f, "proceed"),
}
}
@@ -262,13 +339,60 @@ impl fmt::Display for IndexedChoiceInstruction {
impl fmt::Display for ChoiceInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&ChoiceInstruction::TryMeElse(offset) => write!(f, "try_me_else {}", offset),
&ChoiceInstruction::DynamicElse(offset, Death::Infinity, NextOrFail::Next(i)) => {
write!(f, "dynamic_else {}, {}, {}", offset, "inf", i)
}
&ChoiceInstruction::DynamicElse(offset, Death::Infinity, NextOrFail::Fail(i)) => {
write!(f, "dynamic_else {}, {}, fail({})", offset, "inf", i)
}
&ChoiceInstruction::DynamicElse(offset, Death::Finite(d), NextOrFail::Next(i)) => {
write!(f, "dynamic_else {}, {}, {}", offset, d, i)
}
&ChoiceInstruction::DynamicElse(offset, Death::Finite(d), NextOrFail::Fail(i)) => {
write!(f, "dynamic_else {}, {}, fail({})", offset, d, i)
}
&ChoiceInstruction::DynamicInternalElse(offset, Death::Infinity, NextOrFail::Next(i)) => {
write!(f, "dynamic_internal_else {}, {}, {}", offset, "inf", i)
}
&ChoiceInstruction::DynamicInternalElse(offset, Death::Infinity, NextOrFail::Fail(i)) => {
write!(f, "dynamic_internal_else {}, {}, fail({})", offset, "inf", i)
}
&ChoiceInstruction::DynamicInternalElse(offset, Death::Finite(d), NextOrFail::Next(i)) => {
write!(f, "dynamic_internal_else {}, {}, {}", offset, d, i)
}
&ChoiceInstruction::DynamicInternalElse(offset, Death::Finite(d), NextOrFail::Fail(i)) => {
write!(f, "dynamic_internal_else {}, {}, fail({})", offset, d, i)
}
&ChoiceInstruction::TryMeElse(offset) =>
write!(f, "try_me_else {}", offset),
&ChoiceInstruction::DefaultRetryMeElse(offset) => {
write!(f, "retry_me_else_by_default {}", offset)
}
&ChoiceInstruction::RetryMeElse(offset) => write!(f, "retry_me_else {}", offset),
&ChoiceInstruction::DefaultTrustMe => write!(f, "trust_me_by_default"),
&ChoiceInstruction::TrustMe => write!(f, "trust_me"),
&ChoiceInstruction::RetryMeElse(offset) =>
write!(f, "retry_me_else {}", offset),
&ChoiceInstruction::DefaultTrustMe(_) =>
write!(f, "trust_me_by_default"),
&ChoiceInstruction::TrustMe(_) =>
write!(f, "trust_me"),
}
}
}
impl fmt::Display for IndexingCodePtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&IndexingCodePtr::DynamicExternal(o) => {
write!(f, "IndexingCodePtr::DynamicExternal({})", o)
}
&IndexingCodePtr::External(o) => {
write!(f, "IndexingCodePtr::External({})", o)
}
&IndexingCodePtr::Fail => {
write!(f, "IndexingCodePtr::Fail")
}
&IndexingCodePtr::Internal(o) => {
write!(f, "IndexingCodePtr::Internal({})", o)
}
}
}
}
@@ -279,11 +403,11 @@ impl fmt::Display for IndexingInstruction {
&IndexingInstruction::SwitchOnTerm(a, v, c, l, s) => {
write!(f, "switch_on_term {}, {}, {}, {}, {}", a, v, c, l, s)
}
&IndexingInstruction::SwitchOnConstant(_, num_cs, _) => {
write!(f, "switch_on_constant {}", num_cs)
&IndexingInstruction::SwitchOnConstant(ref constants) => {
write!(f, "switch_on_constant {}", constants.len())
}
&IndexingInstruction::SwitchOnStructure(_, num_ss, _) => {
write!(f, "switch_on_structure {}", num_ss)
&IndexingInstruction::SwitchOnStructure(ref structures) => {
write!(f, "switch_on_structure {}", structures.len())
}
}
}
@@ -295,15 +419,15 @@ impl fmt::Display for SessionError {
&SessionError::ExistenceError(ref err) => {
write!(f, "{}", err)
}
&SessionError::CannotOverwriteBuiltIn(ref msg) => {
write!(f, "cannot overwrite {}", msg)
}
&SessionError::CannotOverwriteImport(ref msg) => {
write!(f, "cannot overwrite import {}", msg)
}
&SessionError::InvalidFileName(ref filename) => {
write!(f, "filename {} is invalid", filename)
}
// &SessionError::CannotOverwriteBuiltIn(ref msg) => {
// write!(f, "cannot overwrite {}", msg)
// }
// &SessionError::CannotOverwriteImport(ref msg) => {
// write!(f, "cannot overwrite import {}", msg)
// }
// &SessionError::InvalidFileName(ref filename) => {
// write!(f, "filename {} is invalid", filename)
// }
&SessionError::ModuleDoesNotContainExport(ref module, ref key) => {
write!(
f,
@@ -319,12 +443,20 @@ impl fmt::Display for SessionError {
&SessionError::NamelessEntry => {
write!(f, "the predicate head is not an atom or clause.")
}
&SessionError::ParserError(ref e) => {
write!(f, "syntax_error({})", e.as_str())
&SessionError::CompilationError(ref e) => {
write!(f, "syntax_error({:?})", e)
}
&SessionError::QueryCannotBeDefinedAsFact => {
write!(f, "queries cannot be defined as facts.")
}
&SessionError::ModuleCannotImportSelf(ref module_name) => {
write!(f, "modules ({}, in this case) cannot import themselves.",
module_name)
}
&SessionError::PredicateNotMultifileOrDiscontiguous(ref compilation_target, ref key) => {
write!(f, "module {} does not define {}/{} as multifile or discontiguous.",
compilation_target.module_name(), key.0, key.1)
}
}
}
}
@@ -364,6 +496,30 @@ impl fmt::Display for ModuleSource {
}
}
impl fmt::Display for IndexingLine {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&IndexingLine::Indexing(ref indexing_instr) => {
write!(f, "{}", indexing_instr)
}
&IndexingLine::IndexedChoice(ref indexed_choice_instrs) => {
for indexed_choice_instr in indexed_choice_instrs {
write!(f, "{}", indexed_choice_instr)?;
}
Ok(())
}
&IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => {
for indexed_choice_instr in indexed_choice_instrs {
write!(f, "dynamic({})", indexed_choice_instr)?;
}
Ok(())
}
}
}
}
impl fmt::Display for Line {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
@@ -372,8 +528,15 @@ impl fmt::Display for Line {
&Line::Control(ref control_instr) => write!(f, "{}", control_instr),
&Line::Cut(ref cut_instr) => write!(f, "{}", cut_instr),
&Line::Fact(ref fact_instr) => write!(f, "{}", fact_instr),
&Line::Indexing(ref indexing_instr) => write!(f, "{}", indexing_instr),
&Line::IndexingCode(ref indexing_instrs) => {
for indexing_instr in indexing_instrs {
write!(f, "{}", indexing_instr)?;
}
Ok(())
}
&Line::IndexedChoice(ref indexed_choice_instr) => write!(f, "{}", indexed_choice_instr),
&Line::DynamicIndexedChoice(ref indexed_choice_instr) => write!(f, "{}", indexed_choice_instr),
&Line::Query(ref query_instr) => write!(f, "{}", query_instr),
}
}

65
tests/scryer.rs Normal file
View File

@@ -0,0 +1,65 @@
/// Loads the file and if some expected output is given checks that it matches
fn test_file(file: &str, expected: Option<&[u8]>) {
use scryer_prolog::*;
let input = machine::Stream::from("");
let output = machine::Stream::from(String::new());
let mut wam = machine::Machine::new(input, output.clone());
wam.load_file(
file.into(),
machine::Stream::from(
std::fs::read_to_string(AsRef::<std::path::Path>::as_ref(file)).unwrap(),
),
);
if let Some(expected) = expected {
let output = output.bytes().unwrap();
assert_eq!(output.as_slice(), expected);
}
}
#[test]
fn builtins() {
test_file("src/tests/builtins.pl", Some(b""));
}
#[test]
fn call_with_inference_limit() {
test_file("src/tests/call_with_inference_limit.pl", Some(b""));
}
#[test]
fn facts() {
test_file("src/tests/facts.pl", Some(b""));
}
#[test]
fn hello_world() {
test_file(
"src/tests/hello_world.pl",
Some("Hello World!\n".as_bytes()),
);
}
#[test]
fn predicates() {
test_file("src/tests/predicates.pl", Some(b""));
}
#[test]
fn rules() {
test_file("src/tests/rules.pl", Some(b""));
}
#[test]
#[ignore] // ignored as this does not appear to terminate
fn setup_call_cleanup() {
test_file("src/tests/setup_call_cleanup.pl", Some(b""));
}
#[test]
fn clpz() {
test_file("src/tests/clpz/test_clpz.pl", Some(b""));
}