diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 94ebc690..ddb8e61d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -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: diff --git a/Cargo.lock b/Cargo.lock index 21afb6e7..360181de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index 3ba2a6c7..0d8dbee1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/README.md b/README.md index 1b7411e1..f11a4c97 100644 --- a/README.md +++ b/README.md @@ -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: diff --git a/build.rs b/build.rs index a9ec444e..0133c93e 100644 --- a/build.rs +++ b/build.rs @@ -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(); diff --git a/crates/num-rug-adapter/Cargo.toml b/crates/num-rug-adapter/Cargo.toml new file mode 100644 index 00000000..8693ac47 --- /dev/null +++ b/crates/num-rug-adapter/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "num-rug-adapter" +version = "0.1.5" +authors = ["Marco A L Barbosa "] +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" diff --git a/crates/num-rug-adapter/src/lib.rs b/crates/num-rug-adapter/src/lib.rs new file mode 100644 index 00000000..a95d42c8 --- /dev/null +++ b/crates/num-rug-adapter/src/lib.rs @@ -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 { + BigInt::from_str_radix(s, radix).map(Integer) + } + + #[inline] + pub fn to_u8(&self) -> Option { + self.0.to_u8() + } + + #[inline] + pub fn to_u32(&self) -> Option { + self.0.to_u32() + } + + #[inline] + pub fn to_u64(&self) -> Option { + self.0.to_u64() + } + + #[inline] + pub fn to_usize(&self) -> Option { + self.0.to_usize() + } + + #[inline] + pub fn to_i32(&self) -> Option { + self.0.to_i32() + } + + #[inline] + pub fn to_isize(&self) -> Option { + 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 { + 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 for Integer { + #[inline] + fn from(s: i32) -> Self { + Integer(BigInt::from(s)) + } +} + +impl From for Integer { + #[inline] + fn from(s: isize) -> Self { + Integer(BigInt::from(s)) + } +} + +impl From for Integer { + #[inline] + fn from(s: u8) -> Self { + Integer(BigInt::from(s)) + } +} + +impl From for Integer { + #[inline] + fn from(s: u32) -> Self { + Integer(BigInt::from(s)) + } +} + +impl From for Integer { + #[inline] + fn from(s: u64) -> Self { + Integer(BigInt::from(s)) + } +} + +impl From 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 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 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 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 for &Integer { + type Output = Integer; + + #[inline] + fn div(self, other: Integer) -> Integer { + Integer(&self.0 / &other.0) + } +} + +impl Shr for Integer { + type Output = Integer; + + #[inline] + fn shr(self, rhs: u32) -> Self::Output { + Integer(self.0 >> rhs as usize) + } +} + +impl Shr for &Integer { + type Output = Integer; + + #[inline] + fn shr(self, rhs: u32) -> Self::Output { + Integer(&self.0 >> rhs as usize) + } +} + +impl ShrAssign for Integer { + #[inline] + fn shr_assign(&mut self, rhs: u32) { + self.0 >>= rhs as usize; + } +} + +impl Shl for Integer { + type Output = Integer; + + #[inline] + fn shl(self, rhs: u32) -> Self::Output { + Integer(self.0 << rhs as usize) + } +} + +impl Shl 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 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 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 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 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 for Integer { + #[inline] + fn eq(&self, other: &i32) -> bool { + self.0 == BigInt::from(*other) + } +} + +impl PartialEq for Integer { + #[inline] + fn eq(&self, other: &i64) -> bool { + self.0 == BigInt::from(*other) + } +} + +impl PartialEq for Integer { + #[inline] + fn eq(&self, other: &isize) -> bool { + self.0 == BigInt::from(*other) + } +} + +impl PartialEq for Integer { + #[inline] + fn eq(&self, other: &usize) -> bool { + self.0 == BigInt::from(*other) + } +} + +impl PartialEq for isize { + #[inline] + fn eq(&self, other: &Integer) -> bool { + other.0 == BigInt::from(*self) + } +} + +impl PartialOrd for Integer { + #[inline] + fn partial_cmp(&self, other: &i32) -> Option { + self.0.partial_cmp(&BigInt::from(*other)) + } +} + +impl PartialOrd for Integer { + #[inline] + fn partial_cmp(&self, other: &i64) -> Option { + self.0.partial_cmp(&BigInt::from(*other)) + } +} + +impl PartialOrd for Integer { + #[inline] + fn partial_cmp(&self, other: &isize) -> Option { + self.0.partial_cmp(&BigInt::from(*other)) + } +} + +impl PartialOrd for Integer { + #[inline] + fn partial_cmp(&self, other: &usize) -> Option { + self.0.partial_cmp(&BigInt::from(*other)) + } +} + +impl FromStr for Integer { + type Err = ::Err; + + #[inline] + fn from_str(s: &str) -> Result { + 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 { + 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 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 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 for Rational { + #[inline] + fn eq(&self, other: &i32) -> bool { + self.0 == BigRational::from(BigInt::from(*other)) + } +} + +impl PartialEq for Rational { + #[inline] + fn eq(&self, other: &i64) -> bool { + self.0 == BigRational::from(BigInt::from(*other)) + } +} + +impl PartialEq for Rational { + #[inline] + fn eq(&self, other: &isize) -> bool { + self == &Rational::from(*other) + } +} + +impl PartialEq for isize { + #[inline] + fn eq(&self, other: &Rational) -> bool { + other == &Rational::from(*self) + } +} + +impl PartialOrd for Rational { + #[inline] + fn partial_cmp(&self, other: &isize) -> Option { + self.0.partial_cmp(&BigRational::from(BigInt::from(*other))) + } +} + +impl PartialOrd for Rational { + #[inline] + fn partial_cmp(&self, other: &i64) -> Option { + self.0.partial_cmp(&BigRational::from(BigInt::from(*other))) + } +} + +impl PartialOrd for Rational { + #[inline] + fn partial_cmp(&self, other: &i32) -> Option { + 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 { + 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 { + type Output; + fn pow(self, rhs: Rhs) -> Self::Output; + } + + impl Pow for Integer { + type Output = Integer; + + fn pow(self, rhs: u32) -> Self::Output { + Integer(num_traits::Pow::pow(&self.0, rhs)) + } + } + + pub trait PowAssign { + fn pow_assign(&mut self, rhs: Rhs); + } + + impl PowAssign 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); + } +} diff --git a/crates/prolog_parser/Cargo.lock b/crates/prolog_parser/Cargo.lock new file mode 100644 index 00000000..57d62880 --- /dev/null +++ b/crates/prolog_parser/Cargo.lock @@ -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" diff --git a/crates/prolog_parser/Cargo.toml b/crates/prolog_parser/Cargo.toml index 05bfc24d..8946bf27 100644 --- a/crates/prolog_parser/Cargo.toml +++ b/crates/prolog_parser/Cargo.toml @@ -2,15 +2,17 @@ name = "prolog_parser" version = "0.8.68" authors = ["Mark Thom "] +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] diff --git a/crates/prolog_parser/src/ast.rs b/crates/prolog_parser/src/ast.rs index 5f7905a3..ac794e6e 100644 --- a/crates/prolog_parser/src/ast.rs +++ b/crates/prolog_parser/src/ast.rs @@ -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; +pub type OpDir = IndexMap; #[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 for ParserError { - fn from(err: ArithmeticError) -> ParserError { - ParserError::Arithmetic(err) - } -} - impl From 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), 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 { + pub fn to_atom(&self) -> Option { 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 { 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 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 { 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 { + pub fn into_constant(self) -> Option { 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 { - 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(); diff --git a/crates/prolog_parser/src/lexer.rs b/crates/prolog_parser/src/lexer.rs index b1656a55..02053035 100644 --- a/crates/prolog_parser/src/lexer.rs +++ b/crates/prolog_parser/src/lexer.rs @@ -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), - 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, 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") // 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") // 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, ) -> 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, ParserError> - { + fn get_single_quoted_item(&mut self) -> Result, 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, ParserError> - { + fn get_double_quoted_item(&mut self) -> Result, 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 - { + fn get_control_escape_sequence(&mut self) -> Result { 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 - { + fn get_octal_escape_sequence(&mut self) -> Result { self.escape_sequence_to_char(|c| octal_digit_char!(c), 8) } - fn get_hexadecimal_escape_sequence(&mut self) -> Result - { + fn get_hexadecimal_escape_sequence(&mut self) -> Result { 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::() - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) - .map_err(|_| ParserError::ParseBigInt( - self.line_num, - self.col_num, - )) + token + .parse::() + .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::() - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) - .map_err(|_| ParserError::ParseBigInt( - self.line_num, - self.col_num, - )) + token + .parse::() + .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::() - .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::() + .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::() - .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::() + .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::() - .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::() + .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::() - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) - .map_err(|_| ParserError::ParseBigInt( - self.line_num, - self.col_num, - )) + token + .parse::() + .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::() - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) - .map_err(|_| ParserError::ParseBigInt( - self.line_num, - self.col_num, - )) + token + .parse::() + .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::() - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) - .map_err(|_| ParserError::ParseBigInt( - self.line_num, - self.col_num, - )) + token + .parse::() + .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), } } } diff --git a/crates/prolog_parser/src/lib.rs b/crates/prolog_parser/src/lib.rs index f8ef7536..2c37cea6 100644 --- a/crates/prolog_parser/src/lib.rs +++ b/crates/prolog_parser/src/lib.rs @@ -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; diff --git a/crates/prolog_parser/src/macros.rs b/crates/prolog_parser/src/macros.rs index e4520aba..c05ed69b 100644 --- a/crates/prolog_parser/src/macros.rs +++ b/crates/prolog_parser/src/macros.rs @@ -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) + }; } diff --git a/crates/prolog_parser/src/parser.rs b/crates/prolog_parser/src/parser.rs index dd665c26..c72d6453 100644 --- a/crates/prolog_parser/src/parser.rs +++ b/crates/prolog_parser/src/parser.rs @@ -1,10 +1,10 @@ -use ast::*; -use lexer::*; -use tabled_rc::*; +use crate::ast::*; +use crate::lexer::*; +use crate::tabled_rc::*; use ordered_float::OrderedFloat; -use rug::ops::NegAssign; +use crate::rug::ops::NegAssign; use std::cell::Cell; use std::io::Read; @@ -16,25 +16,30 @@ enum TokenType { Term, Open, OpenCT, - OpenList, // '[' - OpenCurly, // '{' + OpenList, // '[' + OpenCurly, // '{' HeadTailSeparator, // '|' - Comma, // ',' + Comma, // ',' Close, - CloseList, // ']' - CloseCurly, // '}' - End + CloseList, // ']' + CloseCurly, // '}' + End, } impl TokenType { fn is_sep(self) -> bool { - match self { - TokenType::HeadTailSeparator | TokenType::OpenCT | TokenType::Open | - TokenType::Close | TokenType::OpenList | TokenType::CloseList | - TokenType::OpenCurly | TokenType::CloseCurly | TokenType::Comma - => true, - _ => false - } + matches!( + self, + TokenType::HeadTailSeparator + | TokenType::OpenCT + | TokenType::Open + | TokenType::Close + | TokenType::OpenList + | TokenType::CloseList + | TokenType::OpenCurly + | TokenType::CloseCurly + | TokenType::Comma + ) } } @@ -42,40 +47,47 @@ impl TokenType { struct TokenDesc { tt: TokenType, priority: usize, - spec: u32 + spec: u32, } -pub -fn get_clause_spec(name: ClauseName, arity: usize, op_dir: CompositeOp) -> Option -{ +pub fn get_clause_spec( + name: ClauseName, + arity: usize, + op_dir: &CompositeOpDir, +) -> Option { match arity { 1 => { /* This is a clause with an operator principal functor. Prefix operators are supposed over post. */ - if let Some(OpDirValue(cell, _)) = op_dir.get(name.clone(), Fixity::Pre) { - return Some(cell); + if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::Pre) { + return Some(cell.clone()); } - if let Some(OpDirValue(cell, _)) = op_dir.get(name, Fixity::Post) { - return Some(cell); + if let Some(OpDirValue(cell)) = op_dir.get(name, Fixity::Post) { + return Some(cell.clone()); } - }, - 2 => - if let Some(OpDirValue(cell, _)) = op_dir.get(name, Fixity::In) { - return Some(cell); - }, + } + 2 => { + if let Some(OpDirValue(cell)) = op_dir.get(name, Fixity::In) { + return Some(cell.clone()); + } + } _ => {} }; None } -pub fn get_desc(name: ClauseName, op_dir: CompositeOp) -> Option -{ - let mut op_desc = OpDesc { pre: 0, inf: 0, post: 0, spec: 0 }; +pub fn get_op_desc(name: ClauseName, op_dir: &CompositeOpDir) -> Option { + let mut op_desc = OpDesc { + pre: 0, + inf: 0, + post: 0, + spec: 0, + }; - if let Some(OpDirValue(cell, _)) = op_dir.get(name.clone(), Fixity::Pre) { + if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::Pre) { let (pri, spec) = cell.get(); if pri > 0 { @@ -86,7 +98,7 @@ pub fn get_desc(name: ClauseName, op_dir: CompositeOp) -> Option } } - if let Some(OpDirValue(cell, _)) = op_dir.get(name.clone(), Fixity::Post) { + if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::Post) { let (pri, spec) = cell.get(); if pri > 0 { @@ -95,7 +107,7 @@ pub fn get_desc(name: ClauseName, op_dir: CompositeOp) -> Option } } - if let Some(OpDirValue(cell, _)) = op_dir.get(name.clone(), Fixity::In) { + if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::In) { let (pri, spec) = cell.get(); if pri > 0 { @@ -111,8 +123,7 @@ pub fn get_desc(name: ClauseName, op_dir: CompositeOp) -> Option } } -fn affirm_xfx(priority: usize, d2: TokenDesc, d3: TokenDesc, d1: TokenDesc) -> bool -{ +fn affirm_xfx(priority: usize, d2: TokenDesc, d3: TokenDesc, d1: TokenDesc) -> bool { d2.priority <= priority && is_term!(d3.spec) && is_term!(d1.spec) @@ -120,18 +131,15 @@ fn affirm_xfx(priority: usize, d2: TokenDesc, d3: TokenDesc, d1: TokenDesc) -> b && d1.priority < d2.priority } -fn affirm_yfx(priority: usize, d2: TokenDesc, d3: TokenDesc, d1: TokenDesc) -> bool -{ +fn affirm_yfx(priority: usize, d2: TokenDesc, d3: TokenDesc, d1: TokenDesc) -> bool { d2.priority <= priority - && ((is_term!(d3.spec) && d3.priority < d2.priority) - || (is_lterm!(d3.spec) && d3.priority == d2.priority)) + && ((is_term!(d3.spec) && d3.priority < d2.priority) + || (is_lterm!(d3.spec) && d3.priority == d2.priority)) && is_term!(d1.spec) && d1.priority < d2.priority } - -fn affirm_xfy(priority: usize, d2: TokenDesc, d3: TokenDesc, d1: TokenDesc) -> bool -{ +fn affirm_xfy(priority: usize, d2: TokenDesc, d3: TokenDesc, d1: TokenDesc) -> bool { d2.priority < priority && is_term!(d3.spec) && d3.priority < d2.priority @@ -139,49 +147,35 @@ fn affirm_xfy(priority: usize, d2: TokenDesc, d3: TokenDesc, d1: TokenDesc) -> b && d1.priority <= d2.priority } -fn affirm_yf(d1: TokenDesc, d2: TokenDesc) -> bool -{ +fn affirm_yf(d1: TokenDesc, d2: TokenDesc) -> bool { let is_valid_lterm = is_lterm!(d2.spec) && d2.priority == d1.priority; (is_term!(d2.spec) && d2.priority < d1.priority) || is_valid_lterm } -fn affirm_xf(d1: TokenDesc, d2: TokenDesc) -> bool -{ +fn affirm_xf(d1: TokenDesc, d2: TokenDesc) -> bool { is_term!(d2.spec) && d2.priority < d1.priority } -fn affirm_fy(priority: usize, d1: TokenDesc, d2: TokenDesc) -> bool -{ +fn affirm_fy(priority: usize, d1: TokenDesc, d2: TokenDesc) -> bool { d2.priority < priority && is_term!(d1.spec) && d1.priority <= d2.priority } -fn affirm_fx(priority: usize, d1: TokenDesc, d2: TokenDesc) -> bool -{ +fn affirm_fx(priority: usize, d1: TokenDesc, d2: TokenDesc) -> bool { d2.priority <= priority && is_term!(d1.spec) && d1.priority < d2.priority } -fn sep_to_atom(tt: TokenType) -> Option -{ +fn sep_to_atom(tt: TokenType) -> Option { match tt { - TokenType::Open | TokenType::OpenCT => - Some(clause_name!("(")), - TokenType::Close => - Some(clause_name!(")")), - TokenType::OpenList => - Some(clause_name!("[")), - TokenType::CloseList => - Some(clause_name!("]")), - TokenType::OpenCurly => - Some(clause_name!("{")), - TokenType::CloseCurly => - Some(clause_name!("}")), - TokenType::HeadTailSeparator => - Some(clause_name!("|")), - TokenType::Comma => - Some(clause_name!(",")), - TokenType::End => - Some(clause_name!(".")), - _ => None + TokenType::Open | TokenType::OpenCT => Some(clause_name!("(")), + TokenType::Close => Some(clause_name!(")")), + TokenType::OpenList => Some(clause_name!("[")), + TokenType::CloseList => Some(clause_name!("]")), + TokenType::OpenCurly => Some(clause_name!("{")), + TokenType::CloseCurly => Some(clause_name!("}")), + TokenType::HeadTailSeparator => Some(clause_name!("|")), + TokenType::Comma => Some(clause_name!(",")), + TokenType::End => Some(clause_name!(".")), + _ => None, } } @@ -190,7 +184,7 @@ pub struct OpDesc { pub pre: usize, pub inf: usize, pub post: usize, - pub spec: Specifier + pub spec: Specifier, } #[derive(Debug)] @@ -201,13 +195,12 @@ pub struct Parser<'a, R: Read> { terms: Vec, } -fn read_tokens<'a, R: Read>(lexer: &mut Lexer<'a, R>) -> Result, ParserError> -{ +fn read_tokens(lexer: &mut Lexer) -> Result, ParserError> { let mut tokens = vec![]; loop { let token = lexer.next_token()?; - let at_end = Token::End == token; + let at_end = token.is_end(); tokens.push(token); @@ -227,10 +220,12 @@ impl<'a, R: Read> Parser<'a, R> { atom_tbl: TabledData, flags: MachineFlags, ) -> Self { - Parser { lexer: Lexer::new(atom_tbl, flags, stream), - tokens: vec![], - stack: Vec::new(), - terms: Vec::new() } + Parser { + lexer: Lexer::new(atom_tbl, flags, stream), + tokens: vec![], + stack: Vec::new(), + terms: Vec::new(), + } } #[inline] @@ -255,50 +250,46 @@ impl<'a, R: Read> Parser<'a, R> { fn get_term_name(&mut self, td: TokenDesc) -> Option<(ClauseName, Option)> { match td.tt { - TokenType::HeadTailSeparator => { - Some((clause_name!("|"), Some(SharedOpDesc::new(td.priority, td.spec)))) - } - TokenType::Comma => { - Some((clause_name!(","), Some(SharedOpDesc::new(1000, XFY)))) - } - TokenType::Term => { - match self.terms.pop() { - Some(Term::Constant(_, Constant::Atom(atom, spec))) => - Some((atom, spec)), - Some(term) => { - self.terms.push(term); - None - }, - _ => None + TokenType::HeadTailSeparator => Some(( + clause_name!("|"), + Some(SharedOpDesc::new(td.priority, td.spec)), + )), + TokenType::Comma => Some((clause_name!(","), Some(SharedOpDesc::new(1000, XFY)))), + TokenType::Term => match self.terms.pop() { + Some(Term::Constant(_, Constant::Atom(atom, spec))) => Some((atom, spec)), + Some(term) => { + self.terms.push(term); + None } - } - _ => { - None - } + _ => None, + }, + _ => None, } } - fn push_binary_op(&mut self, td: TokenDesc, spec: Specifier) - { + fn push_binary_op(&mut self, td: TokenDesc, spec: Specifier) { if let Some(arg2) = self.terms.pop() { if let Some((name, shared_op_desc)) = self.get_term_name(td) { if let Some(arg1) = self.terms.pop() { - let term = Term::Clause(Cell::default(), - name, - vec![Box::new(arg1), Box::new(arg2)], - shared_op_desc); + let term = Term::Clause( + Cell::default(), + name, + vec![Box::new(arg1), Box::new(arg2)], + shared_op_desc, + ); self.terms.push(term); - self.stack.push(TokenDesc { tt: TokenType::Term, - priority: td.priority, - spec }); + self.stack.push(TokenDesc { + tt: TokenType::Term, + priority: td.priority, + spec, + }); } } } } - fn push_unary_op(&mut self, td: TokenDesc, spec: Specifier, assoc: u32) - { + fn push_unary_op(&mut self, td: TokenDesc, spec: Specifier, assoc: u32) { if let Some(mut arg1) = self.terms.pop() { if let Some(mut name) = self.terms.pop() { if is_postfix!(assoc) { @@ -306,52 +297,61 @@ impl<'a, R: Read> Parser<'a, R> { } if let Term::Constant(_, Constant::Atom(name, shared_op_desc)) = name { - let term = Term::Clause(Cell::default(), name, vec![Box::new(arg1)], - shared_op_desc); + let term = + Term::Clause(Cell::default(), name, vec![Box::new(arg1)], shared_op_desc); self.terms.push(term); - self.stack.push(TokenDesc { tt: TokenType::Term, - priority: td.priority, - spec }); + self.stack.push(TokenDesc { + tt: TokenType::Term, + priority: td.priority, + spec, + }); } } } } - fn promote_atom_op(&mut self, atom: ClauseName, priority: usize, assoc: u32, - op_dir_val: Option) - { + fn promote_atom_op( + &mut self, + atom: ClauseName, + priority: usize, + assoc: u32, + op_dir_val: Option<&OpDirValue>, + ) { let spec = op_dir_val.map(|op_dir_val| op_dir_val.shared_op_desc()); - self.terms.push(Term::Constant(Cell::default(), Constant::Atom(atom, spec))); - self.stack.push(TokenDesc { tt: TokenType::Term, priority, spec: assoc }); + self.terms + .push(Term::Constant(Cell::default(), Constant::Atom(atom, spec))); + self.stack.push(TokenDesc { + tt: TokenType::Term, + priority, + spec: assoc, + }); } - fn shift(&mut self, token: Token, priority: usize, spec: Specifier) - { + fn shift(&mut self, token: Token, priority: usize, spec: Specifier) { let tt = match token { - Token::Constant(Constant::String(s)) - if self.lexer.flags.double_quotes.is_codes() => { - let mut list = Term::Constant(Cell::default(), Constant::EmptyList); + Token::Constant(Constant::String(s)) if self.lexer.flags.double_quotes.is_codes() => { + let mut list = Term::Constant(Cell::default(), Constant::EmptyList); - for c in s.chars().rev() { - list = Term::Cons( + for c in s.chars().rev() { + list = Term::Cons( + Cell::default(), + Box::new(Term::Constant( Cell::default(), - Box::new(Term::Constant( - Cell::default(), - Constant::Fixnum(c as isize), - )), - Box::new(list), - ); - } - - self.terms.push(list); - TokenType::Term + Constant::Fixnum(c as isize), + )), + Box::new(list), + ); } + + self.terms.push(list); + TokenType::Term + } Token::Constant(c) => { self.terms.push(Term::Constant(Cell::default(), c)); TokenType::Term - }, + } Token::Var(v) => { if v.trim() == "_" { self.terms.push(Term::AnonVar); @@ -360,7 +360,7 @@ impl<'a, R: Read> Parser<'a, R> { } TokenType::Term - }, + } Token::Comma => TokenType::Comma, Token::Open => TokenType::Open, Token::Close => TokenType::Close, @@ -381,18 +381,13 @@ impl<'a, R: Read> Parser<'a, R> { if let Some(desc1) = self.stack.pop() { if let Some(desc2) = self.stack.pop() { if let Some(desc3) = self.stack.pop() { - if is_xfx!(desc2.spec) && affirm_xfx(priority, desc2, desc3, desc1) - { + if is_xfx!(desc2.spec) && affirm_xfx(priority, desc2, desc3, desc1) { self.push_binary_op(desc2, LTERM); continue; - } - else if is_yfx!(desc2.spec) && affirm_yfx(priority, desc2, desc3, desc1) - { + } else if is_yfx!(desc2.spec) && affirm_yfx(priority, desc2, desc3, desc1) { self.push_binary_op(desc2, LTERM); continue; - } - else if is_xfy!(desc2.spec) && affirm_xfy(priority, desc2, desc3, desc1) - { + } else if is_xfy!(desc2.spec) && affirm_xfy(priority, desc2, desc3, desc1) { self.push_binary_op(desc2, TERM); continue; } else { @@ -425,12 +420,12 @@ impl<'a, R: Read> Parser<'a, R> { } } - fn compute_arity_in_brackets(&self) -> Option - { + fn compute_arity_in_brackets(&self) -> Option { let mut arity = 0; for (i, desc) in self.stack.iter().rev().enumerate() { - if i % 2 == 0 { // expect a term or non-comma operator. + if i % 2 == 0 { + // expect a term or non-comma operator. if let TokenType::Comma = desc.tt { return None; } else if is_term!(desc.spec) || is_op!(desc.spec) || is_negate!(desc.spec) { @@ -454,8 +449,7 @@ impl<'a, R: Read> Parser<'a, R> { None } - fn reduce_term(&mut self, op_dir: CompositeOp) -> bool - { + fn reduce_term(&mut self, op_dir: &CompositeOpDir) -> bool { if self.stack.is_empty() { return false; } @@ -464,7 +458,7 @@ impl<'a, R: Read> Parser<'a, R> { let arity = match self.compute_arity_in_brackets() { Some(arity) => arity, - None => return false + None => return false, }; if self.stack.len() > 2 * arity { @@ -475,10 +469,6 @@ impl<'a, R: Read> Parser<'a, R> { return false; } } - - if arity >= 2 && is_prefix!(self.stack[idx].spec) && self.stack[idx].priority > 0 { - return false; - } } else { return false; } @@ -490,9 +480,7 @@ impl<'a, R: Read> Parser<'a, R> { if self.atomize_term(&self.terms[idx - 1]).is_some() { self.stack.truncate(stack_len + 1); - let mut subterms: Vec<_> = self.terms.drain(idx ..) - .map(|t| Box::new(t)) - .collect(); + let mut subterms: Vec<_> = self.terms.drain(idx..).map(Box::new).collect(); if let Some(name) = self.terms.pop().and_then(|t| self.atomize_term(&t)) { // reduce the '.' functor to a cons cell if it applies. @@ -503,11 +491,15 @@ impl<'a, R: Read> Parser<'a, R> { self.terms.push(Term::Cons(Cell::default(), head, tail)); } else { let spec = get_clause_spec(name.clone(), subterms.len(), op_dir); - self.terms.push(Term::Clause(Cell::default(), name, subterms, spec)); + self.terms + .push(Term::Clause(Cell::default(), name, subterms, spec)); } - if let Some(&mut TokenDesc { ref mut priority, ref mut spec, - ref mut tt }) = self.stack.last_mut() + if let Some(&mut TokenDesc { + ref mut priority, + ref mut spec, + ref mut tt, + }) = self.stack.last_mut() { *tt = TokenType::Term; *priority = 0; @@ -523,7 +515,7 @@ impl<'a, R: Read> Parser<'a, R> { } pub fn devour_whitespace(&mut self) -> Result<(), ParserError> { - self.lexer.scan_for_layout()?; + self.lexer.scan_for_layout()?; Ok(()) } @@ -531,8 +523,7 @@ impl<'a, R: Read> Parser<'a, R> { self.stack.clear() } - fn expand_comma_compacted_terms(&mut self, index: usize) -> usize - { + fn expand_comma_compacted_terms(&mut self, index: usize) -> usize { if let Some(term) = self.terms.pop() { let op_desc = self.stack[index - 1]; @@ -548,8 +539,7 @@ impl<'a, R: Read> Parser<'a, R> { self.terms.extend(terms.into_iter()); return arity; } - _ => { - } + _ => {} } } @@ -559,12 +549,12 @@ impl<'a, R: Read> Parser<'a, R> { 0 } - fn compute_arity_in_list(&self) -> Option - { + fn compute_arity_in_list(&self) -> Option { let mut arity = 0; for (i, desc) in self.stack.iter().rev().enumerate() { - if i % 2 == 0 { // expect a term or non-comma operator. + if i % 2 == 0 { + // expect a term or non-comma operator. if let TokenType::Comma = desc.tt { return None; } else if is_term!(desc.spec) || is_op!(desc.spec) { @@ -590,8 +580,7 @@ impl<'a, R: Read> Parser<'a, R> { None } - fn reduce_list(&mut self) -> Result - { + fn reduce_list(&mut self) -> Result { if self.stack.is_empty() { return Ok(false); } @@ -602,7 +591,8 @@ impl<'a, R: Read> Parser<'a, R> { td.tt = TokenType::Term; td.priority = 0; - self.terms.push(Term::Constant(Cell::default(), Constant::EmptyList)); + self.terms + .push(Term::Constant(Cell::default(), Constant::EmptyList)); return Ok(true); } } @@ -611,7 +601,7 @@ impl<'a, R: Read> Parser<'a, R> { let mut arity = match self.compute_arity_in_list() { Some(arity) => arity, - None => return Ok(false) + None => return Ok(false), }; // we know that self.stack.len() >= 2 by this point. @@ -621,12 +611,15 @@ impl<'a, R: Read> Parser<'a, R> { let end_term = if self.stack[idx].tt != TokenType::HeadTailSeparator { Term::Constant(Cell::default(), Constant::EmptyList) } else { - let term = - match self.terms.pop() { - Some(term) => term, - _ => return Err(ParserError::IncompleteReduction(self.lexer.line_num, - self.lexer.col_num)) - }; + let term = match self.terms.pop() { + Some(term) => term, + _ => { + return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )) + } + }; if self.stack[idx].priority > 1000 { arity += self.expand_comma_compacted_terms(idx); @@ -639,15 +632,17 @@ impl<'a, R: Read> Parser<'a, R> { let idx = self.terms.len() - arity; - let list = self.terms.drain(idx ..) - .rev() - .fold(end_term, |acc, t| Term::Cons(Cell::default(), - Box::new(t), - Box::new(acc))); + let list = self.terms.drain(idx..).rev().fold(end_term, |acc, t| { + Term::Cons(Cell::default(), Box::new(t), Box::new(acc)) + }); self.stack.truncate(list_len); - self.stack.push(TokenDesc { tt: TokenType::Term, priority: 0, spec: TERM }); + self.stack.push(TokenDesc { + tt: TokenType::Term, + priority: 0, + spec: TERM, + }); self.terms.push(list); Ok(true) @@ -664,8 +659,7 @@ impl<'a, R: Read> Parser<'a, R> { td.priority = 0; td.spec = TERM; - let term = Term::Constant(Cell::default(), - atom!("{}", self.lexer.atom_tbl)); + let term = Term::Constant(Cell::default(), atom!("{}", self.lexer.atom_tbl)); self.terms.push(term); return Ok(true); } @@ -687,12 +681,20 @@ impl<'a, R: Read> Parser<'a, R> { let term = match self.terms.pop() { Some(term) => term, - _ => return Err(ParserError::IncompleteReduction(self.lexer.line_num, - self.lexer.col_num)) + _ => { + return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )) + } }; - self.terms.push(Term::Clause(Cell::default(), clause_name!("{}"), - vec![Box::new(term)], None)); + self.terms.push(Term::Clause( + Cell::default(), + clause_name!("{}"), + vec![Box::new(term)], + None, + )); return Ok(true); } @@ -716,35 +718,40 @@ impl<'a, R: Read> Parser<'a, R> { let idx = self.stack.len() - 2; - match self.stack.remove(idx) { - td => - match td.tt { - TokenType::Open | TokenType::OpenCT => { - if self.stack[idx].tt == TokenType::Comma { - return false; - } - - if let Some(atom) = sep_to_atom(self.stack[idx].tt) { - self.terms.push(Term::Constant(Cell::default(), Constant::Atom(atom, None))); - } - - self.stack[idx].spec = TERM; - self.stack[idx].tt = TokenType::Term; - self.stack[idx].priority = 0; - true - }, - _ => false + let td = self.stack.remove(idx); + match td.tt { + TokenType::Open | TokenType::OpenCT => { + if self.stack[idx].tt == TokenType::Comma { + return false; } + + if let Some(atom) = sep_to_atom(self.stack[idx].tt) { + self.terms + .push(Term::Constant(Cell::default(), Constant::Atom(atom, None))); + } + + self.stack[idx].spec = TERM; + self.stack[idx].tt = TokenType::Term; + self.stack[idx].priority = 0; + true + } + _ => false, } } - fn shift_op(&mut self, name: ClauseName, op_dir: CompositeOp) -> Result { - if let Some(OpDesc { pre, inf, post, spec }) = get_desc(name.clone(), op_dir) { + fn shift_op(&mut self, name: ClauseName, op_dir: &CompositeOpDir) -> Result { + if let Some(OpDesc { + pre, + inf, + post, + spec, + }) = get_op_desc(name.clone(), op_dir) + { if (pre > 0 && inf + post > 0) || is_negate!(spec) { match self.tokens.last().ok_or(ParserError::UnexpectedEOF)? { // do this when layout hasn't been inserted, // ie. why we don't match on Token::Open. - &Token::OpenCT => { + Token::OpenCT => { // can't be prefix, so either inf == 0 // or post == 0. self.reduce_op(inf + post); @@ -752,9 +759,13 @@ impl<'a, R: Read> Parser<'a, R> { let fixity = if inf > 0 { Fixity::In } else { Fixity::Post }; let op_dir_val = op_dir.get(name.clone(), fixity); - self.promote_atom_op(name, inf + post, spec & (XFX | XFY | YFX | YF | XF), - op_dir_val); - }, + self.promote_atom_op( + name, + inf + post, + spec & (XFX | XFY | YFX | YF | XF), + op_dir_val, + ); + } _ => { self.reduce_op(inf + post); @@ -764,77 +775,89 @@ impl<'a, R: Read> Parser<'a, R> { let fixity = if inf > 0 { Fixity::In } else { Fixity::Post }; let op_dir_val = op_dir.get(name.clone(), fixity); - self.promote_atom_op(name, inf + post, - spec & (XFX | XFY | YFX | XF | YF), - op_dir_val); + self.promote_atom_op( + name, + inf + post, + spec & (XFX | XFY | YFX | XF | YF), + op_dir_val, + ); } else { let op_dir_val = op_dir.get(name.clone(), Fixity::Pre); - self.promote_atom_op(name, pre, spec & (FX | FY | NEGATIVE_SIGN), op_dir_val); + self.promote_atom_op( + name, + pre, + spec & (FX | FY | NEGATIVE_SIGN), + op_dir_val, + ); } } else { let op_dir_val = op_dir.get(name.clone(), Fixity::Pre); - self.promote_atom_op(name, pre, spec & (FX | FY | NEGATIVE_SIGN), op_dir_val); + self.promote_atom_op( + name, + pre, + spec & (FX | FY | NEGATIVE_SIGN), + op_dir_val, + ); } } } } else { - let op_dir_val = op_dir.get(name.clone(), - if pre + inf == 0 { - Fixity::Post - } else if post + pre == 0 { - Fixity::In - } else { - Fixity::Pre - }); + let op_dir_val = op_dir.get( + name.clone(), + if pre + inf == 0 { + Fixity::Post + } else if post + pre == 0 { + Fixity::In + } else { + Fixity::Pre + }, + ); self.reduce_op(pre + inf + post); // only one non-zero priority among these. self.promote_atom_op(name, pre + inf + post, spec, op_dir_val); } Ok(true) - } else { // not an operator. + } else { + // not an operator. Ok(false) } } fn atomize_term(&self, term: &Term) -> Option { match term { - &Term::Constant(_, ref c) => self.atomize_constant(c), - _ => None + Term::Constant(_, ref c) => self.atomize_constant(c), + _ => None, } } fn atomize_constant(&self, c: &Constant) -> Option { match c { - &Constant::Atom(ref name, _) => Some(name.clone()), - &Constant::Char(c) => - Some(clause_name!(c.to_string(), self.lexer.atom_tbl)), - &Constant::EmptyList => - Some(clause_name!(c.to_string(), self.lexer.atom_tbl)), - _ => None + Constant::Atom(ref name, _) => Some(name.clone()), + Constant::Char(c) => Some(clause_name!(c.to_string(), self.lexer.atom_tbl)), + Constant::EmptyList => Some(clause_name!(c.to_string(), self.lexer.atom_tbl)), + _ => None, } } - fn negate_number( - &mut self, - n: N, - negator: Negator, - constr: ToConstant - ) - where Negator: Fn(N) -> N, - ToConstant: Fn(N) -> Constant + fn negate_number(&mut self, n: N, negator: Negator, constr: ToConstant) + where + Negator: Fn(N) -> N, + ToConstant: Fn(N) -> Constant, { if let Some(desc) = self.stack.last().cloned() { if let Some(term) = self.terms.last().cloned() { match term { Term::Constant(_, Constant::Atom(ref name, _)) - if name.as_str() == "-" && (is_prefix!(desc.spec) || is_negate!(desc.spec)) => { - self.stack.pop(); - self.terms.pop(); + if name.as_str() == "-" + && (is_prefix!(desc.spec) || is_negate!(desc.spec)) => + { + self.stack.pop(); + self.terms.pop(); - self.shift(Token::Constant(constr(negator(n))), 0, TERM); - return; - }, + self.shift(Token::Constant(constr(negator(n))), 0, TERM); + return; + } _ => {} } } @@ -843,44 +866,39 @@ impl<'a, R: Read> Parser<'a, R> { self.shift(Token::Constant(constr(n)), 0, TERM); } - fn shift_token(&mut self, token: Token, op_dir: CompositeOp) -> Result<(), ParserError> { + fn shift_token(&mut self, token: Token, op_dir: &CompositeOpDir) -> Result<(), ParserError> { fn negate_rc(mut t: Rc) -> Rc { - match Rc::get_mut(&mut t) { - Some(t) => { - t.neg_assign(); - } - None => { - } + if let Some(t) = Rc::get_mut(&mut t) { + t.neg_assign(); }; t } match token { - Token::Constant(Constant::Fixnum(n)) => - self.negate_number(n, |n| -n, Constant::Fixnum), - Token::Constant(Constant::Integer(n)) => - self.negate_number(n, negate_rc, Constant::Integer), - Token::Constant(Constant::Rational(n)) => - self.negate_number(n, negate_rc, Constant::Rational), - Token::Constant(Constant::Float(n)) => - self.negate_number( - n, - |n| OrderedFloat(-n.into_inner()), - |n| Constant::Float(n) - ), - Token::Constant(c) => + Token::Constant(Constant::Fixnum(n)) => self.negate_number(n, |n| -n, Constant::Fixnum), + Token::Constant(Constant::Integer(n)) => { + self.negate_number(n, negate_rc, Constant::Integer) + } + Token::Constant(Constant::Rational(n)) => { + self.negate_number(n, negate_rc, Constant::Rational) + } + Token::Constant(Constant::Float(n)) => { + self.negate_number(n, |n| OrderedFloat(-n.into_inner()), Constant::Float) + } + Token::Constant(c) => { if let Some(name) = self.atomize_constant(&c) { if !self.shift_op(name, op_dir)? { self.shift(Token::Constant(c), 0, TERM); } } else { self.shift(Token::Constant(c), 0, TERM); - }, + } + } Token::Var(v) => self.shift(Token::Var(v), 0, TERM), - Token::Open => self.shift(Token::Open, 1300, DELIMITER), + Token::Open => self.shift(Token::Open, 1300, DELIMITER), Token::OpenCT => self.shift(Token::OpenCT, 1300, DELIMITER), - Token::Close => + Token::Close => { if !self.reduce_term(op_dir) { if !self.reduce_brackets() { return Err(ParserError::IncompleteReduction( @@ -888,50 +906,55 @@ impl<'a, R: Read> Parser<'a, R> { self.lexer.col_num, )); } - }, - Token::OpenList => self.shift(Token::OpenList, 1300, DELIMITER), - Token::CloseList => + } + } + Token::OpenList => self.shift(Token::OpenList, 1300, DELIMITER), + Token::CloseList => { if !self.reduce_list()? { return Err(ParserError::IncompleteReduction( self.lexer.line_num, self.lexer.col_num, )); - }, + } + } Token::OpenCurly => self.shift(Token::OpenCurly, 1300, DELIMITER), - Token::CloseCurly => + Token::CloseCurly => { if !self.reduce_curly()? { return Err(ParserError::IncompleteReduction( self.lexer.line_num, self.lexer.col_num, )); - }, + } + } Token::HeadTailSeparator => { /* '|' as an operator must have priority > 1000 and can only be infix. * See: http://www.complang.tuwien.ac.at/ulrich/iso-prolog/dtc2#Res_A78 */ - let (priority, spec) = get_desc(clause_name!("|"), op_dir) + let (priority, spec) = get_op_desc(clause_name!("|"), op_dir) .map(|OpDesc { inf, spec, .. }| (inf, spec)) .unwrap_or((1000, DELIMITER)); self.reduce_op(priority); self.shift(Token::HeadTailSeparator, priority, spec); - }, + } Token::Comma => { self.reduce_op(1000); self.shift(Token::Comma, 1000, XFY); - }, - Token::End => - match self.stack.last().map(|t| t.tt) { - Some(TokenType::Open) - | Some(TokenType::OpenCT) - | Some(TokenType::OpenList) - | Some(TokenType::OpenCurly) - | Some(TokenType::HeadTailSeparator) - | Some(TokenType::Comma) - => return Err(ParserError::IncompleteReduction(self.lexer.line_num, - self.lexer.col_num)), - _ => {} + } + Token::End => match self.stack.last().map(|t| t.tt) { + Some(TokenType::Open) + | Some(TokenType::OpenCT) + | Some(TokenType::OpenList) + | Some(TokenType::OpenCurly) + | Some(TokenType::HeadTailSeparator) + | Some(TokenType::Comma) => { + return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )) } + _ => {} + }, } Ok(()) @@ -942,8 +965,18 @@ impl<'a, R: Read> Parser<'a, R> { self.lexer.eof() } - pub fn read_term(&mut self, op_dir: CompositeOp) -> Result - { + #[inline] + pub fn add_lines_read(&mut self, lines_read: usize) { + self.lexer.line_num += lines_read; + } + + #[inline] + pub fn num_lines_read(&self) -> usize { + self.lexer.line_num + } + + // on success, returns the parsed term and the number of lines read. + pub fn read_term(&mut self, op_dir: &CompositeOpDir) -> Result { self.tokens = read_tokens(&mut self.lexer)?; while let Some(token) = self.tokens.pop() { @@ -953,31 +986,27 @@ impl<'a, R: Read> Parser<'a, R> { self.reduce_op(1400); if self.terms.len() > 1 || self.stack.len() > 1 { - return Err(ParserError::IncompleteReduction(self.lexer.line_num, self.lexer.col_num)); + return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )); } match self.terms.pop() { - Some(term) => if self.terms.is_empty() { - Ok(term) - } else { - Err(ParserError::IncompleteReduction(self.lexer.line_num, self.lexer.col_num)) - }, - _ => Err(ParserError::IncompleteReduction(self.lexer.line_num, self.lexer.col_num)) - } - } - - pub fn read(&mut self, op_dir: CompositeOp) -> Result, ParserError> - { - let mut terms = Vec::new(); - - loop { - terms.push(self.read_term(op_dir)?); - - if self.lexer.eof()? { - break; + Some(term) => { + if self.terms.is_empty() { + Ok(term) + } else { + Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )) + } } + _ => Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )), } - - Ok(terms) } } diff --git a/crates/prolog_parser/src/tabled_rc.rs b/crates/prolog_parser/src/tabled_rc.rs index 271ad3bf..47f87d30 100644 --- a/crates/prolog_parser/src/tabled_rc.rs +++ b/crates/prolog_parser/src/tabled_rc.rs @@ -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 { table: Rc>>>, - pub(crate) module_name: Rc + pub(crate) module_name: Rc, } impl fmt::Debug for TabledData { @@ -22,14 +22,15 @@ impl fmt::Debug for TabledData { impl Clone for TabledData { 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 PartialEq for TabledData { - fn eq(&self, other: &TabledData) -> bool - { + fn eq(&self, other: &TabledData) -> bool { Rc::ptr_eq(&self.table, &other.table) && self.module_name == other.module_name } } @@ -39,7 +40,7 @@ impl TabledData { pub fn new(module_name: Rc) -> Self { TabledData { table: Rc::new(RefCell::new(HashSet::new())), - module_name + module_name, } } @@ -51,7 +52,7 @@ impl TabledData { pub struct TabledRc { pub(crate) atom: Rc, - pub table: TabledData + pub table: TabledData, } impl fmt::Debug for TabledRc { @@ -67,27 +68,27 @@ impl fmt::Debug for TabledRc { // from complaining when deriving Clone for StringList. impl Clone for TabledRc { fn clone(&self) -> Self { - TabledRc { atom: self.atom.clone(), table: self.table.clone() } + TabledRc { + atom: self.atom.clone(), + table: self.table.clone(), + } } } impl PartialOrd for TabledRc { - fn partial_cmp(&self, other: &Self) -> Option - { + fn partial_cmp(&self, other: &Self) -> Option { Some(self.atom.cmp(&other.atom)) } } impl Ord for TabledRc { - fn cmp(&self, other: &Self) -> Ordering - { + fn cmp(&self, other: &Self) -> Ordering { self.atom.cmp(&other.atom) } } impl PartialEq for TabledRc { - fn eq(&self, other: &TabledRc) -> bool - { + fn eq(&self, other: &TabledRc) -> bool { self.atom == other.atom } } @@ -103,8 +104,8 @@ impl Hash for TabledRc { impl TabledRc { pub fn new(atom: T, table: TabledData) -> 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 fmt::Display for TabledRc { #[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()) + }; } diff --git a/crates/prolog_parser/tests/bom.rs b/crates/prolog_parser/tests/bom.rs index 3be7278a..8a92c127 100644 --- a/crates/prolog_parser/tests/bom.rs +++ b/crates/prolog_parser/tests/bom.rs @@ -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), } } - diff --git a/crates/prolog_parser/tests/parse_tokens.rs b/crates/prolog_parser/tests/parse_tokens.rs index 768445fd..69b63286 100644 --- a/crates/prolog_parser/tests/parse_tokens.rs +++ b/crates/prolog_parser/tests/parse_tokens.rs @@ -1,5 +1,3 @@ -extern crate prolog_parser; - use prolog_parser::ast::*; use prolog_parser::lexer::{Lexer, Token}; use prolog_parser::tabled_rc::TabledData; diff --git a/src/allocator.rs b/src/allocator.rs index 9034efc5..cc8de305 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -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(&mut self, _: Level, _: GenContext, _: &mut Vec) where Target: CompilationTarget<'a>; - fn mark_non_var(&mut self, _: Level, _: GenContext, _: &'a Cell, _: &mut Vec) - where + fn mark_non_var( + &mut self, + _: Level, + _: GenContext, + _: &'a Cell, + _: &mut Vec, + ) where Target: CompilationTarget<'a>; fn mark_reserved_var( &mut self, @@ -28,8 +34,14 @@ pub trait Allocator<'a> { _: bool, ) where Target: CompilationTarget<'a>; - fn mark_var(&mut self, _: Rc, _: Level, _: &'a Cell, _: GenContext, _: &mut Vec) - where + fn mark_var( + &mut self, + _: Rc, + _: Level, + _: &'a Cell, + _: GenContext, + _: &mut Vec, + ) 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(); diff --git a/src/arithmetic.rs b/src/arithmetic.rs index c4cefafe..87e72d45 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -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>, } -pub type ArithCont = (Code, Option); +pub(crate) type ArithCont = (Code, Option); 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, Rc), @@ -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, interm_c: usize, } -pub trait ArithmeticTermIter<'a> { +pub(crate) trait ArithmeticTermIter<'a> { type Iter: Iterator, ArithmeticError>>; fn iter(self) -> Result; @@ -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(&mut self, src: Iter) -> Result + pub(crate) fn eval(&mut self, src: Iter) -> Result 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(n: &Number, round: Round) -> Result +pub(crate) fn result_f(n: &Number, round: Round) -> Result where Round: Fn(&Number) -> f64, { @@ -432,31 +431,31 @@ impl Add 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 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 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 { 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 { 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 { diff --git a/src/bin/scryer-prolog.rs b/src/bin/scryer-prolog.rs new file mode 100644 index 00000000..4260bdd5 --- /dev/null +++ b/src/bin/scryer-prolog.rs @@ -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); + } +} diff --git a/src/clause_types.rs b/src/clause_types.rs index dbaefb69..4d7e35d6 100644 --- a/src/clause_types.rs +++ b/src/clause_types.rs @@ -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 { + pub(crate) fn from(name: &str, arity: usize) -> Option { 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 { + pub(crate) fn spec(&self) -> Option { 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) -> Self { + pub(crate) fn from(name: ClauseName, arity: usize, spec: Option) -> 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()) diff --git a/src/codegen.rs b/src/codegen.rs index d260cfa0..a678549b 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -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 { - marker: TermMarker, - pub var_count: IndexMap, 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 { - 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, + 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 { + atom_tbl: TabledData, + marker: TermMarker, + pub(crate) var_count: IndexMap, usize>, + settings: CodeGenSettings, + pub(crate) skeleton: PredicateSkeleton, + pub(crate) jmp_by_locs: Vec, + global_jmp_by_locs_offset: usize, +} + +impl<'a, TermMarker: Allocator<'a>> CodeGenerator { + pub(crate) fn new(atom_tbl: TabledData, 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>>(&mut self, iter: Iter) { @@ -131,7 +227,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { 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 { 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 { 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 { target: &mut Vec, ) { 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 { 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 { }; } - fn compile_target( + fn compile_target( &mut self, iter: Iter, term_loc: GenContext, @@ -292,13 +387,14 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { } } - 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 { 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 { 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 { 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 { terms: &'a Vec>, 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 { 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 { 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 { } }, &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 { } }, &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 { 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 { &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 { } } - 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 { 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 { } } - 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 { 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 { + pub(crate) fn compile_rule<'b: 'a>( + &mut self, + rule: &'b Rule, + ) -> Result { let iter = ChunkedIterator::from_rule(rule); let conjunct_info = self.collect_var_data(iter); @@ -739,7 +849,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { 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 { 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 { 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 { } } - 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) -> Result { - 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 { 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 { - let mut code_body = Vec::new(); - let mut code_offsets = CodeOffsets::new(); + ) -> Result { + 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 { }, 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, - ) -> Result { - let mut code = Vec::new(); + ) -> Result { + 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::(&clauses[l..r], optimal_index)? + } else { + self.compile_pred_subseq::(&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) diff --git a/src/debray_allocator.rs b/src/debray_allocator.rs index 9e129828..7525a79a 100644 --- a/src/debray_allocator.rs +++ b/src/debray_allocator.rs @@ -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, 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); diff --git a/src/examples/bimetatrans/bimetatrans_tests.pl b/src/examples/bimetatrans/bimetatrans_tests.pl index 8675dcde..eab6f294 100644 --- a/src/examples/bimetatrans/bimetatrans_tests.pl +++ b/src/examples/bimetatrans/bimetatrans_tests.pl @@ -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)). diff --git a/src/fixtures.rs b/src/fixtures.rs index 907c9227..0ecdd9e8 100644 --- a/src/fixtures.rs +++ b/src/fixtures.rs @@ -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, - pub conflict_set: BTreeSet, +pub(crate) struct TempVarData { + pub(crate) last_term_arity: usize, + pub(crate) use_set: OccurrenceSet, + pub(crate) no_use_set: BTreeSet, + pub(crate) conflict_set: BTreeSet, } 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 = (1..arity).collect(); @@ -83,30 +83,29 @@ impl TempVarData { type VariableFixture<'a> = (VarStatus, Vec<&'a Cell>); #[derive(Debug)] -pub struct VariableFixtures<'a>{ +pub(crate) struct VariableFixtures<'a> { perm_vars: IndexMap, VariableFixture<'a>>, - last_chunk_temp_vars: IndexSet> + last_chunk_temp_vars: IndexSet>, } 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, vs: VariableFixture<'a>) { + pub(crate) fn insert(&mut self, var: Rc, vs: VariableFixture<'a>) { self.perm_vars.insert(var, vs); } - pub fn insert_last_chunk_temp_var(&mut self, var: Rc) { + pub(crate) fn insert_last_chunk_temp_var(&mut self, var: Rc) { 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(&mut self, iter: I, lt_arity: usize, term_loc: GenContext) + pub(crate) fn mark_vars_in_chunk(&mut self, iter: I, lt_arity: usize, term_loc: GenContext) where I: Iterator>, { @@ -219,7 +218,7 @@ impl<'a> VariableFixtures<'a> { } } - pub fn into_iter(self) -> indexmap::map::IntoIter, VariableFixture<'a>> { + pub(crate) fn into_iter(self) -> indexmap::map::IntoIter, 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, - pub safe_vars: IndexSet, +pub(crate) struct UnsafeVarMarker { + pub(crate) unsafe_vars: IndexMap, + pub(crate) safe_vars: IndexSet, } 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) -> Self { + pub(crate) fn from_safe_vars(safe_vars: IndexSet) -> 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)) { diff --git a/src/forms.rs b/src/forms.rs index b99897a1..3d07ec8a 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -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; // vars of predicate, toplevel offset. Vec is always a vector // of vars (we get their adjoining cells this way). -pub type JumpStub = Vec; +pub(crate) type JumpStub = Vec; #[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), - 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, ClauseType, Vec>, 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>, QueryTerm), - pub clauses: Vec, +pub(crate) struct Rule { + pub(crate) head: (ClauseName, Vec>, QueryTerm), + pub(crate) clauses: Vec, } -#[derive(Debug, Clone)] -pub struct Predicate(pub Vec); - -impl Predicate { - #[inline] - pub fn new() -> Self { - Predicate(vec![]) - } - - #[inline] - pub fn clauses(self) -> Vec { - 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) -> 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; 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 { + Some(self.0.clone()) + } + + #[inline] + fn arity(&self) -> usize { + self.1 + } +} + +impl ClauseInfo for Term { + fn name(&self) -> Option { 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 { + 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 { 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); +// pub(crate) type CompiledResult = (Predicate, VecDeque); #[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]> { + pub(crate) fn args(&self) -> Option<&[Box]> { 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 { - 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), - ModuleInitialization(Vec, VecDeque), // goal +pub(crate) enum Declaration { + Dynamic(ClauseName, usize), + MetaPredicate(ClauseName, ClauseName, Vec), // module name, name, meta-specs Module(ModuleDecl), - MultiFile(MultiFileIndicator), NonCountedBacktracking(ClauseName, usize), // name, arity Op(OpDecl), - SetPrologFlag(DoubleQuotes), UseModule(ModuleSource), - UseQualifiedModule(ModuleSource, Vec), + UseQualifiedModule(ModuleSource, IndexSet), } -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, 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, 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, @@ -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; +pub(crate) type ModuleDir = IndexMap; -#[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, +pub(crate) struct ModuleDecl { + pub(crate) name: ClauseName, + pub(crate) exports: Vec, } #[derive(Debug)] -pub struct Module { - pub atom_tbl: TabledData, - 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), - pub goal_expansions: (Predicate, VecDeque), - pub user_term_expansions: (Predicate, VecDeque), // term expansions inherited from the user scope. - pub user_goal_expansions: (Predicate, VecDeque), // same for goal_expansions. - pub local_term_expansions: (Predicate, VecDeque), // expansions local to the module. - pub local_goal_expansions: (Predicate, VecDeque), - 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), Integer(Rc), Rational(Rc), @@ -668,10 +514,9 @@ impl Into 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), // 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 { + 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 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, + pub(crate) clause_clause_locs: SliceDeque, + 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 { + 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(), + } + } +} diff --git a/src/heap_iter.rs b/src/heap_iter.rs index a541d12f..fd057ac3 100644 --- a/src/heap_iter.rs +++ b/src/heap_iter.rs @@ -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, +pub(crate) struct HCPreOrderIterator<'a> { + pub(crate) machine_st: &'a MachineState, + pub(crate) state_stack: Vec, } 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, } 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 { @@ -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 { @@ -334,9 +333,7 @@ impl<'a> Iterator for HCZippedAcyclicIterator<'a> self.first_to_expire = Ordering::Less; None } - _ => { - None - } + _ => None, } } } diff --git a/src/heap_print.rs b/src/heap_print.rs index 2a51fa91..950b3ecd 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -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) -> 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 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 { + pub(crate) fn numbervar(&self, offset: &Integer, addr: Addr) -> Option { 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>; #[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>(mut iter: Iter, c: char) -> bool { if c == '/' { return match iter.next() { @@ -444,8 +421,7 @@ fn non_quoted_graphic_token>(mut iter: Iter, c: char } } -pub(super) -fn non_quoted_token>(mut iter: Iter) -> bool { +pub(super) fn non_quoted_token>(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 { } 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 { + fn check_for_seen(&mut self, iter: &mut HCPreOrderIterator) -> Option { 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> = - if self.max_depth == 0 { - Box::new(buf.chars()) - } else { - Box::new(buf.chars().take(max_depth)) - }; + let buf_iter: Box> = 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 { diff --git a/src/indexing.rs b/src/indexing.rs index bf5403bf..0f368356 100644 --- a/src/indexing.rs +++ b/src/indexing.rs @@ -1,195 +1,1218 @@ -use crate::prolog_parser::ast::*; -use crate::prolog_parser::tabled_rc::*; +use prolog_parser::ast::*; +use prolog_parser::clause_name; +use prolog_parser::tabled_rc::*; +use crate::forms::*; use crate::instructions::*; + use crate::rug::Integer; +use indexmap::IndexMap; -use crate::indexmap::IndexMap; +use slice_deque::{sdeq, SliceDeque}; -use std::collections::VecDeque; use std::convert::TryFrom; use std::hash::Hash; +use std::iter::once; +use std::mem; use std::rc::Rc; #[derive(Debug, Clone, Copy)] -enum IntIndex { - External(usize), +pub(crate) enum IndexingCodePtr { + External(usize), // the index points past the indexing instruction prelude. + DynamicExternal(usize), // an External index of a dynamic predicate, potentially invalidated by retraction. Fail, - Internal(usize), + Internal(usize), // the index points into the indexing instruction prelude. +} + +#[derive(Debug, Clone, Copy)] +enum OptArgIndexKeyType { + Structure, + Constant, + // List, +} + +impl OptArgIndexKey { + #[inline] + fn has_key_type(&self, key_type: OptArgIndexKeyType) -> bool { + match (self, key_type) { + (OptArgIndexKey::Constant(..), OptArgIndexKeyType::Constant) + | (OptArgIndexKey::Structure(..), OptArgIndexKeyType::Structure) + // | (OptArgIndexKey::List(..), OptArgIndexKeyType::List) + => true, + _ => false, + } + } +} + +#[inline] +fn search_skeleton_for_first_key_type( + skeleton: &[ClauseIndexInfo], + key_type: OptArgIndexKeyType, + append_or_prepend: AppendOrPrepend, +) -> Option<&OptArgIndexKey> { + if append_or_prepend.is_append() { + for clause_index_info in skeleton.iter().rev() { + if clause_index_info.opt_arg_index_key.has_key_type(key_type) { + return Some(&clause_index_info.opt_arg_index_key); + } + } + } else { + for clause_index_info in skeleton.iter() { + if clause_index_info.opt_arg_index_key.has_key_type(key_type) { + return Some(&clause_index_info.opt_arg_index_key); + } + } + } + + None +} + +struct IndexingCodeMergingPtr<'a> { + skeleton: &'a mut [ClauseIndexInfo], + indexing_code: &'a mut Vec, + offset: usize, + append_or_prepend: AppendOrPrepend, + is_dynamic: bool, +} + +impl<'a> IndexingCodeMergingPtr<'a> { + #[inline] + fn new( + skeleton: &'a mut [ClauseIndexInfo], + indexing_code: &'a mut Vec, + append_or_prepend: AppendOrPrepend, + ) -> Self { + let is_dynamic = match &indexing_code[0] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => { + match v { + IndexingCodePtr::External(_) => false, + IndexingCodePtr::DynamicExternal(_) => true, + _ => unreachable!() + } + } + _ => unreachable!() + }; + + Self { + skeleton, + indexing_code, + offset: 0, + append_or_prepend, + is_dynamic, + } + } + + fn internalize_constant(&mut self, constant_ptr: IndexingCodePtr) { + let constant_key = search_skeleton_for_first_key_type( + self.skeleton, + OptArgIndexKeyType::Constant, + self.append_or_prepend, + ); + + let mut constants = IndexMap::new(); + + match constant_key { + Some(OptArgIndexKey::Constant(_, _, ref constant, _)) => { + constants.insert(constant.clone(), constant_ptr); + } + _ => { + unreachable!() + } + } + + if let IndexingCodePtr::Internal(_) = constant_ptr { + let last_index = self.indexing_code.len(); + + self.indexing_code.push(IndexingLine::Indexing( + IndexingInstruction::SwitchOnConstant(constants), + )); + + self.indexing_code.swap(self.offset, last_index); + } else { + self.offset = self.indexing_code.len(); + + self.indexing_code.push(IndexingLine::Indexing( + IndexingInstruction::SwitchOnConstant(constants), + )); + } + } + + fn add_static_indexed_choice_for_constant( + &mut self, + external: usize, + constant: Constant, + index: usize, + ) { + let third_level_index = if self.append_or_prepend.is_append() { + sdeq![ + IndexedChoiceInstruction::Try(external), + IndexedChoiceInstruction::Trust(index) + ] + } else { + sdeq![ + IndexedChoiceInstruction::Try(index), + IndexedChoiceInstruction::Trust(external) + ] + }; + + let indexing_code_len = self.indexing_code.len(); + self.indexing_code.push(IndexingLine::IndexedChoice(third_level_index)); + + match &mut self.indexing_code[self.offset] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref mut constants)) => { + constants.insert( + constant, + IndexingCodePtr::Internal(indexing_code_len - self.offset), + ); + } + _ => { + unreachable!() + } + } + } + + fn add_dynamic_indexed_choice_for_constant( + &mut self, + external: usize, + constant: Constant, + index: usize, + ) { + let third_level_index = if self.append_or_prepend.is_append() { + sdeq![external, index] + } else { + sdeq![index, external] + }; + + let indexing_code_len = self.indexing_code.len(); + self.indexing_code.push(IndexingLine::DynamicIndexedChoice(third_level_index)); + + match &mut self.indexing_code[self.offset] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref mut constants)) => { + constants.insert( + constant, + IndexingCodePtr::Internal(indexing_code_len - self.offset), + ); + } + _ => { + unreachable!() + } + } + } + + fn extend_indexed_choice(&mut self, index: usize) { + match &mut self.indexing_code[self.offset] { + IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) + if self.append_or_prepend.is_append() => + { + uncap_choice_seq_with_trust(indexed_choice_instrs); + indexed_choice_instrs.push_back(IndexedChoiceInstruction::Trust(index)); + } + IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => { + uncap_choice_seq_with_try(indexed_choice_instrs); + indexed_choice_instrs.push_front(IndexedChoiceInstruction::Try(index)); + } + IndexingLine::DynamicIndexedChoice(ref mut indexed_choice_instrs) + if self.append_or_prepend.is_append() => + { + indexed_choice_instrs.push_back(index); + } + IndexingLine::DynamicIndexedChoice(ref mut indexed_choice_instrs) => { + indexed_choice_instrs.push_front(index); + } + _ => { + unreachable!() + } + } + } + + fn index_overlapping_constant( + &mut self, + orig_constant: &Constant, + overlapping_constant: Constant, + index: usize, + ) { + loop { + let indexing_code_len = self.indexing_code.len(); + + match &mut self.indexing_code[self.offset] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..)) => { + match *c { + IndexingCodePtr::Fail if self.is_dynamic => { + *c = IndexingCodePtr::DynamicExternal(index); + break; + } + IndexingCodePtr::Fail => { + *c = IndexingCodePtr::External(index); + break; + } + IndexingCodePtr::DynamicExternal(_) | IndexingCodePtr::External(_) => { + let mut constants = IndexMap::new(); + constants.insert(orig_constant.clone(), *c); + + *c = IndexingCodePtr::Internal(indexing_code_len); + + self.indexing_code.push(IndexingLine::Indexing( + IndexingInstruction::SwitchOnConstant(constants), + )); + + self.offset = indexing_code_len; + } + IndexingCodePtr::Internal(o) => { + self.offset += o; + } + } + } + IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(constants)) => { + match constants.get(&overlapping_constant).cloned() { + None | Some(IndexingCodePtr::Fail) if self.is_dynamic => { + constants.insert( + overlapping_constant, + IndexingCodePtr::DynamicExternal(index), + ); + } + None | Some(IndexingCodePtr::Fail) => { + constants.insert( + overlapping_constant, + IndexingCodePtr::External(index), + ); + } + Some(IndexingCodePtr::DynamicExternal(o)) => { + self.add_dynamic_indexed_choice_for_constant(o, overlapping_constant, index); + } + Some(IndexingCodePtr::External(o)) => { + self.add_static_indexed_choice_for_constant(o, overlapping_constant, index); + } + Some(IndexingCodePtr::Internal(o)) => { + self.offset += o; + self.extend_indexed_choice(index); + } + } + + break; + } + IndexingLine::IndexedChoice(_) | IndexingLine::DynamicIndexedChoice(_) => { + self.internalize_constant(IndexingCodePtr::Internal( + indexing_code_len - self.offset, + )); + } + _ => { + unreachable!() + } + } + } + } + + fn index_constant(&mut self, constant: Constant, index: usize) { + loop { + let indexing_code_len = self.indexing_code.len(); + + match &mut self.indexing_code[self.offset] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..)) => { + match *c { + IndexingCodePtr::Fail if self.is_dynamic => { + *c = IndexingCodePtr::DynamicExternal(index); + break; + } + IndexingCodePtr::Fail => { + *c = IndexingCodePtr::External(index); + break; + } + IndexingCodePtr::External(o) => { + *c = IndexingCodePtr::Internal(indexing_code_len - self.offset); + self.internalize_constant(IndexingCodePtr::External(o)); + } + IndexingCodePtr::DynamicExternal(o) => { + *c = IndexingCodePtr::Internal(indexing_code_len - self.offset); + self.internalize_constant(IndexingCodePtr::DynamicExternal(o)); + } + IndexingCodePtr::Internal(o) => { + self.offset += o; + } + } + } + IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(constants)) => { + match constants.get(&constant).cloned() { + None | Some(IndexingCodePtr::Fail) if self.is_dynamic => { + constants.insert(constant, IndexingCodePtr::DynamicExternal(index)); + } + None | Some(IndexingCodePtr::Fail) => { + constants.insert(constant, IndexingCodePtr::External(index)); + } + Some(IndexingCodePtr::DynamicExternal(o)) => { + self.add_dynamic_indexed_choice_for_constant(o, constant, index); + } + Some(IndexingCodePtr::External(o)) => { + self.add_static_indexed_choice_for_constant(o, constant, index); + } + Some(IndexingCodePtr::Internal(o)) => { + self.offset += o; + self.extend_indexed_choice(index); + } + } + + break; + } + IndexingLine::IndexedChoice(_) | IndexingLine::DynamicIndexedChoice(_) => { + self.internalize_constant(IndexingCodePtr::Internal( + indexing_code_len - self.offset, + )); + } + _ => { + unreachable!() + } + } + } + } + + fn internalize_structure(&mut self, structure_ptr: IndexingCodePtr) { + let structure_key = search_skeleton_for_first_key_type( + self.skeleton, + OptArgIndexKeyType::Structure, + self.append_or_prepend, + ); + + let mut structures = IndexMap::new(); + + match structure_key { + Some(OptArgIndexKey::Structure(_, _, ref name, ref arity)) => { + structures.insert((name.clone(), *arity), structure_ptr); + } + _ => { + unreachable!() + } + } + + if let IndexingCodePtr::Internal(_) = structure_ptr { + let last_index = self.indexing_code.len(); + + self.indexing_code.push(IndexingLine::Indexing( + IndexingInstruction::SwitchOnStructure(structures), + )); + + self.indexing_code.swap(self.offset, last_index); + } else { + self.offset = self.indexing_code.len(); + + self.indexing_code.push(IndexingLine::Indexing( + IndexingInstruction::SwitchOnStructure(structures), + )); + } + } + + fn add_static_indexed_choice_for_structure( + &mut self, + external: usize, + key: PredicateKey, + index: usize, + ) { + let third_level_index = if self.append_or_prepend.is_append() { + sdeq![ + IndexedChoiceInstruction::Try(external), + IndexedChoiceInstruction::Trust(index) + ] + } else { + sdeq![ + IndexedChoiceInstruction::Try(index), + IndexedChoiceInstruction::Trust(external) + ] + }; + + let indexing_code_len = self.indexing_code.len(); + self.indexing_code + .push(IndexingLine::IndexedChoice(third_level_index)); + + match &mut self.indexing_code[self.offset] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref mut structures)) => { + structures.insert( + key, + IndexingCodePtr::Internal(indexing_code_len - self.offset), + ); + } + _ => { + unreachable!() + } + } + } + + fn add_dynamic_indexed_choice_for_structure( + &mut self, + external: usize, + key: PredicateKey, + index: usize, + ) { + let third_level_index = if self.append_or_prepend.is_append() { + sdeq![external, index] + } else { + sdeq![index, external] + }; + + let indexing_code_len = self.indexing_code.len(); + self.indexing_code.push(IndexingLine::DynamicIndexedChoice(third_level_index)); + + match &mut self.indexing_code[self.offset] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref mut structures)) => { + structures.insert( + key, + IndexingCodePtr::Internal(indexing_code_len - self.offset), + ); + } + _ => { + unreachable!() + } + } + } + + fn index_structure(&mut self, key: PredicateKey, index: usize) { + loop { + let indexing_code_len = self.indexing_code.len(); + + match &mut self.indexing_code[self.offset] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm( + _, + _, + _, + _, + ref mut s, + )) => match *s { + IndexingCodePtr::Fail if self.is_dynamic => { + *s = IndexingCodePtr::DynamicExternal(index); + break; + } + IndexingCodePtr::Fail => { + *s = IndexingCodePtr::External(index); + break; + } + IndexingCodePtr::DynamicExternal(o) => { + *s = IndexingCodePtr::Internal(indexing_code_len - self.offset); + self.internalize_structure(IndexingCodePtr::DynamicExternal(o)); + } + IndexingCodePtr::External(o) => { + *s = IndexingCodePtr::Internal(indexing_code_len - self.offset); + self.internalize_structure(IndexingCodePtr::External(o)); + } + IndexingCodePtr::Internal(o) => { + self.offset += o; + } + }, + IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(structures)) => { + match structures.get(&key).cloned() { + None | Some(IndexingCodePtr::Fail) if self.is_dynamic => { + structures.insert(key, IndexingCodePtr::DynamicExternal(index)); + } + None | Some(IndexingCodePtr::Fail) => { + structures.insert(key, IndexingCodePtr::External(index)); + } + Some(IndexingCodePtr::DynamicExternal(o)) => { + self.add_dynamic_indexed_choice_for_structure(o, key, index); + } + Some(IndexingCodePtr::External(o)) => { + self.add_static_indexed_choice_for_structure(o, key, index); + } + Some(IndexingCodePtr::Internal(o)) => { + self.offset += o; + self.extend_indexed_choice(index); + } + } + + break; + } + IndexingLine::IndexedChoice(_) | IndexingLine::DynamicIndexedChoice(_) => { + // replace this value, at self.offset, with + // SwitchOnStructures, and swap this IndexedChoice + // vector to the end of self.indexing_code. + self.internalize_structure(IndexingCodePtr::Internal( + indexing_code_len - self.offset, + )); + } + _ => { + unreachable!() + } + } + } + } + + fn index_list(&mut self, index: usize) { + let indexing_code_len = self.indexing_code.len(); + + match &mut self.indexing_code[self.offset] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, _, _, ref mut l, _)) => { + match *l { + IndexingCodePtr::Fail if self.is_dynamic => { + *l = IndexingCodePtr::DynamicExternal(index); + } + IndexingCodePtr::Fail => { + *l = IndexingCodePtr::External(index); + } + IndexingCodePtr::DynamicExternal(o) => { + *l = IndexingCodePtr::Internal(indexing_code_len - self.offset); + + let third_level_index = if self.append_or_prepend.is_append() { + sdeq![o, index] + } else { + sdeq![index, o] + }; + + self.indexing_code + .push(IndexingLine::DynamicIndexedChoice(third_level_index)); + } + IndexingCodePtr::External(o) => { + *l = IndexingCodePtr::Internal(indexing_code_len - self.offset); + + let third_level_index = if self.append_or_prepend.is_append() { + sdeq![ + IndexedChoiceInstruction::Try(o), + IndexedChoiceInstruction::Trust(index) + ] + } else { + sdeq![ + IndexedChoiceInstruction::Try(index), + IndexedChoiceInstruction::Trust(o) + ] + }; + + self.indexing_code + .push(IndexingLine::IndexedChoice(third_level_index)); + } + IndexingCodePtr::Internal(o) => { + self.offset += o; + self.extend_indexed_choice(index); + } + } + } + _ => { + unreachable!() + } + } + } +} + +pub(crate) fn merge_clause_index( + target_indexing_code: &mut Vec, + skeleton: &mut [ClauseIndexInfo], // the clause to be merged is the last element in the skeleton. + new_clause_loc: usize, // the absolute location of the new clause in the code vector. + append_or_prepend: AppendOrPrepend, +) { + let opt_arg_index_key = match append_or_prepend { + AppendOrPrepend::Append => skeleton.last_mut().unwrap().opt_arg_index_key.take(), + AppendOrPrepend::Prepend => skeleton.first_mut().unwrap().opt_arg_index_key.take(), + }; + + let mut merging_ptr = IndexingCodeMergingPtr::new( + skeleton, + target_indexing_code, + append_or_prepend, + ); + + match &opt_arg_index_key { + OptArgIndexKey::Constant(_, index_loc, ref constant, ref overlapping_constants) => { + let offset = new_clause_loc - index_loc + 1; + merging_ptr.index_constant(constant.clone(), offset); + + for overlapping_constant in overlapping_constants { + merging_ptr.offset = 0; + + merging_ptr.index_overlapping_constant( + constant, + overlapping_constant.clone(), + offset, + ); + } + } + OptArgIndexKey::Structure(_, index_loc, ref name, ref arity) => { + merging_ptr.index_structure((name.clone(), *arity), new_clause_loc - index_loc + 1); + } + OptArgIndexKey::List(_, index_loc) => { + merging_ptr.index_list(new_clause_loc - index_loc + 1); + } + OptArgIndexKey::None => { + unreachable!() + } + } + + match append_or_prepend { + AppendOrPrepend::Append => { + skeleton.last_mut().unwrap().opt_arg_index_key = opt_arg_index_key; + } + AppendOrPrepend::Prepend => { + skeleton.first_mut().unwrap().opt_arg_index_key = opt_arg_index_key; + } + } +} + +pub(crate) fn remove_constant_indices( + constant: &Constant, + overlapping_constants: &[Constant], + indexing_code: &mut Vec, + offset: usize, +) { + let mut index = 0; + let iter = once(constant).chain(overlapping_constants.iter()); + + match &mut indexing_code[index] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..)) => { + match *c { + IndexingCodePtr::DynamicExternal(_) | IndexingCodePtr::External(_) => { + *c = IndexingCodePtr::Fail; + return; + } + IndexingCodePtr::Internal(o) => { + index += o; + } + IndexingCodePtr::Fail => { + return; + } + } + } + _ => { + unreachable!() + } + } + + let mut constants_index = 0; + + for constant in iter { + loop { + match &mut indexing_code[index] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant( + ref mut constants, + )) => { + constants_index = index; + + match constants.get(constant).cloned() { + Some(IndexingCodePtr::DynamicExternal(_)) | + Some(IndexingCodePtr::External(_)) | + Some(IndexingCodePtr::Fail) => { + constants.remove(constant); + break; + } + Some(IndexingCodePtr::Internal(o)) => { + index += o; + } + None => { + break; + } + } + } + IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => { + StaticCodeIndices::remove_instruction_with_offset(indexed_choice_instrs, offset); + + if indexed_choice_instrs.len() == 1 { + if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() { + let ext = IndexingCodePtr::External( + indexed_choice_instr.offset() + ); + + match &mut indexing_code[constants_index] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm( + _, + _, + ref mut c, + .., + )) => { + *c = ext; + } + IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant( + ref mut constants, + )) => { + constants.insert(constant.clone(), ext); + } + _ => { + unreachable!() + } + } + } + } + + break; + } + IndexingLine::DynamicIndexedChoice(ref mut indexed_choice_instrs) => { + DynamicCodeIndices::remove_instruction_with_offset(indexed_choice_instrs, offset); + + if indexed_choice_instrs.len() == 1 { + if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() { + let ext = IndexingCodePtr::DynamicExternal(indexed_choice_instr); + + match &mut indexing_code[constants_index] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm( + _, + _, + ref mut c, + .., + )) => { + *c = ext; + } + IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant( + ref mut constants, + )) => { + constants.insert(constant.clone(), ext); + } + _ => { + unreachable!() + } + } + } + } + + break; + } + _ => { + unreachable!() + } + } + } + } + + match &indexing_code[constants_index] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref constants)) + if constants.is_empty() => + { + match &mut indexing_code[0] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..)) => { + *c = IndexingCodePtr::Fail; + } + _ => { + unreachable!() + } + } + } + _ => {} + } +} + +pub(crate) fn remove_structure_index( + name: &ClauseName, + arity: usize, + indexing_code: &mut Vec, + offset: usize, +) { + let mut index = 0; + + match &mut indexing_code[index] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, _, _, _, ref mut s)) => { + match *s { + IndexingCodePtr::DynamicExternal(_) | IndexingCodePtr::External(_) => { + *s = IndexingCodePtr::Fail; + return; + } + IndexingCodePtr::Internal(o) => { + index += o; + } + IndexingCodePtr::Fail => { + return; + } + } + } + _ => { + unreachable!() + } + } + + let mut structures_index = 0; + + loop { + match &mut indexing_code[index] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref mut structures)) => { + structures_index = index; + + match structures.get(&(name.clone(), arity)).cloned() { + Some(IndexingCodePtr::DynamicExternal(_)) | Some(IndexingCodePtr::External(_)) => { + structures.remove(&(name.clone(), arity)); + break; + } + Some(IndexingCodePtr::Internal(o)) => { + index += o; + } + Some(IndexingCodePtr::Fail) | None => { + return; + } + } + } + IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => { + StaticCodeIndices::remove_instruction_with_offset(indexed_choice_instrs, offset); + + if indexed_choice_instrs.len() == 1 { + if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() { + let ext = IndexingCodePtr::External(indexed_choice_instr.offset()); + + match &mut indexing_code[structures_index] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm( + _, + _, + _, + _, + ref mut s, + )) => { + *s = ext; + } + IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure( + ref mut structures, + )) => { + structures.insert((name.clone(), arity), ext); + } + _ => { + unreachable!() + } + } + } + } + + break; + } + IndexingLine::DynamicIndexedChoice(ref mut indexed_choice_instrs) => { + DynamicCodeIndices::remove_instruction_with_offset(indexed_choice_instrs, offset); + + if indexed_choice_instrs.len() == 1 { + if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() { + let ext = IndexingCodePtr::DynamicExternal(indexed_choice_instr); + + match &mut indexing_code[structures_index] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm( + _, + _, + _, + _, + ref mut s, + )) => { + *s = ext; + } + IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure( + ref mut structures, + )) => { + structures.insert((name.clone(), arity), ext); + } + _ => { + unreachable!() + } + } + } + } + + break; + } + _ => { + unreachable!() + } + } + } + + match &indexing_code[structures_index] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref structures)) + if structures.is_empty() => + { + match &mut indexing_code[0] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm( + _, + _, + _, + _, + ref mut s, + )) => { + *s = IndexingCodePtr::Fail; + } + _ => { + unreachable!() + } + } + } + _ => {} + } +} + +pub(crate) fn remove_list_index(indexing_code: &mut Vec, offset: usize) { + let mut index = 0; + + match &mut indexing_code[index] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, _, _, ref mut l, _)) => { + match *l { + IndexingCodePtr::DynamicExternal(_) | IndexingCodePtr::External(_) => { + *l = IndexingCodePtr::Fail; + return; + } + IndexingCodePtr::Internal(o) => { + index += o; + } + IndexingCodePtr::Fail => { + return; + } + } + } + _ => { + unreachable!() + } + } + + match &mut indexing_code[index] { + IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => { + StaticCodeIndices::remove_instruction_with_offset(indexed_choice_instrs, offset); + + if indexed_choice_instrs.len() == 1 { + if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() { + let ext = IndexingCodePtr::External(indexed_choice_instr.offset()); + + match &mut indexing_code[0] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm( + _, + _, + _, + ref mut l, + _, + )) => { + *l = ext; + } + _ => { + unreachable!() + } + } + } + } + } + IndexingLine::DynamicIndexedChoice(ref mut indexed_choice_instrs) => { + DynamicCodeIndices::remove_instruction_with_offset(indexed_choice_instrs, offset); + + if indexed_choice_instrs.len() == 1 { + if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() { + let ext = IndexingCodePtr::DynamicExternal(indexed_choice_instr); + + match &mut indexing_code[0] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm( + _, + _, + _, + ref mut l, + _, + )) => { + *l = ext; + } + _ => { + unreachable!() + } + } + } + } + } + _ => { + unreachable!() + } + } +} + +pub(crate) fn remove_index( + opt_arg_index_key: &OptArgIndexKey, + indexing_code: &mut Vec, + clause_loc: usize, +) { + match opt_arg_index_key { + OptArgIndexKey::Constant(_, _, ref constant, ref overlapping_constants) => { + remove_constant_indices( + constant, + overlapping_constants, + indexing_code, + clause_loc, + ); + } + OptArgIndexKey::Structure(_, _, ref name, ref arity) => { + remove_structure_index( + name, + *arity, + indexing_code, + clause_loc, + ); + } + OptArgIndexKey::List(..) => { + remove_list_index( + indexing_code, + clause_loc, + ); + } + OptArgIndexKey::None => { + unreachable!() + } + } +} + +#[inline] +fn cap_choice_seq(prelude: &mut [IndexedChoiceInstruction]) { + prelude.first_mut().map(|instr| { + *instr = IndexedChoiceInstruction::Try(instr.offset()); + }); + + cap_choice_seq_with_trust(prelude); +} + +#[inline] +fn cap_choice_seq_with_trust(prelude: &mut [IndexedChoiceInstruction]) { + prelude.last_mut().map(|instr| { + if let IndexedChoiceInstruction::Retry(i) = instr { + *instr = IndexedChoiceInstruction::Trust(*i); + } + }); +} + +#[inline] +fn uncap_choice_seq_with_trust(prelude: &mut [IndexedChoiceInstruction]) { + prelude.last_mut().map(|instr| { + if let IndexedChoiceInstruction::Trust(i) = instr { + *instr = IndexedChoiceInstruction::Retry(*i); + } + }); +} + +#[inline] +fn uncap_choice_seq_with_try(prelude: &mut [IndexedChoiceInstruction]) { + prelude.first_mut().map(|instr| { + if let IndexedChoiceInstruction::Try(i) = instr { + *instr = IndexedChoiceInstruction::Retry(*i); + } + }); +} + +pub(crate) fn constant_key_alternatives(constant: &Constant, atom_tbl: TabledData) -> Vec { + let mut constants = vec![]; + + match constant { + Constant::Atom(ref name, ref op) => { + if name.is_char() { + let c = name.as_str().chars().next().unwrap(); + constants.push(Constant::Char(c)); + } + + if op.is_some() { + constants.push(Constant::Atom(name.clone(), None)); + } + } + Constant::Char(c) => { + let atom = clause_name!(c.to_string(), atom_tbl); + constants.push(Constant::Atom(atom, None)); + } + Constant::Fixnum(ref n) => { + constants.push(Constant::Integer(Rc::new(Integer::from(*n)))); + + if *n >= 0 { + if let Ok(n) = usize::try_from(*n) { + constants.push(Constant::Usize(n)); + } + } + } + Constant::Integer(ref n) => { + if let Some(n) = n.to_isize() { + constants.push(Constant::Fixnum(n)); + } + + if let Some(n) = n.to_usize() { + constants.push(Constant::Usize(n)); + } + } + Constant::Usize(n) => { + constants.push(Constant::Integer(Rc::new(Integer::from(*n)))); + + if let Ok(n) = isize::try_from(*n) { + constants.push(Constant::Fixnum(n)); + } + } + _ => {} + } + + constants } #[derive(Debug)] -pub struct CodeOffsets { - atom_tbl: TabledData, - pub constants: IndexMap, - pub lists: ThirdLevelIndex, - pub structures: IndexMap<(ClauseName, usize), ThirdLevelIndex>, +pub(crate) struct StaticCodeIndices { + constants: IndexMap>, + lists: SliceDeque, + structures: IndexMap<(ClauseName, usize), SliceDeque>, } -impl CodeOffsets { - pub fn new() -> Self { - CodeOffsets { - atom_tbl: TabledData::new(Rc::new("_index".to_string())), +#[derive(Debug)] +pub(crate) struct DynamicCodeIndices { + constants: IndexMap>, + lists: SliceDeque, + structures: IndexMap<(ClauseName, usize), SliceDeque>, +} + +pub(crate) trait Indexer { + type ThirdLevelIndex; + + fn new() -> Self; + + fn constants(&mut self) -> &mut IndexMap>; + fn lists(&mut self) -> &mut SliceDeque; + fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque>; + + fn compute_index(is_initial_index: bool, index: usize) -> Self::ThirdLevelIndex; + + fn second_level_index( + indices: IndexMap>, + prelude: &mut SliceDeque, + ) -> IndexMap; + + fn switch_on( + instr_fn: impl FnMut(IndexMap) -> IndexingInstruction, + index: &mut IndexMap>, + prelude: &mut SliceDeque, + ) -> IndexingCodePtr; + + fn switch_on_list( + lists: &mut SliceDeque, + prelude: &mut SliceDeque, + ) -> IndexingCodePtr; + + fn remove_instruction_with_offset( + code: &mut SliceDeque, + offset: usize, + ); + + fn var_offset_wrapper(var_offset: usize) -> IndexingCodePtr; +} + +impl Indexer for StaticCodeIndices { + type ThirdLevelIndex = IndexedChoiceInstruction; + + #[inline] + fn new() -> Self { + Self { constants: IndexMap::new(), - lists: Vec::new(), + lists: sdeq![], structures: IndexMap::new(), } } - fn cap_choice_seq_with_trust(prelude: &mut ThirdLevelIndex) { - prelude.last_mut().map(|instr| { - match instr { - &mut IndexedChoiceInstruction::Retry(i) => { - *instr = IndexedChoiceInstruction::Trust(i) - } - _ => {} - }; - }); + #[inline] + fn constants(&mut self) -> &mut IndexMap> { + &mut self.constants } - fn add_index(is_first_index: bool, index: usize) -> IndexedChoiceInstruction { - if is_first_index { - IndexedChoiceInstruction::Try(index) + #[inline] + fn lists(&mut self) -> &mut SliceDeque { + &mut self.lists + } + + #[inline] + fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque> { + &mut self.structures + } + + fn compute_index(is_initial_index: bool, index: usize) -> IndexedChoiceInstruction { + if is_initial_index { + IndexedChoiceInstruction::Try(index + 1) } else { - IndexedChoiceInstruction::Retry(index) + IndexedChoiceInstruction::Retry(index + 1) } } - fn intercept_overlapping_constant(&mut self, constant: &Constant, index: usize) { - match constant { - &Constant::Atom(ref name, ref op) if name.is_char() => { - let c = name.as_str().chars().next().unwrap(); - let code = self.constants - .entry(Constant::Char(c)) - .or_insert(vec![]); - - code.push(Self::add_index(code.is_empty(), index)); - - if op.is_some() { - let code = self.constants - .entry(Constant::Atom(name.clone(), None)) - .or_insert(vec![]); - - code.push(Self::add_index(false, index)); - } - } - &Constant::Atom(ref name, Some(_)) => { - let code = self.constants - .entry(Constant::Atom(name.clone(), None)) - .or_insert(vec![]); - - code.push(Self::add_index(code.is_empty(), index)); - } - &Constant::Char(c) => { - let atom = clause_name!(c.to_string(), self.atom_tbl.clone()); - - let code = self.constants - .entry(Constant::Atom(atom, None)) - .or_insert(vec![]); - - code.push(Self::add_index(code.is_empty(), index)); - } - &Constant::Fixnum(n) => { - let code = self.constants - .entry(Constant::Integer(Rc::new(Integer::from(n)))) - .or_insert(vec![]); - - code.push(Self::add_index(code.is_empty(), index)); - - if n >= 0 { - if let Ok(n) = usize::try_from(n) { - let code = self.constants - .entry(Constant::Usize(n)) - .or_insert(vec![]); - - code.push(Self::add_index(code.is_empty(), index)); - } - } - } - &Constant::Integer(ref n) => { - if let Some(n) = n.to_isize() { - let code = self.constants - .entry(Constant::Fixnum(n)) - .or_insert(vec![]); - - code.push(Self::add_index(code.is_empty(), index)); - } - - if let Some(n) = n.to_usize() { - let code = self.constants - .entry(Constant::Usize(n)) - .or_insert(vec![]); - - code.push(Self::add_index(code.is_empty(), index)); - } - } - &Constant::Usize(n) => { - let code = self.constants - .entry(Constant::Integer(Rc::new(Integer::from(n)))) - .or_insert(vec![]); - - code.push(Self::add_index(code.is_empty(), index)); - - if let Ok(n) = isize::try_from(n) { - let code = self.constants - .entry(Constant::Fixnum(n)) - .or_insert(vec![]); - - code.push(Self::add_index(code.is_empty(), index)); - } - } - _ => { - } - } - } - - pub fn index_term(&mut self, optimal_arg: &Term, index: usize) { - match optimal_arg { - &Term::Clause(_, ref name, ref terms, _) => { - let code = self - .structures - .entry((name.clone(), terms.len())) - .or_insert(Vec::new()); - - let is_initial_index = code.is_empty(); - code.push(Self::add_index(is_initial_index, index)); - } - &Term::Cons(..) | &Term::Constant(_, Constant::String(_)) => { - let is_initial_index = self.lists.is_empty(); - self.lists.push(Self::add_index(is_initial_index, index)); - } - &Term::Constant(_, ref constant) => { - self.intercept_overlapping_constant(constant, index); - - let code = self.constants - .entry(constant.clone()) - .or_insert(vec![]); - - let is_initial_index = code.is_empty(); - code.push(Self::add_index(is_initial_index, index)); - } - _ => { - } - }; - } - - fn second_level_index( - indices: IndexMap, - prelude: &mut CodeDeque, - ) -> IndexMap - where - Index: Eq + Hash, - { + fn second_level_index( + indices: IndexMap>, + prelude: &mut SliceDeque, + ) -> IndexMap { let mut index_locs = IndexMap::new(); for (key, mut code) in indices.into_iter() { if code.len() > 1 { - index_locs.insert(key, IntIndex::Internal(prelude.len())); - Self::cap_choice_seq_with_trust(&mut code); - prelude.extend(code.into_iter().map(|code| Line::from(code))); + index_locs.insert(key, IndexingCodePtr::Internal(prelude.len() + 1)); + cap_choice_seq_with_trust(&mut code); + prelude.push_back(IndexingLine::from(code)); } else { code.first().map(|i| { - index_locs.insert(key, IntIndex::External(i.offset())); + index_locs.insert(key, IndexingCodePtr::External(i.offset())); }); } } @@ -197,187 +1220,322 @@ impl CodeOffsets { index_locs } - fn no_indices(&self) -> bool { - let no_constants = self.constants.is_empty(); - let no_structures = self.structures.is_empty(); - let no_lists = self.lists.is_empty(); + fn switch_on( + mut instr_fn: impl FnMut(IndexMap) -> IndexingInstruction, + index: &mut IndexMap>, + prelude: &mut SliceDeque, + ) -> IndexingCodePtr { + let index = mem::replace(index, IndexMap::new()); + let index = Self::second_level_index(index, prelude); + + if index.len() > 1 { + let instr = instr_fn(index); + prelude.push_front(IndexingLine::from(instr)); + + IndexingCodePtr::Internal(1) + } else { + index + .into_iter() + .next() + .map(|(_, v)| v) + .unwrap_or(IndexingCodePtr::Fail) + } + } + + fn switch_on_list( + lists: &mut SliceDeque, + prelude: &mut SliceDeque, + ) -> IndexingCodePtr { + if lists.len() > 1 { + cap_choice_seq_with_trust(lists); + let lists = mem::replace(lists, sdeq![]); + prelude.push_back(IndexingLine::from(lists)); + + IndexingCodePtr::Internal(1) + } else { + lists + .first() + .map(|i| IndexingCodePtr::External(i.offset())) + .unwrap_or(IndexingCodePtr::Fail) + } + } + + #[inline] + fn remove_instruction_with_offset(code: &mut SliceDeque, offset: usize) { + for (index, line) in code.iter().enumerate() { + if offset == line.offset() { + code.remove(index); + cap_choice_seq(code); + return; + } + } + } + + #[inline] + fn var_offset_wrapper(var_offset: usize) -> IndexingCodePtr { + IndexingCodePtr::External(var_offset) + } +} + +impl Indexer for DynamicCodeIndices { + type ThirdLevelIndex = usize; + + #[inline] + fn new() -> Self { + Self { + constants: IndexMap::new(), + lists: sdeq![], + structures: IndexMap::new(), + } + } + + #[inline] + fn constants(&mut self) -> &mut IndexMap> { + &mut self.constants + } + + #[inline] + fn lists(&mut self) -> &mut SliceDeque { + &mut self.lists + } + + #[inline] + fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque> { + &mut self.structures + } + + #[inline] + fn compute_index(_: bool, index: usize) -> usize { + index + 1 + } + + fn second_level_index( + indices: IndexMap>, + prelude: &mut SliceDeque, + ) -> IndexMap { + let mut index_locs = IndexMap::new(); + + for (key, code) in indices.into_iter() { + if code.len() > 1 { + index_locs.insert(key, IndexingCodePtr::Internal(prelude.len() + 1)); + prelude.push_back(IndexingLine::DynamicIndexedChoice(code)); + } else { + code.first().map(|i| { + index_locs.insert(key, IndexingCodePtr::DynamicExternal(*i)); + }); + } + } + + index_locs + } + + fn switch_on( + mut instr_fn: impl FnMut(IndexMap) -> IndexingInstruction, + index: &mut IndexMap>, + prelude: &mut SliceDeque, + ) -> IndexingCodePtr { + let index = mem::replace(index, IndexMap::new()); + let index = Self::second_level_index(index, prelude); + + if index.len() > 1 { + let instr = instr_fn(index); + prelude.push_front(IndexingLine::from(instr)); + + IndexingCodePtr::Internal(1) + } else { + index + .into_iter() + .next() + .map(|(_, v)| v) + .unwrap_or(IndexingCodePtr::Fail) + } + } + + fn switch_on_list( + lists: &mut SliceDeque, + prelude: &mut SliceDeque, + ) -> IndexingCodePtr { + if lists.len() > 1 { + let lists = mem::replace(lists, sdeq![]); + prelude.push_back(IndexingLine::DynamicIndexedChoice(lists)); + IndexingCodePtr::Internal(1) + } else { + lists + .first() + .map(|i| IndexingCodePtr::DynamicExternal(*i)) + .unwrap_or(IndexingCodePtr::Fail) + } + } + + #[inline] + fn remove_instruction_with_offset(code: &mut SliceDeque, offset: usize) { + for (index, line) in code.iter().enumerate() { + if offset == *line { + code.remove(index); + return; + } + } + } + + #[inline] + fn var_offset_wrapper(var_offset: usize) -> IndexingCodePtr { + IndexingCodePtr::DynamicExternal(var_offset) + } +} + +#[derive(Debug)] +pub(crate) struct CodeOffsets { + atom_tbl: TabledData, + indices: I, + optimal_index: usize, +} + +impl CodeOffsets { + pub(crate) fn new( + atom_tbl: TabledData, + indices: I, + optimal_index: usize, + ) -> Self { + CodeOffsets { + atom_tbl, + indices, + optimal_index, + } + } + + fn index_list(&mut self, index: usize) { + let is_initial_index = self.indices.lists().is_empty(); + let index = I::compute_index(is_initial_index, index); + self.indices.lists().push_back(index); + } + + fn index_constant(&mut self, constant: &Constant, index: usize) -> Vec { + let overlapping_constants = constant_key_alternatives(constant, self.atom_tbl.clone()); + let code = self.indices.constants().entry(constant.clone()).or_insert(sdeq![]); + + let is_initial_index = code.is_empty(); + code.push_back(I::compute_index(is_initial_index, index)); + + for constant in &overlapping_constants { + let code = self.indices.constants().entry(constant.clone()).or_insert(sdeq![]); + + let is_initial_index = code.is_empty(); + let index = I::compute_index(is_initial_index, index); + + code.push_back(index); + } + + overlapping_constants + } + + fn index_structure(&mut self, name: &ClauseName, arity: usize, index: usize) -> usize { + let code = self.indices + .structures() + .entry((name.clone(), arity)) + .or_insert(sdeq![]); + + let code_len = code.len(); + let is_initial_index = code.is_empty(); + + code.push_back(I::compute_index(is_initial_index, index)); + code_len + } + + pub(crate) fn index_term( + &mut self, + optimal_arg: &Term, + index: usize, + clause_index_info: &mut ClauseIndexInfo, + ) { + match optimal_arg { + &Term::Clause(_, ref name, ref terms, _) => { + clause_index_info.opt_arg_index_key = + OptArgIndexKey::Structure(self.optimal_index, 0, name.clone(), terms.len()); + + self.index_structure(name, terms.len(), index); + } + &Term::Cons(..) | &Term::Constant(_, Constant::String(_)) => { + clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0); + + self.index_list(index); + } + &Term::Constant(_, ref constant) => { + let overlapping_constants = self.index_constant(constant, index); + + clause_index_info.opt_arg_index_key = OptArgIndexKey::Constant( + self.optimal_index, + 0, + constant.clone(), + overlapping_constants, + ); + } + _ => {} + } + } + + pub(crate) fn no_indices(&mut self) -> bool { + let no_constants = self.indices.constants().is_empty(); + let no_structures = self.indices.structures().is_empty(); + let no_lists = self.indices.lists().is_empty(); no_constants && no_structures && no_lists } - fn flatten_index(index: IndexMap, len: usize) -> IndexMap - where - Index: Eq + Hash, - { - let mut flattened_index = IndexMap::new(); - - for (key, int_index) in index.into_iter() { - match int_index { - IntIndex::External(offset) => { - flattened_index.insert(key, offset + len + 1); - } - IntIndex::Internal(offset) => { - flattened_index.insert(key, offset + 1); - } - _ => {} - }; - } - - flattened_index - } - - fn adjust_internal_index(index: IntIndex) -> IntIndex { - match index { - IntIndex::Internal(o) => IntIndex::Internal(o + 1), - IntIndex::External(o) => IntIndex::External(o), - _ => IntIndex::Fail, - } - } - - fn switch_on_constant( - con_ind: IndexMap, - prelude: &mut CodeDeque, - optimal_index: usize, - ) -> IntIndex { - let con_ind = Self::second_level_index(con_ind, prelude); - - if con_ind.len() > 1 { - let index = Self::flatten_index(con_ind, prelude.len()); - let instr = IndexingInstruction::SwitchOnConstant( - optimal_index, - index.len(), - index - ); - - prelude.push_front(Line::from(instr)); - - IntIndex::Internal(1) - } else { - con_ind - .values() - .next() - .map(|index| Self::adjust_internal_index(*index)) - .unwrap_or(IntIndex::Fail) - } - } - - fn switch_on_structure( - str_ind: IndexMap<(ClauseName, usize), ThirdLevelIndex>, - prelude: &mut CodeDeque, - optimal_index: usize, - ) -> IntIndex { - let str_ind = Self::second_level_index(str_ind, prelude); - - if str_ind.len() > 1 { - let index = Self::flatten_index(str_ind, prelude.len()); - let instr = IndexingInstruction::SwitchOnStructure( - optimal_index, - index.len(), - index - ); - - prelude.push_front(Line::from(instr)); - - IntIndex::Internal(1) - } else { - str_ind - .values() - .next() - .map(|index| Self::adjust_internal_index(*index)) - .unwrap_or(IntIndex::Fail) - } - } - - fn switch_on_list(mut lists: ThirdLevelIndex, prelude: &mut CodeDeque) -> IntIndex { - if lists.len() > 1 { - Self::cap_choice_seq_with_trust(&mut lists); - prelude.extend(lists.into_iter().map(|i| Line::from(i))); - IntIndex::Internal(0) - } else { - lists - .first() - .map(|i| IntIndex::External(i.offset())) - .unwrap_or(IntIndex::Fail) - } - } - - fn switch_on_str_offset_from( - str_loc: IntIndex, - prelude_len: usize, - con_loc: IntIndex, - ) -> usize { - match str_loc { - IntIndex::External(o) => o + prelude_len + 1, - IntIndex::Fail => 0, - IntIndex::Internal(_) => match con_loc { - IntIndex::Internal(_) => 2, - _ => 1, - }, - } - } - - fn switch_on_con_offset_from(con_loc: IntIndex, prelude_len: usize) -> usize { - match con_loc { - IntIndex::External(offset) => offset + prelude_len + 1, - IntIndex::Fail => 0, - IntIndex::Internal(offset) => offset, - } - } - - fn switch_on_lst_offset_from( - lst_loc: IntIndex, - prelude_len: usize, - ) -> usize { - match lst_loc { - IntIndex::External(o) => o + prelude_len + 1, - IntIndex::Fail => 0, - IntIndex::Internal(_) => 1, // this internal is always 0. - } - } - - pub fn add_indices(self, code: &mut Code, mut code_body: Code, optimal_index: usize) { + pub(crate) fn compute_indices(mut self, skip_stub_try_me_else: bool) -> Vec { if self.no_indices() { - *code = code_body; - return; + return vec![]; } - let mut prelude = VecDeque::new(); + let mut prelude = sdeq![]; - let lst_loc = Self::switch_on_list(self.lists, &mut prelude); - let str_loc = - Self::switch_on_structure(self.structures, &mut prelude, optimal_index); - let con_loc = - Self::switch_on_constant(self.constants, &mut prelude, optimal_index); + let mut emitted_switch_on_structure = false; + let mut emitted_switch_on_constant = false; - let prelude_length = prelude.len(); + let mut lst_loc = I::switch_on_list(self.indices.lists(), &mut prelude); - for (index, line) in prelude.iter_mut().enumerate() { - match line { - &mut Line::IndexedChoice(IndexedChoiceInstruction::Try(ref mut i)) | - &mut Line::IndexedChoice(IndexedChoiceInstruction::Retry(ref mut i)) | - &mut Line::IndexedChoice(IndexedChoiceInstruction::Trust(ref mut i)) => { - *i += prelude_length - index; - } - _ => { - } - } - } - - let str_loc = Self::switch_on_str_offset_from(str_loc, prelude.len(), con_loc); - let con_loc = Self::switch_on_con_offset_from(con_loc, prelude.len()); - let lst_loc = Self::switch_on_lst_offset_from(lst_loc, prelude.len()); - - let switch_instr = IndexingInstruction::SwitchOnTerm( - optimal_index, - prelude.len() + 1, - con_loc, - lst_loc, - str_loc + let mut str_loc = I::switch_on( + |index| { + emitted_switch_on_structure = true; + IndexingInstruction::SwitchOnStructure(index) + }, + self.indices.structures(), + &mut prelude, ); - prelude.push_front(Line::from(switch_instr)); + let con_loc = I::switch_on( + |index| { + emitted_switch_on_constant = true; + IndexingInstruction::SwitchOnConstant(index) + }, + self.indices.constants(), + &mut prelude, + ); - *code = Vec::from(prelude); - code.append(&mut code_body); + match &mut str_loc { + IndexingCodePtr::Internal(ref mut i) => { + *i += emitted_switch_on_constant as usize; // con_loc.is_internal() as usize; + } + _ => {} + }; + + match &mut lst_loc { + IndexingCodePtr::Internal(ref mut i) => { + *i += emitted_switch_on_constant as usize; // con_loc.is_internal() as usize; + *i += emitted_switch_on_structure as usize; // str_loc.is_internal() as usize; + } + _ => {} + }; + + let var_offset = 1 + skip_stub_try_me_else as usize; + + prelude.push_front(IndexingLine::from(IndexingInstruction::SwitchOnTerm( + self.optimal_index, + I::var_offset_wrapper(var_offset), + con_loc, + lst_loc, + str_loc, + ))); + + prelude.into_iter().collect() } } diff --git a/src/instructions.rs b/src/instructions.rs index c3de3469..90cbeeab 100644 --- a/src/instructions.rs +++ b/src/instructions.rs @@ -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 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), + DynamicIndexedChoice(SliceDeque), +} + +impl From for IndexingLine { + #[inline] + fn from(instr: IndexingInstruction) -> Self { + IndexingLine::Indexing(instr) + } +} + +impl From> for IndexingLine { + #[inline] + fn from(instrs: SliceDeque) -> Self { + IndexingLine::IndexedChoice(instrs) + } +} + +#[derive(Debug)] +pub(crate) enum Line { Arithmetic(ArithmeticInstruction), Choice(ChoiceInstruction), Control(ControlInstruction), Cut(CutInstruction), Fact(FactInstruction), - Indexing(IndexingInstruction), + IndexingCode(Vec), 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) { 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> { + match line { + Line::IndexingCode(ref mut indexing_code) => Some(indexing_code), + _ => None, + } +} + +#[inline] +pub(crate) fn to_indexing_line(line: &Line) -> Option<&Vec> { + 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 { + pub(crate) fn perm_vars(&self) -> Option { 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), - SwitchOnStructure(usize, usize, IndexMap<(ClauseName, usize), usize>), -} - -impl From for Line { - fn from(i: IndexingInstruction) -> Self { - Line::Indexing(i) - } + SwitchOnTerm( + usize, + IndexingCodePtr, + IndexingCodePtr, + IndexingCodePtr, + IndexingCodePtr, + ), + SwitchOnConstant(IndexMap), + 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; +pub(crate) type CompiledFact = Vec; -pub type ThirdLevelIndex = Vec; - -pub type Code = Vec; - -pub type CodeDeque = VecDeque; +pub(crate) type Code = Vec; diff --git a/src/iterators.rs b/src/iterators.rs index 218ed78e..a83c5796 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -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, &'a Term, &'a Term), Constant(Level, &'a Cell, &'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, &'a Constant), Clause( @@ -51,23 +52,16 @@ pub enum TermIterState<'a> { Var(Level, &'a Cell, Rc), } -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>, } @@ -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>, 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>) -> Self { + pub(crate) fn from_rule_head_clause(terms: &'a Vec>) -> 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>), 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>(terms: Iter) -> bool { false } -pub struct ChunkedIterator<'a> { - pub chunk_num: usize, +pub(crate) struct ChunkedIterator<'a> { + pub(crate) chunk_num: usize, iter: Box> + 'a>, deep_cut_encountered: bool, cut_var_in_head: bool, @@ -464,7 +448,7 @@ type ChunkedIteratorItem<'a> = (usize, usize, Vec>); type RuleBodyIteratorItem<'a> = (usize, usize, Vec<&'a QueryTerm>); impl<'a> ChunkedIterator<'a> { - pub fn rule_body_iter(self) -> Box> + 'a> { + pub(crate) fn rule_body_iter(self) -> Box> + '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) -> Self { + */ + pub(crate) fn from_rule_body(p1: &'a QueryTerm, clauses: &'a Vec) -> 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 } diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 00000000..1fd4a4fb --- /dev/null +++ b/src/lib.rs @@ -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::*; diff --git a/src/lib/assoc.pl b/src/lib/assoc.pl index 2ebf1a8e..79e174e6 100644 --- a/src/lib/assoc.pl +++ b/src/lib/assoc.pl @@ -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. % diff --git a/src/lib/atts.pl b/src/lib/atts.pl index fbf440d0..afdebd71 100644 --- a/src/lib/atts.pl +++ b/src/lib/atts.pl @@ -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), diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index 3d7aa79f..ae727d4b 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -1,70 +1,29 @@ -:- op(400, yfx, /). - -% module resolution operator. -:- op(600, xfy, :). - -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). - -/* 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(400, yfx, *). -:- op(200, xfy, [**, ^]). -:- op(500, yfx, [/\, \/, xor]). -:- op(400, yfx, [div, //, rdiv, <<, >>, mod, rem]). -:- op(200, fy, [+, -, \]). - -:- op(1200, xfx, -->). - -% arithmetic comparison operators. -:- op(700, xfx, [>, <, =\=, =:=, >=, =<]). - -% term comparison. -:- op(700, xfx, [==, \==, @=<, @>=, @<, @>]). - -% conditional operators. -:- op(1050, xfy, ->). -:- op(1100, xfy, ;). - -% control. -:- op(700, xfx, [=, =.., \=]). -:- op(900, fy, \+). - :- module(builtins, [(=)/2, (\=)/2, (\+)/1, (',')/2, (->)/2, (;)/2, (=..)/2, (:)/2, (:)/3, (:)/4, (:)/5, (:)/6, (:)/7, (:)/8, (:)/9, (:)/10, (:)/11, (:)/12, abolish/1, asserta/1, assertz/1, at_end_of_stream/0, at_end_of_stream/1, atom_chars/2, atom_codes/2, atom_concat/3, - atom_length/2, bagof/3, catch/3, char_code/2, - clause/2, close/1, close/2, current_input/1, - current_output/1, current_op/3, + atom_length/2, bagof/3, call/1, call/2, call/3, + call/4, call/5, call/6, call/7, call/8, call/9, + catch/3, char_code/2, clause/2, close/1, close/2, + current_input/1, current_output/1, current_op/3, current_predicate/1, current_prolog_flag/2, - expand_goal/2, expand_term/2, fail/0, false/0, - findall/3, findall/4, flush_output/0, - flush_output/1, get_byte/1, get_byte/2, - get_char/1, get_char/2, get_code/1, get_code/2, - halt/0, halt/1, max_arity/1, number_chars/2, - number_codes/2, once/1, op/3, open/3, open/4, - peek_byte/1, peek_byte/2, peek_char/1, - peek_char/2, peek_code/1, peek_code/2, - put_byte/1, put_byte/2, put_code/1, put_code/2, - put_char/1, put_char/2, read_term/2, read_term/3, - repeat/0, retract/1, set_prolog_flag/2, - set_input/1, set_stream_position/2, set_output/1, - setof/3, stream_property/2, sub_atom/5, - subsumes_term/2, term_variables/2, throw/1, - true/0, unify_with_occurs_check/2, write/1, + fail/0, false/0, findall/3, findall/4, + flush_output/0, flush_output/1, get_byte/1, + get_byte/2, get_char/1, get_char/2, get_code/1, + get_code/2, halt/0, halt/1, max_arity/1, + number_chars/2, number_codes/2, once/1, op/3, + open/3, open/4, peek_byte/1, peek_byte/2, + peek_char/1, peek_char/2, peek_code/1, + peek_code/2, put_byte/1, put_byte/2, put_code/1, + put_code/2, put_char/1, put_char/2, read_term/2, + read_term/3, repeat/0, retract/1, + set_prolog_flag/2, set_input/1, + set_stream_position/2, set_output/1, setof/3, + stream_property/2, sub_atom/5, subsumes_term/2, + term_variables/2, throw/1, true/0, + unify_with_occurs_check/2, write/1, write_canonical/1, write_term/2, write_term/3, writeq/1]). @@ -80,13 +39,40 @@ true. false :- '$fail'. -% dynamic module resolution. + +% These are stub versions of call/{1-9} defined for bootstrapping. +% Once Scryer is bootstrapped, each is replaced with a version that +% uses expand_goal to pass the expanded goal along to '$call'. + +call(G) :- '$call'(G). + +call(G, A) :- '$call'(G, A). + +call(G, A, B) :- '$call'(G, A, B). + +call(G, A, B, C) :- '$call'(G, A, B, C). + +call(G, A, B, C, D) :- '$call'(G, A, B, C, D). + +call(G, A, B, C, D, E) :- '$call'(G, A, B, C, D, E). + +call(G, A, B, C, D, E, F) :- '$call'(G, A, B, C, D, E, F). + +call(G, A, B, C, D, E, F, G) :- '$call'(G, A, B, C, D, E, F, G). + +call(G, A, B, C, D, E, F, G, H) :- '$call'(G, A, B, C, D, E, F, G, H). + Module : Predicate :- - ( atom(Module) -> '$module_call'(Module, Predicate) - ; throw(error(type_error(atom, Module), (:)/2)) + ( atom(Module) -> + '$module_call'(Module, Predicate) + ; + throw(error(type_error(atom, Module), (:)/2)) ). + +% dynamic module resolution. + :(Module, Predicate, A1) :- ( atom(Module) -> '$module_call'(A1, Module, Predicate) ; throw(error(type_error(atom, Module), (:)/2)) @@ -137,7 +123,6 @@ Module : Predicate :- ; throw(error(type_error(atom, Module), (:)/2)) ). - % flags. current_prolog_flag(Flag, false) :- Flag == bounded, !. @@ -148,6 +133,10 @@ current_prolog_flag(Flag, Value) :- Flag == double_quotes, !, '$get_double_quote current_prolog_flag(double_quotes, Value) :- '$get_double_quotes'(Value). current_prolog_flag(Flag, _) :- Flag == max_integer, !, '$fail'. current_prolog_flag(Flag, _) :- Flag == min_integer, !, '$fail'. +current_prolog_flag(Flag, OccursCheckEnabled) :- + Flag == occurs_check, + !, + '$is_sto_enabled'(OccursCheckEnabled). current_prolog_flag(Flag, _) :- atom(Flag), throw(error(domain_error(prolog_flag, Flag), current_prolog_flag/2)). % 8.17.2.3 b @@ -171,16 +160,22 @@ set_prolog_flag(min_integer, Value) :- set_prolog_flag(integer_rounding_function, down) :- !. % 7.11.1.4 set_prolog_flag(integer_rounding_function, Value) :- throw(error(domain_error(flag_value, integer_rounding_function + Value), - set_prolog_flag/2)). % 8.17.1.3 e + set_prolog_flag/2)). % 8.17.1.3 e set_prolog_flag(double_quotes, chars) :- !, '$set_double_quotes'(chars). % 7.11.2.5, list of one-char atoms. set_prolog_flag(double_quotes, atom) :- !, '$set_double_quotes'(atom). % 7.11.2.5, list of char codes (UTF8). set_prolog_flag(double_quotes, codes) :- !, '$set_double_quotes'(codes). +set_prolog_flag(occurs_check, true) :- + !, '$set_sto_as_unify'. +set_prolog_flag(occurs_check, false) :- + !, '$set_nsto_as_unify'. +set_prolog_flag(occurs_check, error) :- + !, '$set_sto_with_error_as_unify'. set_prolog_flag(double_quotes, Value) :- throw(error(domain_error(flag_value, double_quotes + Value), - set_prolog_flag/2)). % 8.17.1.3 e + set_prolog_flag/2)). % 8.17.1.3 e set_prolog_flag(Flag, _) :- atom(Flag), throw(error(domain_error(prolog_flag, Flag), set_prolog_flag/2)). % 8.17.1.3 d @@ -192,6 +187,8 @@ set_prolog_flag(Flag, _) :- fail :- '$fail'. +:- meta_predicate \+(0). + \+ G :- call(G), !, false. \+ _. @@ -200,6 +197,8 @@ X \= X :- !, false. _ \= _. +:- meta_predicate once(0). + once(G) :- call(G), !. @@ -207,6 +206,20 @@ repeat. repeat :- repeat. + +:- meta_predicate ','(0, 0). + +:- meta_predicate ','(0, +, +). + +:- meta_predicate ;(0, 0). + +:- meta_predicate ;(0, 0, +). + +:- meta_predicate ->(0, 0). + +:- meta_predicate ->(0, 0, +). + + ','(G1, G2) :- '$get_b_value'(B), ( '$call_with_default_policy'(var(G1)) -> @@ -231,6 +244,8 @@ G1 -> G2 :- ). +:-non_counted_backtracking call_or_cut/3. + call_or_cut(G, B, ErrorPI) :- ( '$call_with_default_policy'(var(G)) -> throw(error(instantiation_error, ErrorPI)) @@ -238,55 +253,80 @@ call_or_cut(G, B, ErrorPI) :- ). -call_or_cut(!, B) :- +:- non_counted_backtracking control_functor/1. + +control_functor(!). +control_functor((_,_)). +control_functor((_;_)). +control_functor((_->_)). + + +:- non_counted_backtracking call_or_cut/2. + +call_or_cut(M:G, B) :- + !, + ( nonvar(G), + '$call_with_default_policy'(control_functor(G)) -> + '$call_with_default_policy'(call_or_cut_interp(G, B)) + ; call(M:G) + ). +call_or_cut(G, B) :- + ( nonvar(G), + '$call_with_default_policy'(control_functor(G)) -> + '$call_with_default_policy'(call_or_cut_interp(G, B)) + ; call(G) + ). + + +:- non_counted_backtracking call_or_cut_interp/2. + +call_or_cut_interp(!, B) :- '$set_cp_by_default'(B). -call_or_cut((G1, G2), B) :- - !, +call_or_cut_interp((G1, G2), B) :- '$call_with_default_policy'(','(G1, G2, B)). -call_or_cut((G1 ; G2), B) :- - !, +call_or_cut_interp((G1 ; G2), B) :- '$call_with_default_policy'(';'(G1, G2, B)). -call_or_cut((G1 -> G2), B) :- - !, +call_or_cut_interp((G1 -> G2), B) :- '$call_with_default_policy'(->(G1, G2, B)). -call_or_cut(G, _) :- - '$call_with_default_policy'(G). :- non_counted_backtracking (',')/3. -','((G1, G2), G3, B) :- + +','(M:G1, G2, B) :- !, - '$call_with_default_policy'(','(G1, G2, B)), - '$call_with_default_policy'(call_or_cut(G3, B, (',')/2)). -','((G1; G2), G3, B) :- - !, - '$call_with_default_policy'(';'(G1, G2, B)), - '$call_with_default_policy'(call_or_cut(G3, B, (',')/2)). -','((G1 -> G2), G3, B) :- - !, - '$call_with_default_policy'(->(G1, G2, B)), - '$call_with_default_policy'(call_or_cut(G3, B, (',')/2)). + ( nonvar(G1), + '$call_with_default_policy'(control_functor(G1)) -> + '$call_with_default_policy'(',-interp'(G1, G2, B)) + ; call(M:G1), + '$call_with_default_policy'(call_or_cut(G2, B, (',')/2)) + ). ','(G1, G2, B) :- '$call_with_default_policy'(call_or_cut(G1, B, (',')/2)), '$call_with_default_policy'(call_or_cut(G2, B, (',')/2)). +:- non_counted_backtracking (',-interp')/3. + +',-interp'((G1, G2), G3, B) :- + '$call_with_default_policy'(','(G1, G2, B)), + '$call_with_default_policy'(call_or_cut(G3, B, (',')/2)). +',-interp'((G1; G2), G3, B) :- + '$call_with_default_policy'(';'(G1, G2, B)), + '$call_with_default_policy'(call_or_cut(G3, B, (',')/2)). +',-interp'((G1 -> G2), G3, B) :- + '$call_with_default_policy'(->(G1, G2, B)), + '$call_with_default_policy'(call_or_cut(G3, B, (',')/2)). + + :- non_counted_backtracking (;)/3. -';'((G1, G2), G3, B) :- + +';'(M:G1, G2, B) :- !, - ( '$call_with_default_policy'(','(G1, G2, B)) - ; '$call_with_default_policy'(call_or_cut(G3, B, (;)/2)) - ). -';'((G1; G2), G3, B) :- - !, - ( '$call_with_default_policy'(';'(G1, G2, B)) - ; '$call_with_default_policy'(call_or_cut(G3, B, (;)/2)) - ). -';'((G1 -> G2), G3, B) :- - !, - ( '$call_with_default_policy'(call_or_cut(G1, B, (->)/2)) -> - '$call_with_default_policy'(call_or_cut(G2, B, (->)/2)) - ; '$call_with_default_policy'(call_or_cut(G3, B, (;)/2)) + ( nonvar(G1), + '$call_with_default_policy'(control_functor(G1)) -> + '$call_with_default_policy'(';-interp'(G1, G2, B)) + ; call(M:G1) + ; '$call_with_default_policy'(call_or_cut(G2, B, (;)/2)) ). ';'(G1, G2, B) :- ( '$call_with_default_policy'(call_or_cut(G1, B, (;)/2)) @@ -294,26 +334,54 @@ call_or_cut(G, _) :- ). +:- non_counted_backtracking ';-interp'/3. + +';-interp'((G1, G2), G3, B) :- + ( '$call_with_default_policy'(','(G1, G2, B)) + ; '$call_with_default_policy'(call_or_cut(G3, B, (;)/2)) + ). +';-interp'((G1; G2), G3, B) :- + ( '$call_with_default_policy'(';'(G1, G2, B)) + ; '$call_with_default_policy'(call_or_cut(G3, B, (;)/2)) + ). +';-interp'((G1 -> G2), G3, B) :- + ( '$call_with_default_policy'(call_or_cut(G1, B, (->)/2)) -> + '$call_with_default_policy'(call_or_cut(G2, B, (->)/2)) + ; '$call_with_default_policy'(call_or_cut(G3, B, (;)/2)) + ). + + :- non_counted_backtracking (->)/3. -->((G1, G2), G3, B) :- + +->(M:G1, G2, B) :- !, + ( nonvar(G1), + '$call_with_default_policy'(control_functor(G1)) -> + '$call_with_default_policy'('->-interp'(G1, G2, B)) + ; call(M:G1) -> + '$call_with_default_policy'(call_or_cut(G2, B, (->)/2)) + ). +->(G1, G2, B) :- + ( '$call_with_default_policy'(call_or_cut(G1, B, (->)/2)) -> + '$call_with_default_policy'(call_or_cut(G2, B, (->)/2)) + ). + + +:- non_counted_backtracking '->-interp'/3. + +'->-interp'((G1, G2), G3, B) :- ( '$call_with_default_policy'(','(G1, G2, B)) -> '$call_with_default_policy'(call_or_cut(G3, B, (->)/2)) ). -->((G1 ; G2), G3, B) :- - !, +'->-interp'((G1 ; G2), G3, B) :- ( '$call_with_default_policy'(';'(G1, G2, B)) -> '$call_with_default_policy'(call_or_cut(G3, B, (->)/2)) ). -->((G1 -> G2), G3, B) :- - !, +'->-interp'((G1 -> G2), G3, B) :- ( '$call_with_default_policy'(->(G1, G2, B)) -> '$call_with_default_policy'(call_or_cut(G3, B, (->)/2)) ). -->(G1, G2, B) :- - ( '$call_with_default_policy'(call_or_cut(G1, B, (->)/2)) - -> '$call_with_default_policy'(call_or_cut(G2, B, (->)/2)) - ). + % univ. @@ -321,19 +389,26 @@ call_or_cut(G, _) :- univ_errors(Term, List, N) :- '$skip_max_list'(N, -1, List, R), ( var(R) -> - ( var(Term), throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 a) - ; true - ) + ( var(Term), + throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 a) + ; true + ) ; R \== [] -> throw(error(type_error(list, List), (=..)/2)) % 8.5.3.3 b) ; List = [H|T] -> - ( var(H), var(Term), % R == [] => List is a proper list. + ( var(H), + var(Term), % R == [] => List is a proper list. throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 c) - ; T \== [], nonvar(H), \+ atom(H), + ; T \== [], + nonvar(H), + \+ atom(H), throw(error(type_error(atom, H), (=..)/2)) % 8.5.3.3 d) - ; compound(H), T == [], + ; compound(H), + T == [], throw(error(type_error(atomic, H), (=..)/2)) % 8.5.3.3 e) - ; var(Term), max_arity(M), N - 1 > M, + ; var(Term), + max_arity(M), + N - 1 > M, throw(error(representation_error(max_arity), (=..)/2)) % 8.5.3.3 g) ; true ) @@ -342,14 +417,17 @@ univ_errors(Term, List, N) :- ; true ). -Term =.. List :- '$call_with_default_policy'(univ_errors(Term, List, N)), - '$call_with_default_policy'(univ_worker(Term, List, N)). +Term =.. List :- + '$call_with_default_policy'(univ_errors(Term, List, N)), + '$call_with_default_policy'(univ_worker(Term, List, N)). :- non_counted_backtracking univ_worker/3. univ_worker(Term, List, _) :- - atomic(Term), !, '$call_with_default_policy'(List = [Term]). + atomic(Term), + !, + '$call_with_default_policy'(List = [Term]). univ_worker(Term, [Name|Args], N) :- var(Term), !, '$call_with_default_policy'(Arity is N-1), @@ -364,46 +442,78 @@ univ_worker(Term, List, _) :- :- non_counted_backtracking get_args/4. get_args(Args, _, _, 0) :- - !, '$call_with_default_policy'(Args = []). + !, + '$call_with_default_policy'(Args = []). get_args([Arg], Func, N, N) :- - !, '$call_with_default_policy'(arg(N, Func, Arg)). + !, + '$call_with_default_policy'(arg(N, Func, Arg)). get_args([Arg|Args], Func, I0, N) :- '$call_with_default_policy'(arg(I0, Func, Arg)), '$call_with_default_policy'(I1 is I0 + 1), '$call_with_default_policy'(get_args(Args, Func, I1, N)). + +:- meta_predicate parse_options_list(?, 0, ?, ?, ?). + +parse_options_list(Options, Selector, DefaultPairs, OptionValues, Stub) :- + '$skip_max_list'(_, -1, Options, Tail), + ( Tail == [] -> + true + ; var(Tail) -> + throw(error(instantiation_error, Stub)) % 8.11.5.3c) + ; Tail \== [] -> + throw(error(type_error(list, Options), Stub)) % 8.11.5.3e) + ), + ( lists:maplist(nonvar, Options), + catch(lists:maplist(Selector, Options, OptionPairs0), + error(E, _), + builtins:throw(error(E, Stub))) -> + lists:append(DefaultPairs, OptionPairs0, OptionPairs1), + keysort(OptionPairs1, OptionPairs), + select_rightmost_options(OptionPairs, OptionValues) + ; + throw(error(instantiation_error, Stub)) % 8.11.5.3c) + ). + + parse_write_options(Options, OptionValues, Stub) :- DefaultOptions = [ignore_ops-false, max_depth-0, numbervars-false, quoted-false, variable_names-[]], - parse_options_list(Options, parse_write_options_, DefaultOptions, OptionValues, Stub). + parse_options_list(Options, builtins:parse_write_options_, DefaultOptions, OptionValues, Stub). parse_write_options_(ignore_ops(IgnoreOps), ignore_ops-IgnoreOps) :- - ( nonvar(IgnoreOps), lists:member(IgnoreOps, [true, false]) + ( nonvar(IgnoreOps), + lists:member(IgnoreOps, [true, false]) ; throw(error(domain_error(write_option, ignore_ops(IgnoreOps)), _)) ). parse_write_options_(quoted(Quoted), quoted-Quoted) :- - ( nonvar(Quoted), lists:member(Quoted, [true, false]) + ( nonvar(Quoted), + lists:member(Quoted, [true, false]) ; throw(error(domain_error(write_option, quoted(Quoted)), _)) ). parse_write_options_(numbervars(NumberVars), numbervars-NumberVars) :- - ( nonvar(NumberVars), lists:member(NumberVars, [true, false]) + ( nonvar(NumberVars), + lists:member(NumberVars, [true, false]) ; throw(error(domain_error(write_option, numbervars(NumberVars)), _)) ). parse_write_options_(variable_names(VNNames), variable_names-VNNames) :- must_be_var_names_list(VNNames). parse_write_options_(max_depth(MaxDepth), max_depth-MaxDepth) :- - ( integer(MaxDepth), MaxDepth >= 0 + ( integer(MaxDepth), + MaxDepth >= 0 ; throw(error(domain_error(write_option, max_depth(MaxDepth)), _)) ). must_be_var_names_list(VarNames) :- '$skip_max_list'(_, -1, VarNames, Tail), - ( Tail == [] -> must_be_var_names_list_(VarNames, VarNames) - ; var(Tail) -> throw(error(instantiation_error, write_term/2)) + ( Tail == [] -> + must_be_var_names_list_(VarNames, VarNames) + ; var(Tail) -> + throw(error(instantiation_error, write_term/2)) ; throw(error(domain_error(write_option, variable_names(VarNames)), write_term/2)) ). @@ -411,8 +521,10 @@ must_be_var_names_list_([], List). must_be_var_names_list_([VarName | VarNames], List) :- ( nonvar(VarName) -> ( VarName = (Atom = _) -> - ( atom(Atom) -> must_be_var_names_list_(VarNames, List) - ; var(Atom) -> throw(error(instantiation_error, write_term/2)) + ( atom(Atom) -> + must_be_var_names_list_(VarNames, List) + ; var(Atom) -> + throw(error(instantiation_error, write_term/2)) ; throw(error(domain_error(write_option, variable_names(List)), write_term/2)) ) ; throw(error(domain_error(write_option, variable_names(List)), write_term/2)) @@ -455,30 +567,9 @@ select_rightmost_options([Option-Value | OptionPairs], OptionValues) :- select_rightmost_options([], []). -parse_options_list(Options, Selector, DefaultPairs, OptionValues, Stub) :- - '$skip_max_list'(_, -1, Options, Tail), - ( Tail == [] -> - true - ; var(Tail) -> - throw(error(instantiation_error, Stub)) % 8.11.5.3c) - ; Tail \== [] -> - throw(error(type_error(list, Options), Stub)) % 8.11.5.3e) - ), - ( lists:maplist(nonvar, Options), - catch(lists:maplist(Selector, Options, OptionPairs0), - error(E, _), - throw(error(E, Stub))) -> - lists:append(DefaultPairs, OptionPairs0, OptionPairs1), - keysort(OptionPairs1, OptionPairs), - select_rightmost_options(OptionPairs, OptionValues) - ; - throw(error(instantiation_error, Stub)) % 8.11.5.3c) - ). - - parse_read_term_options(Options, OptionValues, Stub) :- DefaultOptions = [singletons-_, variables-_, variable_names-_], - parse_options_list(Options, parse_read_term_options_, DefaultOptions, OptionValues, Stub). + parse_options_list(Options, builtins:parse_read_term_options_, DefaultOptions, OptionValues, Stub). parse_read_term_options_(singletons(Vars), singletons-Vars). @@ -498,20 +589,21 @@ read_term(Term, Options) :- read_term(Stream, Term, Options). -% expand_goal. - -expand_goal(Term0, Term) :- '$expand_goal'(Term0, Term). - -% expand_term. - -expand_term(Term0, Term) :- '$expand_term'(Term0, Term). - % term_variables. % ensures List is either a variable or a list. -can_be_list(List, _) :- var(List), !. -can_be_list(List, _) :- '$skip_max_list'(_, -1, List, Tail), ( var(Tail) -> true ; Tail == []), !. -can_be_list(List, PI) :- throw(error(type_error(list, List), PI)). +can_be_list(List, _) :- + var(List), + !. +can_be_list(List, _) :- + '$skip_max_list'(_, -1, List, Tail), + ( var(Tail) -> + true + ; Tail == [] + ), + !. +can_be_list(List, PI) :- + throw(error(type_error(list, List), PI)). term_variables(Term, Vars) :- can_be_list(Vars, term_variables/2), @@ -519,7 +611,14 @@ term_variables(Term, Vars) :- % exceptions. -catch(G,C,R) :- '$get_current_block'(Bb), '$call_with_default_policy'(catch(G,C,R,Bb)). +:- meta_predicate catch(0, ?, 0). + +catch(G,C,R) :- + '$get_current_block'(Bb), + '$call_with_default_policy'(catch(G,C,R,Bb)). + + +:- meta_predicate catch(0, ?, 0, +). :- non_counted_backtracking catch/4. catch(G,C,R,Bb) :- @@ -531,16 +630,30 @@ catch(G,C,R,Bb) :- '$get_ball'(Ball), '$call_with_default_policy'(handle_ball(Ball, C, R)). + :- non_counted_backtracking end_block/2. -end_block(Bb, NBb) :- '$clean_up_block'(NBb), '$reset_block'(Bb). -end_block(Bb, NBb) :- '$reset_block'(NBb), '$fail'. +end_block(Bb, NBb) :- + '$clean_up_block'(NBb), + '$reset_block'(Bb). +end_block(Bb, NBb) :- + '$reset_block'(NBb), + '$fail'. + +:- meta_predicate handle_ball(?, ?, 0). :- non_counted_backtracking handle_ball/3. -handle_ball(C, C, R) :- !, '$erase_ball', call(R). -handle_ball(_, _, _) :- '$unwind_stack'. +handle_ball(C, C, R) :- + !, + '$erase_ball', + call(R). +handle_ball(_, _, _) :- + '$unwind_stack'. throw(Ball) :- '$set_ball'(Ball), '$unwind_stack'. + +% :- meta_predicate '$iterate_find_all'(?, 0, ?, ?). + :- non_counted_backtracking '$iterate_find_all'/4. '$iterate_find_all'(Template, Goal, _, LhOffset) :- call(Goal), @@ -550,14 +663,23 @@ throw(Ball) :- '$set_ball'(Ball), '$unwind_stack'. '$truncate_if_no_lh_growth'(LhOffset), '$get_lh_from_offset'(LhOffset, Solutions). + truncate_lh_to(LhLength) :- '$truncate_lh_to'(LhLength). + +:- meta_predicate findall(?, 0, ?). + findall(Template, Goal, Solutions) :- error:can_be(list, Solutions), '$lh_length'(LhLength), - '$call_with_default_policy'(catch('$iterate_find_all'(Template, Goal, Solutions, LhLength), - Error, - ( truncate_lh_to(LhLength), throw(Error) ))). + '$call_with_default_policy'( + catch(builtins:'$iterate_find_all'(Template, Goal, Solutions, LhLength), + Error, + ( builtins:truncate_lh_to(LhLength), builtins:throw(Error) )) + ). + + +% :- meta_predicate '$iterate_find_all_diff'(?, 0, ?, ?, ?). :- non_counted_backtracking '$iterate_find_all_diff'/5. '$iterate_find_all_diff'(Template, Goal, _, _, LhOffset) :- @@ -569,14 +691,16 @@ findall(Template, Goal, Solutions) :- '$get_lh_from_offset_diff'(LhOffset, Solutions0, Solutions1). +% :- meta_predicate findall(?, 0, ?, ?). + findall(Template, Goal, Solutions0, Solutions1) :- error:can_be(list, Solutions0), error:can_be(list, Solutions1), '$lh_length'(LhLength), - '$call_with_default_policy'(catch('$iterate_find_all_diff'(Template, Goal, Solutions0, - Solutions1, LhLength), - Error, - ( truncate_lh_to(LhLength), throw(Error) ))). + '$call_with_default_policy'(catch(builtins:'$iterate_find_all_diff'(Template, Goal, Solutions0, + Solutions1, LhLength), + Error, + ( builtins:truncate_lh_to(LhLength), builtins:throw(Error) ))). set_difference([X|Xs], [Y|Ys], Zs) :- X == Y, !, set_difference(Xs, [Y|Ys], Zs). @@ -588,7 +712,10 @@ set_difference([], _, []) :- !. set_difference(Xs, [], Xs). group_by_variant([V2-S2 | Pairs], V1-S1, [S2 | Solutions], Pairs0) :- - iso_ext:variant(V1, V2), !, V1 = V2, group_by_variant(Pairs, V2-S2, Solutions, Pairs0). + iso_ext:variant(V1, V2), + !, + V1 = V2, + group_by_variant(Pairs, V2-S2, Solutions, Pairs0). group_by_variant(Pairs, _, [], Pairs). group_by_variants([V-S|Pairs], [V-Solution|Solutions]) :- @@ -603,16 +730,23 @@ iterate_variants([V-Solution|GroupSolutions], V, Solution) :- iterate_variants([_|GroupSolutions], Ws, Solution) :- iterate_variants(GroupSolutions, Ws, Solution). + rightmost_power(Term, FinalTerm, Xs) :- - ( Term = X ^ Y + ( ( Term = X ^ Y + ; Term = _ : X ^ Y + ) -> ( var(Y) -> FinalTerm = Y, Xs = [X] ; Xs = [X | Xss], rightmost_power(Y, FinalTerm, Xss) ) ; Xs = [], FinalTerm = Term ). + findall_with_existential(Template, Goal, PairedSolutions, Witnesses0, Witnesses) :- - ( nonvar(Goal), Goal = _ ^ _ -> + ( nonvar(Goal), + ( Goal = _ ^ _ + ; Goal = _ : (_ ^ _) + ) -> rightmost_power(Goal, Goal1, ExistentialVars0), term_variables(ExistentialVars0, ExistentialVars), sort(Witnesses0, Witnesses1), @@ -623,6 +757,9 @@ findall_with_existential(Template, Goal, PairedSolutions, Witnesses0, Witnesses) findall(Witnesses-Template, Goal, PairedSolutions) ). + +:- meta_predicate bagof(?, 0, ?). + bagof(Template, Goal, Solution) :- error:can_be(list, Solution), term_variables(Template, TemplateVars0), @@ -643,6 +780,9 @@ iterate_variants_and_sort([V-Solution0|GroupSolutions], V, Solution) :- iterate_variants_and_sort([_|GroupSolutions], Ws, Solution) :- iterate_variants_and_sort(GroupSolutions, Ws, Solution). + +:- meta_predicate setof(?, 0, ?). + setof(Template, Goal, Solution) :- error:can_be(list, Solution), term_variables(Template, TemplateVars0), @@ -659,58 +799,67 @@ setof(Template, Goal, Solution) :- '$clause_body_is_valid'(B) :- ( var(B) -> true - ; functor(B, Name, _) -> ( atom(Name), Name \== '.' -> true - ; throw(error(type_error(callable, B), clause/2)) - ) + ; functor(B, Name, _) -> + ( atom(Name), Name \== '.' -> true + ; throw(error(type_error(callable, B), clause/2)) + ) ; throw(error(type_error(callable, B), clause/2)) ). '$module_clause'(H, B, Module) :- - ( var(H) -> throw(error(instantiation_error, clause/2)) - ; functor(H, Name, Arity) -> ( Name == '.' -> throw(error(type_error(callable, H), clause/2)) - ; '$module_head_is_dynamic'(H, Module) -> - '$clause_body_is_valid'(B), - '$get_module_clause'(H, B, Module) - ; throw(error(permission_error(access, private_procedure, Name/Arity), - clause/2)) - ) - ; throw(error(type_error(callable, H), clause/2)) - ). - -clause(H, B) :- - ( var(H) -> throw(error(instantiation_error, clause/2)) + ( var(H) -> + throw(error(instantiation_error, clause/2)) ; functor(H, Name, Arity) -> - ( Name == '.' -> throw(error(type_error(callable, H), clause/2)) - ; Name == (:), Arity =:= 2 -> - arg(1, H, Module), - arg(2, H, F), - '$module_clause'(F, B, Module) - %% '$no_such_predicate' fails if H is not callable. - ; '$no_such_predicate'(H) -> '$fail' - ; '$head_is_dynamic'(H) -> '$clause_body_is_valid'(B), - '$get_clause'(H, B) + ( Name == '.' -> + throw(error(type_error(callable, H), clause/2)) + ; '$head_is_dynamic'(Module, H) -> + '$clause_body_is_valid'(B), + Module:'$clause'(H, B) + ; '$no_such_predicate'(Module, H) -> + '$fail' ; throw(error(permission_error(access, private_procedure, Name/Arity), clause/2)) ) ; throw(error(type_error(callable, H), clause/2)) ). -call_module_asserta(Head, Body, Name, Arity, Module) :- - '$clause_body_is_valid'(Body), - functor(VarHead, Name, Arity), - findall((VarHead :- VarBody), clause(Module:VarHead, VarBody), Clauses), - '$module_asserta'((Head :- Body), Clauses, Name, Arity, Module). -call_asserta(Head, Body, Name, Arity) :- +clause(H, B) :- + ( var(H) -> + throw(error(instantiation_error, clause/2)) + ; functor(H, Name, Arity) -> + ( Name == '.' -> + throw(error(type_error(callable, H), clause/2)) + ; Name == (:), + Arity =:= 2 -> + arg(1, H, Module), + arg(2, H, F), + '$module_clause'(F, B, Module) + ; '$head_is_dynamic'(user, H) -> + '$clause_body_is_valid'(B), + '$clause'(H, B) + ; '$no_such_predicate'(user, H) -> %% '$no_such_predicate' fails if + %% H is not callable. + '$fail' + ; throw(error(permission_error(access, private_procedure, Name/Arity), + clause/2)) + ) + ; throw(error(type_error(callable, H), clause/2)) + ). + +call_asserta(Head, Body, Name, Arity, Module) :- '$clause_body_is_valid'(Body), - functor(VarHead, Name, Arity), - findall((VarHead :- VarBody), clause(VarHead, VarBody), Clauses), - '$asserta'((Head :- Body), Clauses, Name, Arity). + functor(_, Name, Arity), + '$asserta'(Head, Body, Name, Arity, Module). module_asserta_clause(Head, Body, Module) :- - ( var(Head) -> throw(error(instantiation_error, asserta/1)) - ; functor(Head, Name, Arity), atom(Name), Name \== '.' -> - ( '$module_head_is_dynamic'(Head, Module) -> call_module_asserta(Head, Body, Name, Arity, Module) + ( var(Head) -> + throw(error(instantiation_error, asserta/1)) + ; functor(Head, Name, Arity), + atom(Name), + Name \== '.' -> + ( '$head_is_dynamic'(Module, Head) -> + call_asserta(Head, Body, Name, Arity, Module) ; throw(error(permission_error(modify, static_procedure, Name/Arity), asserta/1)) ) ; throw(error(type_error(callable, Head), asserta/1)) @@ -718,166 +867,223 @@ module_asserta_clause(Head, Body, Module) :- asserta_clause(Head, Body) :- ( var(Head) -> throw(error(instantiation_error, asserta/1)) - ; functor(Head, Name, Arity), atom(Name), Name \== '.' -> - ( Name == (:), Arity =:= 2 -> - arg(1, Head, Module), - arg(2, Head, F), - module_asserta_clause(F, Body, Module) - ; '$no_such_predicate'(Head) -> call_asserta(Head, Body, Name, Arity) - ; '$head_is_dynamic'(Head) -> call_asserta(Head, Body, Name, Arity) + ; functor(Head, Name, Arity), + atom(Name), + Name \== '.' -> + ( Name == (:), + Arity =:= 2 -> + arg(1, Head, Module), + arg(2, Head, F), + module_asserta_clause(F, Body, Module) + ; '$head_is_dynamic'(user, Head) -> + call_asserta(Head, Body, Name, Arity, user) + ; '$no_such_predicate'(user, Head) -> + call_asserta(Head, Body, Name, Arity, user) ; throw(error(permission_error(modify, static_procedure, Name/Arity), asserta/1)) ) ; throw(error(type_error(callable, Head), asserta/1)) ). asserta(Clause) :- - ( Clause \= (_ :- _) -> Head = Clause, Body = true, asserta_clause(Head, Body) - ; Clause = (Head :- Body) -> asserta_clause(Head, Body) + ( Clause \= (_ :- _) -> + Head = Clause, + Body = true, + asserta_clause(Head, Body) + ; Clause = (Head :- Body) -> + asserta_clause(Head, Body) ). -call_module_assertz(Head, Body, Name, Arity, Module) :- - '$clause_body_is_valid'(Body), - functor(VarHead, Name, Arity), - findall((VarHead :- VarBody), clause(Module:VarHead, VarBody), Clauses), - '$module_assertz'((Head :- Body), Clauses, Name, Arity, Module). - -call_assertz(Head, Body, Name, Arity) :- - '$clause_body_is_valid'(Body), - functor(VarHead, Name, Arity), - findall((VarHead :- VarBody), clause(VarHead, VarBody), Clauses), - '$assertz'((Head :- Body), Clauses, Name, Arity). - module_assertz_clause(Head, Body, Module) :- - ( var(Head) -> throw(error(instantiation_error, assertz/1)) - ; functor(Head, Name, Arity), atom(Name), Name \== '.' -> - ( '$module_head_is_dynamic'(Head, Module) -> call_module_assertz(Head, Body, Name, Arity, Module) - ; throw(error(permission_error(modify, static_procedure, Name/Arity), assertz/1)) + ( var(Head) -> + throw(error(instantiation_error, assertz/1)) + ; functor(Head, Name, Arity), + atom(Name), + Name \== '.' -> + ( '$head_is_dynamic'(Module, Head) -> + call_assertz(Head, Body, Name, Arity, Module) + ; '$no_such_predicate'(Module, Head) -> + call_assertz(Head, Body, Name, Arity, Module) + ; throw(error(permission_error(modify, static_procedure, Name/Arity), + assertz/1)) ) ; throw(error(type_error(callable, Head), assertz/1)) ). + +call_assertz(Head, Body, Name, Arity, Module) :- + '$clause_body_is_valid'(Body), + functor(_, Name, Arity), + '$assertz'(Head, Body, Name, Arity, Module). + assertz_clause(Head, Body) :- - ( var(Head) -> throw(error(instantiation_error, assertz/1)) - ; functor(Head, Name, Arity), atom(Name), Name \== '.' -> - ( Name == (:), Arity =:= 2 -> - arg(1, Head, Module), - arg(2, Head, F), - module_assertz_clause(F, Body, Module) - ; '$no_such_predicate'(Head) -> - call_assertz(Head, Body, Name, Arity) - ; '$head_is_dynamic'(Head) -> - call_assertz(Head, Body, Name, Arity) - ; throw(error(permission_error(modify, static_procedure, Name/Arity), assertz/1)) + ( var(Head) -> + throw(error(instantiation_error, assertz/1)) + ; functor(Head, Name, Arity), + atom(Name), + Name \== '.' -> + ( Name == (:), + Arity =:= 2 -> + arg(1, Head, Module), + arg(2, Head, F), + module_assertz_clause(F, Body, Module) + ; '$head_is_dynamic'(user, Head) -> + call_assertz(Head, Body, Name, Arity, user) + ; '$no_such_predicate'(user, Head) -> + call_assertz(Head, Body, Name, Arity, user) + ; throw(error(permission_error(modify, static_procedure, Name/Arity), + assertz/1)) ) ; throw(error(type_error(callable, Head), assertz/1)) ). assertz(Clause) :- - ( Clause \= (_ :- _) -> Head = Clause, Body = true, assertz_clause(Head, Body) - ; Clause = (Head :- Body) -> assertz_clause(Head, Body) + ( Clause \= (_ :- _) -> + Head = Clause, + Body = true, + assertz_clause(Head, Body) + ; Clause = (Head :- Body) -> + assertz_clause(Head, Body) ). -first_match_index([Clause0 | Clauses], Clause1, N0, N) :- - ( Clause0 \= Clause1 -> - N1 is N0 + 1, - first_match_index(Clauses, Clause1, N1, N) - ; N0 = N, Clause0 = Clause1 - ). - -retract_clauses([Clause | Clauses0], Head, Body, Name, Arity) :- - functor(VarHead, Name, Arity), - findall((VarHead :- VarBody), clause(VarHead, VarBody), Clauses1), - first_match_index(Clauses1, (Head :- Body), 0, N), - ( Clauses0 == [] -> ! - ; true - ), - '$retract_clause'(Name, Arity, N, Clauses1). -retract_clauses([_ | Clauses0], Head, Body, Name, Arity) :- - retract_clauses(Clauses0, Head, Body, Name, Arity). - -call_retract(Head, Body, Name, Arity) :- - findall((Head :- Body), clause(Head, Body), Clauses), - retract_clauses(Clauses, Head, Body, Name, Arity). module_retract_clauses([Clause|Clauses0], Head, Body, Name, Arity, Module) :- functor(VarHead, Name, Arity), - findall((VarHead :- VarBody), clause(Module:VarHead, VarBody), Clauses1), - first_match_index(Clauses1, (Head :- Body), 0, N), + findall((VarHead :- VarBody), Module:'$clause'(VarHead, VarBody), Clauses1), + ( first_match_index(Clauses1, (Head :- Body), 0, N) -> + '$retract_clause'(Name, Arity, N, Module) + ; Clause = (Head :- Body) + ), ( Clauses0 == [] -> ! ; true - ), - '$module_retract_clause'(Name, Arity, N, Clauses1, Module). + ). + module_retract_clauses([_|Clauses0], Head, Body, Name, Arity, Module) :- module_retract_clauses(Clauses0, Head, Body, Name, Arity, Module). call_module_retract(Head, Body, Name, Arity, Module) :- - findall((Head :- Body), clause(Module:Head, Body), Clauses), + findall((Head :- Body), Module:'$clause'(Head, Body), Clauses), module_retract_clauses(Clauses, Head, Body, Name, Arity, Module). retract_module_clause(Head, Body, Module) :- - ( var(Head) -> throw(error(instantiation_error, retract/1)) - ; functor(Head, Name, Arity), atom(Name), Name \== '.' -> - ( '$module_head_is_dynamic'(Head, Module) -> - call_module_retract(Head, Body, Name, Arity, Module) - ; throw(error(permission_error(modify, static_procedure, Name/Arity), retract/1)) + ( var(Head) -> + throw(error(instantiation_error, retract/1)) + ; functor(Head, Name, Arity), + atom(Name), + Name \== '.' -> + ( '$head_is_dynamic'(Module, Head) -> + ( Module == user -> + call_retract(Head, Body, Name, Arity) + ; call_module_retract(Head, Body, Name, Arity, Module) + ) + ; throw(error(permission_error(modify, static_procedure, Name/Arity), retract/1)) ) ; throw(error(type_error(callable, Head), retract/1)) ). + +first_match_index([Clause | Clauses], Clause, N, N) :- + !. +first_match_index([_ | Clauses], Clause, N0, N) :- + N1 is N0 + 1, + first_match_index(Clauses, Clause, N1, N). + +retract_clauses([Clause | Clauses0], Head, Body, Name, Arity) :- + functor(VarHead, Name, Arity), + findall((VarHead :- VarBody), builtins:'$clause'(VarHead, VarBody), Clauses1), + ( first_match_index(Clauses1, (Head :- Body), 0, N) -> + '$retract_clause'(Name, Arity, N, user) + ; Clause = (Head :- Body) + ), + ( Clauses0 == [] -> ! + ; true + ). + +retract_clauses([_ | Clauses0], Head, Body, Name, Arity) :- + retract_clauses(Clauses0, Head, Body, Name, Arity). + +call_retract(Head, Body, Name, Arity) :- + findall((Head :- Body), builtins:'$clause'(Head, Body), Clauses), + retract_clauses(Clauses, Head, Body, Name, Arity). + retract_clause(Head, Body) :- - ( var(Head) -> throw(error(instantiation_error, retract/1)) - ; functor(Head, Name, Arity), atom(Name), Name \== '.' -> - ( Name == (:), Arity =:= 2 -> - arg(1, Head, Module), - arg(2, Head, F), - retract_module_clause(F, Body, Module) - ; '$head_is_dynamic'(Head) -> call_retract(Head, Body, Name, Arity) - ; '$no_such_predicate'(Head) -> '$fail' - ; throw(error(permission_error(modify, static_procedure, Name/Arity), retract/1)) + ( var(Head) -> + throw(error(instantiation_error, retract/1)) + ; functor(Head, Name, Arity), + atom(Name), + Name \== '.' -> + ( Name == (:), + Arity =:= 2 -> + arg(1, Head, Module), + arg(2, Head, F), + retract_module_clause(F, Body, Module) + ; '$head_is_dynamic'(user, Head) -> + call_retract(Head, Body, Name, Arity) + ; '$no_such_predicate'(user, Head) -> + '$fail' + ; throw(error(permission_error(modify, static_procedure, Name/Arity), retract/1)) ) ; throw(error(type_error(callable, Head), retract/1)) ). retract(Clause) :- - ( Clause \= (_ :- _) -> Head = Clause, Body = true, retract_clause(Head, Body) - ; Clause = (Head :- Body) -> retract_clause(Head, Body) + ( Clause \= (_ :- _) -> + Head = Clause, + Body = true, + retract_clause(Head, Body) + ; Clause = (Head :- Body) -> + retract_clause(Head, Body) ). + module_abolish(Pred, Module) :- - ( var(Pred) -> throw(error(instantiation_error), abolish/1) + ( var(Pred) -> + throw(error(instantiation_error), abolish/1) ; Pred = Name/Arity -> - ( var(Name) -> throw(error(instantiation_error, abolish/1)) + ( var(Name) -> + throw(error(instantiation_error, abolish/1)) ; integer(Arity) -> - ( \+ atom(Name) -> throw(error(type_error(atom, Name), abolish/1)) - ; Arity < 0 -> throw(error(domain_error(not_less_than_zero, Arity), abolish/1)) - ; max_arity(N), Arity > N -> throw(error(representation_error(max_arity), abolish/1)) - ; functor(Head, Name, Arity) -> - ( '$module_head_is_dynamic'(Head, Module) -> - '$abolish_module_clause'(Name, Arity, Module) - ; throw(error(permission_error(modify, static_procedure, Pred), abolish/1)) - ) - ) + ( \+ atom(Name) -> + throw(error(type_error(atom, Name), abolish/1)) + ; Arity < 0 -> + throw(error(domain_error(not_less_than_zero, Arity), abolish/1)) + ; max_arity(N), Arity > N -> + throw(error(representation_error(max_arity), abolish/1)) + ; functor(Head, Name, Arity) -> + ( '$head_is_dynamic'(Module, Head) -> + '$abolish_clause'(Module, Name, Arity) + ; throw(error(permission_error(modify, static_procedure, Pred), abolish/1)) + ) + ) ; throw(error(type_error(integer, Arity), abolish/1)) ) - ; throw(error(type_error(predicate_indicator, Module:Pred), abolish/1)) + ; throw(error(type_error(predicate_indicator, Module:Pred), abolish/1)) ). abolish(Pred) :- - ( var(Pred) -> throw(error(instantiation_error), abolish/1) - ; Pred = Module:InnerPred -> module_abolish(InnerPred, Module) + ( var(Pred) -> + throw(error(instantiation_error), abolish/1) + ; Pred = Module:InnerPred -> + module_abolish(InnerPred, Module) ; Pred = Name/Arity -> - ( var(Name) -> throw(error(instantiation_error, abolish/1)) - ; var(Arity) -> throw(error(instantiation_error, abolish/1)) + ( var(Name) -> + throw(error(instantiation_error, abolish/1)) + ; var(Arity) -> + throw(error(instantiation_error, abolish/1)) ; integer(Arity) -> - ( \+ atom(Name) -> throw(error(type_error(atom, Name), abolish/1)) - ; Arity < 0 -> throw(error(domain_error(not_less_than_zero, Arity), abolish/1)) - ; max_arity(N), Arity > N -> throw(error(representation_error(max_arity), abolish/1)) - ; functor(Head, Name, Arity) -> - ( '$no_such_predicate'(Head) -> true - ; '$head_is_dynamic'(Head) -> '$abolish_clause'(Name, Arity) - ; throw(error(permission_error(modify, static_procedure, Pred), abolish/1)) - ) - ) + ( \+ atom(Name) -> + throw(error(type_error(atom, Name), abolish/1)) + ; Arity < 0 -> + throw(error(domain_error(not_less_than_zero, Arity), abolish/1)) + ; max_arity(N), Arity > N -> + throw(error(representation_error(max_arity), abolish/1)) + ; functor(Head, Name, Arity) -> + ( '$head_is_dynamic'(user, Head) -> + '$abolish_clause'(user, Name, Arity) + ; '$no_such_predicate'(user, Head) -> + true + ; throw(error(permission_error(modify, static_procedure, Pred), abolish/1)) + ) + ) ; throw(error(type_error(integer, Arity), abolish/1)) ) ; throw(error(type_error(predicate_indicator, Pred), abolish/1)) @@ -889,6 +1095,7 @@ abolish(Pred) :- '$get_next_db_ref'(Ref, NextRef), '$iterate_db_refs'(NextRef, Name/Arity). + current_predicate(Pred) :- ( nonvar(Pred), Pred \= _ / _ -> throw(error(type_error(predicate_indicator, Pred), current_predicate/1)) @@ -909,8 +1116,10 @@ can_be_op_specifier(Spec) :- var(Spec). can_be_op_specifier(Spec) :- op_specifier(Spec). current_op(Priority, Spec, Op) :- - ( can_be_op_priority(Priority), can_be_op_specifier(Spec), error:can_be(atom, Op) - -> '$get_next_op_db_ref'(Ref, _), + ( can_be_op_priority(Priority), + can_be_op_specifier(Spec), + error:can_be(atom, Op) -> + '$get_next_op_db_ref'(Ref, _), '$iterate_op_db_refs'(Ref, Priority, Spec, Op) ). @@ -929,36 +1138,52 @@ op_priority(Priority) :- throw(error(domain_error(operator_priority, Priority))) % 8.14.3.3 h) ; true ). + op_priority(Priority) :- throw(error(type_error(integer, Priority), op/3)). % 8.14.3.3 d) -op_specifier(OpSpec) :- atom(OpSpec), +op_specifier(OpSpec) :- + atom(OpSpec), ( lists:member(OpSpec, [yfx, xfy, xfx, yf, fy, xf, fx]), ! ; throw(error(domain_error(operator_specifier, OpSpec), op/3)) % 8.14.3.3 i) ). -op_specifier(OpSpec) :- throw(error(type_error(atom, OpSpec), op/3)). -valid_op(Op) :- atom(Op), - ( Op == (',') -> throw(error(permission_error(modify, operator, (',')), op/3)) % 8.14.3.3 j), k). - ; Op == {} -> throw(error(permission_error(create, operator, {}), op/3)) - ; Op == [] -> throw(error(permission_error(create, operator, []), op/3)) +op_specifier(OpSpec) :- + throw(error(type_error(atom, OpSpec), op/3)). + +valid_op(Op) :- + atom(Op), + ( Op == (',') -> + throw(error(permission_error(modify, operator, (',')), op/3)) % 8.14.3.3 j), k). + ; Op == {} -> + throw(error(permission_error(create, operator, {}), op/3)) + ; Op == [] -> + throw(error(permission_error(create, operator, []), op/3)) ; true ). -op_(Priority, OpSpec, Op) :- '$op'(Priority, OpSpec, Op). +op_(Priority, OpSpec, Op) :- + '$op'(Priority, OpSpec, Op). op(Priority, OpSpec, Op) :- - ( var(Priority) -> throw(error(instantiation_error, op/3)) % 8.14.3.3 a) - ; var(OpSpec) -> throw(error(instantiation_error, op/3)) % 8.14.3.3 b) - ; var(Op) -> throw(error(instantiation_error, op/3)) % 8.14.3.3 c) - ; Op == '|' -> ( op_priority(Priority), op_specifier(OpSpec), - lists:member(OpSpec, [xfx, xfy, yfx]), ( Priority >= 1001 ; Priority == 0 ) - -> '$op'(Priority, OpSpec, Op) - ; throw(error(permission_error(create, operator, (|)), op/3))) % www.complang.tuwien.ac.at/ulrich/iso-prolog/conformity_testing#72 + ( var(Priority) -> + throw(error(instantiation_error, op/3)) % 8.14.3.3 a) + ; var(OpSpec) -> + throw(error(instantiation_error, op/3)) % 8.14.3.3 b) + ; var(Op) -> + throw(error(instantiation_error, op/3)) % 8.14.3.3 c) + ; Op == '|' -> + ( op_priority(Priority), + op_specifier(OpSpec), + lists:member(OpSpec, [xfx, xfy, yfx]), + ( Priority >= 1001 ; Priority == 0 ) + -> '$op'(Priority, OpSpec, Op) + ; throw(error(permission_error(create, operator, (|)), op/3))) % www.complang.tuwien.ac.at/ulrich/iso-prolog/conformity_testing#72 ; valid_op(Op), op_priority(Priority), op_specifier(OpSpec) -> '$op'(Priority, OpSpec, Op) ; list_of_op_atoms(Op), op_priority(Priority), op_specifier(OpSpec) -> - lists:maplist(op_(Priority, OpSpec), Op), ! + lists:maplist(builtins:op_(Priority, OpSpec), Op), + ! ; throw(error(type_error(list, Op), op/3)) % 8.14.3.3 f) ). @@ -973,41 +1198,54 @@ halt(N) :- ). atom_length(Atom, Length) :- - ( var(Atom) -> throw(error(instantiation_error, atom_length/2)) % 8.16.1.3 a) - ; atom(Atom) -> ( var(Length) -> '$atom_length'(Atom, Length) - ; integer(Length), Length >= 0 -> '$atom_length'(Atom, Length) - ; integer(Length) -> throw(error(domain_error(not_less_than_zero, Length), atom_length/2)) - % 8.16.1.3 d) - ; throw(error(type_error(integer, Length), atom_length/2)) % 8.16.1.3 c) - ) + ( var(Atom) -> + throw(error(instantiation_error, atom_length/2)) % 8.16.1.3 a) + ; atom(Atom) -> + ( var(Length) -> + '$atom_length'(Atom, Length) + ; integer(Length), Length >= 0 -> + '$atom_length'(Atom, Length) + ; integer(Length) -> + throw(error(domain_error(not_less_than_zero, Length), atom_length/2)) + % 8.16.1.3 d) + ; throw(error(type_error(integer, Length), atom_length/2)) % 8.16.1.3 c) + ) ; throw(error(type_error(atom, Atom), atom_length/2)) % 8.16.1.3 b) ). atom_chars(Atom, List) :- '$skip_max_list'(_, -1, List, Tail), - ( ( Tail == [] ; var(Tail) ) -> true + ( ( Tail == [] ; var(Tail) ) -> + true ; throw(error(type_error(list, List), atom_chars/2)) ), ( var(Atom) -> - ( var(Tail) -> throw(error(instantiation_error, atom_chars/2)) - ; ground(List) -> '$atom_chars'(Atom, List) + ( var(Tail) -> + throw(error(instantiation_error, atom_chars/2)) + ; ground(List) -> + '$atom_chars'(Atom, List) ; throw(error(instantiation_error, atom_chars/2)) ) - ; atom(Atom) -> '$atom_chars'(Atom, List) + ; atom(Atom) -> + '$atom_chars'(Atom, List) ; throw(error(type_error(atom, Atom), atom_chars/2)) ). atom_codes(Atom, List) :- '$skip_max_list'(_, -1, List, Tail), - ( ( Tail == [] ; var(Tail) ) -> true + ( ( Tail == [] ; var(Tail) ) -> + true ; throw(error(type_error(list, List), atom_codes/2)) ), ( var(Atom) -> - ( var(Tail) -> throw(error(instantiation_error, atom_codes/2)) - ; ground(List), Tail == [] -> '$atom_codes'(Atom, List) + ( var(Tail) -> + throw(error(instantiation_error, atom_codes/2)) + ; ground(List), Tail == [] -> + '$atom_codes'(Atom, List) ; throw(error(instantiation_error, atom_codes/2)) ) - ; atom(Atom) -> '$atom_codes'(Atom, List) + ; atom(Atom) -> + '$atom_codes'(Atom, List) ; throw(error(type_error(atom, Atom), atom_codes/2)) ). @@ -1016,18 +1254,19 @@ atom_concat(Atom_1, Atom_2, Atom_12) :- error:can_be(atom, Atom_2), error:can_be(atom, Atom_12), ( var(Atom_1) -> - ( var(Atom_12) -> throw(error(instantiation_error, atom_concat/3)) + ( var(Atom_12) -> + throw(error(instantiation_error, atom_concat/3)) ; atom_chars(Atom_12, Atom_12_Chars), - lists:append(BeforeChars, AfterChars, Atom_12_Chars), - atom_chars(Atom_1, BeforeChars), - atom_chars(Atom_2, AfterChars) + lists:append(BeforeChars, AfterChars, Atom_12_Chars), + atom_chars(Atom_1, BeforeChars), + atom_chars(Atom_2, AfterChars) ) ; var(Atom_2) -> ( var(Atom_12) -> throw(error(instantiation_error, atom_concat/3)) ; atom_chars(Atom_1, Atom_1_Chars), - atom_chars(Atom_12, Atom_12_Chars), - lists:append(Atom_1_Chars, Atom_2_Chars, Atom_12_Chars), - atom_chars(Atom_2, Atom_2_Chars) + atom_chars(Atom_12, Atom_12_Chars), + lists:append(Atom_1_Chars, Atom_2_Chars, Atom_12_Chars), + atom_chars(Atom_2, Atom_2_Chars) ) ; atom_chars(Atom_1, Atom_1_Chars), atom_chars(Atom_2, Atom_2_Chars), @@ -1041,9 +1280,12 @@ sub_atom(Atom, Before, Length, After, Sub_atom) :- error:can_be(integer, Before), error:can_be(integer, Length), error:can_be(integer, After), - ( integer(Before), Before < 0 -> throw(error(domain_error(not_less_than_zero, Before), sub_atom/5)) - ; integer(Length), Length < 0 -> throw(error(domain_error(not_less_than_zero, Length), sub_atom/5)) - ; integer(After), After < 0 -> throw(error(domain_error(not_less_than_zero, After), sub_atom/5)) + ( integer(Before), Before < 0 -> + throw(error(domain_error(not_less_than_zero, Before), sub_atom/5)) + ; integer(Length), Length < 0 -> + throw(error(domain_error(not_less_than_zero, Length), sub_atom/5)) + ; integer(After), After < 0 -> + throw(error(domain_error(not_less_than_zero, After), sub_atom/5)) ; atom_chars(Atom, AtomChars), lists:append(BeforeChars, LengthAndAfterChars, AtomChars), lists:append(LengthChars, AfterChars, LengthAndAfterChars), @@ -1055,11 +1297,14 @@ sub_atom(Atom, Before, Length, After, Sub_atom) :- char_code(Char, Code) :- ( var(Char) -> - ( var(Code) -> throw(error(instantiation_error, char_code/2)) - ; integer(Code) -> '$char_code'(Char, Code) + ( var(Code) -> + throw(error(instantiation_error, char_code/2)) + ; integer(Code) -> + '$char_code'(Char, Code) ; throw(error(type_error(integer, Code), char_code/2)) ) - ; atom_length(Char, 1) -> '$char_code'(Char, Code) + ; atom_length(Char, 1) -> + '$char_code'(Char, Code) ; throw(error(type_error(character, Char), char_code/2)) ). @@ -1081,7 +1326,8 @@ must_be_number(N, _) :- ), !. must_be_number(N, PI) :- - ( nonvar(N) -> throw(error(type_error(number, N), PI)) + ( nonvar(N) -> + throw(error(type_error(number, N), PI)) ; throw(error(instantiation_error, PI)) ). @@ -1144,7 +1390,7 @@ set_output(S) :- parse_stream_options(Options, OptionValues, Stub) :- DefaultOptions = [alias-[], eof_action-eof_code, reposition-false, type-text], - parse_options_list(Options, parse_stream_options_, DefaultOptions, OptionValues, Stub). + parse_options_list(Options, builtins:parse_stream_options_, DefaultOptions, OptionValues, Stub). parse_stream_options_(type(Type), type-Type) :- @@ -1191,7 +1437,7 @@ open(SourceSink, Mode, Stream, StreamOptions) :- parse_close_options(Options, OptionValues, Stub) :- DefaultOptions = [force-false], - parse_options_list(Options, parse_close_options_, DefaultOptions, OptionValues, Stub). + parse_options_list(Options, builtins:parse_close_options_, DefaultOptions, OptionValues, Stub). parse_close_options_(force(Force), force-Force) :- ( nonvar(Force), lists:member(Force, [true, false]), ! @@ -1282,16 +1528,21 @@ peek_char(S, C) :- '$peek_char'(S, C). +is_stream_position(position_and_lines_read(P, L)) :- + ( var(P) ; integer(P), P >= 0 ), + ( var(L) ; integer(L), L >= 0 ), + !. + +check_stream_property(D, direction, D) :- + ( var(D) -> true ; lists:member(D, [input, output, input_output]), ! ). check_stream_property(file_name(F), file_name, F) :- ( var(F) -> true ; atom(F) ). check_stream_property(mode(M), mode, M) :- ( var(M) -> true ; lists:member(M, [read, write, append]) ). -check_stream_property(D, direction, D) :- - ( var(D) -> true ; lists:member(D, [input, output, input_output]), ! ). check_stream_property(alias(A), alias, A) :- ( var(A) -> true ; atom(A) ). check_stream_property(position(P), position, P) :- - ( var(P) -> true ; integer(P), P >= 0 ). + ( var(P) -> true ; is_stream_position(P)). check_stream_property(end_of_stream(E), end_of_stream, E) :- ( var(E) -> true ; lists:member(E, [not, at, past]) ). check_stream_property(eof_action(A), eof_action, A) :- @@ -1342,8 +1593,8 @@ at_end_of_stream :- set_stream_position(S_or_a, Position) :- ( var(Position) -> throw(error(instantiation_error, set_stream_position/2)) - ; integer(Position), Position >= 0 -> - true + ; Position = position_and_lines_read(P, _), + is_stream_position(Position) -> + '$set_stream_position'(S_or_a, P) ; throw(error(domain_error(stream_position, Position))) - ), - '$set_stream_position'(S_or_a, Position). + ). diff --git a/src/lib/charsio.pl b/src/lib/charsio.pl index 05681bc3..3f30ec17 100644 --- a/src/lib/charsio.pl +++ b/src/lib/charsio.pl @@ -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) diff --git a/src/lib/clpb.pl b/src/lib/clpb.pl index 0b802a46..0310e775 100644 --- a/src/lib/clpb.pl +++ b/src/lib/clpb.pl @@ -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, diff --git a/src/lib/clpz.pl b/src/lib/clpz.pl index a4f66256..3012af78 100644 --- a/src/lib/clpz.pl +++ b/src/lib/clpz.pl @@ -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. diff --git a/src/lib/cont.pl b/src/lib/cont.pl index 8dccdc5e..a5125d96 100644 --- a/src/lib/cont.pl +++ b/src/lib/cont.pl @@ -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'. diff --git a/src/lib/dcgs.pl b/src/lib/dcgs.pl index 942f6b8e..07b82b95 100644 --- a/src/lib/dcgs.pl +++ b/src/lib/dcgs.pl @@ -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 )) :- diff --git a/src/lib/debug.pl b/src/lib/debug.pl index bc9f9df8..ab84f15b 100644 --- a/src/lib/debug.pl +++ b/src/lib/debug.pl @@ -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) ) ). diff --git a/src/lib/diag.pl b/src/lib/diag.pl index d135238b..0fa3896f 100644 --- a/src/lib/diag.pl +++ b/src/lib/diag.pl @@ -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)) + ). diff --git a/src/lib/dif.pl b/src/lib/dif.pl index bb92979a..9c3b8ed8 100644 --- a/src/lib/dif.pl +++ b/src/lib/dif.pl @@ -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). diff --git a/src/lib/error.pl b/src/lib/error.pl index 7e2189c4..99592790 100644 --- a/src/lib/error.pl +++ b/src/lib/error.pl @@ -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) diff --git a/src/lib/format.pl b/src/lib/format.pl index 540bdb9f..fc4c49bb 100644 --- a/src/lib/format.pl +++ b/src/lib/format.pl @@ -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). diff --git a/src/lib/freeze.pl b/src/lib/freeze.pl index 8ab1de9b..c005672f 100644 --- a/src/lib/freeze.pl +++ b/src/lib/freeze.pl @@ -3,6 +3,8 @@ :- use_module(library(atts)). :- use_module(library(dcgs)). +:- meta_predicate freeze(?, 0). + :- attribute frozen/1. verify_attributes(Var, Other, Goals) :- diff --git a/src/lib/http/http_server.pl b/src/lib/http/http_server.pl index 9e6d504b..72657c35 100644 --- a/src/lib/http/http_server.pl +++ b/src/lib/http/http_server.pl @@ -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", []) diff --git a/src/lib/iso_ext.pl b/src/lib/iso_ext.pl index e5ba94c1..7d580497 100644 --- a/src/lib/iso_ext.pl +++ b/src/lib/iso_ext.pl @@ -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). diff --git a/src/lib/lambda.pl b/src/lib/lambda.pl new file mode 100644 index 00000000..56332255 --- /dev/null +++ b/src/lib/lambda.pl @@ -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)). + +/** 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),_)). diff --git a/src/lib/lists.pl b/src/lib/lists.pl index a1acdb6d..0a799672 100644 --- a/src/lib/lists.pl +++ b/src/lib/lists.pl @@ -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). diff --git a/src/lib/ops_and_meta_predicates.pl b/src/lib/ops_and_meta_predicates.pl new file mode 100644 index 00000000..f84d0fd6 --- /dev/null +++ b/src/lib/ops_and_meta_predicates.pl @@ -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, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). diff --git a/src/lib/pairs.pl b/src/lib/pairs.pl index adcfb138..d8023856 100644 --- a/src/lib/pairs.pl +++ b/src/lib/pairs.pl @@ -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). diff --git a/src/lib/pio.pl b/src/lib/pio.pl index 89dfc566..1df9a796 100644 --- a/src/lib/pio.pl +++ b/src/lib/pio.pl @@ -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, []). diff --git a/src/lib/reif.pl b/src/lib/reif.pl index 0e958356..092f93ec 100644 --- a/src/lib/reif.pl +++ b/src/lib/reif.pl @@ -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) ). diff --git a/src/lib/sockets.pl b/src/lib/sockets.pl index 108ac9b9..dd386a3b 100644 --- a/src/lib/sockets.pl +++ b/src/lib/sockets.pl @@ -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) -> diff --git a/src/lib/tabling.pl b/src/lib/tabling.pl index 703da8e3..2163c791 100644 --- a/src/lib/tabling.pl +++ b/src/lib/tabling.pl @@ -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, diff --git a/src/lib/tabling/batched_worklist.pl b/src/lib/tabling/batched_worklist.pl index 99f0619b..8a8b4117 100644 --- a/src/lib/tabling/batched_worklist.pl +++ b/src/lib/tabling/batched_worklist.pl @@ -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(_, _, []). + /** Tabling Worklist management A batched worklist: a worklist that clusters suspensions and answers as diff --git a/src/lib/tabling/global_worklist.pl b/src/lib/tabling/global_worklist.pl index 19502a92..55c437f1 100644 --- a/src/lib/tabling/global_worklist.pl +++ b/src/lib/tabling/global_worklist.pl @@ -13,6 +13,8 @@ :- attribute table_global_worklist/1. +verify_attributes(_, _, []). + put_new_global_worklist :- ( bb_get(table_global_worklist_initialized, _) -> true diff --git a/src/lib/tabling/table_data_structure.pl b/src/lib/tabling/table_data_structure.pl index 0ce989da..69a057e6 100644 --- a/src/lib/tabling/table_data_structure.pl +++ b/src/lib/tabling/table_data_structure.pl @@ -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: diff --git a/src/lib/tabling/table_link_manager.pl b/src/lib/tabling/table_link_manager.pl index ec88f105..c346ea10 100644 --- a/src/lib/tabling/table_link_manager.pl +++ b/src/lib/tabling/table_link_manager.pl @@ -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 diff --git a/src/lib/tabling/trie.pl b/src/lib/tabling/trie.pl index 2e545524..cd855b92 100644 --- a/src/lib/tabling/trie.pl +++ b/src/lib/tabling/trie.pl @@ -47,6 +47,8 @@ :- attribute maybe_just/1, children/1. +verify_attributes(_, _, []). + % Implementation of a prefix tree, a.k.a. trie % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/lib/tabling/wrapper.pl b/src/lib/tabling/wrapper.pl index c66be996..d2d13901 100644 --- a/src/lib/tabling/wrapper.pl +++ b/src/lib/tabling/wrapper.pl @@ -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). diff --git a/src/lib/time.pl b/src/lib/time.pl index 30ec0f45..13df2e42 100644 --- a/src/lib/time.pl +++ b/src/lib/time.pl @@ -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, diff --git a/src/lib/uuid.pl b/src/lib/uuid.pl new file mode 100644 index 00000000..affa3b68 --- /dev/null +++ b/src/lib/uuid.pl @@ -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)). diff --git a/src/loader.pl b/src/loader.pl new file mode 100644 index 00000000..8a409ce2 --- /dev/null +++ b/src/loader.pl @@ -0,0 +1,1404 @@ + +:- module(loader, [consult/1, + expand_goal/3, + expand_term/2, + file_load/2, + load/1, + predicate_property/2, + prolog_load_context/2, + strip_module/3, + use_module/1, + use_module/2 + ]). + + +:- use_module(library(error)). +:- use_module(library(lists)). +:- use_module(library(pairs)). + + +'$print_message_and_fail'(Error) :- + ( Error = error(existence_error(procedure, Expansion), Expansion) -> + ( ( Expansion = goal_expansion/2 + ; Expansion = term_expansion/2 + ) -> + true + ; write('caught: '), + writeq(Error), + nl + ) + ; write('caught: '), + writeq(Error), + nl + ), + '$fail'. + +expand_term(Term, ExpandedTerm) :- + ( catch('$call'(user:term_expansion(Term, ExpandedTerm0)), + E, + '$call'(loader:'$print_message_and_fail'(E))) -> + ( var(ExpandedTerm0) -> + error:instantiation_error(term_expansion/2) + ; ExpandedTerm0 = [_|_] -> + term_expansion_list(ExpandedTerm0, ExpandedTerm, []) + ; expand_term(ExpandedTerm0, ExpandedTerm) + ) + ; Term = ExpandedTerm + ). + +term_expansion_list([], ExpandedTerms, ExpandedTerms). +term_expansion_list([Term|Terms], ExpandedTermsHead, ExpandedTermsTail) :- + expand_term(Term, ExpandedTerm0), + ( var(ExpandedTerm0) -> + error:instantiation_error(term_expansion/2) + ; ExpandedTerm0 = [_|_] -> + term_expansion_list(ExpandedTerm0, ExpandedTermsHead, ExpandedTerms0Tail), + term_expansion_list(Terms, ExpandedTerms0Tail, ExpandedTermsTail) + ; ExpandedTermsHead = [ExpandedTerm0 | ExpandedTerms0Tail], + term_expansion_list(Terms, ExpandedTerms0Tail, ExpandedTermsTail) + ). + + +goal_expansion(Goal, Module, ExpandedGoal) :- + ( atom(Module), + catch('$call'(Module:goal_expansion(Goal, ExpandedGoal0)), + E, + '$call'(loader:'$print_message_and_fail'(E))) -> + ( var(ExpandedGoal0) -> + error:instantiation_error(goal_expansion/2) + ; goal_expansion(ExpandedGoal0, Module, ExpandedGoal) + ) + ; Goal = ExpandedGoal + ). + + + +create_file_load_context(Stream, Path, Evacuable) :- + '$push_load_context'(Stream, Path), + '$push_load_state_payload'(Evacuable). + +create_load_context(Stream, Evacuable) :- + '$push_load_context'(Stream, ''), + '$push_load_state_payload'(Evacuable). + +unload_evacuable(Evacuable) :- + '$pop_load_state_payload'(Evacuable), + '$pop_load_context'. + +run_initialization_goals :- + prolog_load_context(module, Module), + ( predicate_property(Module:'$initialization_goals'(_), dynamic) -> + findall(Goal, '$call'(builtins:retract(Module:'$initialization_goals'(Goal))), Goals), + ( maplist(Module:call, Goals) -> + true + ; true %% initialization goals can fail without thwarting the load. + ) + ; true + ). + +file_load(Stream, Path) :- + file_load(Stream, Path, _), + false. %% Clear the heap. +file_load(_, _). + +file_load(Stream, Path, Evacuable) :- + create_file_load_context(Stream, Path, Evacuable), + catch(loader:load_loop(Stream, Evacuable), + E, + builtins:(loader:unload_evacuable(Evacuable), + loader:'$print_message_and_fail'(E), + builtins:throw(E))), + run_initialization_goals, + '$pop_load_context'. + + +load(Stream) :- + create_load_context(Stream, Evacuable), + catch(loader:load_loop(Stream, Evacuable), + E, + builtins:(loader:unload_evacuable(Evacuable), + loader:'$print_message_and_fail'(E), + builtins:throw(E))), + run_initialization_goals, + '$pop_load_context', + false. %% Clear the heap. +load(_). + + +print_comma_separated_list([VN=_]) :- + write(VN), + !. +print_comma_separated_list([VN=_, VNEq | VNEqs]) :- + write(VN), + write(', '), + print_comma_separated_list([VNEq | VNEqs]). + + +filter_anonymous_vars([], []). +filter_anonymous_vars([VN=V | VNEqs0], VNEqs) :- + ( atom_concat('_', _, VN) -> + filter_anonymous_vars(VNEqs0, VNEqs) + ; VNEqs = [VN=V | VNEqs1], + filter_anonymous_vars(VNEqs0, VNEqs1) + ). + +warn_about_singletons([], _). +warn_about_singletons([Singleton|Singletons], LinesRead) :- + ( filter_anonymous_vars([Singleton|Singletons], VarEqs), + VarEqs \== [] -> + write('Warning: singleton variables '), + print_comma_separated_list(VarEqs), + write(' at line '), + write(LinesRead), + write(' of '), + prolog_load_context(file, File), + write(File), + nl + ; true + ). + + +load_loop(Stream, Evacuable) :- + ( '$devour_whitespace'(Stream) -> + stream_property(Stream, position(position_and_lines_read(_, LinesRead))), + read_term(Stream, Term, [singletons(Singletons)]) + ; Term = end_of_file + ), + ( Term == end_of_file -> + close(Stream), + '$conclude_load'(Evacuable) + ; var(Term) -> + instantiation_error(load/1) + ; warn_about_singletons(Singletons, LinesRead), + compile_term(Term, Evacuable), + load_loop(Stream, Evacuable) + ). + + +compile_term(Term, Evacuable) :- + expand_terms_and_goals(Term, Terms), + !, + ( var(Terms) -> + instantiation_error(load/1) + ; Terms = [_|_] -> + compile_dispatch_or_clause_on_list(Terms, Evacuable) + ; compile_dispatch_or_clause(Terms, Evacuable) + ). + + +inner_meta_specs(0, HeadArg, InnerHeadArgs, InnerMetaSpecs) :- + !, + predicate_property(HeadArg, meta_predicate(InnerMetaSpecs)), + HeadArg =.. [_ | InnerHeadArgs]. + +inner_meta_specs(N, HeadArg, InnerHeadArgs, InnerMetaSpecs) :- + integer(N), + N >= 0, + HeadArg =.. [Functor | InnerHeadArgs], + length(InnerHeadArgs1, N), + append(InnerHeadArgs, InnerHeadArgs1, InnerHeadArgs0), + CompleteHeadArg =.. [Functor | InnerHeadArgs0], + predicate_property(CompleteHeadArg, meta_predicate(InnerMetaSpecs)). + + +module_expanded_head_variables_([], _, HeadVars, HeadVars). +module_expanded_head_variables_([HeadArg | HeadArgs], [MetaSpec | MetaSpecs], HeadVars, HeadVars0) :- + ( ( MetaSpec == (:) + ; integer(MetaSpec), + MetaSpec >= 0 + ) -> + ( var(HeadArg) -> + HeadVars = [HeadArg-HeadArg | HeadVars1], + module_expanded_head_variables_(HeadArgs, MetaSpecs, HeadVars1, HeadVars0) + ; inner_meta_specs(MetaSpec, HeadArg, InnerHeadArgs, InnerMetaSpecs) -> + module_expanded_head_variables_(InnerHeadArgs, InnerMetaSpecs, HeadVars, HeadVars1), + module_expanded_head_variables_(HeadArgs, MetaSpecs, HeadVars1, HeadVars0) + ; module_expanded_head_variables_(HeadArgs, MetaSpecs, HeadVars, HeadVars0) + ) + ; module_expanded_head_variables_(HeadArgs, MetaSpecs, HeadVars, HeadVars0) + ). + +module_expanded_head_variables(Head, HeadVars) :- + ( var(Head) -> + instantiation_error(load/1) + ; predicate_property(Head, meta_predicate(MetaSpecs)), + Head =.. [_ | HeadArgs] -> + module_expanded_head_variables_(HeadArgs, MetaSpecs, HeadVars, []) + ; HeadVars = [] + ). + + +expand_term_goals(Terms0, Terms) :- + ( Terms0 = (Head1 :- Body0) -> + ( var(Head1) -> + instantiation_error(load/1) + ; Head1 = Module:Head2 -> + ( atom(Module) -> + prolog_load_context(module, Target), + module_expanded_head_variables(Head2, HeadVars), + expand_goal(Body0, Target, Body1, HeadVars), + Terms = (Module:Head2 :- Body1) + ; type_error(atom, Module, load/1) + ) + ; prolog_load_context(module, Target), + module_expanded_head_variables(Head1, HeadVars), + expand_goal(Body0, Target, Body1, HeadVars), + Terms = (Head1 :- Body1) + ) + ; Terms = Terms0 + ). + + +expand_terms_and_goals(Term, Terms) :- + expand_term(Term, Terms0), + ( var(Terms0) -> + instantiation_error(load/1) + ; Terms0 = [_|_] -> + maplist(loader:expand_term_goals, Terms0, Terms) + ; expand_term_goals(Terms0, Terms) + ). + + +compile_dispatch_or_clause_on_list([], Evacuable). +compile_dispatch_or_clause_on_list([Term | Terms], Evacuable) :- + compile_dispatch_or_clause(Term, Evacuable), + compile_dispatch_or_clause_on_list(Terms, Evacuable). + + +compile_dispatch_or_clause(Term, Evacuable) :- + ( var(Term) -> + instantiation_error(load/1) + ; compile_dispatch(Term, Evacuable) -> + true + ; compile_clause(Term, Evacuable) + ). + + +compile_dispatch((:- Declaration), Evacuable) :- + ( var(Declaration) -> + instantiation_error(load/1) + ; compile_declaration(Declaration, Evacuable) + ). +compile_dispatch(term_expansion(Term, Terms), Evacuable) :- + '$add_term_expansion_clause'(term_expansion(Term, Terms), Evacuable). +compile_dispatch((term_expansion(Term, Terms) :- Body), Evacuable) :- + '$add_term_expansion_clause'((term_expansion(Term, Terms) :- Body), Evacuable). +compile_dispatch(user:term_expansion(Term, Terms), Evacuable) :- + '$add_term_expansion_clause'(term_expansion(Term, Terms), Evacuable). +compile_dispatch((user:term_expansion(Term, Terms) :- Body), Evacuable) :- + '$add_term_expansion_clause'((term_expansion(Term, Terms) :- Body), Evacuable). +compile_dispatch(goal_expansion(Term, Terms), Evacuable) :- + prolog_load_context(module, user), + '$add_goal_expansion_clause'(user, goal_expansion(Term, Terms), Evacuable). +compile_dispatch((goal_expansion(Term, Terms) :- Body), Evacuable) :- + prolog_load_context(module, user), + '$add_goal_expansion_clause'(user, (goal_expansion(Term, Terms) :- Body), Evacuable). +compile_dispatch(user:goal_expansion(Term, Terms), Evacuable) :- + '$add_goal_expansion_clause'(user, goal_expansion(Term, Terms), Evacuable). +compile_dispatch((user:goal_expansion(Term, Terms) :- Body), Evacuable) :- + '$add_goal_expansion_clause'(user, (goal_expansion(Term, Terms) :- Body), Evacuable). + +remove_module(Module, Evacuable) :- + ( nonvar(Module), + Module = library(ModuleName), + atom(ModuleName), + atom \== [] -> + '$remove_module_exports'(ModuleName, Evacuable) + ; atom(Module), + atom \== [] -> + '$remove_module_exports'(Module, Evacuable) + ; domain_error(module_specifier, Module, use_module/2) + ). + + +compile_declaration(use_module(Module), Evacuable) :- + use_module(Module, [], Evacuable). +compile_declaration(use_module(Module, Exports), Evacuable) :- + ( Exports == [] -> + remove_module(Module, Evacuable) + ; use_module(Module, Exports, Evacuable) + ). +compile_declaration(module(Module, Exports), Evacuable) :- + ( atom(Module) -> + '$declare_module'(Module, Exports, Evacuable) + ; type_error(atom, Module, load/1) + ). +compile_declaration(dynamic(Name/Arity), Evacuable) :- + !, + must_be(atom, Name), + must_be(integer, Arity), + prolog_load_context(module, Module), + '$add_dynamic_predicate'(Module, Name, Arity, Evacuable). +compile_declaration(dynamic(Module:Name/Arity), Evacuable) :- + must_be(atom, Module), + must_be(atom, Name), + must_be(integer, Arity), + '$add_dynamic_predicate'(Module, Name, Arity, Evacuable). +compile_declaration(multifile(Name/Arity), Evacuable) :- + !, + must_be(atom, Name), + must_be(integer, Arity), + prolog_load_context(module, Module), + '$add_multifile_predicate'(Module, Name, Arity, Evacuable). +compile_declaration(multifile(Module:Name/Arity), Evacuable) :- + must_be(atom, Module), + must_be(atom, Name), + must_be(integer, Arity), + '$add_multifile_predicate'(Module, Name, Arity, Evacuable). +compile_declaration(discontiguous(Name/Arity), Evacuable) :- + !, + must_be(atom, Name), + must_be(integer, Arity), + prolog_load_context(module, Module), + '$add_discontiguous_predicate'(Module, Name, Arity, Evacuable). +compile_declaration(discontiguous(Module:Name/Arity), Evacuable) :- + must_be(atom, Module), + must_be(atom, Name), + must_be(integer, Arity), + '$add_discontiguous_predicate'(Module, Name, Arity, Evacuable). +compile_declaration(initialization(Goal), Evacuable) :- + prolog_load_context(module, Module), + assertz(Module:'$initialization_goals'(Goal)). +compile_declaration(set_prolog_flag(Flag, Value), _) :- + set_prolog_flag(Flag, Value). +compile_declaration(non_counted_backtracking(Name/Arity), Evacuable) :- + must_be(atom, Name), + must_be(integer, Arity), + ( Arity >= 0 -> + '$add_non_counted_backtracking'(Name, Arity, Evacuable) + ; domain_error(not_less_than_zero, Arity, load/1) + ). + + +compile_clause((Target:Head :- Body), Evacuable) :- + !, + functor(Head, Name, Arity), + ( '$is_consistent_with_term_queue'(Target, Name, Arity, Evacuable) -> + '$scoped_clause_to_evacuable'(Target, (Head :- Body), Evacuable) + ; '$flush_term_queue'(Evacuable), + compile_term((Target:Head :- Body), Evacuable) + ). +compile_clause(Target:Head, Evacuable) :- + !, + functor(Head, Name, Arity), + ( '$is_consistent_with_term_queue'(Target, Name, Arity, Evacuable) -> + '$scoped_clause_to_evacuable'(Target, Head, Evacuable) + ; '$flush_term_queue'(Evacuable), + compile_term(Target:Head, Evacuable) + ). +compile_clause((Head :- Body), Evacuable) :- + !, + prolog_load_context(module, Target), + functor(Head, Name, Arity), + ( '$is_consistent_with_term_queue'(Target, Name, Arity, Evacuable) -> + '$clause_to_evacuable'((Head :- Body), Evacuable) + ; '$flush_term_queue'(Evacuable), + compile_term((Head :- Body), Evacuable) + ). +compile_clause(Head, Evacuable) :- + prolog_load_context(module, Target), + functor(Head, Name, Arity), + ( '$is_consistent_with_term_queue'(Target, Name, Arity, Evacuable) -> + '$clause_to_evacuable'(Head, Evacuable) + ; '$flush_term_queue'(Evacuable), + compile_term(Head, Evacuable) + ). + + +prolog_load_context(source, Source) :- + %% The absolute path name of the file being compiled. During + %% loading of a PO file, the corresponding source file name is + %% returned. + '$prolog_lc_source'(Source). +prolog_load_context(file, File) :- + %% Outside included files (see Include Declarations) this is the + %% same as the source key. In included files this is the absolute + %% path name of the file being included. + '$prolog_lc_file'(File). +prolog_load_context(directory, Dir) :- + %% The absolute path name of the directory of the file being + %% compiled/loaded. In included files this is the directory of the + %% file being included. + '$prolog_lc_dir'(Dir). +prolog_load_context(module, Module) :- + %% The source module (see ref-mod-mne). This is useful for example + %% if you are defining clauses for user:term_expansion/6 and need + %% to access the source module at compile time. + '$prolog_lc_module'(Module). +prolog_load_context(stream, Stream) :- + %% The stream being compiled or loaded from. + '$prolog_lc_stream'(Stream). +prolog_load_context(term_position, TermPosition) :- + %% TermPosition represents the stream position of the last term read. + '$prolog_lc_stream'(Stream), + stream_property(Stream, position(TermPosition)). + + +consult(Item) :- + ( atom(Item) -> use_module(Item) + ; type_error(atom, Item, consult/1) + ). + + +use_module(Module) :- + '$push_load_state_payload'(Evacuable), + use_module(Module, [], Evacuable). + +use_module(Module, Exports) :- + '$push_load_state_payload'(Evacuable), + ( Exports == [] -> + remove_module(Module, Evacuable) + ; use_module(Module, Exports, Evacuable) + ). + + +%% If use_module is invoked in an existing load context, use its +%% directory. Otherwise, use the relative path of Path. + +load_context_path(Module, Path) :- + ( prolog_load_context(directory, CurrentDir) -> + % Rust's Path module never ends a directory path with '/', so + % add one here. + atom_concat(CurrentDir, '/', CurrentDirSlashed), + atom_concat(CurrentDirSlashed, Module, Path) + ; Module = Path + ). + +path_atom(Dir/File, Path) :- + must_be(atom, File), + !, + path_atom(Dir, DirPath), + foldl(builtins:atom_concat, ['/', DirPath], File, Path). +path_atom(Path, Path) :- + must_be(atom, Path). + +% Try to open the file with the Path name as given; if that fails, +% append '.pl' and try again. +open_file(Path, Stream) :- + ( atom_concat(_, '.pl', Path) -> + open(Path, read, Stream) + ; catch(open(Path, read, Stream), + error(existence_error(source_sink, Path), _), + ( atom_concat(Path, '.pl', ExtendedPath), + open(ExtendedPath, read, Stream) ) + ) + ). + +use_module(Module, Exports, Evacuable) :- + ( var(Module) -> + instantiation_error(load/1) + ; Module = library(Library) -> + ( path_atom(Library, LibraryPath) -> + ( '$load_compiled_library'(LibraryPath, Exports, Evacuable) -> + true + ; '$load_library_as_stream'(LibraryPath, Stream, Path), + file_load(Stream, Path, Subevacuable), + '$use_module'(Evacuable, Subevacuable, Exports) + ) + ; var(Library) -> + instantiation_error(load/1) + ; type_error(atom, Library, load/1) + ) + ; ( path_atom(Module, ModulePath) -> + load_context_path(ModulePath, Path), + open_file(Path, Stream), + file_load(Stream, Path, Subevacuable), + '$use_module'(Evacuable, Subevacuable, Exports) + ; type_error(atom, Library, load/1) + ) + ). + + + +check_predicate_property(meta_predicate, Module, Name, Arity, MetaPredicateTerm) :- + '$cpp_meta_predicate_property'(Module, Name, Arity, MetaPredicateTerm). +check_predicate_property(built_in, _, Name, Arity, built_in) :- + '$cpp_built_in_property'(Name, Arity). +check_predicate_property(dynamic, Module, Name, Arity, dynamic) :- + '$cpp_dynamic_property'(Module, Name, Arity). +check_predicate_property(multifile, Module, Name, Arity, multifile) :- + '$cpp_multifile_property'(Module, Name, Arity). +check_predicate_property(discontiguous, Module, Name, Arity, discontiguous) :- + '$cpp_discontiguous_property'(Module, Name, Arity). + + + +extract_predicate_property(Property, PropertyType) :- + ( var(Property) -> + true + ; functor(Property, PropertyType, _) + ). + +load_context(Module) :- + ( prolog_load_context(module, Module) -> + true + ; Module = user + ). + +predicate_property(Callable, Property) :- + ( var(Callable) -> + instantiation_error(predicate_property/2) + ; functor(Callable, (:), 2), + arg(1, Callable, Module), + arg(2, Callable, Callable0), + atom(Module), + nonvar(Callable0) -> + functor(Callable0, Name, Arity), + ( atom(Name), + Name \== [] -> + extract_predicate_property(Property, PropertyType), + check_predicate_property(PropertyType, Module, Name, Arity, Property) + ; type_error(callable, Callable0, predicate_property/2) + ) + ; functor(Callable, Name, Arity), + ( atom(Name), + Name \== [] -> + extract_predicate_property(Property, PropertyType), + load_context(Module), + check_predicate_property(PropertyType, Module, Name, Arity, Property) + ; type_error(callable, Callable, predicate_property/2) + ) + ). + + +strip_module(M0, G0, M1, G1) :- + ( nonvar(G0), + G0 = (MG1:G2) -> + strip_module(MG1, G2, M1, G1) + ; M0 = M1, + G0 = G1 + ). + +strip_module(Goal, M, G) :- + strip_module(_, Goal, M, G). + + +expand_subgoal(UnexpandedGoals, MS, Module, ExpandedGoals, HeadVars) :- + ( var(UnexpandedGoals) -> + UnexpandedGoals = ExpandedGoals + ; goal_expansion(UnexpandedGoals, Module, UnexpandedGoals1), + ( Module \== user -> + goal_expansion(UnexpandedGoals1, user, Goals) + ; Goals = UnexpandedGoals1 + ), + ( inner_meta_specs(MS, Goals, _, MetaSpecs) -> + expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars) + ; Goals = ExpandedGoals + ) + ; UnexpandedGoals = ExpandedGoals + ). + + +expand_module_name(ESG0, M, ESG) :- + ( var(ESG0) -> + ESG = M:ESG0 + ; ESG0 = _:_ -> + ESG = ESG0 + ; ESG = M:ESG0 + ). + + +expand_meta_predicate_subgoals([SG | SGs], [MS | MSs], M, [ESG | ESGs], HeadVars) :- + ( ( integer(MS), + MS >= 0 + ) -> + ( var(SG), + pairs:same_key(SG, HeadVars, [_|_], _) -> + expand_subgoal(SG, MS, M, ESG, HeadVars) + ; expand_subgoal(SG, MS, M, ESG0, HeadVars), + expand_module_name(ESG0, M, ESG) + ), + expand_meta_predicate_subgoals(SGs, MSs, M, ESGs, HeadVars) + ; ESG = SG, + expand_meta_predicate_subgoals(SGs, MSs, M, ESGs, HeadVars) + ). + +expand_meta_predicate_subgoals([], _, _, [], _). + + +expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars) :- + Goals =.. [GoalFunctor | SubGoals], + ( GoalFunctor == (:), + SubGoals = [M, SubGoal] -> + expand_module_names(SubGoal, MetaSpecs, M, ExpandedSubGoal, HeadVars), + ExpandedGoals = M:ExpandedSubGoal + ; expand_meta_predicate_subgoals(SubGoals, MetaSpecs, Module, ExpandedGoalList, HeadVars), + ExpandedGoals =.. [GoalFunctor | ExpandedGoalList] + ). + + +expand_goal(UnexpandedGoals, Module, ExpandedGoals) :- + expand_goal(UnexpandedGoals, Module, ExpandedGoals, []), + !. + +expand_goal_cases((Goal0, Goals0), Module, ExpandedGoals, HeadVars) :- + ( expand_goal(Goal0, Module, Goal1, HeadVars) -> + expand_goal(Goals0, Module, Goals1, HeadVars), + thread_goals(Goal1, ExpandedGoals, Goals1, (',')) + ; expand_goal(Goals0, Module, Goals1, HeadVars), + ExpandedGoals = (Goal0, Goals1) + ). +expand_goal_cases((Goals0 -> Goals1), Module, ExpandedGoals, HeadVars) :- + expand_goal(Goals0, Module, ExpandedGoals0, HeadVars), + expand_goal(Goals1, Module, ExpandedGoals1, HeadVars), + ExpandedGoals = (ExpandedGoals0 -> ExpandedGoals1). +expand_goal_cases((Goals0 ; Goals1), Module, ExpandedGoals, HeadVars) :- + expand_goal(Goals0, Module, ExpandedGoals0, HeadVars), + expand_goal(Goals1, Module, ExpandedGoals1, HeadVars), + ExpandedGoals = (ExpandedGoals0 ; ExpandedGoals1). +expand_goal_cases((\+ Goals0), Module, ExpandedGoals, HeadVars) :- + expand_goal(Goals0, Module, Goals1, HeadVars), + ExpandedGoals = (\+ Goals1). +expand_goal_cases((Module:Goals0), _, ExpandedGoals, HeadVars) :- + expand_goal(Goals0, Module, Goals1, HeadVars), + ExpandedGoals = (Module:Goals1). + +expand_goal(UnexpandedGoals, Module, ExpandedGoals, HeadVars) :- + ( var(UnexpandedGoals) -> + call(Module:UnexpandedGoals) = ExpandedGoals + ; goal_expansion(UnexpandedGoals, Module, UnexpandedGoals1), + ( Module \== user -> + goal_expansion(UnexpandedGoals1, user, Goals) + ; Goals = UnexpandedGoals1 + ), + ( expand_goal_cases(Goals, Module, ExpandedGoals, HeadVars) -> + true + ; predicate_property(Module:Goals, meta_predicate(MetaSpecs)) -> + expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars) + ; thread_goals(Goals, ExpandedGoals, (',')) + ; Goals = ExpandedGoals + ) + ). + +thread_goals(Goals0, Goals1, Functor) :- + ( var(Goals0) -> + Goals0 = Goals1 + ; ( Goals0 = [G | Gs] -> + ( Gs = [] -> + Goals1 = G + ; Goals1 =.. [Functor, G, Goals2], + thread_goals(Gs, Goals2, Functor) + ) + ; Goals1 = Goals0 + ) + ). + +thread_goals(Goals0, Goals1, Hole, Functor) :- + ( var(Goals0) -> + Goals1 =.. [Functor, Goals0, Hole] + ; ( Goals0 = [G | Gs] -> + ( Gs == [] -> + Goals1 =.. [Functor, G, Hole] + ; Goals1 =.. [Functor, G, Goals2], + thread_goals(Gs, Goals2, Hole, Functor) + ) + ; Goals1 =.. [Functor, Goals0, Hole] + ) + ). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% call/{1-64} with dynamic goal expansion. +% +% The program used to generate the call/N predicates: +% +% +% :- use_module(library(between)). +% :- use_module(library(error)). +% :- use_module(library(lists)). +% :- use_module(library(format)). +% +% call_form_generator(N) :- +% length(Args, N), +% CallHead =.. [call, G | Args], +% N1 is N + 1, +% Form = (CallHead :- ( var(G) -> +% instantiation_error(call/N1) +% ; call_clause(G, Args, N1, G0) -> +% '$call'(G0) +% ; type_error(callable, G, call/N1) +% )), +% portray_clause(Form). +% +% generate_call_forms :- +% between(1, 64, N), +% call_form_generator(N), +% nl, +% false. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +call_clause(M:G1, G0) :- + functor(G1, F, _), + atom(F), + atom(M), + F \== [], + !, + expand_goal(M:G1, M, G0). + +% The '$call' functor is an escape hatch from goal expansion. So far, +% it is used only to avoid infinite recursion into expand_goal/3. + +call_clause('$call'(G), G0) :- + ( var(G), + instantiation_error(call/1) + ; G = M:G1, + !, + functor(G1, F, _), + atom(F), + atom(M), + F \== [], + G0 = M:G1 + ; !, + functor(G, F, _), + atom(F), + F \== [], + load_context(M), + G0 = M:G + ). + +call_clause(G, G0) :- + functor(G, F, _), + atom(F), + F \== [], + load_context(M), + expand_goal(M:G, M, G0). + + +call(G) :- + ( var(G) -> + instantiation_error(call/1) + ; call_clause(G, G0) -> + '$call'(G0) + ; type_error(callable, G, call/1) + ). + + +call_clause(M:G1, Args, _, G0) :- + atom(M), + G1 =.. [F | As], + atom(F), + F \== [], + !, + append(As, Args, As1), + G2 =.. [F | As1], + expand_goal(M:G2, M, G0). + +call_clause('$call'(G1), Args, N, G0) :- + ( var(G1), + instantiation_error(call/N) + ; G1 = M:G2, + !, + atom(M), + G2 =.. [F | As], + atom(F), + F \== [], + append(As, Args, As1), + G3 =.. [F | As1], + G0 = M:G3 + ; !, + G1 =.. [F | As], + atom(F), + F \== [], + load_context(M), + append(As, Args, As1), + G2 =.. [F | As1], + G0 = M:G2 + ). + +call_clause(G, Args, _, G0) :- + G =.. [F | As], + atom(F), + F \== [], + load_context(M), + append(As, Args, As1), + G2 =.. [F | As1], + expand_goal(M:G2, M, G0). + + +call(A,B) :- + ( var(A) -> + instantiation_error(call/2) + ; ( call_clause(A,[B],2,C) -> + '$call'(C) + ; type_error(callable,A,call/2) + ) + ). + +call(A,B,C) :- + ( var(A) -> + instantiation_error(call/3) + ; ( call_clause(A,[B,C],3,D) -> + '$call'(D) + ; type_error(callable,A,call/3) + ) + ). + +call(A,B,C,D) :- + ( var(A) -> + instantiation_error(call/4) + ; ( call_clause(A,[B,C,D],4,E) -> + '$call'(E) + ; type_error(callable,A,call/4) + ) + ). + +call(A,B,C,D,E) :- + ( var(A) -> + instantiation_error(call/5) + ; ( call_clause(A,[B,C,D,E],5,F) -> + '$call'(F) + ; type_error(callable,A,call/5) + ) + ). + +call(A,B,C,D,E,F) :- + ( var(A) -> + instantiation_error(call/6) + ; ( call_clause(A,[B,C,D,E,F],6,G) -> + '$call'(G) + ; type_error(callable,A,call/6) + ) + ). + +call(A,B,C,D,E,F,G) :- + ( var(A) -> + instantiation_error(call/7) + ; ( call_clause(A,[B,C,D,E,F,G],7,H) -> + '$call'(H) + ; type_error(callable,A,call/7) + ) + ). + +call(A,B,C,D,E,F,G,H) :- + ( var(A) -> + instantiation_error(call/8) + ; ( call_clause(A,[B,C,D,E,F,G,H],8,I) -> + '$call'(I) + ; type_error(callable,A,call/8) + ) + ). + +call(A,B,C,D,E,F,G,H,I) :- + ( var(A) -> + instantiation_error(call/9) + ; ( call_clause(A,[B,C,D,E,F,G,H,I],9,J) -> + '$call'(J) + ; type_error(callable,A,call/9) + ) + ). + +call(A,B,C,D,E,F,G,H,I,J) :- + ( var(A) -> + instantiation_error(call/10) + ; ( call_clause(A,[B,C,D,E,F,G,H,I,J],10,K) -> + '$call'(K) + ; type_error(callable,A,call/10) + ) + ). + +call(A,B,C,D,E,F,G,H,I,J,K) :- + ( var(A) -> + instantiation_error(call/11) + ; ( call_clause(A,[B,C,D,E,F,G,H,I,J,K],11,L) -> + '$call'(L) + ; type_error(callable,A,call/11) + ) + ). + +call(A,B,C,D,E,F,G,H,I,J,K,L) :- + ( var(A) -> + instantiation_error(call/12) + ; ( call_clause(A,[B,C,D,E,F,G,H,I,J,K,L],12,M) -> + '$call'(M) + ; type_error(callable,A,call/12) + ) + ). + +call(A,B,C,D,E,F,G,H,I,J,K,L,M) :- + ( var(A) -> + instantiation_error(call/13) + ; ( call_clause(A,[B,C,D,E,F,G,H,I,J,K,L,M],13,N) -> + '$call'(N) + ; type_error(callable,A,call/13) + ) + ). + +call(A,B,C,D,E,F,G,H,I,J,K,L,M,N) :- + ( var(A) -> + instantiation_error(call/14) + ; ( call_clause(A,[B,C,D,E,F,G,H,I,J,K,L,M,N],14,O) -> + '$call'(O) + ; type_error(callable,A,call/14) + ) + ). + +call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O) :- + ( var(A) -> + instantiation_error(call/15) + ; ( call_clause(A,[B,C,D,E,F,G,H,I,J,K,L,M,N,O],15,P) -> + '$call'(P) + ; type_error(callable,A,call/15) + ) + ). + +call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P) :- + ( var(A) -> + instantiation_error(call/16) + ; ( call_clause(A,[B,C,D,E,F,G,H,I,J,K,L,M,N,O,P],16,Q) -> + '$call'(Q) + ; type_error(callable,A,call/16) + ) + ). + +call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q) :- + ( var(A) -> + instantiation_error(call/17) + ; ( call_clause(A,[B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q],17,R) -> + '$call'(R) + ; type_error(callable,A,call/17) + ) + ). + +call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R) :- + ( var(A) -> + instantiation_error(call/18) + ; ( call_clause(A,[B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R],18,S) -> + '$call'(S) + ; type_error(callable,A,call/18) + ) + ). + +call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S) :- + ( var(A) -> + instantiation_error(call/19) + ; ( call_clause(A,[B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S],19,T) -> + '$call'(T) + ; type_error(callable,A,call/19) + ) + ). + +call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T) :- + ( var(A) -> + instantiation_error(call/20) + ; ( call_clause(A,[B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T],20,U) -> + '$call'(U) + ; type_error(callable,A,call/20) + ) + ). + +call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U) :- + ( var(A) -> + instantiation_error(call/21) + ; ( call_clause(A,[B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U],21,V) -> + '$call'(V) + ; type_error(callable,A,call/21) + ) + ). + +call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V) :- + ( var(A) -> + instantiation_error(call/22) + ; ( call_clause(A,[B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V],22,W) -> + '$call'(W) + ; type_error(callable,A,call/22) + ) + ). + +call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W) :- + ( var(A) -> + instantiation_error(call/23) + ; ( call_clause(A,[B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W],23,X) -> + '$call'(X) + ; type_error(callable,A,call/23) + ) + ). + +call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X) :- + ( var(A) -> + instantiation_error(call/24) + ; ( call_clause(A,[B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X],24,Y) -> + '$call'(Y) + ; type_error(callable,A,call/24) + ) + ). + +call(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) :- + ( var(A) -> + instantiation_error(call/25) + ; ( call_clause(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],25,Z) -> + '$call'(Z) + ; type_error(callable,A,call/25) + ) + ). + +call(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) :- + ( var(A) -> + instantiation_error(call/26) + ; ( call_clause(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],26,A1) -> + '$call'(A1) + ; type_error(callable,A,call/26) + ) + ). + +call(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,A1) :- + ( var(A) -> + instantiation_error(call/27) + ; ( call_clause(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,A1],27,B1) -> + '$call'(B1) + ; type_error(callable,A,call/27) + ) + ). + +call(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,A1,B1) :- + ( var(A) -> + instantiation_error(call/28) + ; ( call_clause(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,A1,B1],28,C1) -> + '$call'(C1) + ; type_error(callable,A,call/28) + ) + ). + +call(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,A1,B1,C1) :- + ( var(A) -> + instantiation_error(call/29) + ; ( call_clause(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,A1,B1,C1],29,D1) -> + '$call'(D1) + ; type_error(callable,A,call/29) + ) + ). + +call(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,A1,B1,C1,D1) :- + ( var(A) -> + instantiation_error(call/30) + ; ( call_clause(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,A1,B1,C1,D1],30,E1) -> + '$call'(E1) + ; type_error(callable,A,call/30) + ) + ). + +call(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,A1,B1,C1,D1,E1) :- + ( var(A) -> + instantiation_error(call/31) + ; ( call_clause(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,A1,B1,C1,D1,E1],31,F1) -> + '$call'(F1) + ; type_error(callable,A,call/31) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1) :- + ( var(A) -> + instantiation_error(call/32) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1],32,G1) -> + '$call'(G1) + ; type_error(callable,A,call/32) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1) :- + ( var(A) -> + instantiation_error(call/33) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1],33,H1) -> + '$call'(H1) + ; type_error(callable,A,call/33) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1) :- + ( var(A) -> + instantiation_error(call/34) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1],34,I1) -> + '$call'(I1) + ; type_error(callable,A,call/34) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1) :- + ( var(A) -> + instantiation_error(call/35) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1],35,J1) -> + '$call'(J1) + ; type_error(callable,A,call/35) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1) :- + ( var(A) -> + instantiation_error(call/36) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1],36,K1) -> + '$call'(K1) + ; type_error(callable,A,call/36) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1) :- + ( var(A) -> + instantiation_error(call/37) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1],37,L1) -> + '$call'(L1) + ; type_error(callable,A,call/37) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1) :- + ( var(A) -> + instantiation_error(call/38) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1],38,M1) -> + '$call'(M1) + ; type_error(callable,A,call/38) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1) :- + ( var(A) -> + instantiation_error(call/39) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1],39,N1) -> + '$call'(N1) + ; type_error(callable,A,call/39) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1) :- + ( var(A) -> + instantiation_error(call/40) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1],40,O1) -> + '$call'(O1) + ; type_error(callable,A,call/40) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1) :- + ( var(A) -> + instantiation_error(call/41) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1],41,P1) -> + '$call'(P1) + ; type_error(callable,A,call/41) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1) :- + ( var(A) -> + instantiation_error(call/42) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1],42,Q1) -> + '$call'(Q1) + ; type_error(callable,A,call/42) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1) :- + ( var(A) -> + instantiation_error(call/43) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1],43,R1) -> + '$call'(R1) + ; type_error(callable,A,call/43) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1) :- + ( var(A) -> + instantiation_error(call/44) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1],44,S1) -> + '$call'(S1) + ; type_error(callable,A,call/44) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1) :- + ( var(A) -> + instantiation_error(call/45) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1],45,T1) -> + '$call'(T1) + ; type_error(callable,A,call/45) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1) :- + ( var(A) -> + instantiation_error(call/46) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1],46,U1) -> + '$call'(U1) + ; type_error(callable,A,call/46) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1) :- + ( var(A) -> + instantiation_error(call/47) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1],47,V1) -> + '$call'(V1) + ; type_error(callable,A,call/47) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1) :- + ( var(A) -> + instantiation_error(call/48) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1],48,W1) -> + '$call'(W1) + ; type_error(callable,A,call/48) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1) :- + ( var(A) -> + instantiation_error(call/49) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1],49,X1) -> + '$call'(X1) + ; type_error(callable,A,call/49) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1) :- + ( var(A) -> + instantiation_error(call/50) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1],50,Y1) -> + '$call'(Y1) + ; type_error(callable,A,call/50) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1) :- + ( var(A) -> + instantiation_error(call/51) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1],51,Z1) -> + '$call'(Z1) + ; type_error(callable,A,call/51) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1) :- + ( var(A) -> + instantiation_error(call/52) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1],52,A2) -> + '$call'(A2) + ; type_error(callable,A,call/52) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2) :- + ( var(A) -> + instantiation_error(call/53) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2],53,B2) -> + '$call'(B2) + ; type_error(callable,A,call/53) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2) :- + ( var(A) -> + instantiation_error(call/54) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2],54,C2) -> + '$call'(C2) + ; type_error(callable,A,call/54) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2) :- + ( var(A) -> + instantiation_error(call/55) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2],55,D2) -> + '$call'(D2) + ; type_error(callable,A,call/55) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2) :- + ( var(A) -> + instantiation_error(call/56) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2],56,E2) -> + '$call'(E2) + ; type_error(callable,A,call/56) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2) :- + ( var(A) -> + instantiation_error(call/57) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2],57,F2) -> + '$call'(F2) + ; type_error(callable,A,call/57) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2) :- + ( var(A) -> + instantiation_error(call/58) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2],58,G2) -> + '$call'(G2) + ; type_error(callable,A,call/58) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2) :- + ( var(A) -> + instantiation_error(call/59) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2],59,H2) -> + '$call'(H2) + ; type_error(callable,A,call/59) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2) :- + ( var(A) -> + instantiation_error(call/60) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2],60,I2) -> + '$call'(I2) + ; type_error(callable,A,call/60) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2) :- + ( var(A) -> + instantiation_error(call/61) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2],61,J2) -> + '$call'(J2) + ; type_error(callable,A,call/61) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2) :- + ( var(A) -> + instantiation_error(call/62) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2],62,K2) -> + '$call'(K2) + ; type_error(callable,A,call/62) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2) :- + ( var(A) -> + instantiation_error(call/63) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2],63,L2) -> + '$call'(L2) + ; type_error(callable,A,call/63) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2,L2) :- + ( var(A) -> + instantiation_error(call/64) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2,L2],64,M2) -> + '$call'(M2) + ; type_error(callable,A,call/64) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2,L2,M2) :- + ( var(A) -> + instantiation_error(call/65) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2,L2,M2],65,N2) -> + '$call'(N2) + ; type_error(callable,A,call/65) + ) + ). + +call(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2,L2,M2) :- + ( var(A) -> + instantiation_error(call/65) + ; ( call_clause(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,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2,L2,M2],65,N2) -> + '$call'(N2) + ; type_error(callable,A,call/65) + ) + ). diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs index 110353ac..9ce4eac0 100644 --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@ -1,6 +1,7 @@ -use crate::divrem::*; +use divrem::*; -use crate::prolog_parser::ast::*; +use prolog_parser::ast::*; +use prolog_parser::clause_name; use crate::arithmetic::*; use crate::clause_types::*; @@ -8,8 +9,8 @@ use crate::forms::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::machine_state::*; -use crate::ordered_float::*; use crate::rug::{Integer, Rational}; +use ordered_float::*; use std::cmp; use std::convert::TryFrom; @@ -19,19 +20,16 @@ use std::rc::Rc; #[macro_export] macro_rules! try_numeric_result { - ($s: ident, $e: expr, $caller: expr) => ( + ($s: ident, $e: expr, $caller: expr) => { match $e { - Ok(val) => { - Ok(val) - } + Ok(val) => Ok(val), Err(e) => { - let caller_copy = - $caller.iter().map(|v| v.context_free_clone()).collect(); + let caller_copy = $caller.iter().map(|v| v.context_free_clone()).collect(); Err($s.error_form(MachineError::evaluation_error(e), caller_copy)) } } - ); + }; } fn isize_gcd(n1: isize, n2: isize) -> Option { @@ -83,52 +81,29 @@ fn isize_gcd(n1: isize, n2: isize) -> Option { } impl MachineState { - pub(crate) - fn get_number(&mut self, at: &ArithmeticTerm) -> Result { + pub(crate) fn get_number(&mut self, at: &ArithmeticTerm) -> Result { match at { - &ArithmeticTerm::Reg(r) => { - self.arith_eval_by_metacall(r) - } - &ArithmeticTerm::Interm(i) => Ok(mem::replace( - &mut self.interms[i - 1], - Number::Fixnum(0), - )), - &ArithmeticTerm::Number(ref n) => { - Ok(n.clone()) + &ArithmeticTerm::Reg(r) => self.arith_eval_by_metacall(r), + &ArithmeticTerm::Interm(i) => { + Ok(mem::replace(&mut self.interms[i - 1], Number::Fixnum(0))) } + &ArithmeticTerm::Number(ref n) => Ok(n.clone()), } } - pub(super) - fn rational_from_number( - &self, - n: Number, - ) -> Result, MachineError> { + pub(super) fn rational_from_number(&self, n: Number) -> Result, MachineError> { match n { - Number::Fixnum(n) => { - Ok(Rc::new(Rational::from(n))) - } - Number::Rational(r) => { - Ok(r) - } - Number::Float(OrderedFloat(f)) => { - match Rational::from_f64(f) { - Some(r) => { - Ok(Rc::new(r)) - } - None => { - Err(MachineError::instantiation_error()) - } - } - } - Number::Integer(n) => { - Ok(Rc::new(Rational::from(&*n))) - } + Number::Fixnum(n) => Ok(Rc::new(Rational::from(n))), + Number::Rational(r) => Ok(r), + Number::Float(OrderedFloat(f)) => match Rational::from_f64(f) { + Some(r) => Ok(Rc::new(r)), + None => Err(MachineError::instantiation_error()), + }, + Number::Integer(n) => Ok(Rc::new(Rational::from(&*n))), } } - pub(crate) - fn get_rational( + pub(crate) fn get_rational( &mut self, at: &ArithmeticTerm, caller: MachineStub, @@ -137,12 +112,11 @@ impl MachineState { match self.rational_from_number(n) { Ok(r) => Ok((r, caller)), - Err(e) => Err(self.error_form(e, caller)) + Err(e) => Err(self.error_form(e, caller)), } } - pub(crate) - fn arith_eval_by_metacall(&self, r: RegType) -> Result { + pub(crate) fn arith_eval_by_metacall(&self, r: RegType) -> Result { let caller = MachineError::functor_stub(clause_name!("is"), 2); let mut interms: Vec = Vec::with_capacity(64); @@ -163,9 +137,8 @@ impl MachineState { "min" => interms.push(self.min(a1, a2)?), "rdiv" => { let r1 = self.rational_from_number(a1); - let r2 = r1.and_then(|r1| { - self.rational_from_number(a2).map(|r2| (r1, r2)) - }); + let r2 = + r1.and_then(|r1| self.rational_from_number(a2).map(|r2| (r1, r2))); match r2 { Ok((r1, r2)) => { @@ -242,21 +215,18 @@ impl MachineState { &HeapCellValue::Addr(Addr::Fixnum(n)) => { interms.push(Number::Fixnum(n)); } - &HeapCellValue::Addr(Addr::Float(n)) => { - interms.push(Number::Float(n)) - } - &HeapCellValue::Integer(ref n) => { - interms.push(Number::Integer(n.clone())) - } + &HeapCellValue::Addr(Addr::Float(n)) => interms.push(Number::Float(n)), + &HeapCellValue::Integer(ref n) => interms.push(Number::Integer(n.clone())), &HeapCellValue::Addr(Addr::Usize(n)) => { interms.push(Number::Integer(Rc::new(Integer::from(n)))); } - &HeapCellValue::Rational(ref n) => { - interms.push(Number::Rational(n.clone())) - } + &HeapCellValue::Rational(ref n) => interms.push(Number::Rational(n.clone())), &HeapCellValue::Atom(ref name, _) if name.as_str() == "pi" => { interms.push(Number::Float(OrderedFloat(f64::consts::PI))) } + &HeapCellValue::Atom(ref name, _) if name.as_str() == "e" => { + interms.push(Number::Float(OrderedFloat(f64::consts::E))) + } &HeapCellValue::NamedStr(arity, ref name, _) => { let evaluable_stub = MachineError::functor_stub(name.clone(), arity); @@ -282,10 +252,7 @@ impl MachineState { )); } &HeapCellValue::Addr(addr) if addr.is_ref() => { - return Err(self.error_form( - MachineError::instantiation_error(), - caller, - )); + return Err(self.error_form(MachineError::instantiation_error(), caller)); } val => { return Err(self.type_error( @@ -301,8 +268,7 @@ impl MachineState { Ok(interms.pop().unwrap()) } - pub(crate) - fn rdiv(&self, r1: Rc, r2: Rc) -> Result { + pub(crate) fn rdiv(&self, r1: Rc, r2: Rc) -> Result { if &*r2 == &0 { let stub = MachineError::functor_stub(clause_name!("(rdiv)"), 2); Err(self.error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) @@ -311,27 +277,21 @@ impl MachineState { } } - pub(crate) - fn int_floor_div(&self, n1: Number, n2: Number) -> Result { + pub(crate) fn int_floor_div(&self, n1: Number, n2: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("(div)"), 2); let modulus = self.modulus(n1.clone(), n2.clone())?; self.idiv(try_numeric_result!(self, n1 - modulus, stub)?, n2) } - pub(crate) - fn idiv(&self, n1: Number, n2: Number) -> Result { + pub(crate) fn idiv(&self, n1: Number, n2: Number) -> Result { match (n1, n2) { (Number::Fixnum(n1), Number::Fixnum(n2)) => { if n2 == 0 { let stub = MachineError::functor_stub(clause_name!("(//)"), 2); - Err(self.error_form( - MachineError::evaluation_error( - EvalError::ZeroDivisor - ), - stub, - )) + Err(self + .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) } else { if let Some(result) = n1.checked_div(n2) { Ok(Number::from(result)) @@ -347,12 +307,8 @@ impl MachineState { if &*n2 == &0 { let stub = MachineError::functor_stub(clause_name!("(//)"), 2); - Err(self.error_form( - MachineError::evaluation_error( - EvalError::ZeroDivisor - ), - stub, - )) + Err(self + .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) } else { Ok(Number::from(Integer::from(n1) / &*n2)) } @@ -361,12 +317,8 @@ impl MachineState { if n1 == 0 { let stub = MachineError::functor_stub(clause_name!("(//)"), 2); - Err(self.error_form( - MachineError::evaluation_error( - EvalError::ZeroDivisor - ), - stub, - )) + Err(self + .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) } else { Ok(Number::from(&*n2 / Integer::from(n1))) } @@ -375,25 +327,19 @@ impl MachineState { if &*n2 == &0 { let stub = MachineError::functor_stub(clause_name!("(//)"), 2); - Err(self.error_form( - MachineError::evaluation_error( - EvalError::ZeroDivisor - ), - stub, - )) + Err(self + .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) } else { - Ok(Number::from(<(Integer, Integer)>::from(n1.div_rem_ref(&*n2)).0)) + Ok(Number::from( + <(Integer, Integer)>::from(n1.div_rem_ref(&*n2)).0, + )) } } (Number::Fixnum(_), n2) | (Number::Integer(_), n2) => { let stub = MachineError::functor_stub(clause_name!("(//)"), 2); Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - n2, - ), + MachineError::type_error(self.heap.h(), ValidType::Integer, n2), stub, )) } @@ -401,19 +347,14 @@ impl MachineState { let stub = MachineError::functor_stub(clause_name!("(//)"), 2); Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - n1, - ), + MachineError::type_error(self.heap.h(), ValidType::Integer, n1), stub, )) } } } - pub(crate) - fn div(&self, n1: Number, n2: Number) -> Result { + pub(crate) fn div(&self, n1: Number, n2: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("(/)"), 2); if n2.is_zero() { @@ -423,8 +364,7 @@ impl MachineState { } } - pub(crate) - fn atan2(&self, n1: Number, n2: Number) -> Result { + pub(crate) fn atan2(&self, n1: Number, n2: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("is"), 2); if n1.is_zero() && n2.is_zero() { @@ -437,8 +377,7 @@ impl MachineState { } } - pub(crate) - fn int_pow(&self, n1: Number, n2: Number) -> Result { + pub(crate) fn int_pow(&self, n1: Number, n2: Number) -> Result { if n1.is_zero() && n2.is_negative() { let stub = MachineError::functor_stub(clause_name!("is"), 2); return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)); @@ -451,11 +390,7 @@ impl MachineState { let stub = MachineError::functor_stub(clause_name!("^"), 2); Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Float, - n - ), + MachineError::type_error(self.heap.h(), ValidType::Float, n), stub, )) } else { @@ -477,11 +412,7 @@ impl MachineState { let stub = MachineError::functor_stub(clause_name!("^"), 2); Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Float, - n - ), + MachineError::type_error(self.heap.h(), ValidType::Float, n), stub, )) } else { @@ -495,11 +426,7 @@ impl MachineState { let stub = MachineError::functor_stub(clause_name!("^"), 2); Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Float, - n - ), + MachineError::type_error(self.heap.h(), ValidType::Float, n), stub, )) } else { @@ -513,11 +440,7 @@ impl MachineState { let stub = MachineError::functor_stub(clause_name!("^"), 2); Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Float, - n - ), + MachineError::type_error(self.heap.h(), ValidType::Float, n), stub, )) } else { @@ -548,8 +471,7 @@ impl MachineState { } } - pub(crate) - fn gcd(&self, n1: Number, n2: Number) -> Result { + pub(crate) fn gcd(&self, n1: Number, n2: Number) -> Result { match (n1, n2) { (Number::Fixnum(n1), Number::Fixnum(n2)) => { if let Some(result) = isize_gcd(n1, n2) { @@ -558,8 +480,8 @@ impl MachineState { Ok(Number::from(Integer::from(n1).gcd(&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)) => { let n1 = Integer::from(n1); Ok(Number::from(Integer::from(n2.gcd_ref(&n1)))) } @@ -571,11 +493,7 @@ impl MachineState { let stub = MachineError::functor_stub(clause_name!("gcd"), 2); Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - n - ), + MachineError::type_error(self.heap.h(), ValidType::Integer, n), stub, )) } @@ -584,19 +502,14 @@ impl MachineState { let stub = MachineError::functor_stub(clause_name!("gcd"), 2); Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - n, - ), + MachineError::type_error(self.heap.h(), ValidType::Integer, n), stub, )) } } } - pub(crate) - fn float_pow(&self, n1: Number, n2: Number) -> Result { + pub(crate) fn float_pow(&self, n1: Number, n2: Number) -> Result { let f1 = result_f(&n1, rnd_f); let f2 = result_f(&n2, rnd_f); @@ -612,8 +525,12 @@ impl MachineState { )?))) } - pub(crate) - fn pow(&self, n1: Number, n2: Number, culprit: &'static str) -> Result { + pub(crate) fn pow( + &self, + n1: Number, + n2: Number, + culprit: &'static str, + ) -> Result { if n2.is_negative() && n1.is_zero() { let stub = MachineError::functor_stub(clause_name!(culprit), 2); return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)); @@ -623,8 +540,11 @@ impl MachineState { } #[inline] - pub(crate) - fn unary_float_fn_template(&self, n1: Number, f: FloatFn) -> Result + pub(crate) fn unary_float_fn_template( + &self, + n1: Number, + f: FloatFn, + ) -> Result where FloatFn: Fn(f64) -> f64, { @@ -637,56 +557,47 @@ impl MachineState { } #[inline] - pub(crate) - fn sin(&self, n1: Number) -> Result { + pub(crate) fn sin(&self, n1: Number) -> Result { self.unary_float_fn_template(n1, |f| f.sin()) } #[inline] - pub(crate) - fn cos(&self, n1: Number) -> Result { + pub(crate) fn cos(&self, n1: Number) -> Result { self.unary_float_fn_template(n1, |f| f.cos()) } #[inline] - pub(crate) - fn tan(&self, n1: Number) -> Result { + pub(crate) fn tan(&self, n1: Number) -> Result { self.unary_float_fn_template(n1, |f| f.tan()) } #[inline] - pub(crate) - fn log(&self, n1: Number) -> Result { + pub(crate) fn log(&self, n1: Number) -> Result { self.unary_float_fn_template(n1, |f| f.log(f64::consts::E)) } #[inline] - pub(crate) - fn exp(&self, n1: Number) -> Result { + pub(crate) fn exp(&self, n1: Number) -> Result { self.unary_float_fn_template(n1, |f| f.exp()) } #[inline] - pub(crate) - fn asin(&self, n1: Number) -> Result { + pub(crate) fn asin(&self, n1: Number) -> Result { self.unary_float_fn_template(n1, |f| f.asin()) } #[inline] - pub(crate) - fn acos(&self, n1: Number) -> Result { + pub(crate) fn acos(&self, n1: Number) -> Result { self.unary_float_fn_template(n1, |f| f.acos()) } #[inline] - pub(crate) - fn atan(&self, n1: Number) -> Result { + pub(crate) fn atan(&self, n1: Number) -> Result { self.unary_float_fn_template(n1, |f| f.atan()) } #[inline] - pub(crate) - fn sqrt(&self, n1: Number) -> Result { + pub(crate) fn sqrt(&self, n1: Number) -> Result { if n1.is_negative() { let stub = MachineError::functor_stub(clause_name!("is"), 2); return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)); @@ -696,27 +607,23 @@ impl MachineState { } #[inline] - pub(crate) - fn float(&self, n: Number) -> Result { + pub(crate) fn float(&self, n: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("is"), 2); try_numeric_result!(self, result_f(&n, rnd_f), stub) } #[inline] - pub(crate) - fn floor(&self, n1: Number) -> Number { + pub(crate) fn floor(&self, n1: Number) -> Number { rnd_i(&n1).to_owned() } #[inline] - pub(crate) - fn ceiling(&self, n1: Number) -> Number { + pub(crate) fn ceiling(&self, n1: Number) -> Number { -self.floor(-n1) } #[inline] - pub(crate) - fn truncate(&self, n: Number) -> Number { + pub(crate) fn truncate(&self, n: Number) -> Number { if n.is_negative() { -self.floor(n.abs()) } else { @@ -724,8 +631,7 @@ impl MachineState { } } - pub(crate) - fn round(&self, n: Number) -> Result { + pub(crate) fn round(&self, n: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("is"), 2); let result = n + Number::Float(OrderedFloat(0.5f64)); @@ -734,8 +640,7 @@ impl MachineState { Ok(self.floor(result)) } - pub(crate) - fn shr(&self, n1: Number, n2: Number) -> Result { + pub(crate) fn shr(&self, n1: Number, n2: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("(>>)"), 2); match (n1, n2) { @@ -756,38 +661,26 @@ impl MachineState { _ => Ok(Number::from(n1 >> u32::max_value())), } } - (Number::Integer(n1), Number::Fixnum(n2)) => { - match u32::try_from(n2) { - Ok(n2) => Ok(Number::from(Integer::from(&*n1 >> n2))), - _ => Ok(Number::from(Integer::from(&*n1 >> u32::max_value()))), - } - } - (Number::Integer(n1), Number::Integer(n2)) => - match n2.to_u32() { - Some(n2) => Ok(Number::from(Integer::from(&*n1 >> n2))), - _ => Ok(Number::from(Integer::from(&*n1 >> u32::max_value()))), - }, + (Number::Integer(n1), Number::Fixnum(n2)) => match u32::try_from(n2) { + Ok(n2) => Ok(Number::from(Integer::from(&*n1 >> n2))), + _ => Ok(Number::from(Integer::from(&*n1 >> u32::max_value()))), + }, + (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() { + Some(n2) => Ok(Number::from(Integer::from(&*n1 >> n2))), + _ => Ok(Number::from(Integer::from(&*n1 >> u32::max_value()))), + }, (Number::Integer(_), n2) => Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - n2, - ), + MachineError::type_error(self.heap.h(), ValidType::Integer, n2), stub, )), (n1, _) => Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - n1, - ), + MachineError::type_error(self.heap.h(), ValidType::Integer, n1), stub, )), } } - pub(crate) - fn shl(&self, n1: Number, n2: Number) -> Result { + pub(crate) fn shl(&self, n1: Number, n2: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("(<<)"), 2); match (n1, n2) { @@ -808,263 +701,181 @@ impl MachineState { _ => Ok(Number::from(n1 << u32::max_value())), } } - (Number::Integer(n1), Number::Fixnum(n2)) => { - match u32::try_from(n2) { - Ok(n2) => Ok(Number::from(Integer::from(&*n1 << n2))), - _ => Ok(Number::from(Integer::from(&*n1 << u32::max_value()))), - } - } + (Number::Integer(n1), Number::Fixnum(n2)) => match u32::try_from(n2) { + Ok(n2) => Ok(Number::from(Integer::from(&*n1 << n2))), + _ => Ok(Number::from(Integer::from(&*n1 << u32::max_value()))), + }, (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() { Some(n2) => Ok(Number::from(Integer::from(&*n1 << n2))), _ => Ok(Number::from(Integer::from(&*n1 << u32::max_value()))), }, (Number::Integer(_), n2) => Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - n2, - ), + MachineError::type_error(self.heap.h(), ValidType::Integer, n2), stub, )), (n1, _) => Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - n1, - ), + MachineError::type_error(self.heap.h(), ValidType::Integer, n1), stub, )), } } - pub(crate) - fn bitwise_complement(&self, n1: Number) -> Result { + pub(crate) fn bitwise_complement(&self, n1: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("(\\)"), 2); match n1 { Number::Fixnum(n) => Ok(Number::Fixnum(!n)), Number::Integer(n1) => Ok(Number::from(Integer::from(!&*n1))), _ => Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - n1, - ), + MachineError::type_error(self.heap.h(), ValidType::Integer, n1), stub, )), } } - pub(crate) - fn xor(&self, n1: Number, n2: Number) -> Result { + pub(crate) fn xor(&self, n1: Number, n2: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("(xor)"), 2); match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - Ok(Number::from(n1 ^ n2)) - } + (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::from(n1 ^ n2)), (Number::Fixnum(n1), Number::Integer(n2)) => { let n1 = Integer::from(n1); Ok(Number::from(n1 ^ &*n2)) } - (Number::Integer(n1), Number::Fixnum(n2)) => { - Ok(Number::from(&*n1 ^ Integer::from(n2))) - } + (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::from(&*n1 ^ Integer::from(n2))), (Number::Integer(n1), Number::Integer(n2)) => { Ok(Number::from(Integer::from(&*n1 ^ &*n2))) } - (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => { - Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - n2 - ), - stub, - )) - } - (n1, _) => { - Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - n1 - ), - stub, - )) - } - } - } - - pub(crate) - fn and(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(/\\)"), 2); - - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - Ok(Number::from(n1 & n2)) - } - (Number::Fixnum(n1), Number::Integer(n2)) => { - let n1 = Integer::from(n1); - Ok(Number::from(n1 & &*n2)) - } - (Number::Integer(n1), Number::Fixnum(n2)) => { - Ok(Number::from(&*n1 & Integer::from(n2))) - } - (Number::Integer(n1), Number::Integer(n2)) => { - Ok(Number::from(Integer::from(&*n1 & &*n2))) - } - (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => { - Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - n2, - ), - stub, - )) - } + (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form( + MachineError::type_error(self.heap.h(), ValidType::Integer, n2), + stub, + )), (n1, _) => Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - n1, - ), + MachineError::type_error(self.heap.h(), ValidType::Integer, n1), stub, )), } } - pub(crate) - fn or(&self, n1: Number, n2: Number) -> Result { + pub(crate) fn and(&self, n1: Number, n2: Number) -> Result { + let stub = MachineError::functor_stub(clause_name!("(/\\)"), 2); + + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::from(n1 & n2)), + (Number::Fixnum(n1), Number::Integer(n2)) => { + let n1 = Integer::from(n1); + Ok(Number::from(n1 & &*n2)) + } + (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::from(&*n1 & Integer::from(n2))), + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(Number::from(Integer::from(&*n1 & &*n2))) + } + (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form( + MachineError::type_error(self.heap.h(), ValidType::Integer, n2), + stub, + )), + (n1, _) => Err(self.error_form( + MachineError::type_error(self.heap.h(), ValidType::Integer, n1), + stub, + )), + } + } + + pub(crate) fn or(&self, n1: Number, n2: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("(\\/)"), 2); match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - Ok(Number::from(n1 | n2)) - } + (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::from(n1 | n2)), (Number::Fixnum(n1), Number::Integer(n2)) => { let n1 = Integer::from(n1); Ok(Number::from(n1 | &*n2)) } - (Number::Integer(n1), Number::Fixnum(n2)) => { - Ok(Number::from(&*n1 | Integer::from(n2))) - } + (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::from(&*n1 | Integer::from(n2))), (Number::Integer(n1), Number::Integer(n2)) => { Ok(Number::from(Integer::from(&*n1 | &*n2))) } - (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => { - Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - n2, - ), - stub, - )) - } - (n1, _) => { - Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - n1 - ), - stub, - )) - } + (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form( + MachineError::type_error(self.heap.h(), ValidType::Integer, n2), + stub, + )), + (n1, _) => Err(self.error_form( + MachineError::type_error(self.heap.h(), ValidType::Integer, n1), + stub, + )), } } - pub(crate) - fn modulus(&self, x: Number, y: Number) -> Result { + pub(crate) fn modulus(&self, x: Number, y: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("(mod)"), 2); match (x, y) { (Number::Fixnum(n1), Number::Fixnum(n2)) => { if n2 == 0 { - Err(self.error_form( - MachineError::evaluation_error(EvalError::ZeroDivisor), - stub, - )) + Err(self + .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) } else { Ok(Number::from(n1.rem_floor(n2))) } } (Number::Fixnum(n1), Number::Integer(n2)) => { if &*n2 == &0 { - Err(self.error_form( - MachineError::evaluation_error(EvalError::ZeroDivisor), - stub, - )) + Err(self + .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) } else { let n1 = Integer::from(n1); - Ok(Number::from(<(Integer, Integer)>::from(n1.div_rem_floor_ref(&*n2)).1)) + Ok(Number::from( + <(Integer, Integer)>::from(n1.div_rem_floor_ref(&*n2)).1, + )) } } (Number::Integer(n1), Number::Fixnum(n2)) => { if n2 == 0 { - Err(self.error_form( - MachineError::evaluation_error(EvalError::ZeroDivisor), - stub, - )) + Err(self + .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) } else { let n2 = Integer::from(n2); - Ok(Number::from(<(Integer, Integer)>::from(n1.div_rem_floor_ref(&n2)).1)) + Ok(Number::from( + <(Integer, Integer)>::from(n1.div_rem_floor_ref(&n2)).1, + )) } } (Number::Integer(x), Number::Integer(y)) => { if &*y == &0 { - Err(self.error_form( - MachineError::evaluation_error(EvalError::ZeroDivisor), - stub, - )) + Err(self + .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) } else { - Ok(Number::from(<(Integer, Integer)>::from(x.div_rem_floor_ref(&*y)).1)) + Ok(Number::from( + <(Integer, Integer)>::from(x.div_rem_floor_ref(&*y)).1, + )) } } - (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => { - Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - n2, - ), - stub, - )) - } + (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form( + MachineError::type_error(self.heap.h(), ValidType::Integer, n2), + stub, + )), (n1, _) => Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - n1, - ), + MachineError::type_error(self.heap.h(), ValidType::Integer, n1), stub, )), } } - pub(crate) - fn remainder(&self, n1: Number, n2: Number) -> Result { + pub(crate) fn remainder(&self, n1: Number, n2: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("(rem)"), 2); match (n1, n2) { (Number::Fixnum(n1), Number::Fixnum(n2)) => { if n2 == 0 { - Err(self.error_form( - MachineError::evaluation_error(EvalError::ZeroDivisor), - stub, - )) + Err(self + .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) } else { Ok(Number::from(n1 % n2)) } } (Number::Fixnum(n1), Number::Integer(n2)) => { if &*n2 == &0 { - Err(self.error_form( - MachineError::evaluation_error(EvalError::ZeroDivisor), - stub, - )) + Err(self + .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) } else { let n1 = Integer::from(n1); Ok(Number::from(n1 % &*n2)) @@ -1072,10 +883,8 @@ impl MachineState { } (Number::Integer(n1), Number::Fixnum(n2)) => { if n2 == 0 { - Err(self.error_form( - MachineError::evaluation_error(EvalError::ZeroDivisor), - stub, - )) + Err(self + .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) } else { let n2 = Integer::from(n2); Ok(Number::from(&*n1 % n2)) @@ -1083,37 +892,24 @@ impl MachineState { } (Number::Integer(n1), Number::Integer(n2)) => { if &*n2 == &0 { - Err(self.error_form( - MachineError::evaluation_error(EvalError::ZeroDivisor), - stub, - )) + Err(self + .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) } else { Ok(Number::from(Integer::from(&*n1 % &*n2))) } } - (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => { - Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - n2, - ), - stub, - )) - } + (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form( + MachineError::type_error(self.heap.h(), ValidType::Integer, n2), + stub, + )), (n1, _) => Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - n1, - ), + MachineError::type_error(self.heap.h(), ValidType::Integer, n1), stub, )), } } - pub(crate) - fn max(&self, n1: Number, n2: Number) -> Result { + pub(crate) fn max(&self, n1: Number, n2: Number) -> Result { match (n1, n2) { (Number::Fixnum(n1), Number::Fixnum(n2)) => { if n1 > n2 { @@ -1154,8 +950,7 @@ impl MachineState { } } - pub(crate) - fn min(&self, n1: Number, n2: Number) -> Result { + pub(crate) fn min(&self, n1: Number, n2: Number) -> Result { match (n1, n2) { (Number::Fixnum(n1), Number::Fixnum(n2)) => { if n1 < n2 { @@ -1196,8 +991,7 @@ impl MachineState { } } - pub(crate) - fn sign(&self, n: Number) -> Number { + pub(crate) fn sign(&self, n: Number) -> Number { if n.is_positive() { Number::from(1) } else if n.is_negative() { diff --git a/src/machine/attributed_variables.pl b/src/machine/attributed_variables.pl index 8756eb3c..b5049e3a 100644 --- a/src/machine/attributed_variables.pl +++ b/src/machine/attributed_variables.pl @@ -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([], _). diff --git a/src/machine/attributed_variables.rs b/src/machine/attributed_variables.rs index c7b198d5..aee385f0 100644 --- a/src/machine/attributed_variables.rs +++ b/src/machine/attributed_variables.rs @@ -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 { + pub(super) fn gather_attr_vars_created_since(&self, b: usize) -> IntoIter { 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 { - let mut seen_set = IndexSet::new(); + pub(super) fn attr_vars_of_term(&self, addr: Addr) -> Vec { + let mut seen_set = IndexSet::new(); let mut seen_vars = vec![]; let mut iter = self.acyclic_pre_order_iter(addr); diff --git a/src/machine/code_repo.rs b/src/machine/code_repo.rs index b9045c72..bb21462e 100644 --- a/src/machine/code_repo.rs +++ b/src/machine/code_repo.rs @@ -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) { - 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, - ) -> 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::::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> { 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, + } } } } diff --git a/src/machine/code_walker.rs b/src/machine/code_walker.rs index 152395c5..9bde8a36 100644 --- a/src/machine/code_walker.rs +++ b/src/machine/code_walker.rs @@ -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, - 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) -> 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, 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 } } } +*/ diff --git a/src/machine/compile.rs b/src/machine/compile.rs index 36544eba..bfea3f2f 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -1,1454 +1,2262 @@ -use crate::prolog_parser::ast::*; -use crate::prolog_parser::parser::get_desc; -use crate::prolog_parser::tabled_rc::TabledData; +use prolog_parser::clause_name; use crate::codegen::*; use crate::debray_allocator::*; -use crate::forms::*; -use crate::instructions::*; -use crate::iterators::*; -use crate::machine::code_walker::*; -use crate::machine::machine_errors::*; -use crate::machine::machine_indices::*; -use crate::machine::term_expansion::ExpansionAdditionResult; -use crate::machine::toplevel::*; +use crate::indexing::{IndexingCodePtr, merge_clause_index, remove_index}; +use crate::machine::load_state::*; +use crate::machine::loader::*; +use crate::machine::preprocessor::*; +use crate::machine::term_stream::*; use crate::machine::*; -use crate::indexmap::{IndexMap, IndexSet}; - -use crate::ref_thread_local::RefThreadLocal; +use slice_deque::sdeq; use std::cell::Cell; use std::collections::VecDeque; -use std::fs::File; -use std::mem; -use std::path::PathBuf; +use std::ops::Range; -#[allow(dead_code)] -pub fn print_code(code: &Code) { - for clause in code { - match clause { - &Line::Arithmetic(ref arith) => println!("{}", arith), - &Line::Fact(ref fact_instr) => println!("{}", fact_instr), - &Line::Cut(ref cut) => println!("{}", cut), - &Line::Choice(ref choice) => println!("{}", choice), - &Line::Control(ref control) => println!("{}", control), - &Line::IndexedChoice(ref choice) => println!("{}", choice), - &Line::Indexing(ref indexing) => println!("{}", indexing), - &Line::Query(ref query_instr) => println!("{}", query_instr), - } - } +struct StandaloneCompileResult { + clause_code: Code, + standalone_skeleton: PredicateSkeleton, } -fn fix_filename( - atom_tbl: TabledData, - mut path: PathBuf, -) -> Result -{ - if !path.is_file() { - if path.extension().is_none() { - path.set_extension("pl"); - } - - if !path.is_file() { - let filename = clause_name!(path.to_string_lossy().to_string(), atom_tbl); - return Err(SessionError::InvalidFileName(filename)); - } - } - - Ok(path) -} - -fn load_module( - wam: &mut Machine, +pub(super) fn bootstrapping_compile( stream: Stream, - suppress_warnings: bool, - listing_src: &ListingSource, -) -> Result { - // follow the operation of compile_user_module, but before - // compiling, check that a module is declared in the file. if not, - // throw an exception. - let mut indices = default_index_store!(wam.indices.atom_tbl.clone()); - setup_indices(wam, clause_name!("builtins"), &mut indices)?; - - let mut compiler = ListingCompiler::new( - &wam.code_repo, - suppress_warnings, - listing_src.clone(), - ); - - let mut stream = parsing_stream(stream)?; - - let results = compiler.gather_items( - wam, - &mut stream, - &mut indices, - ); - - let module_name = if let Some(ref module) = &compiler.module { - module.module_decl.name.clone() - } else { - // this impromptu definition (namely, its exports) will be filled out later. - let module_decl = ModuleDecl { name: listing_src.name(), exports: vec![] }; - - let mut module = Module::new(module_decl, wam.indices.atom_tbl.clone(), listing_src.clone()); - let module_name = module.module_decl.name.clone(); - - module.is_impromptu_module = true; - - compiler.module = Some(module); - module_name - }; - - results.and_then(|results| compile_work_impl(&mut compiler, wam, indices, results)) - .or_else(|e| { - wam.indices.take_module(module_name.clone()); - compiler.print_error(&e); - Err(e) - })?; - - Ok(module_name) -} - -pub(super) -fn load_module_from_file( wam: &mut Machine, - path_buf: PathBuf, - suppress_warnings: bool, -) -> Result { - let mut path_buf = fix_filename(wam.indices.atom_tbl.clone(), path_buf)?; - let filename = clause_name!(path_buf.to_string_lossy().to_string(), wam.indices.atom_tbl); + listing_src: ListingSource, +) -> Result<(), SessionError> { + let stream = &mut parsing_stream(stream)?; + let term_stream = BootstrappingTermStream::from_prolog_stream( + stream, + wam.machine_st.atom_tbl.clone(), + wam.machine_st.flags, + listing_src, + ); - let file_handle = Stream::from_file_as_input(filename.clone(), File::open(&path_buf).or_else(|_| { - Err(SessionError::InvalidFileName(filename.clone())) - })?); + let loader = Loader::new(term_stream, wam); + loader.load()?; - path_buf.pop(); - - let listing_src = ListingSource::from_file_and_path(filename, path_buf); - load_module(wam, file_handle, suppress_warnings, &listing_src) + Ok(()) } -pub type PredicateCompileQueue = (Predicate, VecDeque); - // throw errors if declaration or query found. -fn compile_relation( +pub(super) fn compile_relation( cg: &mut CodeGenerator, - tl: &TopLevel -) -> Result { + tl: &TopLevel, +) -> Result { match tl { - &TopLevel::Declaration(_) | &TopLevel::Query(_) => Err(ParserError::ExpectedRel), - &TopLevel::Predicate(ref clauses) => cg.compile_predicate(&clauses.0), + &TopLevel::Query(_) => Err(CompilationError::ExpectedRel), + &TopLevel::Predicate(ref clauses) => cg.compile_predicate(&clauses), &TopLevel::Fact(ref fact, ..) => Ok(cg.compile_fact(fact)), &TopLevel::Rule(ref rule, ..) => cg.compile_rule(rule), } } -fn issue_singleton_warnings( - src_name: ClauseName, - terms_and_locs: Vec<(Term, usize, usize)>, -) { - for (term, line_num, _col_num) in terms_and_locs { - let mut singletons = vec![]; - let mut var_count = IndexMap::new(); - - for subterm in breadth_first_iter(&term, true) { - if let TermRef::Var(_, _, var) = subterm { - let entry = var_count.entry(var).or_insert(0); - *entry += 1; - } - } - - for (var, count) in var_count { - if count == 1 && !var.starts_with("_") && var.as_str() != "!" { - singletons.push(var); - } - } - - if let Some(last_var) = singletons.pop() { - print!("Warning: {}:{}: Singleton variables: [", - src_name, line_num); - - for var in singletons { - print!("{}, ", var); - } - - println!("{}]", last_var); - } - } -} - -// set first jmp_by_call or jmp_by_index instruction to code.len() - -// idx, where idx is the place it occurs. It only does this to the -// *first* uninitialized jmp index it encounters, then returns. -fn set_first_index(code: &mut Code) { - let code_len = code.len(); - - for (idx, line) in code.iter_mut().enumerate() { - match line { - &mut Line::Control(ControlInstruction::JmpBy(_, ref mut offset, ..)) - if *offset == 0 => - { - *offset = code_len - idx; - debug_assert!(*offset > 0); - - break; - } - _ => {} - }; - } -} - -pub fn compile_appendix( +pub(super) fn compile_appendix( code: &mut Code, - queue: &VecDeque, + mut queue: VecDeque, + jmp_by_locs: Vec, non_counted_bt: bool, -) -> Result<(), ParserError> { - for tl in queue.iter() { - set_first_index(code); - let mut cg = CodeGenerator::::new(non_counted_bt); - let decl_code = compile_relation(&mut cg, tl)?; + atom_tbl: TabledData, +) -> Result<(), CompilationError> { + let mut jmp_by_locs = VecDeque::from(jmp_by_locs); + + while let Some(jmp_by_offset) = jmp_by_locs.pop_front() { + let code_len = code.len(); + + match &mut code[jmp_by_offset] { + &mut Line::Control(ControlInstruction::JmpBy(_, ref mut offset, ..)) => { + *offset = code_len - jmp_by_offset; + } + _ => { + unreachable!() + } + } + + // false because the inner predicate is a one-off, hence not extensible. + let settings = CodeGenSettings { + global_clock_tick: None, + is_extensible: false, + non_counted_bt, + }; + + let mut cg = CodeGenerator::::new(atom_tbl.clone(), settings); + + let tl = queue.pop_front().unwrap(); + let decl_code = compile_relation(&mut cg, &tl)?; + + jmp_by_locs.extend(cg.jmp_by_locs.into_iter().map(|offset| offset + code.len())); code.extend(decl_code.into_iter()); } Ok(()) } -fn append_trivial_goal(name: &ClauseName, pred: &mut Predicate) -{ - let var = Box::new(Term::Var(Cell::default(), Rc::new(String::from("X")))); - let body = QueryTerm::Clause( - Cell::default(), - ClauseType::from(clause_name!("$at_end_of_expansion"), 0, None), - vec![], - false - ); +fn lower_bound_of_target_clause(skeleton: &PredicateSkeleton, target_pos: usize) -> usize { + if target_pos == 0 { + return 0; + } - let rule = Rule { - head: (name.clone(), vec![var.clone(), var], body), - clauses: vec![] - }; + let arg_num = skeleton.clauses[target_pos - 1].opt_arg_index_key.arg_num(); - pred.0.push(PredicateClause::Rule(rule, 0, 0)); + if arg_num == 0 { + return target_pos - 1; + } + + for index in (0..target_pos - 1).rev() { + let current_arg_num = skeleton.clauses[index].opt_arg_index_key.arg_num(); + + if current_arg_num == 0 || current_arg_num != arg_num { + return index + 1; + } + } + + 0 } -impl CodeRepo { - pub fn compile_hook( - &mut self, - hook: CompileTimeHook, - ) -> Result<(), ParserError> { - let key = (hook.name(), hook.arity()); - - match self.term_dir.get_mut(&key) { - Some(ref mut preds) => { - append_trivial_goal(&key.0, &mut preds.0); - - let mut cg = CodeGenerator::::new(false); - let mut code = cg.compile_predicate(&(preds.0).0)?; - - compile_appendix(&mut code, &preds.1, false)?; - - (preds.0).0.pop(); - - Ok(match hook { - CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => { - self.term_expanders = code - } - CompileTimeHook::UserGoalExpansion | CompileTimeHook::GoalExpansion => { - self.goal_expanders = code - } - }) - } - None => Ok(match hook { - CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => { - if self.term_expanders.is_empty() { - let mut preds = Predicate::new(); - append_trivial_goal(&key.0, &mut preds); - - let mut cg = CodeGenerator::::new(false); - self.term_expanders = cg.compile_predicate(&preds.0)?; - } - } - CompileTimeHook::UserGoalExpansion | CompileTimeHook::GoalExpansion => { - if self.goal_expanders.is_empty() { - let mut preds = Predicate::new(); - append_trivial_goal(&key.0, &mut preds); - - let mut cg = CodeGenerator::::new(false); - self.goal_expanders = cg.compile_predicate(&preds.0)?; - } - } - }) +fn derelictize_try_me_else( + code: &mut Code, + index: usize, + retraction_info: &mut RetractionInfo, +) -> Option { + match &mut code[index] { + Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(0))) => None, + Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(ref mut o))) => { + retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(index, *o)); + Some(mem::replace(o, 0)) + } + Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(0))) => None, + Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(ref mut o))) => { + retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(index, *o)); + Some(mem::replace(o, 0)) + } + Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Fail(_))) | + Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Fail(_))) => None, + Line::Choice(ChoiceInstruction::TryMeElse(0)) => None, + Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => { + retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(index, *o)); + Some(mem::replace(o, 0)) + } + _ => { + unreachable!() } } } -fn compile_query( - terms: Vec, - queue: VecDeque, -) -> Result<(Code, AllocVarDict), ParserError> { - // count backtracking inferences. - let mut cg = CodeGenerator::::new(false); - let mut code = cg.compile_query(&terms)?; - - compile_appendix(&mut code, &queue, false)?; - Ok((code, cg.take_vars())) -} - -fn add_hooks_to_mockup( - code_repo: &mut CodeRepo, - hook: CompileTimeHook, - expansions: (Predicate, VecDeque), +fn merge_indices( + code: &mut Code, + target_index_loc: usize, + index_range: Range, + skeleton: &mut [ClauseIndexInfo], + retraction_info: &mut RetractionInfo, ) { - let key = (hook.name(), hook.arity()); - let preds = code_repo - .term_dir - .entry(key.clone()) - .or_insert((Predicate::new(), VecDeque::from(vec![]))); + for clause_index in index_range { + if let Some(index_loc) = skeleton[clause_index] + .opt_arg_index_key + .switch_on_term_loc() + { + let clause_loc = + find_inner_choice_instr(code, skeleton[clause_index].clause_start, index_loc); - (preds.0).0.extend((expansions.0).0.into_iter()); - preds.1.extend(expansions.1.into_iter()); -} + let target_indexing_line = to_indexing_line_mut(&mut code[target_index_loc]).unwrap(); -fn setup_module_expansions(wam: &mut Machine, module: &Module) { - let term_expansions = module.term_expansions.clone(); - let goal_expansions = module.goal_expansions.clone(); + skeleton[clause_index] + .opt_arg_index_key + .set_switch_on_term_loc(target_index_loc); - add_hooks_to_mockup( - &mut wam.code_repo, - CompileTimeHook::TermExpansion, - term_expansions, - ); - - add_hooks_to_mockup( - &mut wam.code_repo, - CompileTimeHook::GoalExpansion, - goal_expansions, - ); -} - -pub(super) -fn compile_into_module( - wam: &mut Machine, - module_name: ClauseName, - src: Stream, - name: ClauseName, -) -> EvalSession { - let mut indices = default_index_store!(wam.atom_tbl_of(&name)); - let module = wam.indices.take_module(module_name.clone()).unwrap(); - - indices.code_dir = module.code_dir.clone(); - indices.op_dir = module.op_dir.clone(); - indices.atom_tbl = module.atom_tbl.clone(); - - let mut compiler = ListingCompiler::new( - &wam.code_repo, - true, - module.listing_src.clone(), - ); - - match compile_into_module_impl(wam, &mut compiler, module, src, indices) { - Ok(()) => { - EvalSession::EntrySuccess - } - Err(e) => { - compiler.drop_expansions(&mut wam.code_repo); - EvalSession::from(e) - } - } -} - -fn compile_into_module_impl( - wam: &mut Machine, - compiler: &mut ListingCompiler, - module: Module, - src: Stream, - mut indices: IndexStore, -) -> Result<(), SessionError> { - setup_module_expansions(wam, &module); - - let module_name = module.module_decl.name.clone(); - // compiler.module = Some(module); This trips the goal expansion up. Should be possible to 'merge' modules. - // A much better strategy! - wam.indices.insert_module(module); - - wam.code_repo.compile_hook(CompileTimeHook::TermExpansion)?; - wam.code_repo.compile_hook(CompileTimeHook::GoalExpansion)?; - - let mut results = compiler.gather_items( - wam, - &mut parsing_stream(src)?, - &mut indices, - )?; - - compiler.adapt_in_situ_code( - results.worker_results, - wam, - &mut indices.code_dir, - &mut indices.module_dir, - &mut results.in_situ_code, - &results.in_situ_code_dir, - &results.in_situ_module_dir, - )?; - - let mut clause_code_generator = ClauseCodeGenerator::new( - results.in_situ_code.len(), - module_name.clone() - ); - - clause_code_generator.generate_clause_code(&results.dynamic_clause_map, wam)?; - - let top_level_term_dir = results.top_level_term_dirs.consolidate(); - let module = wam.indices.take_module(module_name).unwrap(); - - add_module( - wam, - module, - indices, - top_level_term_dir, - ); - - wam.code_repo.code.extend(results.in_situ_code.into_iter()); - clause_code_generator.add_clause_code(wam, results.dynamic_clause_map); - - Ok(compiler.drop_expansions(&mut wam.code_repo)) -} - -#[derive(Debug)] -pub struct GatherResult { - dynamic_clause_map: DynamicClauseMap, - pub(crate) worker_results: Vec, - toplevel_results: Vec, - toplevel_indices: IndexStore, - addition_results: ExpansionAdditionResult, - top_level_terms: Vec<(Term, usize, usize)>, - top_level_term_dirs: TermDirQuantum, - module_term_dirs: TermDirQuantum, - in_situ_code_dir: InSituCodeDir, - in_situ_code: Code, - in_situ_module_dir: ModuleStubDir, -} - -#[derive(Debug)] -pub struct ClauseCodeGenerator { - len_offset: usize, - code: Code, - module_name: ClauseName, - pi_to_loc: IndexMap, -} - -impl ClauseCodeGenerator { - #[inline] - fn new(len_offset: usize, module_name: ClauseName) -> Self { - ClauseCodeGenerator { - len_offset, - code: vec![], - module_name, - pi_to_loc: IndexMap::new(), - } - } - - // compiles the latest version of clause/2. - fn generate_clause_code( - &mut self, - dynamic_clause_map: &DynamicClauseMap, - wam: &Machine, - ) -> Result<(), SessionError> { - for ((name, arity), heads_and_tails) in dynamic_clause_map { - if heads_and_tails.is_empty() { - continue; - } - - let predicate = Predicate( - heads_and_tails - .iter() - .map(|(head, tail)| { - let clause = Term::Clause( - Cell::default(), - clause_name!("clause"), - vec![Box::new(head.clone()), Box::new(tail.clone())], - None, - ); - - PredicateClause::Fact(clause, 0, 0) - }) - .collect(), + merge_clause_index( + target_indexing_line, + &mut skeleton[0..clause_index + 1], + clause_loc, + AppendOrPrepend::Append, ); - let p = self.code.len() + wam.code_repo.code.len() + self.len_offset; - let mut cg = CodeGenerator::::new(false); - - let mut decl_code = compile_relation( - &mut cg, - &TopLevel::Predicate(predicate), - )?; - - compile_appendix(&mut decl_code, &VecDeque::new(), false)?; - - self.pi_to_loc.insert((name.clone(), *arity), p); - self.code.extend(decl_code.into_iter()); + retraction_info.push_record(RetractionRecord::AddedIndex( + skeleton[clause_index].opt_arg_index_key.clone(), + clause_loc, + )); + } else { + break; } - - Ok(()) } +} - fn add_clause_code(self, wam: &mut Machine, dynamic_code_dir: DynamicClauseMap) - { - wam.code_repo.code.extend(self.code.into_iter()); - - if self.module_name.as_str() == "user" { - for ((name, arity), _) in &dynamic_code_dir { - wam.indices.code_dir.entry((name.clone(), *arity)) - .or_insert(CodeIndex::dynamic_undefined(clause_name!("user"))); +fn find_outer_choice_instr( + code: &Code, + mut index: usize, +) -> usize { + loop { + match &code[index] { + Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(i))) | + Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(i))) + if *i > 0 => + { + index += i; + } + _ => { + return index; } } + } +} - for ((name, arity), _) in dynamic_code_dir { - wam.indices.dynamic_code_dir.insert((name.owning_module(), name, arity), - DynamicPredicateInfo::default()); - } - - for ((name, arity), p) in self.pi_to_loc { - let entry = wam - .indices - .dynamic_code_dir - .entry((name.owning_module(), name, arity)) - .or_insert(DynamicPredicateInfo::default()); - - entry.clauses_subsection_p = p; +fn find_inner_choice_instr( + code: &Code, + mut index: usize, + index_loc: usize, +) -> usize { + loop { + match &code[index] { + Line::Choice(ChoiceInstruction::TryMeElse(o)) | + Line::Choice(ChoiceInstruction::RetryMeElse(o)) => { + if *o > 0 { + return index; + } else { + index = index_loc; + } + } + &Line::Choice(ChoiceInstruction::DynamicElse(_, _, next_or_fail)) | + &Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, next_or_fail)) => { + match next_or_fail { + NextOrFail::Next(i) => { + if i == 0 { + index = index_loc; + } else { + return index; + } + } + NextOrFail::Fail(_) => { + return index; + } + } + } + Line::Choice(ChoiceInstruction::TrustMe(_)) => { + return index; + } + Line::IndexingCode(indexing_code) => match &indexing_code[0] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => { + match v { + IndexingCodePtr::External(v) => { + index += v; + } + IndexingCodePtr::DynamicExternal(v) => { + match &code[index + v] { + &Line::Choice(ChoiceInstruction::DynamicInternalElse( + _, + _, + NextOrFail::Next(0), + )) => { + return index + v; + } + _ => { + index += v; + } + } + } + _ => unreachable!() + } + } + _ => { + unreachable!(); + } + }, + Line::Control(ControlInstruction::RevJmpBy(offset)) => { + index -= offset; + } + _ => { + /* Here we land at the line after a TryMeElse(0), + * which happens iff a single clause belongs to the + * indexed subsequence. So, end the search by pointing + * to the original derelict TryMeElse. + */ + return index - 1; + } } } } -fn insert_or_refresh_term_dir_quantum( - term_dir: &TermDir, +fn remove_index_from_subsequence( + code: &mut Code, + opt_arg_index_key: &OptArgIndexKey, + clause_start: usize, + retraction_info: &mut RetractionInfo, +) { + if let Some(index_loc) = opt_arg_index_key.switch_on_term_loc() { + let clause_start = find_inner_choice_instr(code, clause_start, index_loc); + + let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap(); + + let offset = clause_start - index_loc + 1; + + remove_index(opt_arg_index_key, target_indexing_line, offset); + + // TODO: this isn't sufficiently precise. The removed offset could + // appear anywhere inside an Internal record. + retraction_info.push_record(RetractionRecord::RemovedIndex( + index_loc, + opt_arg_index_key.clone(), + offset, + )); + } +} + +fn merge_indexed_subsequences( + code: &mut Code, + skeleton: &mut PredicateSkeleton, + lower_upper_bound: usize, + upper_lower_bound: usize, + retraction_info: &mut RetractionInfo, +) -> Option { + // patch the inner-threaded choice instructions to link the + // two sequences, patch lower_bound's outer-threaded choice + // instruction to TrustMe (or RetryMeElse), and derelict-ize + // target_pos + 1's inner TryMeElse. + + let inner_trust_me_loc = skeleton.clauses[upper_lower_bound - 2].clause_start; + + let inner_try_me_else_loc = find_inner_choice_instr( + code, + skeleton.clauses[upper_lower_bound].clause_start, + skeleton.clauses[upper_lower_bound] + .opt_arg_index_key + .switch_on_term_loc() + .unwrap(), + ); + + match &mut code[inner_try_me_else_loc] { + Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => { + retraction_info.push_record(RetractionRecord::ModifiedTryMeElse( + inner_try_me_else_loc, + *o, + )); + + match *o { + 0 => { + code[inner_try_me_else_loc] = Line::Choice(ChoiceInstruction::TrustMe(0)); + } + o => match &code[inner_try_me_else_loc + o] { + Line::Control(ControlInstruction::RevJmpBy(0)) => { + code[inner_try_me_else_loc] = Line::Choice(ChoiceInstruction::TrustMe(o)); + } + _ => { + code[inner_try_me_else_loc] = + Line::Choice(ChoiceInstruction::RetryMeElse(o)); + } + }, + } + } + _ => {} + } + + thread_choice_instr_at_to( + code, + inner_trust_me_loc, + inner_try_me_else_loc, + retraction_info, + ); + + let mut end_of_upper_lower_bound = None; + + for index in upper_lower_bound..skeleton.clauses.len() { + if !skeleton.clauses[index].opt_arg_index_key.is_some() { + end_of_upper_lower_bound = Some(index); + break; + } + } + + let outer_threaded_choice_instr_loc = skeleton.clauses[lower_upper_bound].clause_start - 2; + + match end_of_upper_lower_bound { + Some(outer_threaded_clause_index) => { + thread_choice_instr_at_to( + code, + outer_threaded_choice_instr_loc, + skeleton.clauses[outer_threaded_clause_index].clause_start, + retraction_info, + ); + } + None => match &mut code[outer_threaded_choice_instr_loc] { + Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => { + retraction_info + .push_record(RetractionRecord::ModifiedTryMeElse(inner_trust_me_loc, *o)); + + *o = 0; + + return Some(IndexPtr::Index(outer_threaded_choice_instr_loc + 1)); + } + _ => {} + }, + } + + None +} + +fn delete_from_skeleton( + compilation_target: CompilationTarget, key: PredicateKey, - term_dirs: &mut TermDirQuantum -) { - match term_dir.get(&key) { - Some((ref preds, ref queue)) => { - let entry = TermDirQuantumEntry::from(preds, queue); - term_dirs.insert_or_refresh(key, entry); - } - None => { - let entry = TermDirQuantumEntry::from(&Predicate::new(), &VecDeque::new()); - term_dirs.insert_or_refresh(key, entry); + skeleton: &mut PredicateSkeleton, + target_pos: usize, + retraction_info: &mut RetractionInfo, +) -> usize { + let clause_index_info = skeleton.clauses.remove(target_pos); + let clause_clause_loc = skeleton.clause_clause_locs.remove(target_pos); + + if target_pos < skeleton.clause_assert_margin { + skeleton.clause_assert_margin -= 1; + } + + retraction_info.push_record(RetractionRecord::RemovedSkeletonClause( + compilation_target, + key, + target_pos, + clause_index_info, + clause_clause_loc, + )); + + clause_clause_loc +} + +fn blunt_leading_choice_instr( + code: &mut Code, + mut instr_loc: usize, + retraction_info: &mut RetractionInfo, +) -> usize { + loop { + match &mut code[instr_loc] { + Line::Choice(ChoiceInstruction::RetryMeElse(o)) => { + retraction_info.push_record(RetractionRecord::ModifiedRetryMeElse(instr_loc, *o)); + + code[instr_loc] = Line::Choice(ChoiceInstruction::TryMeElse(*o)); + + return instr_loc; + } + Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(_))) | + Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(_))) => { + return instr_loc; + } + &mut Line::Choice(ChoiceInstruction::DynamicElse(b, d, NextOrFail::Fail(o))) => { + retraction_info.push_record( + RetractionRecord::AppendedNextOrFail(instr_loc, NextOrFail::Fail(o)), + ); + + code[instr_loc] = Line::Choice( + ChoiceInstruction::DynamicElse(b, d, NextOrFail::Next(0)), + ); + + return instr_loc; + } + &mut Line::Choice(ChoiceInstruction::DynamicInternalElse(b, d, NextOrFail::Fail(o))) => { + retraction_info.push_record( + RetractionRecord::AppendedNextOrFail(instr_loc, NextOrFail::Fail(o)), + ); + + code[instr_loc] = Line::Choice( + ChoiceInstruction::DynamicInternalElse(b, d, NextOrFail::Next(0)), + ); + + return instr_loc; + } + Line::Choice(ChoiceInstruction::TrustMe(o)) => { + retraction_info + .push_record(RetractionRecord::AppendedTrustMe(instr_loc, *o, false)); + + code[instr_loc] = Line::Choice(ChoiceInstruction::TryMeElse(0)); + return instr_loc + 1; + } + Line::Choice(ChoiceInstruction::TryMeElse(0)) => { + return instr_loc + 1; + } + Line::Choice(ChoiceInstruction::TryMeElse(o)) => { + instr_loc += *o; + } + Line::Control(ControlInstruction::RevJmpBy(o)) => { + instr_loc -= *o; + } + _ => { + unreachable!() + } } } } -#[derive(Debug)] -pub struct ListingCompiler { - module: Option, - user_term_dir: TermDir, - orig_term_expansion_lens: (usize, usize), - orig_goal_expansion_lens: (usize, usize), - initialization_goals: (Vec, VecDeque), - suppress_warnings: bool, - listing_src: ListingSource, // a file? a module? -} - -fn add_toplevel( - wam: &mut Machine, - indices: IndexStore, - term_dir: TermDir, +fn set_switch_var_offset_to_choice_instr( + code: &mut Code, + index_loc: usize, + offset: usize, + retraction_info: &mut RetractionInfo, ) { - wam.add_batched_code_dir(indices.code_dir); - wam.add_batched_ops(indices.op_dir); - wam.add_in_situ_module_dir(indices.module_dir); + let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap(); - wam.code_repo.term_dir.extend(term_dir.into_iter()); + let v = match &target_indexing_line[0] { + &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => { + match v { + IndexingCodePtr::External(v) | IndexingCodePtr::DynamicExternal(v) => v, + _ => unreachable!() + } + } + _ => { + unreachable!(); + } + }; + + match &code[index_loc + v] { + Line::Choice(ChoiceInstruction::TryMeElse(_)) | + Line::Choice(ChoiceInstruction::DynamicElse(..)) | + Line::Choice(ChoiceInstruction::DynamicInternalElse(..)) => {} + _ => { + set_switch_var_offset(code, index_loc, offset, retraction_info); + } + } } #[inline] -fn add_module( - wam: &mut Machine, - mut module: Module, - indices: IndexStore, - term_dir: TermDir, +fn set_switch_var_offset( + code: &mut Code, + index_loc: usize, + offset: usize, + retraction_info: &mut RetractionInfo, ) { - module.code_dir.extend(indices.code_dir); - module.op_dir.extend(indices.op_dir); - module.term_dir.extend(term_dir); + let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap(); - wam.add_in_situ_module_dir(indices.module_dir); - wam.add_module(module); -} - -fn add_non_module_code( - wam: &mut Machine, - dynamic_clause_map: DynamicClauseMap, - code: Code, - indices: IndexStore, - term_dir: TermDir, -) -> Result<(), SessionError> { - wam.check_toplevel_code(&indices)?; - - let mut clause_code_generator = ClauseCodeGenerator::new(code.len(), clause_name!("user")); - clause_code_generator.generate_clause_code(&dynamic_clause_map, wam)?; - - add_toplevel(wam, indices, term_dir); - wam.code_repo.code.extend(code); - clause_code_generator.add_clause_code(wam, dynamic_clause_map); - - Ok(()) -} - -pub(super) -fn load_library( - wam: &mut Machine, - name: ClauseName, - suppress_warnings: bool, -) -> Result { - match LIBRARIES.borrow().get(name.as_str()) { - Some(code) => { - let listing_src = ListingSource::User; - - load_module( - wam, - Stream::from(*code), - suppress_warnings, - &listing_src, - ) - } - None => { - let err = ExistenceError::ModuleSource(ModuleSource::Library( - name.clone() - )); - - Err(SessionError::ExistenceError(err)) - } - } -} - -impl ListingCompiler { - #[inline] - pub fn new( - code_repo: &CodeRepo, - suppress_warnings: bool, - listing_src: ListingSource, - ) -> Self { - ListingCompiler { - module: None, - user_term_dir: TermDir::new(), - orig_term_expansion_lens: code_repo - .term_dir_entry_len((clause_name!("term_expansion"), 2)), - orig_goal_expansion_lens: code_repo - .term_dir_entry_len((clause_name!("goal_expansion"), 2)), - initialization_goals: (vec![], VecDeque::from(vec![])), - suppress_warnings, - listing_src - } - } - - /* Replace calls to self with a localized index cell, not - * available to the global CodeIndex. This is done to implement - * logical update semantics for dynamic database updates. - */ - fn localize_self_calls(&mut self, key: PredicateKey, code: &mut Code, p: usize, target_p: usize) - { - let (name, arity) = key; - - let self_idx = CodeIndex::default(); - set_code_index!(self_idx, IndexPtr::Index(target_p), self.get_module_name()); - - walk_code_mut(code, p, |instr| - match instr { - Line::Control(ControlInstruction::CallClause(ref mut ct, ..)) => { - match ct { - ClauseType::Named(ref ct_name, ct_arity, ref mut idx) - if ct_name == &name && arity == *ct_arity => - { - *idx = self_idx.clone(); - } - ClauseType::Op(ref op_name, ref shared_op_desc, ref mut idx) - if op_name == &name && shared_op_desc.arity() == arity => - { - *idx = self_idx.clone(); - } - _ => {} - } + let old_v = match &mut target_indexing_line[0] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, ref mut v, ..)) => { + match *v { + IndexingCodePtr::DynamicExternal(_) => { + mem::replace(v, IndexingCodePtr::DynamicExternal(offset)) } - _ => {} - }, + IndexingCodePtr::External(_) => { + mem::replace(v, IndexingCodePtr::External(offset)) + } + _ => unreachable!() + } + } + _ => { + unreachable!() + } + }; + + retraction_info.push_record(RetractionRecord::ReplacedSwitchOnTermVarIndex( + index_loc, old_v, + )); +} + +fn internalize_choice_instr_at( + code: &mut Code, + instr_loc: usize, + retraction_info: &mut RetractionInfo, +) { + match &mut code[instr_loc] { + Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Fail(_))) | + Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Fail(_))) => { + } + Line::Choice(ChoiceInstruction::DynamicElse(_, _, ref mut o @ NextOrFail::Next(0))) => { + retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, 0)); + *o = NextOrFail::Fail(0); + } + &mut Line::Choice(ChoiceInstruction::DynamicElse(b, d, NextOrFail::Next(o))) => { + retraction_info.push_record( + RetractionRecord::AppendedNextOrFail(instr_loc, NextOrFail::Next(o)), + ); + + match &mut code[instr_loc + o] { + Line::Control(ControlInstruction::RevJmpBy(p)) if *p == 0 => { + code[instr_loc] = Line::Choice( + ChoiceInstruction::DynamicElse(b, d, NextOrFail::Fail(o)), + ); + } + _ => { + code[instr_loc] = Line::Choice( + ChoiceInstruction::DynamicElse(b, d, NextOrFail::Next(o)), + ); + } + } + } + Line::Choice(ChoiceInstruction::DynamicInternalElse( + _, _, ref mut o @ NextOrFail::Next(0), + )) => { + retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, 0)); + *o = NextOrFail::Fail(0); + } + &mut Line::Choice(ChoiceInstruction::DynamicInternalElse(b, d, NextOrFail::Next(o))) => { + retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, o)); + + match &mut code[instr_loc + o] { + Line::Control(ControlInstruction::RevJmpBy(p)) if *p == 0 => { + code[instr_loc] = Line::Choice( + ChoiceInstruction::DynamicInternalElse(b, d, NextOrFail::Fail(o)), + ); + } + _ => { + code[instr_loc] = Line::Choice( + ChoiceInstruction::DynamicInternalElse(b, d, NextOrFail::Next(o)), + ); + } + } + } + Line::Choice(ChoiceInstruction::TryMeElse(0)) => { + retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(instr_loc, 0)); + + code[instr_loc] = Line::Choice(ChoiceInstruction::TrustMe(0)); + } + Line::Choice(ChoiceInstruction::TryMeElse(o)) => { + let o = *o; + + retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(instr_loc, o)); + + match &mut code[instr_loc + o] { + Line::Control(ControlInstruction::RevJmpBy(p)) if *p == 0 => { + code[instr_loc] = Line::Choice(ChoiceInstruction::TrustMe(o)); + } + _ => { + code[instr_loc] = Line::Choice(ChoiceInstruction::RetryMeElse(o)); + } + } + } + _ => { + unreachable!(); + } + } +} + +fn thread_choice_instr_at_to( + code: &mut Code, + mut instr_loc: usize, + target_loc: usize, + retraction_info: &mut RetractionInfo, +) { + loop { + match &mut code[instr_loc] { + Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) | + Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o)) + if target_loc >= instr_loc => + { + retraction_info.push_record(RetractionRecord::ReplacedChoiceOffset(instr_loc, *o)); + + *o = target_loc - instr_loc; + return; + } + Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(ref mut o))) | + Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(ref mut o))) + if target_loc >= instr_loc => + { + retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, *o)); + *o = target_loc - instr_loc; + return; + } + Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(ref mut o))) | + Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(ref mut o))) => { + instr_loc += *o; + } + Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) | + Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o)) => { + instr_loc += *o; + } + Line::Control(ControlInstruction::RevJmpBy(ref mut o)) if instr_loc >= target_loc => { + retraction_info.push_record(RetractionRecord::ModifiedRevJmpBy(instr_loc, *o)); + + *o = instr_loc - target_loc; + return; + } + &mut Line::Choice(ChoiceInstruction::DynamicElse(birth, death, ref mut fail)) + if target_loc >= instr_loc => + { + retraction_info.push_record( + RetractionRecord::AppendedNextOrFail(instr_loc, *fail), + ); + + code[instr_loc] = + Line::Choice(ChoiceInstruction::DynamicElse( + birth, death, NextOrFail::Next(target_loc - instr_loc), + )); + + return; + } + Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Fail(o))) + if *o > 0 => + { + instr_loc += *o; + } + &mut Line::Choice(ChoiceInstruction::DynamicInternalElse(birth, death, ref mut fail)) + if target_loc >= instr_loc => + { + retraction_info.push_record( + RetractionRecord::AppendedNextOrFail(instr_loc, *fail), + ); + + code[instr_loc] = + Line::Choice(ChoiceInstruction::DynamicInternalElse( + birth, death, NextOrFail::Next(target_loc - instr_loc), + )); + + return; + } + Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Fail(o))) + if *o > 0 => + { + instr_loc += *o; + } + Line::Choice(ChoiceInstruction::TrustMe(ref mut o)) if target_loc >= instr_loc => { + retraction_info.push_record( + RetractionRecord::AppendedTrustMe(instr_loc, *o, false), + //choice_instr.is_default()), + ); + + code[instr_loc] = + Line::Choice(ChoiceInstruction::RetryMeElse(target_loc - instr_loc)); + + return; + } + Line::Choice(ChoiceInstruction::TrustMe(o)) if *o > 0 => { + instr_loc += *o; + } + _ => { + unreachable!() + } + } + } +} + +fn remove_non_leading_clause( + code: &mut Code, + preceding_choice_instr_loc: usize, + non_indexed_choice_instr_loc: usize, + retraction_info: &mut RetractionInfo, +) -> Option { + match &mut code[non_indexed_choice_instr_loc] { + Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o)) => { + let o = *o; + + thread_choice_instr_at_to( + code, + preceding_choice_instr_loc, + non_indexed_choice_instr_loc + o, + retraction_info, + ); + + None + } + Line::Choice(ChoiceInstruction::TrustMe(_)) => { + match &mut code[preceding_choice_instr_loc] { + Line::Choice(ChoiceInstruction::RetryMeElse(o)) => { + retraction_info.push_record(RetractionRecord::ModifiedRetryMeElse( + preceding_choice_instr_loc, + *o, + )); + + code[preceding_choice_instr_loc] = Line::Choice(ChoiceInstruction::TrustMe(0)); + + None + } + Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => { + retraction_info.push_record(RetractionRecord::ModifiedTryMeElse( + preceding_choice_instr_loc, + *o, + )); + + *o = 0; + + Some(IndexPtr::Index(preceding_choice_instr_loc + 1)) + } + _ => { + unreachable!(); + } + } + } + _ => { + unreachable!(); + } + } +} + +fn finalize_retract( + key: PredicateKey, + compilation_target: CompilationTarget, + skeleton: &mut PredicateSkeleton, + code_index: CodeIndex, + target_pos: usize, + index_ptr_opt: Option, + retraction_info: &mut RetractionInfo, +) -> usize { + let clause_clause_loc = delete_from_skeleton( + compilation_target.clone(), + key.clone(), + skeleton, + target_pos, + retraction_info, + ); + + if let Some(index_ptr) = index_ptr_opt { + set_code_index( + retraction_info, + &compilation_target, + key, + &code_index, + index_ptr, ); } - fn use_module( - &mut self, - submodule: ClauseName, - code_repo: &mut CodeRepo, - flags: MachineFlags, - wam_indices: &mut IndexStore, - indices: &mut IndexStore, - ) -> Result<(), SessionError> { - let module_name = self.get_module_name(); + clause_clause_loc +} - if let Some(mut submodule) = wam_indices.take_module(submodule) { - unwind_protect!( - indices.use_module(code_repo, flags, &submodule), - wam_indices.insert_module(submodule) - ); +fn remove_leading_unindexed_clause( + code: &mut Code, + non_indexed_choice_instr_loc: usize, + retraction_info: &mut RetractionInfo, +) -> Option { + match &mut code[non_indexed_choice_instr_loc] { + Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => { + if *o > 0 { + retraction_info.push_record(RetractionRecord::ModifiedTryMeElse( + non_indexed_choice_instr_loc, + *o, + )); - if let Some(ref mut module) = &mut self.module { - module.remove_module(module_name, &submodule); - unwind_protect!( - module.use_module(code_repo, flags, &submodule), - wam_indices.insert_module(submodule) + let o = mem::replace(o, 0); + + let index_ptr = blunt_leading_choice_instr( + code, + non_indexed_choice_instr_loc + o, + retraction_info, ); + + Some(IndexPtr::Index(index_ptr)) } else { - submodule.inserted_expansions = true; - wam_indices.remove_module(clause_name!("user"), &submodule); + Some(IndexPtr::DynamicUndefined) } - - Ok(wam_indices.insert_module(submodule)) - } else { - let err = ExistenceError::ModuleSource(ModuleSource::File( - module_name, - )); - - Err(SessionError::ExistenceError(err)) + } + _ => { + unreachable!(); } } +} - fn use_qualified_module( - &mut self, - submodule: ClauseName, - code_repo: &mut CodeRepo, - flags: MachineFlags, - exports: &Vec, - wam_indices: &mut IndexStore, - indices: &mut IndexStore, - ) -> Result<(), SessionError> { - let module_name = self.get_module_name(); - - if let Some(mut submodule) = wam_indices.take_module(submodule) { - unwind_protect!( - indices.use_qualified_module(code_repo, flags, &submodule, exports), - wam_indices.insert_module(submodule) - ); - - if let &mut Some(ref mut module) = &mut self.module { - module.remove_module(module_name, &submodule); - unwind_protect!( - module.use_qualified_module(code_repo, flags, &submodule, exports), - wam_indices.insert_module(submodule) - ); - } else { - submodule.inserted_expansions = true; - wam_indices.remove_module(clause_name!("user"), &submodule); +fn find_dynamic_outer_choice_instr( + code: &Code, + index_loc: usize, +) -> usize { + match &code[index_loc] { + Line::IndexingCode(indexing_code) => { + match &indexing_code[0] { + &IndexingLine::Indexing( + IndexingInstruction::SwitchOnTerm( + _, + IndexingCodePtr::DynamicExternal(v), + .., + ) + ) => { + index_loc + v - 2 + } + _ => unreachable!() } - - Ok(wam_indices.insert_module(submodule)) - } else { - let err = ExistenceError::ModuleSource(ModuleSource::File( - module_name - )); - - Err(SessionError::ExistenceError(err)) } + _ => unreachable!() } +} - #[inline] - fn get_module_name(&self) -> ClauseName { - self.module - .as_ref() - .map(|module| module.module_decl.name.clone()) - .unwrap_or(ClauseName::BuiltIn("user")) - } +fn prepend_compiled_clause( + code: &mut Code, + compilation_target: CompilationTarget, + key: PredicateKey, + mut clause_code: Code, + skeleton: &mut PredicateSkeleton, + retraction_info: &mut RetractionInfo, + global_clock_tick: usize, +) -> IndexPtr { + let clause_loc = code.len(); + let mut prepend_queue = sdeq![]; - fn generate_init_goal_code( - &mut self, - ) -> Result { - let query_terms = mem::replace(&mut self.initialization_goals.0, vec![]); - let queue = mem::replace(&mut self.initialization_goals.1, VecDeque::new()); + let target_arg_num = skeleton.clauses[0].opt_arg_index_key.arg_num(); + let head_arg_num = skeleton.clauses[1].opt_arg_index_key.arg_num(); + + let settings = CodeGenSettings { + global_clock_tick: if skeleton.is_dynamic { + Some(global_clock_tick) + } else { + None + }, + is_extensible: true, + non_counted_bt: false, + }; - compile_query(query_terms, queue) - .map(|(code, _)| code) - .map_err(SessionError::from) - } + let clause_loc = if skeleton.clauses[0] + .opt_arg_index_key + .switch_on_term_loc() + .is_some() + { + match skeleton.clauses[1].opt_arg_index_key.switch_on_term_loc() { + Some(index_loc) if target_arg_num == head_arg_num => { + prepend_queue.extend(clause_code.drain(3..)); - fn set_code_index( - &mut self, - wam: &Machine, - key: PredicateKey, - in_situ_code: &mut Code, - code_dir: &mut CodeDir, - in_situ_code_dir: &InSituCodeDir, - decl: PredicateCompileQueue, - ) -> Result<(), SessionError> { - let p = wam.code_repo.code.len(); + skeleton.clauses[0].opt_arg_index_key += index_loc - 1; + skeleton.clauses[0].clause_start = clause_loc + 2; - let idx = code_dir - .entry(key.clone()) - .or_insert(CodeIndex::default()); + retraction_info.push_record(RetractionRecord::AddedIndex( + skeleton.clauses[0].opt_arg_index_key.clone(), + skeleton.clauses[0].clause_start, + )); - Ok(match in_situ_code_dir.get(&key) { - Some(in_situ_p) => { - set_code_index!(idx, IndexPtr::Index(p + *in_situ_p), self.get_module_name()); - self.localize_self_calls(key, in_situ_code, *in_situ_p, p + *in_situ_p); + let outer_thread_choice_loc = if skeleton.is_dynamic { + find_dynamic_outer_choice_instr(code, index_loc) + } else { + skeleton.clauses[1].clause_start - 2 + }; + + retraction_info.push_record(RetractionRecord::SkeletonClauseStartReplaced( + compilation_target, + key.clone(), + 1, + skeleton.clauses[1].clause_start, + )); + + skeleton.clauses[1].clause_start = + find_inner_choice_instr(code, skeleton.clauses[1].clause_start, index_loc); + + let inner_thread_rev_offset = + 3 + prepend_queue.len() + clause_loc - skeleton.clauses[1].clause_start; + + prepend_queue.push_back(Line::Control(ControlInstruction::RevJmpBy( + inner_thread_rev_offset, + ))); + + prepend_queue.push_front(Line::Choice( + settings.internal_try_me_else(prepend_queue.len()), + )); + + // prepend_queue is now: + // | TryMeElse N_2 + // | (clause_code) + // +N_2 | RevJmpBy (RetryMeElse(M_1) or TryMeElse(0) at index_loc + 1) + + prepend_queue.push_front(Line::Control(ControlInstruction::RevJmpBy( + 1 + clause_loc - index_loc, + ))); + + let outer_thread_choice_offset = // outer_thread_choice_loc WAS index_loc - 1.. + match derelictize_try_me_else(code, outer_thread_choice_loc, retraction_info) { + Some(next_subseq_offset) => { + // skeleton.clauses[1] has a non-stub TryMeElse. + + let outer_thread_rev_offset = + prepend_queue.len() + 1 + clause_loc - outer_thread_choice_loc - + next_subseq_offset; + + prepend_queue.push_back( + Line::Control(ControlInstruction::RevJmpBy(outer_thread_rev_offset)) + ); + + prepend_queue.len() + } + None => { + // This case occurs when the clauses of + // the host predicate, up to and including + // the prepending of this clause, are + // indexed. + + // The outer TryMeElse / RevJmpBy pushed + // in this case are stub instructions + // awaiting the addition of unindexed + // clauses. + + prepend_queue.push_back( + Line::Control(ControlInstruction::RevJmpBy(0)), + ); + + 0 + } + }; + + prepend_queue.push_front(Line::Choice( + settings.try_me_else(outer_thread_choice_offset), + )); + + // prepend_queue is now: + // | TryMeElse N_3 + // | RevJmpBy (SwitchOnTerm at index_loc) + // | TryMeElse N_2 + // | (clause_code) + // N_2 | RevJmpBy (RetryMeElse(M_1) or TryMeElse(0) at index_loc + 1) + // N_3 | RevJmpBy (TryMeElse(N_1) at index_loc - 1 or TrustMe if N_1 == 0) + + let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap(); + + merge_clause_index( + target_indexing_line, + &mut skeleton.clauses, + clause_loc + 2, // == skeleton.clauses[0].clause_start + AppendOrPrepend::Prepend, + ); + + set_switch_var_offset(code, index_loc, clause_loc - index_loc + 2, retraction_info); + + internalize_choice_instr_at( + code, + skeleton.clauses[1].clause_start, + retraction_info, + ); + + code.extend(prepend_queue.into_iter()); + + if skeleton.is_dynamic { + clause_loc + } else { + clause_loc + (outer_thread_choice_offset == 0) as usize + } + } + _ => { + prepend_queue.extend(clause_code.drain(1..)); + + skeleton.clauses[0].opt_arg_index_key += clause_loc; + skeleton.clauses[0].clause_start = clause_loc + 2; + + let old_clause_start = + match skeleton.clauses[1].opt_arg_index_key.switch_on_term_loc() { + Some(index_loc) if skeleton.is_dynamic => { + find_dynamic_outer_choice_instr(code, index_loc) + } + Some(_) => { + skeleton.clauses[1].clause_start - 2 + } + None => { + skeleton.clauses[1].clause_start + } + }; + + let inner_thread_rev_offset = + 2 + prepend_queue.len() + clause_loc - old_clause_start; + + // this is a stub for chaining inner-threaded choice + // instructions. + prepend_queue.push_back(Line::Control(ControlInstruction::RevJmpBy(0))); + + let prepend_queue_len = prepend_queue.len(); + + match &mut prepend_queue[1] { + Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) if *o == 0 => { + *o = prepend_queue_len - 2; + } + Line::Choice(ChoiceInstruction::DynamicInternalElse( + _, _, ref mut o @ NextOrFail::Next(0), + )) => { + *o = NextOrFail::Fail(prepend_queue_len - 2); + } + _ => { + unreachable!(); + } + } + + prepend_queue.push_back(Line::Control(ControlInstruction::RevJmpBy( + inner_thread_rev_offset, + ))); + + prepend_queue.push_front(Line::Choice( + settings.try_me_else(prepend_queue.len()), + )); + + // prepend_queue is now: + // | TryMeElse(N_2) + // | SwitchOnTerm 2, ... + // | TryMeElse(0) + // | (clause_code) + // +N_2 | RevJmpBy (RetryMeElse(M_1)) + + internalize_choice_instr_at(code, old_clause_start, retraction_info); + + code.extend(prepend_queue.into_iter()); + + clause_loc // + (outer_thread_choice_offset == 0 as usize) + } + } + } else { + match skeleton.clauses[1].opt_arg_index_key.switch_on_term_loc() { + Some(index_loc) => { + prepend_queue.extend(clause_code.drain(1..)); + + let old_clause_start = if skeleton.is_dynamic { + find_dynamic_outer_choice_instr(code, index_loc) + } else { + skeleton.clauses[1].clause_start - 2 + }; + + let inner_thread_rev_offset = + 1 + prepend_queue.len() + clause_loc - old_clause_start; + + prepend_queue.push_back(Line::Control(ControlInstruction::RevJmpBy( + inner_thread_rev_offset, + ))); + + prepend_queue.push_front(Line::Choice( + settings.try_me_else(prepend_queue.len()), + )); + + // prepend_queue is now: + // | TryMeElse(N_2) + // | (clause_code) + // +N_2 | RevJmpBy (RetryMeElse(M_1)) + + internalize_choice_instr_at(code, old_clause_start, retraction_info); + + code.extend(prepend_queue.into_iter()); + + // skeleton.clauses[0].opt_arg_index_key += clause_loc; + skeleton.clauses[0].clause_start = clause_loc; + + clause_loc // + (outer_thread_choice_offset == 0 as usize) } None => { - let (decl, queue) = decl; + prepend_queue.extend(clause_code.drain(1..)); - let mut cg = CodeGenerator::::new(false); - let mut decl_code = cg.compile_predicate(&decl.0)?; + let old_clause_start = skeleton.clauses[1].clause_start; - compile_appendix(&mut decl_code, &queue, false)?; + let inner_thread_rev_offset = + 1 + prepend_queue.len() + clause_loc - old_clause_start; - let in_situ_p = in_situ_code.len(); + prepend_queue.push_back(Line::Control(ControlInstruction::RevJmpBy( + inner_thread_rev_offset, + ))); - in_situ_code.extend(decl_code.into_iter()); + prepend_queue.push_front(Line::Choice( + settings.try_me_else(prepend_queue.len()), + )); - set_code_index!(idx, IndexPtr::Index(p + in_situ_p), self.get_module_name()); - self.localize_self_calls(key, in_situ_code, in_situ_p, p + in_situ_p); + // prepend_queue is now: + // | TryMeElse(N_2) + // | (clause_code) + // +N_2 | RevJmpBy (RetryMeElse(M_1)) + + internalize_choice_instr_at(code, old_clause_start, retraction_info); + + code.extend(prepend_queue.into_iter()); + + // skeleton.clauses[0].opt_arg_index_key += clause_loc; + skeleton.clauses[0].clause_start = clause_loc; + + clause_loc } + } + }; + + if skeleton.is_dynamic { + IndexPtr::DynamicIndex(clause_loc) + } else { + IndexPtr::Index(clause_loc) + } +} + +fn append_compiled_clause( + code: &mut Code, + mut clause_code: Code, + skeleton: &mut PredicateSkeleton, + retraction_info: &mut RetractionInfo, + global_clock_tick: usize, +) -> Option { + let clause_loc = code.len(); + let target_pos = skeleton.clauses.len() - 1; + let lower_bound = lower_bound_of_target_clause(skeleton, target_pos); + + let settings = CodeGenSettings { + global_clock_tick: if skeleton.is_dynamic { + Some(global_clock_tick) + } else { + None + }, + is_extensible: true, + non_counted_bt: false, + }; + + skeleton.clauses[target_pos].clause_start = clause_loc; + + let mut code_ptr_opt = None; + + let lower_bound_arg_num = skeleton.clauses[lower_bound].opt_arg_index_key.arg_num(); + let target_arg_num = skeleton.clauses[target_pos].opt_arg_index_key.arg_num(); + + let threaded_choice_instr_loc = match skeleton.clauses[lower_bound] + .opt_arg_index_key + .switch_on_term_loc() + { + Some(index_loc) if lower_bound_arg_num == target_arg_num => { + code.push(Line::Choice(settings.internal_trust_me())); + + code.extend(clause_code.drain(3..)); // skip the indexing code + + // set skeleton[target_pos].opt_arg_index_key to + // index_loc. its original value is always 1. + skeleton.clauses[target_pos].opt_arg_index_key += index_loc - 1; + + retraction_info.push_record(RetractionRecord::AddedIndex( + skeleton.clauses[target_pos].opt_arg_index_key.clone(), + skeleton.clauses[target_pos].clause_start, + )); + + let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap(); + + merge_clause_index( + target_indexing_line, + &mut skeleton.clauses[lower_bound..], + clause_loc, + AppendOrPrepend::Append, + ); + + let target_pos_clause_start = find_inner_choice_instr( + code, + skeleton.clauses[target_pos - 1].clause_start, + index_loc, + ); + + let target_pos_clause_start = find_outer_choice_instr( + code, + target_pos_clause_start, + ); + + if lower_bound + 1 == target_pos { + set_switch_var_offset_to_choice_instr( + code, + index_loc, + target_pos_clause_start - index_loc, + retraction_info, + ); + } + + target_pos_clause_start // skeleton.clauses[target_pos - 1].clause_start + } + _ => { + code.push(Line::Choice(settings.trust_me())); + + skeleton.clauses[target_pos].opt_arg_index_key += clause_loc; + code.extend(clause_code.drain(1..)); + + match skeleton.clauses[lower_bound] + .opt_arg_index_key + .switch_on_term_loc() + { + Some(_) => { + if lower_bound == 0 { + code_ptr_opt = Some(skeleton.clauses[lower_bound].clause_start - 2); + } + + find_outer_choice_instr(code, skeleton.clauses[lower_bound].clause_start - 2) + } + None => { + if lower_bound == 0 { + code_ptr_opt = Some(skeleton.clauses[lower_bound].clause_start); + } + + match skeleton.clauses[target_pos] + .opt_arg_index_key + .switch_on_term_loc() + { + Some(index_loc) => { + // point to the inner-threaded TryMeElse(0) if target_pos is + // indexed, and make switch_on_term point one line after it in + // its variable offset. + skeleton.clauses[target_pos].clause_start += 2; + + if !skeleton.is_dynamic { + set_switch_var_offset(code, index_loc, 2, retraction_info); + } + } + None => {} + } + + find_outer_choice_instr(code, skeleton.clauses[lower_bound].clause_start) + } + } + } + }; + + thread_choice_instr_at_to(code, threaded_choice_instr_loc, clause_loc, retraction_info); + + code_ptr_opt.map(|p| { + if skeleton.is_dynamic { + IndexPtr::DynamicIndex(p) + } else { + IndexPtr::Index(p) + } + }) +} + +#[inline] +fn mergeable_indexed_subsequences( + lower_bound: usize, + target_pos: usize, + skeleton: &PredicateSkeleton, +) -> bool { + let lower_bound_arg_num = skeleton.clauses[lower_bound].opt_arg_index_key.arg_num(); + + if target_pos + 1 < skeleton.clauses.len() { + let succ_arg_num = skeleton.clauses[target_pos + 1].opt_arg_index_key.arg_num(); + let target_arg_num = skeleton.clauses[target_pos].opt_arg_index_key.arg_num(); + + return target_arg_num != succ_arg_num && lower_bound_arg_num == succ_arg_num; + } + + false +} + +impl<'a> LoadState<'a> { + fn compile_standalone_clause( + &mut self, + term: Term, + settings: CodeGenSettings, + atom_tbl: TabledData, + ) -> Result { + let mut preprocessor = Preprocessor::new(self.wam.machine_st.flags); + let mut cg = CodeGenerator::::new(atom_tbl.clone(), settings); + + let clause = self.try_term_to_tl(term, &mut preprocessor)?; + let queue = preprocessor.parse_queue(self)?; + + let mut clause_code = cg.compile_predicate(&vec![clause])?; + + compile_appendix( + &mut clause_code, + queue, + cg.jmp_by_locs, + settings.non_counted_bt, + atom_tbl, + )?; + + Ok(StandaloneCompileResult { + clause_code, + standalone_skeleton: cg.skeleton, }) } - fn adapt_in_situ_code( + fn compile( &mut self, - decls: Vec, - wam: &Machine, - code_dir: &mut CodeDir, - module_dir: &mut ModuleDir, - in_situ_code: &mut Code, - in_situ_code_dir: &InSituCodeDir, - in_situ_module_dir: &ModuleStubDir, + key: PredicateKey, + predicates: &mut PredicateQueue, + settings: CodeGenSettings, ) -> Result<(), SessionError> { - for decl in decls { - let key = decl.0 - .predicate_indicator() - .ok_or(SessionError::NamelessEntry)?; + let code_index = self.get_or_insert_code_index( + key.clone(), + predicates.compilation_target.clone(), + ); - let (name, _arity) = key.clone(); - let module_name = name.owning_module(); + let code_len = self.wam.code_repo.code.len(); + let mut code_ptr = code_len; - match in_situ_module_dir.get(&module_name) { - Some(ref module_stub) if name.has_table(&module_stub.atom_tbl) => { - let module = - module_dir.entry(module_name.clone()) - .or_insert_with(|| { - let module_decl = ModuleDecl { - name: module_name.clone(), - exports: vec![] - }; + let mut cg = + CodeGenerator::::new(self.wam.machine_st.atom_tbl.clone(), settings); - Module::new( - module_decl, - module_stub.atom_tbl.clone(), - self.listing_src.clone(), - ) - }); + let mut clauses = vec![]; + let mut preprocessor = Preprocessor::new(self.wam.machine_st.flags); - self.set_code_index( - wam, - key, - in_situ_code, - &mut module.code_dir, - &module_stub.in_situ_code_dir, - decl, - )?; + for term in predicates.predicates.drain(0 ..) { + clauses.push(self.try_term_to_tl(term, &mut preprocessor)?); + } + + let queue = preprocessor.parse_queue(self)?; + let mut code = cg.compile_predicate(&clauses)?; + + compile_appendix( + &mut code, + queue, + cg.jmp_by_locs, + settings.non_counted_bt, + self.wam.machine_st.atom_tbl.clone(), + )?; + + if settings.is_extensible { + let mut clause_clause_locs = sdeq![]; + + for clause_index_info in cg.skeleton.clauses.iter_mut() { + clause_index_info.clause_start += code_len; + clause_index_info.opt_arg_index_key += code_len; + + clause_clause_locs.push_back(clause_index_info.clause_start); + } + + match &mut code[0] { + Line::Choice(ChoiceInstruction::TryMeElse(0)) => { + code_ptr += 1; } - _ => { - self.set_code_index( - wam, - key, - in_situ_code, - code_dir, - in_situ_code_dir, - decl, - )?; + _ => {} + } + + match self + .wam + .indices + .get_predicate_skeleton_mut(&predicates.compilation_target, &key) + { + Some(skeleton) => { + self.retraction_info + .push_record(RetractionRecord::SkeletonClauseTruncateBack( + predicates.compilation_target.clone(), + key.clone(), + skeleton.clauses.len(), + )); + + skeleton.clauses.extend(cg.skeleton.clauses.into_iter()); + skeleton.clause_clause_locs.extend_from_slice( + &clause_clause_locs[0 ..] + ); + } + None => { + cg.skeleton.clause_clause_locs.extend_from_slice( + &clause_clause_locs[0 ..] + ); + + self.add_extensible_predicate( + key.clone(), + cg.skeleton, + predicates.compilation_target.clone(), + ); + } + } + + match self + .wam + .indices + .get_local_predicate_skeleton_mut( + &self.compilation_target, + predicates.compilation_target.clone(), + key.clone(), + ) + { + Some(skeleton) => { + self.retraction_info + .push_record(RetractionRecord::SkeletonLocalClauseTruncateBack( + self.compilation_target.clone(), + predicates.compilation_target.clone(), + key.clone(), + skeleton.clause_clause_locs.len(), + )); + + skeleton.clause_clause_locs.extend_from_slice( + &clause_clause_locs[0 ..] + ); + } + None => { + let mut skeleton = PredicateSkeleton::new(); + skeleton.clause_clause_locs = clause_clause_locs; + + self.add_local_extensible_predicate( + predicates.compilation_target.clone(), + key.clone(), + skeleton, + ); } } } + set_code_index( + &mut self.retraction_info, + &predicates.compilation_target, + key, + &code_index, + if settings.is_dynamic() { + IndexPtr::DynamicIndex(code_ptr) + } else { + IndexPtr::Index(code_ptr) + }, + ); + + self.wam.code_repo.code.extend(code.into_iter()); Ok(()) } - fn add_term_dir_terms( + fn record_incremental_compile( &mut self, - hook: CompileTimeHook, - code_repo: &mut CodeRepo, key: PredicateKey, - clause: PredicateClause, - queue: VecDeque, - ) -> (usize, usize) { - let preds = code_repo - .term_dir - .entry(key.clone()) - .or_insert((Predicate::new(), VecDeque::from(vec![]))); - - let (mut len, mut queue_len) = ((preds.0).0.len(), preds.1.len()); - - if self.module.is_some() && hook.has_module_scope() { - let module_preds = self - .user_term_dir - .entry(key.clone()) - .or_insert((Predicate::new(), VecDeque::from(vec![]))); - - if let Some(ref mut module) = &mut self.module { - module.add_expansion_record(hook, clause.clone(), queue.clone()); - module.add_local_expansion(hook, clause.clone(), queue.clone()); - } - - (module_preds.0).0.push(clause); - module_preds.1.extend(queue.into_iter()); - - (preds.0).0.extend((module_preds.0).0.iter().cloned()); - preds.1.extend(module_preds.1.iter().cloned()); - } else { - let module_preds = self - .user_term_dir - .entry(key.clone()) - .or_insert((Predicate::new(), VecDeque::from(vec![]))); - - len += 1; - queue_len += queue.len(); - - (preds.0).0.push(clause); - preds.1.extend(queue.into_iter()); - - (preds.0).0.extend((module_preds.0).0.iter().cloned()); - preds.1.extend(module_preds.1.iter().cloned()); - } - - (len, queue_len) + compilation_target: CompilationTarget, + append_or_prepend: AppendOrPrepend, + ) { + self.retraction_info + .push_record(match compilation_target { + CompilationTarget::User => match append_or_prepend { + AppendOrPrepend::Append => { + RetractionRecord::AppendedUserExtensiblePredicate(key) + } + AppendOrPrepend::Prepend => { + RetractionRecord::PrependedUserExtensiblePredicate(key) + } + }, + CompilationTarget::Module(module_name) => match append_or_prepend { + AppendOrPrepend::Append => RetractionRecord::AppendedModuleExtensiblePredicate( + module_name, + key, + ), + AppendOrPrepend::Prepend => { + RetractionRecord::PrependedModuleExtensiblePredicate( + module_name, + key, + ) + } + }, + }); } - fn submit_op( + pub(super) fn incremental_compile_clause( &mut self, - wam: &Machine, - indices: &mut IndexStore, - op_decl: &OpDecl, + key: PredicateKey, + clause: Term, + compilation_target: CompilationTarget, + non_counted_bt: bool, + append_or_prepend: AppendOrPrepend, ) -> Result<(), SessionError> { - let spec = get_desc( - op_decl.name(), - composite_op!( - self.module.is_some(), - &wam.indices.op_dir, - &mut indices.op_dir - ), + self.record_incremental_compile( + key.clone(), + compilation_target.clone(), + append_or_prepend, ); - op_decl.submit(self.get_module_name(), spec, &mut indices.op_dir) + let settings = match self + .wam + .indices + .get_predicate_skeleton_mut(&compilation_target, &key) + { + Some(skeleton) if !skeleton.clauses.is_empty() => { + CodeGenSettings { + global_clock_tick: if skeleton.is_dynamic { + Some(self.wam.machine_st.global_clock) + } else { + None + }, + is_extensible: true, + non_counted_bt, + } + }, + skeleton_opt => { + let settings = CodeGenSettings { + global_clock_tick: if let Some(skeleton) = skeleton_opt { + if skeleton.is_dynamic { + Some(self.wam.machine_st.global_clock) + } else { + None + } + } else { + None + }, + is_extensible: true, + non_counted_bt, + }; + + let mut predicate_queue = predicate_queue![clause]; + predicate_queue.compilation_target = compilation_target; + + return self.compile(key, &mut predicate_queue, settings); + } + }; + + let atom_tbl = self.wam.machine_st.atom_tbl.clone(); + + let StandaloneCompileResult { + clause_code, + mut standalone_skeleton, + } = self.compile_standalone_clause(clause, settings, atom_tbl)?; + + let code_len = self.wam.code_repo.code.len(); + + let skeleton = match self + .wam + .indices + .get_predicate_skeleton_mut(&compilation_target, &key) + { + Some(skeleton) if !skeleton.clauses.is_empty() => skeleton, + _ => unreachable!() + }; + + match append_or_prepend { + AppendOrPrepend::Append => { + let clause_index_info = standalone_skeleton.clauses.pop_back().unwrap(); + skeleton.clauses.push_back(clause_index_info); + + skeleton.clause_clause_locs.push_back(code_len); + + self.retraction_info + .push_record(RetractionRecord::SkeletonClausePopBack( + compilation_target.clone(), + key.clone(), + )); + + let result = append_compiled_clause( + &mut self.wam.code_repo.code, + clause_code, + skeleton, + &mut self.retraction_info, + self.wam.machine_st.global_clock, + ); + + match self + .wam + .indices + .get_local_predicate_skeleton_mut( + &self.compilation_target, + compilation_target.clone(), + key.clone(), + ) + { + Some(skeleton) => { + self.retraction_info.push_record( + RetractionRecord::SkeletonLocalClauseClausePopBack( + self.compilation_target.clone(), + compilation_target.clone(), + key.clone(), + ), + ); + + skeleton.clause_clause_locs.push_back(code_len); + } + None => { + let mut skeleton = PredicateSkeleton::new(); + skeleton.clause_clause_locs.push_back(code_len); + + self.add_local_extensible_predicate( + compilation_target.clone(), + key.clone(), + skeleton, + ); + } + } + + let code_index = self.get_or_insert_code_index( + key.clone(), + compilation_target.clone(), + ); + + if let Some(new_code_ptr) = result { + set_code_index( + &mut self.retraction_info, + &compilation_target, + key, + &code_index, + new_code_ptr, + ); + } + + Ok(()) + } + AppendOrPrepend::Prepend => { + let clause_index_info = standalone_skeleton.clauses.pop_back().unwrap(); + skeleton.clauses.push_front(clause_index_info); + + skeleton.clause_clause_locs.push_front(code_len); + skeleton.clause_assert_margin += 1; + + self.retraction_info + .push_record(RetractionRecord::SkeletonClausePopFront( + compilation_target.clone(), + key.clone(), + )); + + let new_code_ptr = prepend_compiled_clause( + &mut self.wam.code_repo.code, + compilation_target.clone(), + key.clone(), + clause_code, + skeleton, + &mut self.retraction_info, + self.wam.machine_st.global_clock, + ); + + match self + .wam + .indices + .get_local_predicate_skeleton_mut( + &self.compilation_target, + compilation_target.clone(), + key.clone(), + ) + { + Some(skeleton) => { + self.retraction_info.push_record( + RetractionRecord::SkeletonLocalClauseClausePopFront( + self.compilation_target.clone(), + compilation_target.clone(), + key.clone(), + ), + ); + + skeleton.clause_clause_locs.push_front(code_len); + } + None => { + let mut skeleton = PredicateSkeleton::new(); + skeleton.clause_clause_locs.push_front(code_len); + + self.add_local_extensible_predicate( + compilation_target.clone(), + key.clone(), + skeleton, + ); + } + } + + let code_index = self.get_or_insert_code_index( + key.clone(), + compilation_target.clone(), + ); + + set_code_index( + &mut self.retraction_info, + &compilation_target, + key, + &code_index, + new_code_ptr, + ); + + Ok(()) + } + } } - fn process_decl( - &mut self, - decl: Declaration, - wam: &mut Machine, - indices: &mut IndexStore, - flags: MachineFlags, - non_counted_bt_preds: &mut IndexSet, - ) -> Result<(), SessionError> { - match decl { - Declaration::Dynamic(..) => { - Ok(()) + pub(super) fn retract_dynamic_clause(&mut self, key: PredicateKey, target_pos: usize) -> usize { + let skeleton = match self + .wam + .indices + .get_predicate_skeleton_mut(&self.compilation_target, &key) + { + Some(skeleton) => skeleton, + None => { + unreachable!(); } - Declaration::EndOfFile => { - Ok(()) + }; + + let clause_loc = match skeleton.clauses[target_pos] + .opt_arg_index_key + .switch_on_term_loc() + { + Some(index_loc) => { + find_inner_choice_instr( + &self.wam.code_repo.code, + skeleton.clauses[target_pos].clause_start, + index_loc, + ) } - Declaration::Hook(hook, clause, queue) => { - let key = (hook.name(), hook.arity()); - let (len, queue_len) = - self.add_term_dir_terms(hook, &mut wam.code_repo, key.clone(), clause, queue); + None => { + skeleton.clauses[target_pos].clause_start + } + }; - let result = wam - .code_repo - .compile_hook(hook) - .map_err(SessionError::from); + match &mut self.wam.code_repo.code[clause_loc] { + Line::Choice(ChoiceInstruction::DynamicElse(_, ref mut d, _)) | + Line::Choice(ChoiceInstruction::DynamicInternalElse(_, ref mut d, _)) => { + *d = Death::Finite(self.wam.machine_st.global_clock); + } + _ => unreachable!() + } - wam.code_repo.truncate_terms(key, len, queue_len); + delete_from_skeleton( + self.compilation_target.clone(), + key, + skeleton, + target_pos, + &mut self.retraction_info, + ) + } + + pub(super) fn retract_clause(&mut self, key: PredicateKey, target_pos: usize) -> usize { + let code_index = self.get_or_insert_code_index( + key.clone(), + self.compilation_target.clone(), + ); + + let skeleton = match self + .wam + .indices + .get_predicate_skeleton_mut(&self.compilation_target, &key) + { + Some(skeleton) => skeleton, + None => { + unreachable!(); + } + }; + + let code = &mut self.wam.code_repo.code; + let lower_bound = lower_bound_of_target_clause(skeleton, target_pos); + let lower_bound_is_unindexed = !skeleton.clauses[lower_bound].opt_arg_index_key.is_some(); + + if target_pos == 0 || (lower_bound + 1 == target_pos && lower_bound_is_unindexed) { + // the clause preceding target_pos, if there is one, is of key type + // OptArgIndexKey::None. + match skeleton.clauses[target_pos] + .opt_arg_index_key + .switch_on_term_loc() + { + Some(index_loc) => { + let inner_clause_start = find_inner_choice_instr( + code, + skeleton.clauses[target_pos].clause_start, + index_loc, + ); + + remove_index_from_subsequence( + code, + &skeleton.clauses[target_pos].opt_arg_index_key, + inner_clause_start, + &mut self.retraction_info, + ); + + match derelictize_try_me_else( + code, + inner_clause_start, + &mut self.retraction_info, + ) { + Some(offset) => { + let instr_loc = find_inner_choice_instr( + code, + inner_clause_start + offset, + index_loc, + ); + + let clause_loc = blunt_leading_choice_instr( + code, + instr_loc, + &mut self.retraction_info, + ); + + set_switch_var_offset( + code, + index_loc, + clause_loc - index_loc, + &mut self.retraction_info, + ); + + self.retraction_info.push_record( + RetractionRecord::SkeletonClauseStartReplaced( + self.compilation_target.clone(), + key.clone(), + target_pos + 1, + skeleton.clauses[target_pos + 1].clause_start, + ), + ); + + skeleton.clauses[target_pos + 1].clause_start = + skeleton.clauses[target_pos].clause_start; + + return delete_from_skeleton( + self.compilation_target.clone(), + key, + skeleton, + target_pos, + &mut self.retraction_info, + ); + } + None => { + let index_ptr_opt = if target_pos > 0 { + let preceding_choice_instr_loc = + skeleton.clauses[target_pos - 1].clause_start; + + remove_non_leading_clause( + code, + preceding_choice_instr_loc, + skeleton.clauses[target_pos].clause_start - 2, + &mut self.retraction_info, + ) + } else { + remove_leading_unindexed_clause( + code, + skeleton.clauses[target_pos].clause_start - 2, + &mut self.retraction_info, + ) + }; + + return finalize_retract( + key, + self.compilation_target.clone(), + skeleton, + code_index, + target_pos, + index_ptr_opt, + &mut self.retraction_info, + ); + } + } + } + None => {} + } + } + + let index_ptr_opt = match skeleton.clauses[lower_bound] + .opt_arg_index_key + .switch_on_term_loc() + { + Some(target_indexing_loc) + if mergeable_indexed_subsequences(lower_bound, target_pos, skeleton) => + { + let lower_bound_clause_start = find_inner_choice_instr( + code, + skeleton.clauses[lower_bound].clause_start, + target_indexing_loc, + ); + + let result; + + match skeleton.clauses[target_pos + 1] + .opt_arg_index_key + .switch_on_term_loc() + { + Some(later_indexing_loc) if later_indexing_loc < target_indexing_loc => { + let target_indexing_line = mem::replace( + &mut code[target_indexing_loc], + Line::Control(ControlInstruction::RevJmpBy( + target_indexing_loc - later_indexing_loc, + )), + ); + + match target_indexing_line { + Line::IndexingCode(indexing_code) => { + self.retraction_info.push_record( + RetractionRecord::ReplacedIndexingLine( + target_indexing_loc, + indexing_code, + ), + ); + } + _ => {} + } + + result = merge_indexed_subsequences( + code, + skeleton, + lower_bound, + target_pos + 1, + &mut self.retraction_info, + ); + + merge_indices( + code, + later_indexing_loc, + 0..target_pos - lower_bound, + &mut skeleton.clauses[lower_bound..], + &mut self.retraction_info, + ); + + set_switch_var_offset( + code, + later_indexing_loc, + lower_bound_clause_start - later_indexing_loc, + &mut self.retraction_info, + ); + } + _ => { + result = merge_indexed_subsequences( + code, + skeleton, + lower_bound, + target_pos + 1, + &mut self.retraction_info, + ); + + merge_indices( + code, + target_indexing_loc, + target_pos + 1 - lower_bound..skeleton.clauses.len() - lower_bound, + &mut skeleton.clauses[lower_bound..], + &mut self.retraction_info, + ); + + set_switch_var_offset_to_choice_instr( + code, + target_indexing_loc, + lower_bound_clause_start - target_indexing_loc, + &mut self.retraction_info, + ); + } + }; result } - Declaration::Module(module_decl) => { - if self.module.is_none() { - let module_name = module_decl.name.clone(); - let atom_tbl = TabledData::new(module_name.to_rc()); + _ => { + if target_pos > 0 { + remove_index_from_subsequence( + code, + &skeleton.clauses[target_pos].opt_arg_index_key, + skeleton.clauses[target_pos].clause_start, + &mut self.retraction_info, + ); - for export in module_decl.exports.iter() { - if let ModuleExport::OpDecl(ref op_decl) = export { - self.submit_op(wam, indices, op_decl)?; + match skeleton.clauses[target_pos] + .opt_arg_index_key + .switch_on_term_loc() + { + Some(index_loc) => { + let preceding_choice_instr_loc = find_inner_choice_instr( + code, + skeleton.clauses[target_pos - 1].clause_start, + index_loc, + ); + + remove_non_leading_clause( + code, + preceding_choice_instr_loc, + skeleton.clauses[target_pos].clause_start, + &mut self.retraction_info, + ); + + match &mut code[preceding_choice_instr_loc] { + Line::Choice(ChoiceInstruction::TryMeElse(0)) => { + set_switch_var_offset( + code, + index_loc, + preceding_choice_instr_loc + 1 - index_loc, + &mut self.retraction_info, + ); + } + _ => {} + } + + None + } + None => { + let preceding_choice_instr_loc = + if skeleton.clauses[lower_bound].opt_arg_index_key.is_some() { + skeleton.clauses[lower_bound].clause_start - 2 + } else { + skeleton.clauses[lower_bound].clause_start + }; + + remove_non_leading_clause( + code, + preceding_choice_instr_loc, + skeleton.clauses[target_pos].clause_start, + &mut self.retraction_info, + ) } } - - let listing_src = self.listing_src.clone(); - - Ok(self.module = Some(Module::new(module_decl, atom_tbl, listing_src))) } else { - Err(SessionError::from(ParserError::InvalidModuleDecl)) - } - } - Declaration::ModuleInitialization(query_terms, queue) => { - self.initialization_goals.0.extend(query_terms.into_iter()); - self.initialization_goals.1.extend(queue.into_iter()); - - Ok(()) - } - Declaration::MultiFile(..) => { - Ok(()) - } - Declaration::NonCountedBacktracking(name, arity) => { - non_counted_bt_preds.insert((name, arity)); - Ok(()) - } - Declaration::Op(op_decl) => { - self.submit_op(wam, indices, &op_decl) - } - Declaration::SetPrologFlag(dbl_quotes) => { - wam.machine_st.flags.double_quotes = dbl_quotes; - Ok(()) - } - Declaration::UseModule(ModuleSource::Library(name)) => { - let name = if !wam.indices.modules.contains_key(&name) { - load_library(wam, name, true)? - } else { - name - }; - - self.use_module(name, &mut wam.code_repo, flags, &mut wam.indices, indices) - } - Declaration::UseModule(ModuleSource::File(filename)) => { - let mut path_buf = self.listing_src.path(); - path_buf.push(filename.as_str()); - - let name = load_module_from_file(wam, path_buf, true)?; - self.use_module(name, &mut wam.code_repo, flags, &mut wam.indices, indices) - } - Declaration::UseQualifiedModule(ModuleSource::Library(name), exports) => { - let name = if !wam.indices.modules.contains_key(&name) { - load_library(wam, name, true)? - } else { - name - }; - - self.use_qualified_module( - name, - &mut wam.code_repo, - flags, - &exports, - &mut wam.indices, - indices - ) - } - Declaration::UseQualifiedModule(ModuleSource::File(filename), exports) => { - let mut path_buf = self.listing_src.path(); - path_buf.push(filename.as_str()); - - let name = load_module_from_file(wam, path_buf, true)?; - - self.use_qualified_module( - name, - &mut wam.code_repo, - flags, - &exports, - &mut wam.indices, - indices, - ) - } - } - } - - fn setup_multifile_decl( - &self, - indicator: MultiFileIndicator, - worker: &mut TopLevelBatchWorker, - ) -> Result<(), SessionError> { - match indicator { - MultiFileIndicator::LocalScoped(name, arity) => { - let term_dir = &worker.term_stream.wam.code_repo.term_dir; - let key = (name, arity); - let term_dirs = &mut worker.term_dirs; - - insert_or_refresh_term_dir_quantum(term_dir, key, term_dirs); - } - MultiFileIndicator::ModuleScoped((module_name, key)) => { - match worker.term_stream.wam.indices.modules.get(&module_name) { - Some(ref module) => { - let term_dir = &module.term_dir; - let term_dirs = worker.intra_module_term_dirs - .entry(module_name) - .or_insert(TermDirQuantum::new()); - - insert_or_refresh_term_dir_quantum(term_dir, key, term_dirs); - } - None => { - let err = ExistenceError::ModuleSource(ModuleSource::File( - module_name, - )); - - return Err(SessionError::ExistenceError(err)); - } + remove_leading_unindexed_clause( + code, + skeleton.clauses[target_pos].clause_start, + &mut self.retraction_info, + ) } } }; + finalize_retract( + key, + self.compilation_target.clone(), + skeleton, + code_index, + target_pos, + index_ptr_opt, + &mut self.retraction_info, + ) + } +} + +impl<'a, TS: TermStream> Loader<'a, TS> { + pub(super) fn compile_clause_clauses>( + &mut self, + key: PredicateKey, + compilation_target: CompilationTarget, + clause_clauses: ClauseIter, + append_or_prepend: AppendOrPrepend, + ) -> Result<(), SessionError> { + let clause_predicates = clause_clauses.map(|(head, body)| { + Term::Clause( + Cell::default(), + clause_name!("$clause"), + vec![Box::new(head), Box::new(body)], + None, + ) + }); + + let clause_clause_compilation_target = match compilation_target { + CompilationTarget::User => CompilationTarget::Module(clause_name!("builtins")), + _ => compilation_target.clone(), + }; + + let mut num_clause_predicates = 0; + + for clause_term in clause_predicates { + self.load_state.incremental_compile_clause( + (clause_name!("$clause"), 2), + clause_term, + clause_clause_compilation_target.clone(), + false, // non_counted_bt is false. + append_or_prepend, + )?; + + num_clause_predicates += 1; + } + + let locs_vec: Vec<_> = match self + .load_state + .wam + .indices + .get_predicate_skeleton_mut(&compilation_target, &key) + { + Some(skeleton) if append_or_prepend.is_append() => { + let tail_num = skeleton.clause_clause_locs.len() - num_clause_predicates; + skeleton.clause_clause_locs[tail_num ..] + .iter() + .cloned() + .collect() + } + Some(skeleton) => { + skeleton.clause_clause_locs[0 .. num_clause_predicates] + .iter() + .cloned() + .collect() + } + None => { + unreachable!() + } + }; + + match self.load_state.wam.indices.get_predicate_skeleton_mut( + &clause_clause_compilation_target, + &(clause_name!("$clause"), 2), + ) { + Some(skeleton) if append_or_prepend.is_append() => { + for _ in 0 .. num_clause_predicates { + skeleton.clause_clause_locs.pop_back(); + } + + for loc in locs_vec { + skeleton.clause_clause_locs.push_back(loc); + } + } + Some(skeleton) => { + for _ in 0 .. num_clause_predicates { + skeleton.clause_clause_locs.pop_front(); + } + + for loc in locs_vec.into_iter().rev() { + skeleton.clause_clause_locs.push_front(loc); + } + } + None => { + unreachable!(); + } + } + Ok(()) } - fn process_and_commit_decl( - &mut self, - decl: Declaration, - worker: &mut TopLevelBatchWorker, - indices: &mut IndexStore, - flags: MachineFlags, - ) -> Result<(), SessionError> { - let mut update_expansion_lengths = false; + pub(super) fn compile_and_submit(&mut self) -> Result<(), SessionError> { + let key = self + .predicates + .first() + .and_then(|cl| { + let arity = ClauseInfo::arity(cl); + ClauseInfo::name(cl).map(|name| (name, arity)) + }) + .ok_or(SessionError::NamelessEntry)?; - match &decl { - &Declaration::Dynamic(ref name, arity) => { - worker - .dynamic_clause_map - .entry((name.clone(), arity)) - .or_insert(vec![]); + let mut predicate_info = self + .load_state + .wam + .indices + .get_predicate_skeleton(&self.predicates.compilation_target, &key) + .map(|skeleton| skeleton.predicate_info()) + .unwrap_or_default(); - indices.code_dir - .entry((name.clone(), arity)) - .or_insert(CodeIndex::dynamic_undefined(self.get_module_name())); - } - &Declaration::Hook(hook, _, ref queue) if self.module.is_none() => worker - .term_stream - .incr_expansion_lens(hook.user_scope(), 1, queue.len()), - &Declaration::Hook(hook, _, ref queue) if !hook.has_module_scope() => { - worker.term_stream.incr_expansion_lens(hook, 1, queue.len()) - } - &Declaration::MultiFile(ref indicator) => { - self.setup_multifile_decl(indicator.clone(), worker)?; - } - &Declaration::UseModule(_) | &Declaration::UseQualifiedModule(..) => { - update_expansion_lengths = true - } - _ => {} - }; + let local_predicate_info = self + .load_state + .wam + .indices + .get_local_predicate_skeleton( + &self.load_state.compilation_target, + self.predicates.compilation_target.clone(), + key.clone(), + ) + .map(|skeleton| skeleton.predicate_info()) + .unwrap_or_default(); - let result = self.process_decl( - decl, - &mut worker.term_stream.wam, - indices, - flags, - &mut worker.non_counted_bt_preds, - ); - - if update_expansion_lengths { - worker.term_stream.update_expansion_lens(); + if local_predicate_info.must_retract_local_clauses() { + self.retract_local_clauses(&key, predicate_info.is_dynamic); } - result - } - - pub(crate) - fn gather_items( - &mut self, - wam: &mut Machine, - src: &mut ParsingStream, - indices: &mut IndexStore, - ) -> Result { - let flags = wam.machine_flags(); - let atom_tbl = indices.atom_tbl.clone(); - let mut worker = TopLevelBatchWorker::new(src, atom_tbl.clone(), flags, wam); - - let mut toplevel_results = vec![]; - let mut toplevel_indices = default_index_store!(atom_tbl.clone()); - - let mut top_level_term_dirs = TermDirQuantum::new(); - - while let Some(decl) = worker.consume(indices)? { - if decl.is_module_decl() { - toplevel_indices.copy_and_swap(indices); - mem::swap(&mut worker.results, &mut toplevel_results); - worker.in_module = true; - - self.process_and_commit_decl(decl, &mut worker, indices, flags)?; - - if let Some(ref module) = &self.module { - worker.term_stream.set_atom_tbl(module.atom_tbl.clone()); - - top_level_term_dirs = mem::replace( - &mut worker.term_dirs, - TermDirQuantum::new(), - ); - } - } else if decl.is_end_of_file() { - break; + let do_incremental_compile = + if self.load_state.compilation_target == self.predicates.compilation_target { + predicate_info.compile_incrementally() } else { - self.process_and_commit_decl(decl, &mut worker, indices, flags)?; + local_predicate_info.is_multifile && predicate_info.compile_incrementally() + }; + + let predicates_len = self.predicates.len(); + let non_counted_bt = self.non_counted_bt_preds.contains(&key); + + if do_incremental_compile { + for term in self.predicates.predicates.drain(0 ..) { + self.load_state.incremental_compile_clause( + key.clone(), + term, + self.predicates.compilation_target.clone(), + non_counted_bt, + AppendOrPrepend::Append, + )?; } - } - - let addition_results = worker.term_stream.rollback_expansion_code()?; - - let module_term_dirs = if self.module.is_some() { - worker.term_dirs } else { - top_level_term_dirs = worker.term_dirs; - TermDirQuantum::new() - }; + if self.load_state.compilation_target != self.predicates.compilation_target { + if !local_predicate_info.is_extensible { + if predicate_info.is_multifile { + println!("Warning: overwriting multifile predicate {}:{}/{} because \ + it was not locally declared multifile.", + self.predicates.compilation_target, key.0, key.1); + } - Ok(GatherResult { - worker_results: worker.results, - dynamic_clause_map: worker.dynamic_clause_map, - toplevel_results, - toplevel_indices, - addition_results, - top_level_terms: worker.term_stream.top_level_terms(), - top_level_term_dirs, - module_term_dirs, - in_situ_code_dir: worker.term_stream.wam.indices.take_in_situ_code_dir(), - in_situ_code: worker.term_stream.wam.code_repo.take_in_situ_code(), - in_situ_module_dir: worker.term_stream.wam.indices.take_in_situ_module_dir(), - }) - } + if let Some(skeleton) = self.load_state + .wam + .indices + .remove_predicate_skeleton( + &self.predicates.compilation_target, + &key, + ) + { + if predicate_info.is_dynamic { + let clause_clause_compilation_target = + match &self.predicates.compilation_target { + CompilationTarget::User => { + CompilationTarget::Module(clause_name!("builtins")) + } + module => { + module.clone() + } + }; - fn drop_expansions(&self, code_repo: &mut CodeRepo) { - let (te_len, te_queue_len) = self.orig_term_expansion_lens; - let (ge_len, ge_queue_len) = self.orig_goal_expansion_lens; + self.load_state.retract_local_clauses_by_locs( + clause_clause_compilation_target, + (clause_name!("$clause"), 2), + (0 .. skeleton.clauses.len()).map(Some).collect(), + false, // the builtin M:'$clause'/2 is never dynamic. + ); - code_repo.truncate_terms((clause_name!("term_expansion"), 2), te_len, te_queue_len); - code_repo.truncate_terms((clause_name!("goal_expansion"), 2), ge_len, ge_queue_len); + predicate_info.is_dynamic = false; + } - discard_result!(code_repo.compile_hook(CompileTimeHook::UserGoalExpansion)); - discard_result!(code_repo.compile_hook(CompileTimeHook::UserTermExpansion)); - } - - fn print_error(&self, e: &SessionError) { - if let &SessionError::ParserError(ref e) = e { - if let Some((line_num, _col_num)) = e.line_and_col_num() { - println!("{}:{}: {}", self.listing_src.name(), line_num, e.as_str()); + self.load_state.retraction_info.push_record( + RetractionRecord::RemovedSkeleton( + self.predicates.compilation_target.clone(), + key.clone(), + skeleton, + ), + ); + } + } } + + let settings = CodeGenSettings { + global_clock_tick: if predicate_info.is_dynamic { + Some(self.load_state.wam.machine_st.global_clock) + } else { + None + }, + is_extensible: predicate_info.is_extensible, + non_counted_bt, + }; + + self.load_state.compile(key.clone(), &mut self.predicates, settings)?; } - } -} -fn compile_work_impl( - compiler: &mut ListingCompiler, - wam: &mut Machine, - mut indices: IndexStore, - mut results: GatherResult, -) -> Result<(), SessionError> { - if let Some(ref mut module) = &mut compiler.module { - // compile the module-level goal and term expansions and store - // their locations to the module's code_dir. - let mut decls = module.take_local_expansions(); + if predicate_info.is_dynamic { + self.load_state.wam.machine_st.global_clock += 1; - if !decls.is_empty() { - append_trivial_goal(&clause_name!("term_expansion"), &mut decls[0].0); - append_trivial_goal(&clause_name!("goal_expansion"), &mut decls[1].0); - - results.worker_results.extend(decls.into_iter()); - } - } - - let top_level_term_dir = results.top_level_term_dirs.consolidate(); - let module_term_dir = results.module_term_dirs.consolidate(); - - let mut code = results.in_situ_code; - - let in_situ_code_dir = results.in_situ_code_dir; - let in_situ_module_dir = results.in_situ_module_dir; - - compiler.adapt_in_situ_code( - results.worker_results, - wam, - &mut indices.code_dir, - &mut indices.module_dir, - &mut code, - &in_situ_code_dir, - &in_situ_module_dir, - )?; - - compiler.adapt_in_situ_code( - results.toplevel_results, - wam, - &mut results.toplevel_indices.code_dir, - &mut indices.module_dir, - &mut code, - &in_situ_code_dir, - &in_situ_module_dir, - )?; - - if let Some(ref mut module) = &mut compiler.module { - if !module.is_impromptu_module { - module.user_term_expansions = results.addition_results.take_term_expansions(); - module.user_goal_expansions = results.addition_results.take_goal_expansions(); - } - } - - wam.code_repo.compile_hook(CompileTimeHook::UserTermExpansion)?; - wam.code_repo.compile_hook(CompileTimeHook::UserGoalExpansion)?; - - if let Some(mut module) = compiler.module.take() { - if module.is_impromptu_module { - module.module_decl.exports = indices.code_dir.keys().cloned() - .filter(|(name, _)| name.owning_module().as_str() != "builtins") - .map(ModuleExport::PredicateKey) + let clauses_vec: Vec<_> = self.clause_clauses + .drain(0 .. predicates_len) .collect(); - module.module_decl.exports.extend( - indices.op_dir.iter() - .map(|((name, _), OpDirValue (shared_op_desc, _))| - ModuleExport::OpDecl(OpDecl( - shared_op_desc.prec(), - shared_op_desc.assoc(), - name.clone(), - )) - ) - ); + self.compile_clause_clauses( + key, + self.predicates.compilation_target.clone(), + clauses_vec.into_iter(), + AppendOrPrepend::Append, + )?; } - let mut clause_code_generator = - ClauseCodeGenerator::new(code.len(), module.module_decl.name.clone()); - - wam.check_toplevel_code(&results.toplevel_indices)?; - clause_code_generator.generate_clause_code(&results.dynamic_clause_map, wam)?; - - if let Some(ref module) = wam.indices.modules.swap_remove(&module.module_decl.name) { - wam.indices.remove_module(clause_name!("user"), module); - } - - if module.is_impromptu_module { - add_module(wam, module, indices, module_term_dir); - - let module = wam.indices.take_module(compiler.listing_src.name()).unwrap(); - - wam.indices.use_module(&mut wam.code_repo, wam.machine_st.flags, &module)?; - wam.indices.insert_module(module); - } else { - add_module(wam, module, indices, module_term_dir); - } - - add_toplevel(wam, results.toplevel_indices, top_level_term_dir); - wam.code_repo.code.extend(code.into_iter()); - - clause_code_generator.add_clause_code(wam, results.dynamic_clause_map); - } else { - add_non_module_code( - wam, - results.dynamic_clause_map, - code, - indices, - top_level_term_dir, - )?; - } - - let init_goal_code = compiler.generate_init_goal_code()?; - - if init_goal_code.len() > 0 { - if !wam.run_init_code(init_goal_code) { - println!("Warning: initialization goal for {} failed", - compiler.listing_src.name()); - } - } - - if !compiler.suppress_warnings { - issue_singleton_warnings( - compiler.listing_src.name(), - results.top_level_terms, - ); - } - - Ok(()) -} - -fn compile_work( - compiler: &mut ListingCompiler, - wam: &mut Machine, - src: Stream, - mut indices: IndexStore, -) -> EvalSession { - let mut stream = try_eval_session!(parsing_stream(src)); - let src = &mut stream; - let results = try_eval_session!(compiler.gather_items(wam, src, &mut indices)); - - try_eval_session!(compile_work_impl(compiler, wam, indices, results)); - - EvalSession::EntrySuccess -} - -/* This is a truncated version of compile_user_module, used for -compiling code composing special forms, ie. the code that calls -M:verify_attributes on attributed variables. */ -pub fn compile_special_form( - wam: &mut Machine, - src: Stream, - listing_src: ListingSource, -) -> Result { - let mut indices = default_index_store!(wam.indices.atom_tbl.clone()); - setup_indices(wam, clause_name!("builtins"), &mut indices)?; - - let mut src = parsing_stream(src)?; - let mut compiler = ListingCompiler::new(&wam.code_repo, true, listing_src); - let mut results = compiler.gather_items(wam, &mut src, &mut indices)?; - - compiler.adapt_in_situ_code( - results.worker_results, - wam, - &mut indices.code_dir, - &mut indices.module_dir, - &mut results.in_situ_code, - &results.in_situ_code_dir, - &results.in_situ_module_dir, - )?; - - let p = wam.code_repo.code.len(); - let top_level_term_dir = results.top_level_term_dirs.consolidate(); - - add_toplevel(wam, indices, top_level_term_dir); - - wam.code_repo.code.extend(results.in_situ_code.into_iter()); - - Ok(p) -} - -#[inline] -pub fn compile_listing( - wam: &mut Machine, - src: Stream, - indices: IndexStore, - suppress_warnings: bool, - listing_src: ListingSource, -) -> EvalSession { - let mut compiler = ListingCompiler::new(&wam.code_repo, suppress_warnings, listing_src); - - match compile_work(&mut compiler, wam, src, indices) { - EvalSession::Error(e) => { - compiler.drop_expansions(&mut wam.code_repo); - compiler.print_error(&e); - - EvalSession::Error(e) - } - result => result, + Ok(()) } } - -pub(super) fn setup_indices( - wam: &mut Machine, - module: ClauseName, - indices: &mut IndexStore, -) -> Result<(), SessionError> { - if let Some(module) = wam.indices.take_module(module.clone()) { - let flags = wam.machine_flags(); - let result = indices.use_module(&mut wam.code_repo, flags, &module); - - wam.indices.insert_module(module); - result - } else { - let err = ExistenceError::ModuleSource(ModuleSource::Library( - module - )); - - Err(SessionError::ExistenceError(err)) - } -} - -pub fn compile_user_module( - wam: &mut Machine, - src: Stream, - suppress_warnings: bool, - listing_src: ListingSource, -) -> EvalSession { - let mut indices = default_index_store!(wam.indices.atom_tbl.clone()); - try_eval_session!(setup_indices(wam, clause_name!("builtins"), &mut indices)); - compile_listing(wam, src, indices, suppress_warnings, listing_src) -} diff --git a/src/machine/copier.rs b/src/machine/copier.rs index ba2eff53..fdd52c96 100644 --- a/src/machine/copier.rs +++ b/src/machine/copier.rs @@ -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 { +pub(crate) trait CopierTarget: IndexMut { 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 { fn threshold(&self) -> usize; } -pub(crate) -fn copy_term(target: T, addr: Addr, attr_var_policy: AttrVarPolicy) { +pub(crate) fn copy_term(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 CopyTermState { scan: 0, old_h: target.threshold(), target, - attr_var_policy + attr_var_policy, } } @@ -59,14 +57,11 @@ impl CopyTermState { 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 CopyTermState { *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 CopyTermState { 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 CopyTermState { 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 CopyTermState { 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 CopyTermState { 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 CopyTermState { 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 CopyTermState { 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) + } } } } diff --git a/src/machine/dynamic_database.rs b/src/machine/dynamic_database.rs deleted file mode 100644 index 6fc01b4c..00000000 --- a/src/machine/dynamic_database.rs +++ /dev/null @@ -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 { - 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, - 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); - } -} diff --git a/src/machine/heap.rs b/src/machine/heap.rs index 8f741f66..067bfa93 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -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 Drop for HeapTemplate { } #[derive(Debug)] -pub(crate) -struct HeapIntoIter { +pub(crate) struct HeapIntoIter { offset: usize, buf: RawBlock, } impl Drop for HeapIntoIter { 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::()); heap.buf.deallocate(); @@ -66,9 +67,7 @@ impl Iterator for HeapIntoIter { self.offset += mem::size_of::(); 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 Iterator for HeapIntoIter { } #[derive(Debug)] -pub(crate) -struct HeapIter<'a, T: RawBlockTraits> { +pub(crate) struct HeapIter<'a, T: RawBlockTraits> { offset: usize, buf: &'a RawBlock, } impl<'a, T: RawBlockTraits> HeapIter<'a, T> { - pub(crate) - fn new(buf: &'a RawBlock, offset: usize) -> Self { + pub(crate) fn new(buf: &'a RawBlock, offset: usize) -> Self { HeapIter { buf, offset } } } @@ -97,9 +94,7 @@ impl<'a, T: RawBlockTraits> Iterator for HeapIter<'a, T> { self.offset += mem::size_of::(); 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>(heap: I, h: usize) { +pub(crate) fn print_heap_terms<'a, I: Iterator>(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, } impl<'a, T: RawBlockTraits> HeapIterMut<'a, T> { - pub(crate) - fn new(buf: &'a mut RawBlock, offset: usize) -> Self { + pub(crate) fn new(buf: &'a mut RawBlock, offset: usize) -> Self { HeapIterMut { buf, offset } } } @@ -136,9 +128,7 @@ impl<'a, T: RawBlockTraits> Iterator for HeapIterMut<'a, T> { self.offset += mem::size_of::(); 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 HeapTemplate { #[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 HeapTemplate { } #[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 HeapTemplate { 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 HeapTemplate { } #[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 HeapTemplate { } #[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 HeapTemplate { } #[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 HeapTemplate { 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 HeapTemplate { 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 HeapTemplate { } #[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::() + self.buf.base as usize; let mut h = new_top; @@ -398,30 +333,27 @@ impl HeapTemplate { } #[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::() } - pub(crate) - fn append(&mut self, vals: Vec) { + pub(crate) fn append(&mut self, vals: Vec) { 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(&mut self, values: Iter) -> usize - where Iter: Iterator, - SrcT: Into + pub(crate) fn to_list(&mut self, values: Iter) -> usize + where + Iter: Iterator, + SrcT: Into, { let head_addr = self.h(); let mut h = head_addr; @@ -439,35 +371,33 @@ impl HeapTemplate { } /* 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::()) } - 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::()) } - pub(crate) - fn into_iter(mut self) -> HeapIntoIter { - HeapIntoIter { buf: self.buf.take(), offset: 0 } + pub(crate) fn into_iter(mut self) -> HeapIntoIter { + HeapIntoIter { + buf: self.buf.take(), + offset: 0, + } } - pub(crate) - fn extend>(&mut self, iter: Iter) { + pub(crate) fn extend>(&mut self, iter: Iter) { for hcv in iter { self.push(hcv); } } - pub(crate) - fn to_local_code_ptr(&self, addr: &Addr) -> Option { + pub(crate) fn to_local_code_ptr(&self, addr: &Addr) -> Option { let extract_integer = |s: usize| -> Option { 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 HeapTemplate { 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 HeapTemplate { 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)), } } } diff --git a/src/machine/load_state.rs b/src/machine/load_state.rs new file mode 100644 index 00000000..b2567725 --- /dev/null +++ b/src/machine/load_state.rs @@ -0,0 +1,1201 @@ +use crate::machine::machine_indices::*; +use crate::machine::preprocessor::*; +use crate::machine::*; +use crate::machine::term_stream::*; + +use prolog_parser::clause_name; + +use indexmap::IndexSet; +use ref_thread_local::RefThreadLocal; +use slice_deque::{sdeq, SliceDeque}; + +type ModuleOpExports = Vec<(OpDecl, Option<(usize, Specifier)>)>; + +/* + * We will want to borrow these fields from Loader separately, without + * restricting access to other fields by borrowing them mutably. + */ +pub(super) struct LoadState<'a> { + pub(super) compilation_target: CompilationTarget, + pub(super) module_op_exports: ModuleOpExports, + pub(super) retraction_info: RetractionInfo, + pub(super) wam: &'a mut Machine, +} + +pub(super) fn set_code_index( + retraction_info: &mut RetractionInfo, + compilation_target: &CompilationTarget, + key: PredicateKey, + code_index: &CodeIndex, + code_ptr: IndexPtr, +) { + let record = match compilation_target { + CompilationTarget::User => { + if IndexPtr::Undefined == code_index.get() { + code_index.set(code_ptr); + RetractionRecord::AddedUserPredicate(key) + } else { + // TODO: emit warning about overwriting previous record + let replaced = code_index.replace(code_ptr); + RetractionRecord::ReplacedUserPredicate(key, replaced) + } + } + CompilationTarget::Module(ref module_name) => { + if IndexPtr::Undefined == code_index.get() { + code_index.set(code_ptr); + RetractionRecord::AddedModulePredicate(module_name.clone(), key) + } else { + // TODO: emit warning about overwriting previous record + let replaced = code_index.replace(code_ptr); + RetractionRecord::ReplacedModulePredicate(module_name.clone(), key, replaced) + } + } + }; + + retraction_info.push_record(record); +} + +fn add_op_decl_as_module_export( + module_op_dir: &mut OpDir, + compilation_target: &CompilationTarget, + retraction_info: &mut RetractionInfo, + wam_op_dir: &mut OpDir, + module_op_exports: &mut ModuleOpExports, + op_decl: &OpDecl, +) { + /* + insert the operator at top-level so it can + inform the parser. it will be retracted + from the user-level op_dir when the load + succeeds. + */ + + match op_decl.insert_into_op_dir(wam_op_dir) { + Some((prec, spec)) => { + retraction_info.push_record(RetractionRecord::ReplacedUserOp( + op_decl.clone(), + prec, + spec, + )); + + module_op_exports.push((op_decl.clone(), Some((prec, spec)))); + } + None => { + retraction_info.push_record(RetractionRecord::AddedUserOp(op_decl.clone())); + module_op_exports.push((op_decl.clone(), None)); + } + } + + add_op_decl(retraction_info, compilation_target, module_op_dir, op_decl); +} + +pub(super) fn add_op_decl( + retraction_info: &mut RetractionInfo, + compilation_target: &CompilationTarget, + op_dir: &mut OpDir, + op_decl: &OpDecl, +) { + match op_decl.insert_into_op_dir(op_dir) { + Some((prec, spec)) => match &compilation_target { + CompilationTarget::User => { + retraction_info.push_record(RetractionRecord::ReplacedUserOp( + op_decl.clone(), + prec, + spec, + )); + } + CompilationTarget::Module(ref module_name) => { + retraction_info.push_record(RetractionRecord::ReplacedModuleOp( + module_name.clone(), + op_decl.clone(), + prec, + spec, + )); + } + }, + None => match &compilation_target { + CompilationTarget::User => { + retraction_info.push_record(RetractionRecord::AddedUserOp(op_decl.clone())); + } + CompilationTarget::Module(ref module_name) => { + retraction_info.push_record(RetractionRecord::AddedModuleOp( + module_name.clone(), + op_decl.clone(), + )); + } + }, + } +} + +pub(super) fn import_module_exports( + retraction_info: &mut RetractionInfo, + compilation_target: &CompilationTarget, + imported_module: &Module, + code_dir: &mut CodeDir, + op_dir: &mut OpDir, + meta_predicates: &mut MetaPredicateDir, +) -> Result<(), SessionError> { + for export in imported_module.module_decl.exports.iter() { + match export { + ModuleExport::PredicateKey((ref name, arity)) => { + let key = (name.clone(), *arity); + + if let Some(meta_specs) = imported_module.meta_predicates.get(&key) { + meta_predicates.insert(key.clone(), meta_specs.clone()); + } + + if let Some(src_code_index) = imported_module.code_dir.get(&key) { + let target_code_index = code_dir + .entry(key.clone()) + .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) + .clone(); + + set_code_index( + retraction_info, + compilation_target, + key, + &target_code_index, + src_code_index.get(), + ); + } else { + return Err(SessionError::ModuleDoesNotContainExport( + imported_module.module_decl.name.clone(), + (name.clone(), *arity), + )); + } + } + ModuleExport::OpDecl(ref op_decl) => { + add_op_decl(retraction_info, compilation_target, op_dir, op_decl); + } + } + } + + Ok(()) +} + +fn import_module_exports_into_module( + retraction_info: &mut RetractionInfo, + compilation_target: &CompilationTarget, + imported_module: &Module, + code_dir: &mut CodeDir, + op_dir: &mut OpDir, + meta_predicates: &mut MetaPredicateDir, + wam_op_dir: &mut OpDir, + module_op_exports: &mut ModuleOpExports, +) -> Result<(), SessionError> { + for export in imported_module.module_decl.exports.iter() { + match export { + ModuleExport::PredicateKey((ref name, arity)) => { + let key = (name.clone(), *arity); + + if let Some(meta_specs) = imported_module.meta_predicates.get(&key) { + meta_predicates.insert(key.clone(), meta_specs.clone()); + } + + if let Some(src_code_index) = imported_module.code_dir.get(&key) { + let target_code_index = code_dir + .entry(key.clone()) + .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) + .clone(); + + set_code_index( + retraction_info, + compilation_target, + key, + &target_code_index, + src_code_index.get(), + ); + } else { + return Err(SessionError::ModuleDoesNotContainExport( + imported_module.module_decl.name.clone(), + (name.clone(), *arity), + )); + } + } + ModuleExport::OpDecl(ref op_decl) => { + add_op_decl_as_module_export( + op_dir, + compilation_target, + retraction_info, + wam_op_dir, + module_op_exports, + op_decl, + ); + } + } + } + + Ok(()) +} + +fn import_qualified_module_exports( + retraction_info: &mut RetractionInfo, + compilation_target: &CompilationTarget, + imported_module: &Module, + exports: &IndexSet, + code_dir: &mut CodeDir, + op_dir: &mut OpDir, + meta_predicates: &mut MetaPredicateDir, +) -> Result<(), SessionError> { + for export in imported_module.module_decl.exports.iter() { + if !exports.contains(export) { + continue; + } + + match export { + ModuleExport::PredicateKey((ref name, arity)) => { + let key = (name.clone(), *arity); + + if let Some(meta_specs) = imported_module.meta_predicates.get(&key) { + meta_predicates.insert(key.clone(), meta_specs.clone()); + } + + if let Some(src_code_index) = imported_module.code_dir.get(&key) { + let target_code_index = code_dir + .entry(key.clone()) + .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) + .clone(); + + set_code_index( + retraction_info, + compilation_target, + key, + &target_code_index, + src_code_index.get(), + ); + } else { + return Err(SessionError::ModuleDoesNotContainExport( + imported_module.module_decl.name.clone(), + (name.clone(), *arity), + )); + } + } + ModuleExport::OpDecl(ref op_decl) => { + add_op_decl(retraction_info, compilation_target, op_dir, op_decl); + } + } + } + + Ok(()) +} + +fn import_qualified_module_exports_into_module( + retraction_info: &mut RetractionInfo, + compilation_target: &CompilationTarget, + imported_module: &Module, + exports: &IndexSet, + code_dir: &mut CodeDir, + op_dir: &mut OpDir, + meta_predicates: &mut MetaPredicateDir, + wam_op_dir: &mut OpDir, + module_op_exports: &mut ModuleOpExports, +) -> Result<(), SessionError> { + for export in imported_module.module_decl.exports.iter() { + if !exports.contains(export) { + continue; + } + + match export { + ModuleExport::PredicateKey((ref name, arity)) => { + let key = (name.clone(), *arity); + + if let Some(meta_specs) = imported_module.meta_predicates.get(&key) { + meta_predicates.insert(key.clone(), meta_specs.clone()); + } + + if let Some(src_code_index) = imported_module.code_dir.get(&key) { + let target_code_index = code_dir + .entry(key.clone()) + .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) + .clone(); + + set_code_index( + retraction_info, + compilation_target, + key, + &target_code_index, + src_code_index.get(), + ); + } else { + return Err(SessionError::ModuleDoesNotContainExport( + imported_module.module_decl.name.clone(), + (name.clone(), *arity), + )); + } + } + ModuleExport::OpDecl(ref op_decl) => { + add_op_decl_as_module_export( + op_dir, + compilation_target, + retraction_info, + wam_op_dir, + module_op_exports, + op_decl, + ); + } + } + } + + Ok(()) +} + +impl<'a> LoadState<'a> { + pub(super) fn retract_local_clauses( + &mut self, + compilation_target: CompilationTarget, + key: PredicateKey, + clause_locs: &SliceDeque, + ) { + let (clause_target_poses, is_dynamic) = self + .wam + .indices + .get_predicate_skeleton(&compilation_target, &key) + .map(|skeleton| { + (clause_locs + .iter() + .map(|clause_clause_loc| { + skeleton.target_pos_of_clause_clause_loc( + *clause_clause_loc, + ) + }) + .collect(), + skeleton.is_dynamic) + }).unwrap(); + + self.retract_local_clauses_by_locs( + compilation_target, + key, + clause_target_poses, + is_dynamic, + ); + } + + pub(super) fn retract_local_clauses_by_locs( + &mut self, + compilation_target: CompilationTarget, + key: PredicateKey, + mut clause_target_poses: Vec>, + is_dynamic: bool, + ) { + let old_compilation_target = mem::replace( + &mut self.compilation_target, + compilation_target, + ); + + while let Some(target_pos_opt) = clause_target_poses.pop() { + match target_pos_opt { + Some(target_pos) if is_dynamic => { + self.retract_dynamic_clause(key.clone(), target_pos); + } + Some(target_pos) => { + self.retract_clause(key.clone(), target_pos); + } + None => { + // Here because the clause was been removed + // earlier, e.g., by retract, without updating the + // local skeleton. In this case, do nothing. + } + } + } + + self.compilation_target = old_compilation_target; + } + + pub(super) fn retract_local_clause_clauses( + &mut self, + clause_clause_compilation_target: CompilationTarget, + clause_locs: &SliceDeque, + ) { + let key = (clause_name!("$clause"), 2); + + match self + .wam + .indices + .get_local_predicate_skeleton_mut( + &self.compilation_target, + clause_clause_compilation_target.clone(), + key.clone(), + ) + { + Some(skeleton) => { + self.retraction_info.push_record( + RetractionRecord::RemovedLocalSkeletonClauseLocations( + self.compilation_target.clone(), + clause_clause_compilation_target.clone(), + key.clone(), + mem::replace(&mut skeleton.clause_clause_locs, sdeq![]), + ), + ); + + skeleton.reset(); + } + None => { + // The local skeleton might be removed when reloading + // or redefining a module, in which case no retraction + // record is necessary. + } + }; + + self.retract_local_clauses( + clause_clause_compilation_target, + key, + &clause_locs, + ); + } + + pub(super) fn try_term_to_tl( + &mut self, + term: Term, + preprocessor: &mut Preprocessor, + ) -> Result { + let tl = preprocessor.try_term_to_tl( + self, + term, + CutContext::BlocksCuts, + )?; + + Ok(match tl { + TopLevel::Fact(fact) => PredicateClause::Fact(fact), + TopLevel::Rule(rule) => PredicateClause::Rule(rule), + TopLevel::Query(_) => return Err(SessionError::QueryCannotBeDefinedAsFact), + _ => unreachable!(), + }) + } + + #[inline] + pub(super) fn remove_module_op_exports(&mut self) { + for (mut op_decl, record) in self.module_op_exports.drain(0..) { + op_decl.remove(&mut self.wam.indices.op_dir); + + if let Some((prec, spec)) = record { + op_decl.prec = prec; + op_decl.spec = spec; + op_decl.insert_into_op_dir(&mut self.wam.indices.op_dir); + } + } + } + + pub(super) fn remove_module_exports(&mut self, module_name: ClauseName) { + let removed_module = match self.wam.indices.modules.remove(&module_name) { + Some(module) => module, + None => return, + }; + + fn remove_module_exports( + removed_module: &Module, + code_dir: &mut CodeDir, + op_dir: &mut OpDir, + retraction_info: &mut RetractionInfo, + predicate_retractor: impl Fn(PredicateKey, IndexPtr) -> RetractionRecord, + op_retractor: impl Fn(OpDecl, usize, Specifier) -> RetractionRecord, + ) { + for export in removed_module.module_decl.exports.iter() { + match export { + ModuleExport::PredicateKey(ref key) => { + match (removed_module.code_dir.get(key), code_dir.get(key)) { + (Some(module_code_index), Some(target_code_index)) + if module_code_index.get() == target_code_index.get() => { + let old_index_ptr = target_code_index.replace(IndexPtr::Undefined); + + retraction_info.push_record( + predicate_retractor(key.clone(), old_index_ptr), + ); + } + _ => {} + } + } + ModuleExport::OpDecl(op_decl) => { + let op_dir_value_opt = op_dir.remove(&(op_decl.name.clone(), op_decl.fixity())); + + if let Some(op_dir_value) = op_dir_value_opt { + let (prec, spec) = op_dir_value.shared_op_desc().get(); + + retraction_info.push_record( + op_retractor(op_decl.clone(), prec, spec), + ); + } + } + } + } + } + + match &self.compilation_target { + CompilationTarget::User => { + remove_module_exports( + &removed_module, + &mut self.wam.indices.code_dir, + &mut self.wam.indices.op_dir, + &mut self.retraction_info, + RetractionRecord::ReplacedUserPredicate, + RetractionRecord::ReplacedUserOp, + ); + } + CompilationTarget::Module(ref target_module_name) + if target_module_name.as_str() != module_name.as_str() => { + let predicate_retractor = |key, index_ptr| { + RetractionRecord::ReplacedModulePredicate( + module_name.clone(), key, index_ptr, + ) + }; + + let op_retractor = |op_decl, prec, spec| { + RetractionRecord::ReplacedModuleOp( + module_name.clone(), op_decl, prec, spec, + ) + }; + + if let Some(module) = self.wam.indices.modules.get_mut(target_module_name) { + remove_module_exports( + &removed_module, + &mut module.code_dir, + &mut module.op_dir, + &mut self.retraction_info, + predicate_retractor, + op_retractor, + ); + } else { + unreachable!() + } + } + CompilationTarget::Module(_) => {}, + }; + + self.wam.indices.modules.insert(module_name, removed_module); + } + + fn get_or_insert_local_code_index( + &mut self, + module_name: ClauseName, + key: PredicateKey, + ) -> CodeIndex { + match self.wam.indices.modules.get_mut(&module_name) { + Some(ref mut module) => module + .code_dir + .entry(key) + .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) + .clone(), + None => { + self.add_dynamically_generated_module(&module_name); + + match self.wam.indices.modules.get_mut(&module_name) { + Some(ref mut module) => { + module + .code_dir + .entry(key) + .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) + .clone() + } + None => { + unreachable!() + } + } + } + } + } + + pub(super) fn get_or_insert_code_index( + &mut self, + key: PredicateKey, + compilation_target: CompilationTarget, + ) -> CodeIndex { + match compilation_target { + CompilationTarget::User => self + .wam + .indices + .code_dir + .entry(key) + .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) + .clone(), + CompilationTarget::Module(module_name) => { + self.get_or_insert_local_code_index(module_name, key) + } + } + } + + pub(super) fn get_or_insert_qualified_code_index( + &mut self, + module_name: ClauseName, + key: PredicateKey, + ) -> CodeIndex { + if module_name.as_str() == "user" { + return self + .wam + .indices + .code_dir + .entry(key) + .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) + .clone(); + } else { + self.get_or_insert_local_code_index(module_name, key) + } + } + + #[inline] + pub(super) fn add_extensible_predicate( + &mut self, + key: PredicateKey, + skeleton: PredicateSkeleton, + compilation_target: CompilationTarget, + ) { + match compilation_target { + CompilationTarget::User => { + self.wam + .indices + .extensible_predicates + .insert(key.clone(), skeleton); + + let record = RetractionRecord::AddedExtensiblePredicate( + CompilationTarget::User, + key, + ); + + self.retraction_info.push_record(record); + } + CompilationTarget::Module(module_name) => { + if let Some(module) = self.wam.indices.modules.get_mut(&module_name) { + module + .extensible_predicates + .insert(key.clone(), skeleton); + + let record = RetractionRecord::AddedExtensiblePredicate( + CompilationTarget::Module(module_name), + key, + ); + + self.retraction_info.push_record(record); + } else { + unreachable!() + } + } + } + } + + #[inline] + pub(super) fn add_local_extensible_predicate( + &mut self, + local_compilation_target: CompilationTarget, + key: PredicateKey, + skeleton: PredicateSkeleton, + ) { + match self.compilation_target.clone() { + CompilationTarget::User => { + self.wam + .indices + .local_extensible_predicates + .insert((local_compilation_target.clone(), key.clone()), skeleton); + } + CompilationTarget::Module(module_name) => { + if let Some(module) = self.wam.indices.modules.get_mut(&module_name) { + module + .local_extensible_predicates + .insert((local_compilation_target.clone(), key.clone()), skeleton); + } else { + unreachable!() + } + } + } + } + + pub(super) fn add_op_decl(&mut self, op_decl: &OpDecl) { + match &self.compilation_target { + CompilationTarget::User => { + add_op_decl( + &mut self.retraction_info, + &self.compilation_target, + &mut self.wam.indices.op_dir, + op_decl, + ); + } + CompilationTarget::Module(ref module_name) => { + match self.wam.indices.modules.get_mut(module_name) { + Some(ref mut module) => { + add_op_decl_as_module_export( + &mut module.op_dir, + &self.compilation_target, + &mut self.retraction_info, + &mut self.wam.indices.op_dir, + &mut self.module_op_exports, + op_decl, + ); + } + _ => { + unreachable!() + } + } + } + } + } + + pub(super) fn get_clause_type( + &mut self, + name: ClauseName, + arity: usize, + fixity: Option, + ) -> ClauseType { + match ClauseType::from(name, arity, fixity) { + ClauseType::Named(name, arity, _) => { + let idx = self.get_or_insert_code_index( + (name.clone(), arity), + self.compilation_target.clone(), + ); + + ClauseType::Named(name, arity, idx) + } + ClauseType::Op(name, fixity, _) => { + let idx = self.get_or_insert_code_index( + (name.clone(), arity), + self.compilation_target.clone(), + ); + + ClauseType::Op(name, fixity, idx) + } + ct => ct, + } + } + + pub(super) fn get_qualified_clause_type( + &mut self, + module_name: ClauseName, + name: ClauseName, + arity: usize, + fixity: Option, + ) -> ClauseType { + match ClauseType::from(name, arity, fixity) { + ClauseType::Named(name, arity, _) => { + let key = (name.clone(), arity); + let idx = self.get_or_insert_qualified_code_index(module_name, key); + + ClauseType::Named(name, arity, idx) + } + ClauseType::Op(name, fixity, _) => { + let key = (name.clone(), arity); + let idx = self.get_or_insert_qualified_code_index(module_name, key); + + ClauseType::Op(name, fixity, idx) + } + ct => ct, + } + } + + pub(super) fn add_meta_predicate_record( + &mut self, + module_name: ClauseName, + name: ClauseName, + meta_specs: Vec, + ) { + let arity = meta_specs.len(); + let key = (name, arity); + + match module_name.as_str() { + "user" => { + match self + .wam + .indices + .meta_predicates + .insert(key.clone(), meta_specs) + { + Some(old_meta_specs) => { + self.retraction_info + .push_record(RetractionRecord::ReplacedMetaPredicate( + module_name.clone(), + key.0, + old_meta_specs, + )); + } + None => { + self.retraction_info + .push_record(RetractionRecord::AddedMetaPredicate( + module_name.clone(), + key, + )); + } + } + } + _ => { + match self.wam.indices.modules.get_mut(&module_name) { + Some(ref mut module) => { + match module.meta_predicates.insert(key.clone(), meta_specs) { + Some(old_meta_specs) => { + self.retraction_info.push_record( + RetractionRecord::ReplacedMetaPredicate( + module_name.clone(), + key.0, + old_meta_specs, + ), + ); + } + None => { + self.retraction_info.push_record( + RetractionRecord::AddedMetaPredicate(module_name.clone(), key), + ); + } + } + } + None => { + self.add_dynamically_generated_module(&module_name); + + if let Some(module) = self.wam.indices.modules.get_mut(&module_name) { + module.meta_predicates.insert(key.clone(), meta_specs); + } else { + unreachable!() + } + + self.retraction_info + .push_record(RetractionRecord::AddedMetaPredicate( + module_name.clone(), + key, + )); + } + } + } + } + } + + pub(super) fn add_dynamically_generated_module(&mut self, module_name: &ClauseName) { + let module_decl = ModuleDecl { + name: module_name.clone(), + exports: vec![], + }; + + let listing_src = ListingSource::DynamicallyGenerated; + let module = Module::new(module_decl, listing_src); + + self.retraction_info + .push_record(RetractionRecord::AddedModule(module_name.clone())); + + self.wam.indices.modules.insert(module_name.clone(), module); + } + + fn import_builtins_in_module( + &mut self, + code_dir: &mut CodeDir, + op_dir: &mut OpDir, + meta_predicates: &mut MetaPredicateDir, + ) { + if let Some(builtins) = self.wam.indices.modules.get(&clause_name!("builtins")) { + import_module_exports( + &mut self.retraction_info, + &self.compilation_target, + builtins, + code_dir, + op_dir, + meta_predicates, + ).unwrap(); + } + } + + pub(crate) fn add_module(&mut self, module_decl: ModuleDecl, listing_src: ListingSource) { + let module_name = module_decl.name.clone(); + self.remove_module_exports(module_name.clone()); + + match self.wam.indices.modules.get_mut(&module_name) { + Some(module) => { + let old_module_decl = mem::replace(&mut module.module_decl, module_decl.clone()); + + let local_extensible_predicates = mem::replace( + &mut module.local_extensible_predicates, + LocalExtensiblePredicates::new(), + ); + + for ((compilation_target, key), skeleton) in local_extensible_predicates.iter() { + self.retract_local_clauses( + compilation_target.clone(), + key.clone(), + &skeleton.clause_clause_locs, + ); + + let is_dynamic = self + .wam + .indices + .get_predicate_skeleton(&compilation_target, &key) + .map(|skeleton| skeleton.is_dynamic) + .unwrap_or(false); + + if is_dynamic { + let clause_clause_compilation_target = match compilation_target { + CompilationTarget::User => { + CompilationTarget::Module(clause_name!("builtins")) + } + module => { + module.clone() + } + }; + + self.retract_local_clause_clauses( + clause_clause_compilation_target, + &skeleton.clause_clause_locs, + ); + } + } + + self.retraction_info.push_record(RetractionRecord::ReplacedModule( + old_module_decl, + listing_src.clone(), + local_extensible_predicates, + )); + } + None => {} + } + + let mut module = match self.wam.indices.modules.remove(&module_name) { + Some(mut module) => { + module.listing_src = listing_src; + module + } + None => { + self.retraction_info + .push_record(RetractionRecord::AddedModule(module_name.clone())); + + Module::new(module_decl, listing_src) + } + }; + + self.import_builtins_in_module( + &mut module.code_dir, + &mut module.op_dir, + &mut module.meta_predicates, + ); + + for export in &module.module_decl.exports { + if let ModuleExport::OpDecl(ref op_decl) = export { + add_op_decl_as_module_export( + &mut module.op_dir, + &self.compilation_target, // this is a Module. + &mut self.retraction_info, + &mut self.wam.indices.op_dir, + &mut self.module_op_exports, + op_decl, + ); + } + } + + if let Some(load_context) = self.wam.load_contexts.last_mut() { + load_context.module = module_name.clone(); + } + + self.wam.indices.modules.insert(module_name, module); + } + + pub(super) fn import_module(&mut self, module_name: ClauseName) -> Result<(), SessionError> { + if let Some(module) = self.wam.indices.modules.remove(&module_name) { + match &self.compilation_target { + CompilationTarget::User => { + import_module_exports( + &mut self.retraction_info, + &self.compilation_target, + &module, + &mut self.wam.indices.code_dir, + &mut self.wam.indices.op_dir, + &mut self.wam.indices.meta_predicates, + )?; + } + CompilationTarget::Module(ref defining_module_name) => { + match self.wam.indices.modules.get_mut(defining_module_name) { + Some(ref mut target_module) => { + import_module_exports_into_module( + &mut self.retraction_info, + &self.compilation_target, + &module, + &mut target_module.code_dir, + &mut target_module.op_dir, + &mut target_module.meta_predicates, + &mut self.wam.indices.op_dir, + &mut self.module_op_exports, + )?; + } + None => { + // we find ourselves here because we're trying to import + // a module into itself as it is being defined. + self.wam.indices.modules.insert(module_name.clone(), module); + return Err(SessionError::ModuleCannotImportSelf(module_name)); + } + } + } + } + + self.wam.indices.modules.insert(module_name, module); + Ok(()) + } else { + Err(SessionError::ExistenceError(ExistenceError::Module( + module_name, + ))) + } + } + + pub(super) fn import_qualified_module( + &mut self, + module_name: ClauseName, + exports: IndexSet, + ) -> Result<(), SessionError> { + if let Some(module) = self.wam.indices.modules.remove(&module_name) { + match &self.compilation_target { + CompilationTarget::User => { + import_qualified_module_exports( + &mut self.retraction_info, + &self.compilation_target, + &module, + &exports, + &mut self.wam.indices.code_dir, + &mut self.wam.indices.op_dir, + &mut self.wam.indices.meta_predicates, + )?; + } + CompilationTarget::Module(ref defining_module_name) => { + match self.wam.indices.modules.get_mut(defining_module_name) { + Some(ref mut target_module) => { + import_qualified_module_exports_into_module( + &mut self.retraction_info, + &self.compilation_target, + &module, + &exports, + &mut target_module.code_dir, + &mut target_module.op_dir, + &mut target_module.meta_predicates, + &mut self.wam.indices.op_dir, + &mut self.module_op_exports, + )?; + } + None => { + // we find ourselves here because we're trying to import + // a module into itself as it is being defined. + self.wam.indices.modules.insert(module_name.clone(), module); + return Err(SessionError::ModuleCannotImportSelf(module_name)); + } + } + } + } + + self.wam.indices.modules.insert(module_name, module); + Ok(()) + } else { + Err(SessionError::ExistenceError(ExistenceError::Module( + module_name, + ))) + } + } + + pub(crate) fn use_module(&mut self, module_src: ModuleSource) -> Result<(), SessionError> { + let (stream, listing_src) = match module_src { + ModuleSource::File(filename) => { + let mut path_buf = PathBuf::from(filename.as_str()); + path_buf.set_extension("pl"); + let file = File::open(&path_buf)?; + + ( + Stream::from_file_as_input(filename.clone(), file), + ListingSource::File(filename, path_buf), + ) + } + ModuleSource::Library(library) => match LIBRARIES.borrow().get(library.as_str()) { + Some(code) => { + if let Some(ref module) = self.wam.indices.modules.get(&library) { + if let ListingSource::DynamicallyGenerated = &module.listing_src { + (Stream::from(*code), ListingSource::User) + } else { + return self.import_module(library); + } + } else { + (Stream::from(*code), ListingSource::User) + } + } + None => { + return self.import_module(library); + } + }, + }; + + let compilation_target = { + let stream = &mut parsing_stream(stream)?; + + let ts = BootstrappingTermStream::from_prolog_stream( + stream, + self.wam.machine_st.atom_tbl.clone(), + self.wam.machine_st.flags, + listing_src, + ); + + let subloader = Loader::new(ts, self.wam); + subloader.load()? + }; + + match compilation_target { + CompilationTarget::User => { + // nothing to do. + Ok(()) + } + CompilationTarget::Module(module_name) => self.import_module(module_name), + } + } + + pub(crate) fn use_qualified_module( + &mut self, + module_src: ModuleSource, + exports: IndexSet, + ) -> Result<(), SessionError> { + let (stream, listing_src) = match module_src { + ModuleSource::File(filename) => { + let mut path_buf = PathBuf::from(filename.as_str()); + path_buf.set_extension("pl"); + let file = File::open(&path_buf)?; + + ( + Stream::from_file_as_input(filename.clone(), file), + ListingSource::File(filename, path_buf), + ) + } + ModuleSource::Library(library) => match LIBRARIES.borrow().get(library.as_str()) { + Some(code) => { + if self.wam.indices.modules.contains_key(&library) { + return self.import_qualified_module(library, exports); + } else { + (Stream::from(*code), ListingSource::User) + } + } + None => { + return self.import_qualified_module(library, exports); + } + }, + }; + + let compilation_target = { + let stream = &mut parsing_stream(stream)?; + + let ts = BootstrappingTermStream::from_prolog_stream( + stream, + self.wam.machine_st.atom_tbl.clone(), + self.wam.machine_st.flags, + listing_src, + ); + + let subloader = Loader::new(ts, self.wam); + subloader.load()? + }; + + match compilation_target { + CompilationTarget::User => { + // nothing to do. + Ok(()) + } + CompilationTarget::Module(module_name) => { + self.import_qualified_module(module_name, exports) + } + } + } + + #[inline] + pub(super) fn composite_op_dir(&self) -> CompositeOpDir { + match &self.compilation_target { + CompilationTarget::User => CompositeOpDir::new(&self.wam.indices.op_dir, None), + CompilationTarget::Module(ref module_name) => { + match self.wam.indices.modules.get(module_name) { + Some(ref module) => { + CompositeOpDir::new(&self.wam.indices.op_dir, Some(&module.op_dir)) + } + None => { + unreachable!() + } + } + } + } + } +} diff --git a/src/machine/loader.rs b/src/machine/loader.rs new file mode 100644 index 00000000..c5c5e2e8 --- /dev/null +++ b/src/machine/loader.rs @@ -0,0 +1,2261 @@ +use prolog_parser::ast::*; +use prolog_parser::{clause_name, temp_v}; + +use crate::forms::*; +use crate::indexing::*; +use crate::machine::load_state::*; +use crate::machine::machine_indices::*; +use crate::machine::preprocessor::*; +use crate::machine::*; + +use indexmap::IndexSet; +use slice_deque::{sdeq, SliceDeque}; + +use std::cell::Cell; +use std::convert::TryFrom; +use std::rc::Rc; + +/* + * The loader compiles Prolog terms read from a TermStream instance, + * which may be incremental or monolithic. The monolithic term stream + * reads from a file. It's used only to bootstrap Scryer at + * start-up. Once Scryer is bootstrapped, all compilation and loading + * work is divided between loader.pl and loader.rs. + * + * loader.pl does a few high-level things more easily handled from + * Prolog that are not supported (or needed) during bootstrapping: + * term and goal expansion, loading modules from different streams, + * verifying certain kinds of declarations, perhaps (in the future?) + * compiling inline disjunctions. + * + * Since the loader can operate incrementally, it uses an intermittent + * structure to rebuild the loader between invocations. Preprocessor + * needs access to a &'a mut Machine for as long as it lives, and we + * can't have copies of &'a mut Machine distributed among multiple + * owners. + * + * When loading a module, we modify the records of the WAM with the + * location of new predicates, with new meta-predicate information, + * new term and goal expansions, new dynamic clauses, etc. Should the + * loader fail later, all changes must be rolled back, restoring the + * WAM to its prior state. Retraction records describe individual changes + * made by the loader, and they may be used later. + */ + +#[derive(Debug)] +pub(crate) enum RetractionRecord { + AddedMetaPredicate(ClauseName, PredicateKey), + ReplacedMetaPredicate(ClauseName, ClauseName, Vec), + AddedModule(ClauseName), + ReplacedModule(ModuleDecl, ListingSource, LocalExtensiblePredicates), + AppendedModuleExtensiblePredicate(ClauseName, PredicateKey), + PrependedModuleExtensiblePredicate(ClauseName, PredicateKey), + AddedModuleOp(ClauseName, OpDecl), + ReplacedModuleOp(ClauseName, OpDecl, usize, Specifier), + AddedModulePredicate(ClauseName, PredicateKey), + ReplacedModulePredicate(ClauseName, PredicateKey, IndexPtr), + AddedDiscontiguousPredicate(CompilationTarget, PredicateKey), + AddedDynamicPredicate(CompilationTarget, PredicateKey), + AddedMultifilePredicate(CompilationTarget, PredicateKey), + AddedUserOp(OpDecl), + ReplacedUserOp(OpDecl, usize, Specifier), + AddedExtensiblePredicate(CompilationTarget, PredicateKey), + AppendedUserExtensiblePredicate(PredicateKey), + PrependedUserExtensiblePredicate(PredicateKey), + AddedUserPredicate(PredicateKey), + ReplacedUserPredicate(PredicateKey, IndexPtr), + AddedIndex(OptArgIndexKey, usize), //, Vec), + RemovedIndex(usize, OptArgIndexKey, usize), + ReplacedChoiceOffset(usize, usize), + AppendedTrustMe(usize, usize, bool), + ReplacedSwitchOnTermVarIndex(usize, IndexingCodePtr), + ModifiedTryMeElse(usize, usize), + ModifiedRetryMeElse(usize, usize), + ModifiedRevJmpBy(usize, usize), + SkeletonClausePopBack(CompilationTarget, PredicateKey), + SkeletonClausePopFront(CompilationTarget, PredicateKey), + SkeletonLocalClauseClausePopBack(CompilationTarget, CompilationTarget, PredicateKey), + SkeletonLocalClauseClausePopFront(CompilationTarget, CompilationTarget, PredicateKey), + SkeletonLocalClauseTruncateBack(CompilationTarget, CompilationTarget, PredicateKey, usize), + SkeletonClauseTruncateBack(CompilationTarget, PredicateKey, usize), + SkeletonClauseStartReplaced(CompilationTarget, PredicateKey, usize, usize), + RemovedSkeletonClause( + CompilationTarget, + PredicateKey, + usize, + ClauseIndexInfo, + usize, + ), + ReplacedIndexingLine(usize, Vec), + RemovedLocalSkeletonClauseLocations( + CompilationTarget, + CompilationTarget, + PredicateKey, + SliceDeque, + ), + RemovedSkeleton(CompilationTarget, PredicateKey, PredicateSkeleton), + ReplacedDynamicElseOffset(usize, usize), + AppendedNextOrFail(usize, NextOrFail), +} + +/* + * Retractions to be performed on rollback are represented by + * individual records, and the original extent of the code vector of + * the IndexStore, of which there are several (one per module). The + * "extent" of a code vector is its length prior to an attempted + * module load. The only code vector of the WAM's IndexStore, "code", + * is shared by all modules, including the default "user" module. + */ + +pub(super) struct RetractionInfo { + orig_code_extent: usize, + records: Vec, +} + +impl RetractionInfo { + #[inline] + pub(super) fn new(orig_code_extent: usize) -> Self { + Self { + orig_code_extent, + records: vec![], //BTreeMap::new(), + } + } + + #[inline] + pub(crate) fn push_record(&mut self, record: RetractionRecord) { + self.records.push(record); + } + + #[inline] + pub(crate) fn reset(&mut self, code_len: usize) -> Self { + let orig_code_extent = self.orig_code_extent; + self.orig_code_extent = code_len; + + Self { + orig_code_extent, + records: mem::replace(&mut self.records, vec![]), + } + } +} + +impl<'a> Drop for LoadState<'a> { + fn drop(&mut self) { + while let Some(record) = self.retraction_info.records.pop() { + match record { + RetractionRecord::AddedMetaPredicate(target_module_name, key) => { + match target_module_name.as_str() { + "user" => { + self.wam.indices.meta_predicates.remove(&key); + } + _ => match self.wam.indices.modules.get_mut(&target_module_name) { + Some(ref mut module) => { + module.meta_predicates.remove(&key); + } + _ => { + unreachable!() + } + }, + } + } + RetractionRecord::ReplacedMetaPredicate(target_module_name, name, meta_specs) => { + match target_module_name.as_str() { + "user" => { + self.wam + .indices + .meta_predicates + .insert((name, meta_specs.len()), meta_specs); + } + _ => match self.wam.indices.modules.get_mut(&target_module_name) { + Some(ref mut module) => { + module + .meta_predicates + .insert((name, meta_specs.len()), meta_specs); + } + _ => { + unreachable!() + } + }, + } + } + RetractionRecord::AddedModule(module_name) => { + self.wam.indices.modules.remove(&module_name); + } + RetractionRecord::ReplacedModule( + module_decl, + listing_src, + local_extensible_predicates, + ) => match self.wam.indices.modules.get_mut(&module_decl.name) { + Some(ref mut module) => { + module.module_decl = module_decl; + module.listing_src = listing_src; + module.local_extensible_predicates = local_extensible_predicates; + } + _ => { + unreachable!() + } + }, + RetractionRecord::AddedDiscontiguousPredicate(compilation_target, key) => { + match compilation_target { + CompilationTarget::User => { + self.wam + .indices + .extensible_predicates + .get_mut(&key) + .map(|skeleton| { + skeleton.is_discontiguous = false; + }); + } + CompilationTarget::Module(module_name) => { + match self.wam.indices.modules.get_mut(&module_name) { + Some(ref mut module) => { + module.extensible_predicates.get_mut(&key).map(|skeleton| { + skeleton.is_discontiguous = false; + }); + } + None => {} + } + } + } + } + RetractionRecord::AddedDynamicPredicate(compilation_target, key) => { + match compilation_target { + CompilationTarget::User => { + self.wam + .indices + .extensible_predicates + .get_mut(&key) + .map(|skeleton| { + skeleton.is_dynamic = false; + }); + } + CompilationTarget::Module(module_name) => { + match self.wam.indices.modules.get_mut(&module_name) { + Some(ref mut module) => { + module.extensible_predicates.get_mut(&key).map(|skeleton| { + skeleton.is_dynamic = false; + }); + } + None => {} + } + } + } + } + RetractionRecord::AddedMultifilePredicate(compilation_target, key) => { + match compilation_target { + CompilationTarget::User => { + self.wam + .indices + .extensible_predicates + .get_mut(&key) + .map(|skeleton| { + skeleton.is_multifile = false; + }); + } + CompilationTarget::Module(module_name) => { + match self.wam.indices.modules.get_mut(&module_name) { + Some(ref mut module) => { + module.extensible_predicates.get_mut(&key).map(|skeleton| { + skeleton.is_multifile = false; + }); + } + None => {} + } + } + } + } + RetractionRecord::AppendedModuleExtensiblePredicate(module_name, key) => { + self.wam + .indices + .get_predicate_skeleton_mut(&CompilationTarget::Module(module_name), &key) + .map(|skeleton| { + skeleton.clauses.pop_back(); + }); + } + RetractionRecord::PrependedModuleExtensiblePredicate(module_name, key) => { + self.wam + .indices + .get_predicate_skeleton_mut(&CompilationTarget::Module(module_name), &key) + .map(|skeleton| { + skeleton.clauses.pop_front(); + }); + } + RetractionRecord::AddedModuleOp(module_name, mut op_decl) => { + match self.wam.indices.modules.get_mut(&module_name) { + Some(ref mut module) => { + op_decl.remove(&mut module.op_dir); + } + None => {} + } + } + RetractionRecord::ReplacedModuleOp(module_name, mut op_decl, prec, spec) => { + match self.wam.indices.modules.get_mut(&module_name) { + Some(ref mut module) => { + op_decl.prec = prec; + op_decl.spec = spec; + op_decl.insert_into_op_dir(&mut module.op_dir); + } + None => {} + } + } + RetractionRecord::AddedModulePredicate(module_name, key) => { + match self.wam.indices.modules.get_mut(&module_name) { + Some(ref mut module) => { + module.code_dir.remove(&key); + } + None => {} + } + } + RetractionRecord::ReplacedModulePredicate(module_name, key, old_code_idx) => { + match self.wam.indices.modules.get_mut(&module_name) { + Some(ref mut module) => { + module + .code_dir + .get_mut(&key) + .map(|code_idx| code_idx.replace(old_code_idx)); + } + None => {} + } + } + RetractionRecord::AddedExtensiblePredicate(compilation_target, key) => { + self.wam + .indices + .remove_predicate_skeleton(&compilation_target, &key); + } + RetractionRecord::AppendedUserExtensiblePredicate(key) => { + self.wam + .indices + .get_predicate_skeleton_mut(&CompilationTarget::User, &key) + .map(|skeleton| { + skeleton.clauses.pop_back(); + }); + } + RetractionRecord::PrependedUserExtensiblePredicate(key) => { + self.wam + .indices + .get_predicate_skeleton_mut(&CompilationTarget::User, &key) + .map(|skeleton| { + skeleton.clauses.pop_front(); + }); + } + RetractionRecord::AddedUserOp(mut op_decl) => { + op_decl.remove(&mut self.wam.indices.op_dir); + } + RetractionRecord::ReplacedUserOp(mut op_decl, prec, spec) => { + op_decl.prec = prec; + op_decl.spec = spec; + op_decl.insert_into_op_dir(&mut self.wam.indices.op_dir); + } + RetractionRecord::AddedUserPredicate(key) => { + self.wam.indices.code_dir.remove(&key); + } + RetractionRecord::ReplacedUserPredicate(key, old_code_idx) => { + self.wam + .indices + .code_dir + .get_mut(&key) + .map(|code_idx| code_idx.replace(old_code_idx)); + } + RetractionRecord::AddedIndex(index_key, clause_loc) => { + // WAS: inner_index_locs) => { + if let Some(index_loc) = index_key.switch_on_term_loc() { + let indexing_code = match &mut self.wam.code_repo.code[index_loc] { + Line::IndexingCode(indexing_code) => indexing_code, + _ => { + unreachable!() + } + }; + + match index_key { + OptArgIndexKey::Constant( + _, + index_loc, + constant, + overlapping_constants, + ) => { + remove_constant_indices( + &constant, + &overlapping_constants, + indexing_code, + clause_loc - index_loc, // WAS: &inner_index_locs, + ); + } + OptArgIndexKey::Structure(_, index_loc, name, arity) => { + remove_structure_index( + &name, + arity, + indexing_code, + clause_loc - index_loc, // WAS: &inner_index_locs, + ); + } + OptArgIndexKey::List(_, index_loc) => { + remove_list_index( + indexing_code, + clause_loc - index_loc, // WAS: &inner_index_locs, + ); + } + OptArgIndexKey::None => { + unreachable!(); + } + } + } + } + RetractionRecord::RemovedIndex(_index_loc, _index_key, _clause_loc) => { + // TODO: this needs to be fixed! RemovedIndex doesn't provide + // enough information to restore the index. Correct that, then + // write the retraction logic of this arm. + } + RetractionRecord::ReplacedChoiceOffset(instr_loc, offset) => { + match &mut self.wam.code_repo.code[instr_loc] { + Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) + | Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o)) + | Line::Choice(ChoiceInstruction::DefaultRetryMeElse(ref mut o)) => { + *o = offset; + } + _ => { + unreachable!(); + } + } + } + RetractionRecord::AppendedTrustMe(instr_loc, offset, is_default) => { + match &mut self.wam.code_repo.code[instr_loc] { + Line::Choice(ref mut choice_instr) => { + *choice_instr = if is_default { + ChoiceInstruction::DefaultTrustMe(offset) + } else { + ChoiceInstruction::TrustMe(offset) + }; + } + _ => { + unreachable!(); + } + } + } + RetractionRecord::ReplacedSwitchOnTermVarIndex(index_loc, old_v) => { + match &mut self.wam.code_repo.code[index_loc] { + Line::IndexingCode(ref mut indexing_code) => match &mut indexing_code[0] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm( + _, + ref mut v, + .., + )) => { + *v = old_v; + } + _ => {} + }, + _ => {} + } + } + RetractionRecord::ModifiedTryMeElse(instr_loc, o) => { + self.wam.code_repo.code[instr_loc] = + Line::Choice(ChoiceInstruction::TryMeElse(o)); + } + RetractionRecord::ModifiedRetryMeElse(instr_loc, o) => { + self.wam.code_repo.code[instr_loc] = + Line::Choice(ChoiceInstruction::RetryMeElse(o)); + } + RetractionRecord::ModifiedRevJmpBy(instr_loc, o) => { + self.wam.code_repo.code[instr_loc] = + Line::Control(ControlInstruction::RevJmpBy(o)); + } + RetractionRecord::SkeletonClausePopBack(compilation_target, key) => { + match self + .wam + .indices + .get_predicate_skeleton_mut(&compilation_target, &key) + { + Some(skeleton) => { + skeleton.clauses.pop_back(); + skeleton.clause_clause_locs.pop_back(); + } + None => {} + } + } + RetractionRecord::SkeletonClausePopFront(compilation_target, key) => { + match self + .wam + .indices + .get_predicate_skeleton_mut(&compilation_target, &key) + { + Some(skeleton) => { + skeleton.clauses.pop_front(); + skeleton.clause_clause_locs.pop_front(); + skeleton.clause_assert_margin -= 1; + } + None => {} + } + } + RetractionRecord::SkeletonLocalClauseClausePopFront( + src_compilation_target, + local_compilation_target, + key, + ) => { + match self.wam.indices.get_local_predicate_skeleton_mut( + &src_compilation_target, + local_compilation_target, + key, + ) { + Some(skeleton) => { + skeleton.clause_clause_locs.pop_front(); + } + None => {} + } + } + RetractionRecord::SkeletonLocalClauseClausePopBack( + src_compilation_target, + local_compilation_target, + key, + ) => { + match self.wam.indices.get_local_predicate_skeleton_mut( + &src_compilation_target, + local_compilation_target, + key, + ) { + Some(skeleton) => { + skeleton.clause_clause_locs.pop_back(); + } + None => {} + } + } + RetractionRecord::SkeletonLocalClauseTruncateBack( + src_compilation_target, + local_compilation_target, + key, + len, + ) => { + match self.wam.indices.get_local_predicate_skeleton_mut( + &src_compilation_target, + local_compilation_target, + key, + ) { + Some(skeleton) => { + skeleton.clause_clause_locs.truncate_back(len); + } + None => {} + } + } + RetractionRecord::SkeletonClauseTruncateBack(compilation_target, key, len) => { + match self + .wam + .indices + .get_predicate_skeleton_mut(&compilation_target, &key) + { + Some(skeleton) => { + skeleton.clauses.truncate_back(len); + skeleton.clause_clause_locs.truncate_back(len); + } + None => {} + } + } + RetractionRecord::SkeletonClauseStartReplaced( + compilation_target, + key, + target_pos, + clause_start, + ) => { + match self + .wam + .indices + .get_predicate_skeleton_mut(&compilation_target, &key) + { + Some(skeleton) => { + skeleton.clauses[target_pos].clause_start = clause_start; + } + None => {} + } + } + RetractionRecord::RemovedSkeletonClause( + compilation_target, + key, + target_pos, + clause_index_info, + clause_clause_loc, + ) => { + match self + .wam + .indices + .get_predicate_skeleton_mut(&compilation_target, &key) + { + Some(skeleton) => { + skeleton + .clause_clause_locs + .insert(target_pos, clause_clause_loc); + skeleton.clauses.insert(target_pos, clause_index_info); + } + None => {} + } + } + RetractionRecord::ReplacedIndexingLine(index_loc, indexing_code) => { + self.wam.code_repo.code[index_loc] = Line::IndexingCode(indexing_code); + } + RetractionRecord::RemovedLocalSkeletonClauseLocations( + compilation_target, + local_compilation_target, + key, + clause_locs, + ) => { + match self.wam.indices.get_local_predicate_skeleton_mut( + &compilation_target, + local_compilation_target, + key, + ) { + Some(skeleton) => skeleton.clause_clause_locs = clause_locs, + None => {} + } + } + RetractionRecord::RemovedSkeleton(compilation_target, key, skeleton) => { + match compilation_target { + CompilationTarget::User => { + self.wam.indices.extensible_predicates.insert(key, skeleton); + } + CompilationTarget::Module(module_name) => { + if let Some(module) = self.wam.indices.modules.get_mut(&module_name) { + module.extensible_predicates.insert(key, skeleton); + } + } + } + } + RetractionRecord::ReplacedDynamicElseOffset(instr_loc, next) => { + match &mut self.wam.code_repo.code[instr_loc] { + Line::Choice(ChoiceInstruction::DynamicElse( + _, _, NextOrFail::Next(ref mut o), + )) | + Line::Choice(ChoiceInstruction::DynamicInternalElse( + _, _, NextOrFail::Next(ref mut o), + )) => { + *o = next; + } + _ => {} + } + } + RetractionRecord::AppendedNextOrFail(instr_loc, fail) => { + match &mut self.wam.code_repo.code[instr_loc] { + Line::Choice(ChoiceInstruction::DynamicElse( + _, _, ref mut next_or_fail, + )) | + Line::Choice(ChoiceInstruction::DynamicInternalElse( + _, _, ref mut next_or_fail, + )) => { + *next_or_fail = fail; + } + _ => {} + } + } + } + } + + // TODO: necessary? unnecessary? + // self.wam.code_repo.code.truncate(self.retraction_info.orig_code_extent); + } +} + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub(crate) enum CompilationTarget { + Module(ClauseName), + User, +} + +impl Default for CompilationTarget { + #[inline] + fn default() -> Self { + CompilationTarget::User + } +} + +impl CompilationTarget { + #[inline] + pub(super) fn take(&mut self) -> CompilationTarget { + mem::replace(self, CompilationTarget::User) + } + + #[inline] + pub(crate) fn module_name(&self) -> ClauseName { + match self { + CompilationTarget::User => { + clause_name!("user") + } + CompilationTarget::Module(ref module_name) => module_name.clone(), + } + } +} + +pub(crate) struct PredicateQueue { + pub(super) predicates: Vec, + pub(super) compilation_target: CompilationTarget, +} + +impl PredicateQueue { + #[inline] + pub(super) fn push(&mut self, clause: Term) { + self.predicates.push(clause); + } + + #[inline] + pub(crate) fn first(&self) -> Option<&Term> { + self.predicates.first() + } + + #[inline] + pub(crate) fn is_empty(&self) -> bool { + self.predicates.is_empty() + } + + #[inline] + pub(super) fn take(&mut self) -> Self { + Self { + predicates: mem::replace(&mut self.predicates, vec![]), + compilation_target: self.compilation_target.take(), + } + } + + #[inline] + pub(super) fn len(&self) -> usize { + self.predicates.len() + } +} + +macro_rules! predicate_queue { + [$($v:expr),*] => ( + PredicateQueue { + predicates: vec![$($v,)*], + compilation_target: CompilationTarget::default(), + } + ) +} + +pub(crate) struct Loader<'a, TermStream> { + pub(super) load_state: LoadState<'a>, + pub(super) predicates: PredicateQueue, + pub(super) clause_clauses: Vec<(Term, Term)>, + term_stream: TermStream, + pub(super) non_counted_bt_preds: IndexSet, +} + +impl<'a, TS: TermStream> Loader<'a, TS> { + #[inline] + pub(super) fn new(term_stream: TS, wam: &'a mut Machine) -> Self { + let load_state = LoadState { + compilation_target: CompilationTarget::User, + module_op_exports: vec![], + retraction_info: RetractionInfo::new(wam.code_repo.code.len()), + wam, + }; + + Self { + load_state, + term_stream, + non_counted_bt_preds: IndexSet::new(), + predicates: predicate_queue![], + clause_clauses: vec![], + } + } + + pub(crate) fn load(mut self) -> Result { + while let Some(decl) = self.dequeue_terms()? { + self.load_decl(decl)?; + } + + TS::evacuate(self) + } + + fn dequeue_terms(&mut self) -> Result, SessionError> { + while !self.term_stream.eof()? { + let term = self.term_stream.next(&self.load_state.composite_op_dir())?; + + // if is_consistent is false, self.predicates is not empty. + if !term.is_consistent(&self.predicates) { + self.compile_and_submit()?; + } + + let term = match term { + Term::Clause(_, name, terms, _) if name.as_str() == ":-" && terms.len() == 1 => { + return Ok(Some(setup_declaration(&self.load_state, terms)?)); + } + term => term, + }; + + self.predicates.push(term); + } + + Ok(None) + } + + pub(super) fn load_decl(&mut self, decl: Declaration) -> Result<(), SessionError> { + match decl { + Declaration::Dynamic(name, arity) => { + let compilation_target = self.load_state.compilation_target.clone(); + self.add_dynamic_predicate(compilation_target, name, arity)?; + } + Declaration::MetaPredicate(module_name, name, meta_specs) => { + self.load_state + .add_meta_predicate_record(module_name, name, meta_specs); + } + Declaration::Module(module_decl) => { + self.load_state.compilation_target = + CompilationTarget::Module(module_decl.name.clone()); + + self.predicates.compilation_target = self.load_state.compilation_target.clone(); + + self.load_state + .add_module(module_decl, self.term_stream.listing_src().clone()); + } + Declaration::NonCountedBacktracking(name, arity) => { + self.non_counted_bt_preds.insert((name, arity)); + } + Declaration::Op(op_decl) => { + self.load_state.add_op_decl(&op_decl); + } + Declaration::UseModule(module_src) => { + self.load_state.use_module(module_src)?; + } + Declaration::UseQualifiedModule(module_src, exports) => { + self.load_state.use_qualified_module(module_src, exports)?; + } + } + + Ok(()) + } + + pub(super) fn read_term_from_heap(&self, heap_term_loc: RegType) -> Result { + let machine_st = &self.load_state.wam.machine_st; + let term_addr = machine_st[heap_term_loc]; + + if machine_st.is_cyclic_term(term_addr) { + return Err(SessionError::from(CompilationError::CannotParseCyclicTerm)); + } + + let mut term_stack = vec![]; + + for addr in machine_st.post_order_iter(term_addr) { + match machine_st.heap.index_addr(&addr).as_ref() { + HeapCellValue::Addr(Addr::Lis(_)) | HeapCellValue::Addr(Addr::PStrLocation(..)) => { + let tail = term_stack.pop().unwrap(); + let head = term_stack.pop().unwrap(); + + term_stack.push(Term::Cons(Cell::default(), Box::new(head), Box::new(tail))); + } + HeapCellValue::Addr(addr) => { + if let Some(r) = addr.as_var() { + let offset_string = match r { + Ref::HeapCell(h) | Ref::AttrVar(h) => format!("_{}", h), + Ref::StackCell(fr, sc) => format!("_s_{}_{}", fr, sc), + }; + + term_stack.push(Term::Var(Cell::default(), Rc::new(offset_string))); + } else { + match addr.as_constant_index(machine_st) { + Some(constant) => { + term_stack.push(Term::Constant(Cell::default(), constant)); + } + None => { + return Err(SessionError::from(CompilationError::UnreadableTerm)); + } + } + } + } + HeapCellValue::Atom(ref name, ref shared_op_desc) => { + term_stack.push(Term::Constant( + Cell::default(), + Constant::Atom(name.clone(), shared_op_desc.clone()), + )); + } + HeapCellValue::Integer(ref integer) => { + term_stack.push(Term::Constant( + Cell::default(), + Constant::Integer(integer.clone()), + )); + } + HeapCellValue::NamedStr(arity, ref name, ref shared_op_desc) => { + let subterms = term_stack + .drain(term_stack.len() - arity..) + .map(Box::new) + .collect(); + + term_stack.push(Term::Clause( + Cell::default(), + name.clone(), + subterms, + shared_op_desc.clone(), + )); + } + HeapCellValue::PartialString(..) => { + let string = machine_st.heap_pstr_iter(addr).to_string(); + term_stack.push(Term::Constant( + Cell::default(), + Constant::String(Rc::new(string)), + )); + } + HeapCellValue::Rational(ref rational) => { + term_stack.push(Term::Constant( + Cell::default(), + Constant::Rational(rational.clone()), + )); + } + _ => { + return Err(SessionError::from(CompilationError::UnreadableTerm)); + } + } + } + + debug_assert!(term_stack.len() == 1); + Ok(term_stack.pop().unwrap()) + } + + fn extract_module_export_list_from_heap( + &self, + r: RegType, + ) -> Result, SessionError> { + let export_list = self.read_term_from_heap(r)?; + let atom_tbl = self.load_state.wam.machine_st.atom_tbl.clone(); + let export_list = setup_module_export_list(export_list, atom_tbl)?; + + Ok(export_list.into_iter().collect()) + } + + fn add_clause_clause(&mut self, term: Term) -> Result<(), CompilationError> { + match term { + Term::Clause(_, turnstile, mut terms, _) + if turnstile.as_str() == ":-" && terms.len() == 2 => + { + let body = *terms.pop().unwrap(); + let head = *terms.pop().unwrap(); + + self.clause_clauses.push((head, body)); + } + head @ Term::Constant(_, Constant::Atom(..)) | head @ Term::Clause(..) => { + let body = + Term::Constant(Cell::default(), Constant::Atom(clause_name!("true"), None)); + + self.clause_clauses.push((head, body)); + } + _ => { + return Err(CompilationError::InadmissibleFact); + } + } + + Ok(()) + } + + fn add_extensible_predicate_declaration( + &mut self, + compilation_target: CompilationTarget, + name: ClauseName, + arity: usize, + flag_accessor: impl Fn(&mut PredicateSkeleton) -> &mut bool, + retraction_fn: impl Fn(CompilationTarget, PredicateKey) -> RetractionRecord, + ) -> Result<(), SessionError> { + let key = (name, arity); + let mut throw_permission_error = false; + + match &compilation_target { + CompilationTarget::User => { + match self + .load_state + .wam + .indices + .extensible_predicates + .get_mut(&key) + { + Some(ref mut skeleton) => { + if !*flag_accessor(skeleton) { + *flag_accessor(skeleton) = true; + + self.load_state.retraction_info.push_record(retraction_fn( + compilation_target.clone(), + key.clone(), + )); + } + } + None => { + if self.load_state.compilation_target == compilation_target { + let mut skeleton = PredicateSkeleton::new(); + *flag_accessor(&mut skeleton) = true; + + self.load_state.add_extensible_predicate( + key.clone(), + skeleton, + CompilationTarget::User, + ); + } else { + throw_permission_error = true; + } + } + } + } + CompilationTarget::Module(ref module_name) => { + match self.load_state.wam.indices.modules.get_mut(module_name) { + Some(ref mut module) => match module.extensible_predicates.get_mut(&key) { + Some(ref mut skeleton) => { + if !*flag_accessor(skeleton) { + *flag_accessor(skeleton) = true; + + self.load_state.retraction_info.push_record(retraction_fn( + compilation_target.clone(), + key.clone(), + )); + } + } + None => { + if self.load_state.compilation_target == compilation_target { + let mut skeleton = PredicateSkeleton::new(); + *flag_accessor(&mut skeleton) = true; + + self.load_state.add_extensible_predicate( + key.clone(), + skeleton, + compilation_target.clone(), + ); + } else { + throw_permission_error = true; + } + } + }, + None => { + self.load_state + .add_dynamically_generated_module(module_name); + + let mut skeleton = PredicateSkeleton::new(); + *flag_accessor(&mut skeleton) = true; + + self.load_state.add_extensible_predicate( + key.clone(), + skeleton, + compilation_target.clone(), + ); + } + } + } + } + + if !throw_permission_error { + match self.load_state.compilation_target.clone() { + CompilationTarget::User => { + match self + .load_state + .wam + .indices + .local_extensible_predicates + .get_mut(&(compilation_target.clone(), key.clone())) + { + Some(ref mut skeleton) => { + if !*flag_accessor(skeleton) { + *flag_accessor(skeleton) = true; + } + } + None => { + let mut skeleton = PredicateSkeleton::new(); + *flag_accessor(&mut skeleton) = true; + + self.load_state.add_local_extensible_predicate( + compilation_target.clone(), + key.clone(), + skeleton, + ); + } + } + } + CompilationTarget::Module(ref module_name) => { + match self.load_state.wam.indices.modules.get_mut(module_name) { + Some(ref mut module) => match module + .local_extensible_predicates + .get_mut(&(compilation_target.clone(), key.clone())) + { + Some(ref mut skeleton) => { + if !*flag_accessor(skeleton) { + *flag_accessor(skeleton) = true; + } + } + None => { + let mut skeleton = PredicateSkeleton::new(); + *flag_accessor(&mut skeleton) = true; + + self.load_state.add_local_extensible_predicate( + compilation_target.clone(), + key.clone(), + skeleton, + ); + } + }, + None => { + self.load_state + .add_dynamically_generated_module(module_name); + + let mut skeleton = PredicateSkeleton::new(); + *flag_accessor(&mut skeleton) = true; + + self.load_state.add_local_extensible_predicate( + compilation_target.clone(), + key.clone(), + skeleton, + ); + } + } + } + } + + Ok(()) + } else { + Err(SessionError::PredicateNotMultifileOrDiscontiguous( + compilation_target, + key, + )) + } + } + + fn add_discontiguous_predicate( + &mut self, + compilation_target: CompilationTarget, + name: ClauseName, + arity: usize, + ) -> Result<(), SessionError> { + self.add_extensible_predicate_declaration( + compilation_target, + name, + arity, + |skeleton| &mut skeleton.is_discontiguous, + RetractionRecord::AddedDiscontiguousPredicate, + ) + } + + fn add_dynamic_predicate( + &mut self, + compilation_target: CompilationTarget, + name: ClauseName, + arity: usize, + ) -> Result<(), SessionError> { + self.add_extensible_predicate_declaration( + compilation_target.clone(), + name.clone(), + arity, + |skeleton| &mut skeleton.is_dynamic, + RetractionRecord::AddedDynamicPredicate, + )?; + + let code_index = self + .load_state + .get_or_insert_code_index((name.clone(), arity), compilation_target.clone()); + + if let IndexPtr::Undefined = code_index.get() { + set_code_index( + &mut self.load_state.retraction_info, + &compilation_target, + (name, arity), + &code_index, + IndexPtr::DynamicUndefined, + ); + } + + Ok(()) + } + + fn add_multifile_predicate( + &mut self, + compilation_target: CompilationTarget, + name: ClauseName, + arity: usize, + ) -> Result<(), SessionError> { + self.add_extensible_predicate_declaration( + compilation_target, + name, + arity, + |skeleton| &mut skeleton.is_multifile, + RetractionRecord::AddedMultifilePredicate, + ) + } + + fn add_clause_clause_if_dynamic(&mut self, term: &Term) -> Result<(), SessionError> { + if let Some(predicate_name) = ClauseInfo::name(term) { + let arity = ClauseInfo::arity(term); + + let is_dynamic = self + .load_state + .wam + .indices + .get_predicate_skeleton( + &self.predicates.compilation_target, + &(predicate_name, arity), + ) + .map(|skeleton| skeleton.is_dynamic) + .unwrap_or(false); + + if is_dynamic { + self.add_clause_clause(term.clone())?; + } + } + + Ok(()) + } + + pub(super) fn retract_local_clauses(&mut self, key: &PredicateKey, is_dynamic: bool) { + let clause_locs = match self + .load_state + .wam + .indices + .get_local_predicate_skeleton_mut( + &self.load_state.compilation_target, + self.predicates.compilation_target.clone(), + key.clone(), + ) { + Some(skeleton) if !skeleton.clause_clause_locs.is_empty() => { + mem::replace(&mut skeleton.clause_clause_locs, sdeq![]) + } + _ => return, + }; + + self.load_state.retraction_info.push_record( + RetractionRecord::RemovedLocalSkeletonClauseLocations( + self.load_state.compilation_target.clone(), + self.predicates.compilation_target.clone(), + key.clone(), + clause_locs.clone(), + ), + ); + + self.load_state.retract_local_clauses( + self.predicates.compilation_target.clone(), + key.clone(), + &clause_locs, + ); + + if is_dynamic { + let clause_clause_compilation_target = match &self.predicates.compilation_target { + CompilationTarget::User => CompilationTarget::Module(clause_name!("builtins")), + module_name => module_name.clone(), + }; + + self.load_state + .retract_local_clause_clauses(clause_clause_compilation_target, &clause_locs); + } + } +} + +impl Machine { + pub(crate) fn use_module(&mut self) { + let subevacuable_addr = self + .machine_st + .store(self.machine_st.deref(self.machine_st[temp_v!(2)])); + + let module_src = ModuleSource::Library(match subevacuable_addr { + Addr::LoadStatePayload(payload) => match &self.machine_st.heap[payload] { + HeapCellValue::LoadStatePayload(payload) => match &payload.compilation_target { + CompilationTarget::Module(ref module_name) => module_name.clone(), + CompilationTarget::User => { + return; + } + }, + _ => { + unreachable!() + } + }, + _ => { + unreachable!() + } + }); + + let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(1)); + + let use_module = || { + let export_list = loader.extract_module_export_list_from_heap(temp_v!(3))?; + + if export_list.is_empty() { + loader.load_state.use_module(module_src)?; + } else { + loader + .load_state + .use_qualified_module(module_src, export_list)?; + } + + LiveTermStream::evacuate(loader) + }; + + let result = use_module(); + self.restore_load_state_payload(result, evacuable_h); + } + + pub(crate) fn load_compiled_library(&mut self) { + let library = atom_from!( + self.machine_st, + self.machine_st + .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + ); + + if let Some(module) = self.indices.modules.get(&library) { + if let ListingSource::DynamicallyGenerated = module.listing_src { + self.machine_st.fail = true; + return; + } + + let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3)); + + let import_module = || { + let export_list = loader.extract_module_export_list_from_heap(temp_v!(2))?; + + if export_list.is_empty() { + loader.load_state.import_module(library)?; + } else { + loader + .load_state + .import_qualified_module(library, export_list)?; + } + + LiveTermStream::evacuate(loader) + }; + + let result = import_module(); + self.restore_load_state_payload(result, evacuable_h); + } else { + self.machine_st.fail = true; + } + } + + pub(crate) fn declare_module(&mut self) { + let module_name = atom_from!( + self.machine_st, + self.machine_st + .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + ); + + // let export_list = self.machine_st.extract_module_export_list(temp_v!(2)); + let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3)); + + let declare_module = || { + // let export_list = export_list?; + let exports = loader.extract_module_export_list_from_heap(temp_v!(2))?; + + let module_decl = ModuleDecl { + name: module_name, + exports: exports.into_iter().collect(), + }; + + loader.load_decl(Declaration::Module(module_decl))?; + LiveTermStream::evacuate(loader) + }; + + let result = declare_module(); + self.restore_load_state_payload(result, evacuable_h); + } + + #[inline] + pub(crate) fn add_discontiguous_predicate(&mut self) { + self.add_extensible_predicate_declaration( + |loader, compilation_target, clause_name, arity| { + loader.add_discontiguous_predicate(compilation_target, clause_name, arity) + }, + ); + } + + #[inline] + pub(crate) fn add_dynamic_predicate(&mut self) { + self.add_extensible_predicate_declaration( + |loader, compilation_target, clause_name, arity| { + loader.add_dynamic_predicate(compilation_target, clause_name, arity) + }, + ); + } + + #[inline] + pub(crate) fn add_multifile_predicate(&mut self) { + self.add_extensible_predicate_declaration( + |loader, compilation_target, clause_name, arity| { + loader.add_multifile_predicate(compilation_target, clause_name, arity) + }, + ); + } + + fn add_extensible_predicate_declaration( + &mut self, + decl_adder: impl Fn( + &mut Loader, + CompilationTarget, + ClauseName, + usize, + ) -> Result<(), SessionError>, + ) { + let module_name = atom_from!( + self.machine_st, + self.machine_st + .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + ); + + let compilation_target = match module_name.as_str() { + "user" => CompilationTarget::User, + _ => CompilationTarget::Module(module_name), + }; + + let predicate_name = atom_from!( + self.machine_st, + self.machine_st + .store(self.machine_st.deref(self.machine_st[temp_v!(2)])) + ); + + let arity = self + .machine_st + .store(self.machine_st.deref(self.machine_st[temp_v!(3)])); + + let arity = match Number::try_from((arity, &self.machine_st.heap)) { + Ok(Number::Integer(n)) if &*n >= &0 && &*n <= &MAX_ARITY => Ok(n.to_usize().unwrap()), + Ok(Number::Fixnum(n)) if n >= 0 && n <= MAX_ARITY as isize => { + Ok(usize::try_from(n).unwrap()) + } + _ => Err(SessionError::from(CompilationError::InvalidRuleHead)), + }; + + let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(4)); + + let add_predicate_decl = || { + decl_adder(&mut loader, compilation_target, predicate_name, arity?)?; + LiveTermStream::evacuate(loader) + }; + + let result = add_predicate_decl(); + self.restore_load_state_payload(result, evacuable_h); + } + + pub(crate) fn add_term_expansion_clause(&mut self) { + let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(2)); + + let add_clause = || { + let term = loader.read_term_from_heap(temp_v!(1))?; + + loader.load_state.incremental_compile_clause( + (clause_name!("term_expansion"), 2), + term, + CompilationTarget::User, + false, + AppendOrPrepend::Append, + )?; + + LiveTermStream::evacuate(loader) + }; + + let result = add_clause(); + self.restore_load_state_payload(result, evacuable_h); + } + + pub(crate) fn add_goal_expansion_clause(&mut self) { + let target_module_name = atom_from!( + self.machine_st, + self.machine_st + .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + ); + + let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3)); + + let compilation_target = match target_module_name.as_str() { + "user" => CompilationTarget::User, + _ => CompilationTarget::Module(target_module_name), + }; + + let add_clause = || { + let term = loader.read_term_from_heap(temp_v!(2))?; + + loader.load_state.incremental_compile_clause( + (clause_name!("goal_expansion"), 2), + term, + compilation_target, + false, // backtracking inferences are counted by call_with_inference_limit. + AppendOrPrepend::Append, + )?; + + LiveTermStream::evacuate(loader) + }; + + let result = add_clause(); + self.restore_load_state_payload(result, evacuable_h); + } + + pub(crate) fn loader_from_heap_evacuable( + &mut self, + r: RegType, + ) -> (Loader, usize) { + let (load_state_payload, evacuable_h) = match self + .machine_st + .store(self.machine_st.deref(self.machine_st[r])) + { + Addr::LoadStatePayload(h) => ( + mem::replace( + &mut self.machine_st.heap[h], + HeapCellValue::Addr(Addr::EmptyList), + ), + h, + ), + _ => { + unreachable!() + } + }; + + match load_state_payload { + HeapCellValue::LoadStatePayload(payload) => { + (Loader::from_load_state_payload(self, payload), evacuable_h) + } + _ => { + unreachable!() + } + } + } + + #[inline] + pub(crate) fn push_load_state_payload(&mut self) { + let payload = Box::new(LoadStatePayload::new(self)); + let addr = Addr::LoadStatePayload( + self.machine_st + .heap + .push(HeapCellValue::LoadStatePayload(payload)), + ); + + self.machine_st + .bind(self.machine_st[temp_v!(1)].as_var().unwrap(), addr); + } + + #[inline] + pub(crate) fn pop_load_state_payload(&mut self) { + let load_state_payload = match self + .machine_st + .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + { + Addr::LoadStatePayload(h) => mem::replace( + &mut self.machine_st.heap[h], + HeapCellValue::Addr(Addr::EmptyList), + ), + _ => { + unreachable!() + } + }; + + match load_state_payload { + HeapCellValue::LoadStatePayload(payload) => { + Loader::from_load_state_payload(self, payload); + } + _ => { + // unlike in loader_from_heap_evacuable, + // pop_load_state_payload is allowed to fail to find a + // LoadStatePayload in the heap, as a Rust-side + // top-level command may have failed to write the + // load state payload back to the heap. + } + } + } + + #[inline] + pub(crate) fn pop_load_context(&mut self) { + self.load_contexts.pop(); + } + + pub(crate) fn push_load_context(&mut self) { + let stream = try_or_fail!( + self.machine_st, + self.machine_st.get_stream_or_alias( + self.machine_st[temp_v!(1)], + &self.indices, + "$push_load_context", + 2, + ) + ); + + let path = atom_from!( + self.machine_st, + self.machine_st + .store(self.machine_st.deref(self.machine_st[temp_v!(2)])) + ); + + self.load_contexts + .push(LoadContext::new(path.as_str(), stream)); + } + + pub(crate) fn restore_load_state_payload( + &mut self, + result: Result, + evacuable_h: usize, + ) { + match result { + Ok(payload) => { + self.machine_st.heap[evacuable_h] = + HeapCellValue::LoadStatePayload(Box::new(payload)); + } + Err(e) => { + self.throw_session_error(e, (clause_name!("load"), 1)); + } + } + } + + pub(crate) fn scoped_clause_to_evacuable(&mut self) { + let module_name = atom_from!( + self.machine_st, + self.machine_st + .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + ); + + let (loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3)); + + let compilation_target = match module_name.as_str() { + "user" => CompilationTarget::User, + _ => CompilationTarget::Module(module_name), + }; + + let result = loader.read_and_enqueue_term(temp_v!(2), compilation_target); + self.restore_load_state_payload(result, evacuable_h); + } + + pub(crate) fn clause_to_evacuable(&mut self) { + let (loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(2)); + let compilation_target = loader.load_state.compilation_target.clone(); + + let result = loader.read_and_enqueue_term(temp_v!(1), compilation_target); + self.restore_load_state_payload(result, evacuable_h); + } + + pub(crate) fn conclude_load(&mut self) { + let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(1)); + + let compile_final_terms = || { + if !loader.predicates.is_empty() { + loader.compile_and_submit()?; + } + + loader.load_state.remove_module_op_exports(); + LiveTermStream::evacuate(loader) + }; + + let result = compile_final_terms(); + self.restore_load_state_payload(result, evacuable_h); + } + + pub(crate) fn load_context_source(&mut self) { + if let Some(load_context) = self.load_contexts.last() { + let path_str = load_context.path.to_str().unwrap(); + let path_atom = clause_name!(path_str.to_string(), self.machine_st.atom_tbl); + + let path_addr = Addr::Con( + self.machine_st + .heap + .push(HeapCellValue::Atom(path_atom, None)), + ); + + self.machine_st.unify(path_addr, self.machine_st[temp_v!(1)]); + } else { + self.machine_st.fail = true; + } + } + + pub(crate) fn load_context_file(&mut self) { + if let Some(load_context) = self.load_contexts.last() { + match load_context.path.file_name() { + Some(file_name) if load_context.path.is_file() => { + let file_name_str = file_name.to_str().unwrap(); + let file_name_atom = + clause_name!(file_name_str.to_string(), self.machine_st.atom_tbl); + + let file_name_addr = Addr::Con( + self.machine_st + .heap + .push(HeapCellValue::Atom(file_name_atom, None)), + ); + + self.machine_st.unify(file_name_addr, self.machine_st[temp_v!(1)]); + return; + } + _ => { + return self.load_context_module(); + } + } + } + + self.machine_st.fail = true; + } + + pub(crate) fn load_context_directory(&mut self) { + if let Some(load_context) = self.load_contexts.last() { + if let Some(directory) = load_context.path.parent() { + let directory_str = directory.to_str().unwrap(); + + let directory_atom = + clause_name!(directory_str.to_string(), self.machine_st.atom_tbl); + + let directory_addr = Addr::Con( + self.machine_st + .heap + .push(HeapCellValue::Atom(directory_atom, None)), + ); + + self.machine_st.unify(directory_addr, self.machine_st[temp_v!(1)]); + return; + } + } + + self.machine_st.fail = true; + } + + pub(crate) fn load_context_module(&mut self) { + if let Some(load_context) = self.load_contexts.last() { + let module_name_addr = Addr::Con( + self.machine_st + .heap + .push(HeapCellValue::Atom(load_context.module.clone(), None)), + ); + + self.machine_st.unify(module_name_addr, self.machine_st[temp_v!(1)]); + } else { + self.machine_st.fail = true; + } + } + + pub(crate) fn load_context_stream(&mut self) { + if let Some(load_context) = self.load_contexts.last() { + let stream_addr = Addr::Stream( + self.machine_st + .heap + .push(HeapCellValue::Stream(load_context.stream.clone())), + ); + + self.machine_st.unify(stream_addr, self.machine_st[temp_v!(1)]); + } else { + self.machine_st.fail = true; + } + } + + pub(crate) fn compile_assert(&mut self, append_or_prepend: AppendOrPrepend) { + let key = self + .machine_st + .read_predicate_key(self.machine_st[temp_v!(3)], self.machine_st[temp_v!(4)]); + + let module_name = atom_from!( + self.machine_st, + self.machine_st + .store(self.machine_st.deref(self.machine_st[temp_v!(5)])) + ); + + let compilation_target = match module_name.as_str() { + "user" => CompilationTarget::User, + _ => CompilationTarget::Module(module_name), + }; + + let compile_assert = || { + let mut loader = Loader::new(LiveTermStream::new(ListingSource::User), self); + + loader.load_state.compilation_target = compilation_target.clone(); + + let head = loader.read_term_from_heap(temp_v!(1))?; + let body = loader.read_term_from_heap(temp_v!(2))?; + + let asserted_clause = Term::Clause( + Cell::default(), + clause_name!(":-"), + vec![Box::new(head.clone()), Box::new(body.clone())], + fetch_op_spec(clause_name!(":-"), 2, &loader.load_state.wam.indices.op_dir), + ); + + // if a new predicate was just created, make it dynamic. + loader.add_dynamic_predicate( + compilation_target.clone(), + key.0.clone(), + key.1, + )?; + + loader.load_state.incremental_compile_clause( + key.clone(), + asserted_clause, + compilation_target.clone(), + false, + append_or_prepend, + )?; + + // the global clock is incremented after each assertion. + loader.load_state.wam.machine_st.global_clock += 1; + + loader.compile_clause_clauses( + key, + compilation_target, + std::iter::once((head, body)), + append_or_prepend, + )?; + + LiveTermStream::evacuate(loader) + }; + + match compile_assert() { + Ok(_) => {} + Err(e) => { + let error_pi = match append_or_prepend { + AppendOrPrepend::Append => (clause_name!("assertz"), 1), + AppendOrPrepend::Prepend => (clause_name!("asserta"), 1), + }; + + self.throw_session_error(e, error_pi); + } + } + } + + pub(crate) fn abolish_clause(&mut self) { + let module_name = atom_from!( + self.machine_st, + self.machine_st + .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + ); + + let key = self + .machine_st + .read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]); + + let compilation_target = match module_name.as_str() { + "user" => CompilationTarget::User, + _ => CompilationTarget::Module(module_name), + }; + + let abolish_clause = || { + let mut loader = Loader::new(LiveTermStream::new(ListingSource::User), self); + loader.load_state.compilation_target = compilation_target; + + let clause_clause_compilation_target = match &loader.load_state.compilation_target { + CompilationTarget::User => CompilationTarget::Module(clause_name!("builtins")), + module => module.clone(), + }; + + let mut clause_clause_target_poses: Vec<_> = loader + .load_state + .wam + .indices + .get_predicate_skeleton(&loader.load_state.compilation_target, &key) + .map(|skeleton| { + loader + .load_state + .wam + .indices + .get_predicate_skeleton( + &clause_clause_compilation_target, + &(clause_name!("$clause"), 2), + ) + .map(|clause_clause_skeleton| { + skeleton + .clause_clause_locs + .iter() + .map(|clause_clause_loc| { + clause_clause_skeleton + .target_pos_of_clause_clause_loc(*clause_clause_loc) + .unwrap() + }) + .collect() + }) + .unwrap() + }) + .unwrap(); + + loader + .load_state + .wam + .indices + .get_predicate_skeleton_mut(&loader.load_state.compilation_target, &key) + .map(|skeleton| skeleton.reset()); + + let code_index = loader + .load_state + .get_or_insert_code_index(key, loader.load_state.compilation_target.clone()); + + code_index.set(IndexPtr::DynamicUndefined); + + loader.load_state.compilation_target = clause_clause_compilation_target; + + while let Some(target_pos) = clause_clause_target_poses.pop() { + loader + .load_state + .retract_clause((clause_name!("$clause"), 2), target_pos); + } + + LiveTermStream::evacuate(loader) + }; + + match abolish_clause() { + Ok(_) => {} + Err(e) => { + self.throw_session_error(e, (clause_name!("abolish"), 1)); + } + } + } + + pub(crate) fn retract_clause(&mut self) { + let key = self + .machine_st + .read_predicate_key(self.machine_st[temp_v!(1)], self.machine_st[temp_v!(2)]); + + let target_pos = self + .machine_st + .store(self.machine_st.deref(self.machine_st[temp_v!(3)])); + + let target_pos = match Number::try_from((target_pos, &self.machine_st.heap)) { + Ok(Number::Integer(n)) => n.to_usize().unwrap(), + Ok(Number::Fixnum(n)) => usize::try_from(n).unwrap(), + _ => unreachable!(), + }; + + let module_name = atom_from!( + self.machine_st, + self.machine_st + .store(self.machine_st.deref(self.machine_st[temp_v!(4)])) + ); + + let compilation_target = match module_name.as_str() { + "user" => CompilationTarget::User, + _ => CompilationTarget::Module(module_name), + }; + + let clause_clause_compilation_target = match &compilation_target { + CompilationTarget::User => CompilationTarget::Module(clause_name!("builtins")), + _ => compilation_target.clone(), + }; + + let retract_clause = || { + let mut loader = Loader::new(LiveTermStream::new(ListingSource::User), self); + loader.load_state.compilation_target = compilation_target; + + let clause_clause_loc = loader.load_state.retract_dynamic_clause(key, target_pos); + + // the global clock is incremented after each retraction. + loader.load_state.wam.machine_st.global_clock += 1; + + let target_pos = match loader.load_state.wam.indices.get_predicate_skeleton( + &clause_clause_compilation_target, + &(clause_name!("$clause"), 2), + ) { + Some(skeleton) => skeleton + .target_pos_of_clause_clause_loc(clause_clause_loc) + .unwrap(), + None => { + unreachable!(); + } + }; + + loader.load_state.compilation_target = clause_clause_compilation_target; + loader + .load_state + .retract_clause((clause_name!("$clause"), 2), target_pos); + + LiveTermStream::evacuate(loader) + }; + + match retract_clause() { + Ok(_) => {} + Err(e) => { + self.throw_session_error(e, (clause_name!("retract"), 1)); + } + } + } + + pub(crate) fn is_consistent_with_term_queue(&mut self) { + let module_name = atom_from!( + self.machine_st, + self.machine_st + .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + ); + + let key = self + .machine_st + .read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]); + + let compilation_target = match module_name.as_str() { + "user" => CompilationTarget::User, + _ => CompilationTarget::Module(module_name), + }; + + let (loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(4)); + + loader.load_state.wam.machine_st.fail = (!loader.predicates.is_empty() + && loader.predicates.compilation_target != compilation_target) + || !key.is_consistent(&loader.predicates); + + let result = LiveTermStream::evacuate(loader); + self.restore_load_state_payload(result, evacuable_h); + } + + pub(crate) fn flush_term_queue(&mut self) { + let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(1)); + + let flush_term_queue = || { + if !loader.predicates.is_empty() { + loader.compile_and_submit()?; + } + + LiveTermStream::evacuate(loader) + }; + + let result = flush_term_queue(); + self.restore_load_state_payload(result, evacuable_h); + } + + pub(crate) fn remove_module_exports(&mut self) { + let module_name = atom_from!( + self.machine_st, + self.machine_st + .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + ); + + let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(2)); + + let remove_module_exports = || { + loader.load_state.remove_module_exports(module_name); + LiveTermStream::evacuate(loader) + }; + + let result = remove_module_exports(); + self.restore_load_state_payload(result, evacuable_h); + } + + pub(crate) fn add_non_counted_backtracking(&mut self) { + let key = self + .machine_st + .read_predicate_key(self.machine_st[temp_v!(1)], self.machine_st[temp_v!(2)]); + + let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3)); + loader.non_counted_bt_preds.insert(key); + + let result = LiveTermStream::evacuate(loader); + self.restore_load_state_payload(result, evacuable_h); + } + + pub(crate) fn meta_predicate_property(&mut self) { + let module_name = atom_from!( + self.machine_st, + self.machine_st + .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + ); + + let (predicate_name, arity) = self + .machine_st + .read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]); + + let compilation_target = match module_name.as_str() { + "user" => CompilationTarget::User, + _ => CompilationTarget::Module(module_name), + }; + + match self + .indices + .get_meta_predicate_spec(predicate_name, arity, &compilation_target) + { + Some(meta_specs) => { + let list_loc = self + .machine_st + .heap + .to_list(meta_specs.iter().map(|meta_spec| match meta_spec { + MetaSpec::Minus => HeapCellValue::Atom(clause_name!("+"), None), + MetaSpec::Plus => HeapCellValue::Atom(clause_name!("-"), None), + MetaSpec::Either => HeapCellValue::Atom(clause_name!("?"), None), + MetaSpec::RequiresExpansionWithArgument(ref arg_num) => { + HeapCellValue::Addr(Addr::Usize(*arg_num)) + } + })); + + let heap_loc = self.machine_st.heap.push(HeapCellValue::NamedStr( + 1, + clause_name!("meta_predicate"), + None, + )); + + self.machine_st + .heap + .push(HeapCellValue::Addr(Addr::HeapCell(list_loc))); + + self.machine_st.unify(Addr::HeapCell(heap_loc), self.machine_st[temp_v!(4)]); + } + None => { + self.machine_st.fail = true; + } + } + } + + pub(crate) fn dynamic_property(&mut self) { + let module_name = atom_from!( + self.machine_st, + self.machine_st + .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + ); + + let key = self + .machine_st + .read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]); + + let compilation_target = match module_name.as_str() { + "user" => CompilationTarget::User, + _ => CompilationTarget::Module(module_name), + }; + + match self + .indices + .get_predicate_skeleton(&compilation_target, &key) + { + Some(skeleton) => { + self.machine_st.fail = !skeleton.is_dynamic; + } + None => { + self.machine_st.fail = true; + } + } + } + + pub(crate) fn multifile_property(&mut self) { + let module_name = atom_from!( + self.machine_st, + self.machine_st + .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + ); + + let key = self + .machine_st + .read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]); + + let compilation_target = match module_name.as_str() { + "user" => CompilationTarget::User, + _ => CompilationTarget::Module(module_name), + }; + + match self + .indices + .get_predicate_skeleton(&compilation_target, &key) + { + Some(skeleton) => { + self.machine_st.fail = !skeleton.is_multifile; + } + None => { + self.machine_st.fail = true; + } + } + } + + pub(crate) fn discontiguous_property(&mut self) { + let module_name = atom_from!( + self.machine_st, + self.machine_st + .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + ); + + let key = self + .machine_st + .read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]); + + let compilation_target = match module_name.as_str() { + "user" => CompilationTarget::User, + _ => CompilationTarget::Module(module_name), + }; + + match self + .indices + .get_predicate_skeleton(&compilation_target, &key) + { + Some(skeleton) => { + self.machine_st.fail = !skeleton.is_discontiguous; + } + None => { + self.machine_st.fail = true; + } + } + } + + pub(crate) fn builtin_property(&mut self) { + let key = self + .machine_st + .read_predicate_key(self.machine_st[temp_v!(1)], self.machine_st[temp_v!(2)]); + + match ClauseType::from(key.0, key.1, None) { + ClauseType::BuiltIn(_) | ClauseType::Inlined(..) | ClauseType::CallN => { + return; + } + ClauseType::Named(ref name, arity, _) => { + if let Some(module) = self.indices.modules.get(&(clause_name!("builtins"))) { + self.machine_st.fail = !module.code_dir.contains_key(&(name.clone(), arity)); + + return; + } + } + ClauseType::Op(ref name, ref op_desc, _) => { + if let Some(module) = self.indices.modules.get(&(clause_name!("builtins"))) { + self.machine_st.fail = !module + .code_dir + .contains_key(&(name.clone(), op_desc.arity())); + + return; + } + } + _ => {} + } + + self.machine_st.fail = true; + } +} + +impl<'a> Loader<'a, LiveTermStream> { + pub(super) fn to_load_state_payload(mut self) -> LoadStatePayload { + LoadStatePayload { + term_stream: mem::replace( + &mut self.term_stream, + LiveTermStream::new(ListingSource::User), + ), + non_counted_bt_preds: mem::replace(&mut self.non_counted_bt_preds, IndexSet::new()), + compilation_target: self.load_state.compilation_target.take(), + retraction_info: mem::replace( + &mut self.load_state.retraction_info, + RetractionInfo::new(self.load_state.wam.code_repo.code.len()), + ), + predicates: self.predicates.take(), + clause_clauses: mem::replace(&mut self.clause_clauses, vec![]), + module_op_exports: mem::replace(&mut self.load_state.module_op_exports, vec![]), + } + } + + pub(super) fn from_load_state_payload( + wam: &'a mut Machine, + mut payload: Box, + ) -> Self { + Loader { + term_stream: mem::replace( + &mut payload.term_stream, + LiveTermStream::new(ListingSource::User), + ), + non_counted_bt_preds: mem::replace(&mut payload.non_counted_bt_preds, IndexSet::new()), + clause_clauses: mem::replace(&mut payload.clause_clauses, vec![]), + predicates: payload.predicates.take(), + load_state: LoadState { + compilation_target: payload.compilation_target.take(), + module_op_exports: mem::replace(&mut payload.module_op_exports, vec![]), + retraction_info: mem::replace(&mut payload.retraction_info, RetractionInfo::new(0)), + wam, + }, + } + } + + fn read_and_enqueue_term( + mut self, + term_reg: RegType, + compilation_target: CompilationTarget, + ) -> Result { + if self.predicates.compilation_target != compilation_target { + if !self.predicates.is_empty() { + self.compile_and_submit()?; + } + + self.predicates.compilation_target = compilation_target; + } + + let term = self.read_term_from_heap(term_reg)?; + + self.add_clause_clause_if_dynamic(&term)?; + self.term_stream.term_queue.push_back(term); + + self.load() + } +} + +#[inline] +pub(super) fn load_module( + code_dir: &mut CodeDir, + op_dir: &mut OpDir, + meta_predicate_dir: &mut MetaPredicateDir, + compilation_target: &CompilationTarget, + module: &Module, +) { + import_module_exports( + &mut RetractionInfo::new(0), + &compilation_target, + module, + code_dir, + op_dir, + meta_predicate_dir, + ) + .unwrap(); +} diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index 1dcc1db8..fbfb1bcf 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -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(h: usize, valid_type: ValidType, culprit: T) -> Self { + pub(super) fn type_error(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( + pub(super) fn permission_error( 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(error: DomainErrorType, culprit: T) -> Self { + pub(super) fn domain_error(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>(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 for CompilationError { + #[inline] + fn from(err: ArithmeticError) -> CompilationError { + CompilationError::Arithmetic(err) + } +} + +impl From 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( + pub(crate) fn type_error( &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 for EvalSession { + #[inline] fn from(err: SessionError) -> Self { EvalSession::Error(err) } } +impl From for SessionError { + #[inline] + fn from(err: std::io::Error) -> SessionError { + SessionError::from(ParserError::from(err)) + } +} + impl From for SessionError { + #[inline] fn from(err: ParserError) -> Self { - SessionError::ParserError(err) + SessionError::CompilationError(CompilationError::from(err)) + } +} + +impl From for SessionError { + #[inline] + fn from(err: CompilationError) -> Self { + SessionError::CompilationError(err) } } impl From for EvalSession { + #[inline] fn from(err: ParserError) -> Self { - EvalSession::from(SessionError::ParserError(err)) + EvalSession::from(SessionError::from(err)) } } diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs index 13fb6ae7..ab2f332d 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -1,39 +1,40 @@ -use crate::prolog_parser::ast::*; -use crate::prolog_parser::tabled_rc::*; +use prolog_parser::ast::*; +use prolog_parser::clause_name; use crate::clause_types::*; use crate::fixtures::*; use crate::forms::*; +use crate::instructions::*; use crate::machine::code_repo::CodeRepo; -use crate::machine::Ball; use crate::machine::heap::*; use crate::machine::machine_state::*; use crate::machine::partial_string::*; use crate::machine::raw_block::RawBlockTraits; use crate::machine::streams::Stream; -use crate::instructions::*; -use crate::ordered_float::OrderedFloat; +use crate::machine::term_stream::LoadStatePayload; +use crate::machine::CompilationTarget; use crate::rug::{Integer, Rational}; +use ordered_float::OrderedFloat; -use crate::indexmap::IndexMap; +use indexmap::IndexMap; -use std::cell::RefCell; +use std::cell::Cell; use std::cmp::Ordering; -use std::collections::{BTreeMap, BTreeSet, VecDeque}; +use std::collections::{BTreeMap, BTreeSet}; use std::convert::TryFrom; use std::fmt; -use std::mem; +// use std::mem; use std::net::TcpListener; -use std::ops::{Add, AddAssign, Sub, SubAssign}; +use std::ops::{Add, AddAssign, Deref, Sub, SubAssign}; use std::rc::Rc; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct OrderedOpDirKey(pub ClauseName, pub Fixity); +pub(crate) struct OrderedOpDirKey(pub(crate) ClauseName, pub(crate) Fixity); -pub type OssifiedOpDir = BTreeMap; +pub(crate) type OssifiedOpDir = BTreeMap; #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum DBRef { +pub(crate) enum DBRef { NamedPred(ClauseName, usize, Option), Op( usize, @@ -46,7 +47,7 @@ pub enum DBRef { // 7.2 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum TermOrderCategory { +pub(crate) enum TermOrderCategory { Variable, FloatingPoint, Integer, @@ -55,7 +56,7 @@ pub enum TermOrderCategory { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum Addr { +pub(crate) enum Addr { AttrVar(usize), Char(char), Con(usize), @@ -64,6 +65,7 @@ pub enum Addr { Fixnum(isize), Float(OrderedFloat), Lis(usize), + LoadStatePayload(usize), HeapCell(usize), PStrLocation(usize, usize), // location of pstr in heap, offset into string in bytes. StackCell(usize, usize), @@ -74,14 +76,14 @@ pub enum Addr { } #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, PartialOrd)] -pub enum Ref { +pub(crate) enum Ref { AttrVar(usize), HeapCell(usize), StackCell(usize, usize), } impl Ref { - pub fn as_addr(self) -> Addr { + pub(crate) fn as_addr(self) -> Addr { match self { Ref::AttrVar(h) => Addr::AttrVar(h), Ref::HeapCell(h) => Addr::HeapCell(h), @@ -94,20 +96,14 @@ impl Ord for Ref { fn cmp(&self, other: &Ref) -> Ordering { match (self, other) { (Ref::AttrVar(h1), Ref::AttrVar(h2)) - | (Ref::HeapCell(h1), Ref::HeapCell(h2)) - | (Ref::HeapCell(h1), Ref::AttrVar(h2)) - | (Ref::AttrVar(h1), Ref::HeapCell(h2)) => { - h1.cmp(&h2) - } + | (Ref::HeapCell(h1), Ref::HeapCell(h2)) + | (Ref::HeapCell(h1), Ref::AttrVar(h2)) + | (Ref::AttrVar(h1), Ref::HeapCell(h2)) => h1.cmp(&h2), (Ref::StackCell(fr1, sc1), Ref::StackCell(fr2, sc2)) => { fr1.cmp(&fr2).then_with(|| sc1.cmp(&sc2)) } - (Ref::StackCell(..), _) => { - Ordering::Greater - } - (_, Ref::StackCell(..)) => { - Ordering::Less - } + (Ref::StackCell(..), _) => Ordering::Greater, + (_, Ref::StackCell(..)) => Ordering::Less, } } } @@ -122,68 +118,51 @@ impl PartialEq for Addr { impl PartialOrd for Addr { fn partial_cmp(&self, r: &Ref) -> Option { match self { - &Addr::StackCell(fr, sc) => { - match *r { - Ref::AttrVar(_) | Ref::HeapCell(_) => { + &Addr::StackCell(fr, sc) => match *r { + Ref::AttrVar(_) | Ref::HeapCell(_) => Some(Ordering::Greater), + Ref::StackCell(fr1, sc1) => { + if fr1 < fr || (fr1 == fr && sc1 < sc) { Some(Ordering::Greater) - } - Ref::StackCell(fr1, sc1) => { - if fr1 < fr || (fr1 == fr && sc1 < sc) { - Some(Ordering::Greater) - } else if fr1 == fr && sc1 == sc { - Some(Ordering::Equal) - } else { - Some(Ordering::Less) - } - } - } - } - &Addr::HeapCell(h) | &Addr::AttrVar(h) => { - match r { - Ref::StackCell(..) => { + } else if fr1 == fr && sc1 == sc { + Some(Ordering::Equal) + } else { Some(Ordering::Less) } - Ref::AttrVar(h1) | Ref::HeapCell(h1) => { - h.partial_cmp(h1) - } } - } - _ => { - None - } + }, + &Addr::HeapCell(h) | &Addr::AttrVar(h) => match r { + Ref::StackCell(..) => Some(Ordering::Less), + Ref::AttrVar(h1) | Ref::HeapCell(h1) => h.partial_cmp(h1), + }, + _ => None, } } } impl Addr { #[inline] - pub fn is_heap_bound(&self) -> bool { + pub(crate) fn is_heap_bound(&self) -> bool { match self { - Addr::Char(_) | Addr::EmptyList | - Addr::CutPoint(_) | Addr::Usize(_) | Addr::Fixnum(_) | - Addr::Float(_) => { - false - } - _ => { - true - } + Addr::Char(_) + | Addr::EmptyList + | Addr::CutPoint(_) + | Addr::Usize(_) + | Addr::Fixnum(_) + | Addr::Float(_) => false, + _ => true, } } #[inline] - pub fn is_ref(&self) -> bool { + pub(crate) fn is_ref(&self) -> bool { match self { - Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::AttrVar(_) => { - true - } - _ => { - false - } + Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::AttrVar(_) => true, + _ => false, } } #[inline] - pub fn as_var(&self) -> Option { + pub(crate) fn as_var(&self) -> Option { match self { &Addr::AttrVar(h) => Some(Ref::AttrVar(h)), &Addr::HeapCell(h) => Some(Ref::HeapCell(h)), @@ -192,96 +171,58 @@ impl Addr { } } - pub(super) - fn order_category(&self, heap: &Heap) -> Option { + pub(super) fn order_category(&self, heap: &Heap) -> Option { match Number::try_from((*self, heap)) { Ok(Number::Integer(_)) | Ok(Number::Fixnum(_)) | Ok(Number::Rational(_)) => { Some(TermOrderCategory::Integer) } - Ok(Number::Float(_)) => { - Some(TermOrderCategory::FloatingPoint) - } - _ => { - match self { - Addr::HeapCell(_) | Addr::AttrVar(_) | Addr::StackCell(..) => { - Some(TermOrderCategory::Variable) - } - Addr::Float(_) => { - Some(TermOrderCategory::FloatingPoint) - } - &Addr::Con(h) => { - match &heap[h] { - HeapCellValue::Atom(..) => { - Some(TermOrderCategory::Atom) - } - HeapCellValue::DBRef(_) => { - None - } - _ => { - unreachable!() - } - } - } - Addr::Char(_) | Addr::EmptyList => { - Some(TermOrderCategory::Atom) - } - Addr::Fixnum(_) | Addr::Usize(_) => { - Some(TermOrderCategory::Integer) - } - Addr::Lis(_) | Addr::PStrLocation(..) | Addr::Str(_) => { - Some(TermOrderCategory::Compound) - } - Addr::CutPoint(_) | Addr::Stream(_) | Addr::TcpListener(_) => { - None - } + Ok(Number::Float(_)) => Some(TermOrderCategory::FloatingPoint), + _ => match self { + Addr::HeapCell(_) | Addr::AttrVar(_) | Addr::StackCell(..) => { + Some(TermOrderCategory::Variable) } - } - } - } - - pub fn as_constant_index(&self, machine_st: &MachineState) -> Option { - match self { - &Addr::Char(c) => { - Some(Constant::Char(c)) - } - &Addr::Con(h) => { - match &machine_st.heap[h] { - &HeapCellValue::Atom(ref name, _) if name.is_char() => { - Some(Constant::Char(name.as_str().chars().next().unwrap())) - } - &HeapCellValue::Atom(ref name, _) => { - Some(Constant::Atom(name.clone(), None)) - } - &HeapCellValue::Integer(ref n) => { - Some(Constant::Integer(n.clone())) - } - &HeapCellValue::Rational(ref n) => { - Some(Constant::Rational(n.clone())) - } + Addr::Float(_) => Some(TermOrderCategory::FloatingPoint), + &Addr::Con(h) => match &heap[h] { + HeapCellValue::Atom(..) => Some(TermOrderCategory::Atom), + HeapCellValue::DBRef(_) => None, _ => { - None + unreachable!() } + }, + Addr::Char(_) | Addr::EmptyList => Some(TermOrderCategory::Atom), + Addr::Fixnum(_) | Addr::Usize(_) => Some(TermOrderCategory::Integer), + Addr::Lis(_) | Addr::PStrLocation(..) | Addr::Str(_) => { + Some(TermOrderCategory::Compound) } - } - &Addr::EmptyList => { - Some(Constant::EmptyList) - } - &Addr::Fixnum(n) => { - Some(Constant::Fixnum(n)) - } - &Addr::Float(f) => { - Some(Constant::Float(f)) - } - &Addr::Usize(n) => { - Some(Constant::Usize(n)) - } - _ => { - None - } + Addr::CutPoint(_) + | Addr::LoadStatePayload(_) + | Addr::Stream(_) + | Addr::TcpListener(_) => None, + }, } } - pub fn is_protected(&self, e: usize) -> bool { + pub(crate) fn as_constant_index(&self, machine_st: &MachineState) -> Option { + match self { + &Addr::Char(c) => Some(Constant::Char(c)), + &Addr::Con(h) => match &machine_st.heap[h] { + &HeapCellValue::Atom(ref name, _) if name.is_char() => { + Some(Constant::Char(name.as_str().chars().next().unwrap())) + } + &HeapCellValue::Atom(ref name, _) => Some(Constant::Atom(name.clone(), None)), + &HeapCellValue::Integer(ref n) => Some(Constant::Integer(n.clone())), + &HeapCellValue::Rational(ref n) => Some(Constant::Rational(n.clone())), + _ => None, + }, + &Addr::EmptyList => Some(Constant::EmptyList), + &Addr::Fixnum(n) => Some(Constant::Fixnum(n)), + &Addr::Float(f) => Some(Constant::Float(f)), + &Addr::Usize(n) => Some(Constant::Usize(n)), + _ => None, + } + } + + pub(crate) fn is_protected(&self, e: usize) -> bool { match self { &Addr::StackCell(addr, _) if addr >= e => false, _ => true, @@ -351,10 +292,12 @@ impl SubAssign for Addr { } #[derive(Debug, Clone, Copy)] -pub enum TrailRef { +pub(crate) enum TrailRef { Ref(Ref), AttrVarHeapLink(usize), AttrVarListLink(usize, usize), + BlackboardEntry(usize), + BlackboardOffset(usize, usize), // key atom heap location, key value heap location } impl From for TrailRef { @@ -364,11 +307,12 @@ impl From for TrailRef { } #[derive(Debug)] -pub enum HeapCellValue { +pub(crate) enum HeapCellValue { Addr(Addr), Atom(ClauseName, Option), DBRef(DBRef), Integer(Rc), + LoadStatePayload(Box), NamedStr(usize, ClauseName, Option), // arity, name, precedence/Specifier if it has one. Rational(Rc), PartialString(PartialString, bool), // the partial string, a bool indicating whether it came from a Constant. @@ -378,57 +322,39 @@ pub enum HeapCellValue { impl HeapCellValue { #[inline] - pub fn as_addr(&self, focus: usize) -> Addr { + pub(crate) fn as_addr(&self, focus: usize) -> Addr { match self { - HeapCellValue::Addr(ref a) => { - *a - } - HeapCellValue::Atom(..) | HeapCellValue::DBRef(..) | HeapCellValue::Integer(..) | - HeapCellValue::Rational(..) => { - Addr::Con(focus) - } - HeapCellValue::NamedStr(_, _, _) => { - Addr::Str(focus) - } - HeapCellValue::PartialString(..) => { - Addr::PStrLocation(focus, 0) - } - HeapCellValue::Stream(_) => { - Addr::Stream(focus) - } - HeapCellValue::TcpListener(_) => { - Addr::TcpListener(focus) - } + HeapCellValue::Addr(ref a) => *a, + HeapCellValue::Atom(..) + | HeapCellValue::DBRef(..) + | HeapCellValue::Integer(..) + | HeapCellValue::Rational(..) => Addr::Con(focus), + HeapCellValue::LoadStatePayload(_) => Addr::LoadStatePayload(focus), + HeapCellValue::NamedStr(_, _, _) => Addr::Str(focus), + HeapCellValue::PartialString(..) => Addr::PStrLocation(focus, 0), + HeapCellValue::Stream(_) => Addr::Stream(focus), + HeapCellValue::TcpListener(_) => Addr::TcpListener(focus), } } #[inline] - pub fn context_free_clone(&self) -> HeapCellValue { + pub(crate) fn context_free_clone(&self) -> HeapCellValue { match self { - &HeapCellValue::Addr(addr) => { - HeapCellValue::Addr(addr) - } - &HeapCellValue::Atom(ref name, ref op) => { - HeapCellValue::Atom(name.clone(), op.clone()) - } - &HeapCellValue::DBRef(ref db_ref) => { - HeapCellValue::DBRef(db_ref.clone()) - } - &HeapCellValue::Integer(ref n) => { - HeapCellValue::Integer(n.clone()) + &HeapCellValue::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::Atom(clause_name!("$live_term_stream"), None) } &HeapCellValue::NamedStr(arity, ref name, ref op) => { HeapCellValue::NamedStr(arity, name.clone(), op.clone()) } - &HeapCellValue::Rational(ref r) => { - HeapCellValue::Rational(r.clone()) - } + &HeapCellValue::Rational(ref r) => HeapCellValue::Rational(r.clone()), &HeapCellValue::PartialString(ref pstr, has_tail) => { HeapCellValue::PartialString(pstr.clone(), has_tail) } - &HeapCellValue::Stream(ref stream) => { - HeapCellValue::Stream(stream.clone()) - } + &HeapCellValue::Stream(ref stream) => HeapCellValue::Stream(stream.clone()), &HeapCellValue::TcpListener(_) => { HeapCellValue::Atom(clause_name!("$tcp_listener"), None) } @@ -443,51 +369,44 @@ impl From for HeapCellValue { } } -#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] -pub enum IndexPtr { +#[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub(crate) enum IndexPtr { DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined. - Undefined, - InSituDirEntry(usize), + DynamicIndex(usize), Index(usize), - UserGoalExpansion, - UserTermExpansion + Undefined, } #[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)] -pub struct CodeIndex(pub Rc>); +pub(crate) struct CodeIndex(pub(crate) Rc>); + +impl Deref for CodeIndex { + type Target = Cell; + + #[inline] + fn deref(&self) -> &Self::Target { + self.0.deref() + } +} impl CodeIndex { #[inline] - pub fn new(ptr: IndexPtr, module_name: ClauseName) -> Self { - CodeIndex(Rc::new(RefCell::new(( ptr, module_name )))) + pub(super) fn new(ptr: IndexPtr) -> Self { + CodeIndex(Rc::new(Cell::new(ptr))) } #[inline] - pub fn is_undefined(&self) -> bool { - let index_ptr = &self.0.borrow().0; - - match index_ptr { - &IndexPtr::Undefined | &IndexPtr::DynamicUndefined => true, - _ => false + pub(crate) fn is_undefined(&self) -> bool { + match self.0.get() { + IndexPtr::Undefined => true, // | &IndexPtr::DynamicUndefined => true, + _ => false, } } - #[inline] - pub fn dynamic_undefined(module_name: ClauseName) -> Self { - CodeIndex(Rc::new(RefCell::new(( - IndexPtr::DynamicUndefined, - module_name - )))) - } - - #[inline] - pub fn module_name(&self) -> ClauseName { - self.0.borrow().1.clone() - } - - pub fn local(&self) -> Option { - match self.0.borrow().0 { + pub(crate) fn local(&self) -> Option { + match self.0.get() { IndexPtr::Index(i) => Some(i), + IndexPtr::DynamicIndex(i) => Some(i), _ => None, } } @@ -495,154 +414,141 @@ impl CodeIndex { impl Default for CodeIndex { fn default() -> Self { - CodeIndex(Rc::new(RefCell::new(( - IndexPtr::Undefined, - clause_name!(""), - )))) + CodeIndex(Rc::new(Cell::new(IndexPtr::Undefined))) } } -impl From<(usize, ClauseName)> for CodeIndex { - fn from(value: (usize, ClauseName)) -> Self { - CodeIndex(Rc::new(RefCell::new((IndexPtr::Index(value.0), value.1)))) - } -} - -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum DynamicAssertPlace { - Back, - Front, -} - -impl DynamicAssertPlace { - #[inline] - pub fn predicate_name(self) -> ClauseName { - match self { - DynamicAssertPlace::Back => clause_name!("assertz"), - DynamicAssertPlace::Front => clause_name!("asserta"), - } - } - - #[inline] - pub fn push_to_queue(self, addrs: &mut VecDeque, new_addr: Addr) { - match self { - DynamicAssertPlace::Back => addrs.push_back(new_addr), - DynamicAssertPlace::Front => addrs.push_front(new_addr), - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum DynamicTransactionType { - Abolish, - Assert(DynamicAssertPlace), - ModuleAbolish, - ModuleAssert(DynamicAssertPlace), - ModuleRetract, - Retract, // dynamic index of the clause to remove. -} - #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)] -pub enum REPLCodePtr { - CompileBatch, +pub(crate) enum REPLCodePtr { + AddDiscontiguousPredicate, + AddDynamicPredicate, + AddMultifilePredicate, + AddGoalExpansionClause, + AddTermExpansionClause, + ClauseToEvacuable, + ScopedClauseToEvacuable, + ConcludeLoad, + DeclareModule, + LoadCompiledLibrary, + LoadContextSource, + LoadContextFile, + LoadContextDirectory, + LoadContextModule, + LoadContextStream, + PopLoadContext, + PopLoadStatePayload, + PushLoadContext, + PushLoadStatePayload, UseModule, - UseQualifiedModule, - UseModuleFromFile, - UseQualifiedModuleFromFile + BuiltInProperty, + MetaPredicateProperty, + MultifileProperty, + DiscontiguousProperty, + DynamicProperty, + AbolishClause, + Asserta, + Assertz, + Retract, + IsConsistentWithTermQueue, + FlushTermQueue, + RemoveModuleExports, + AddNonCountedBacktracking, } #[derive(Debug, Clone, PartialEq)] -pub enum CodePtr { +pub(crate) enum CodePtr { BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call. CallN(usize, LocalCodePtr, bool), // arity, local, last call. Local(LocalCodePtr), - DynamicTransaction(DynamicTransactionType, LocalCodePtr), // the type of transaction, the return pointer. - REPL(REPLCodePtr, LocalCodePtr), // the REPL code, the return pointer. + // DynamicTransaction(DynamicTransactionType, LocalCodePtr), // the type of transaction, the return pointer. + REPL(REPLCodePtr, LocalCodePtr), // the REPL code, the return pointer. VerifyAttrInterrupt(usize), // location of the verify attribute interrupt code in the CodeDir. } impl CodePtr { - pub fn local(&self) -> LocalCodePtr { + pub(crate) fn local(&self) -> LocalCodePtr { match self { &CodePtr::BuiltInClause(_, ref local) - | &CodePtr::CallN(_, ref local, _) - | &CodePtr::Local(ref local) => local.clone(), + | &CodePtr::CallN(_, ref local, _) + | &CodePtr::Local(ref local) => local.clone(), &CodePtr::VerifyAttrInterrupt(p) => LocalCodePtr::DirEntry(p), - &CodePtr::REPL(_, p) | &CodePtr::DynamicTransaction(_, p) => p, + &CodePtr::REPL(_, p) => p, // | &CodePtr::DynamicTransaction(_, p) => p, + } + } + + #[inline] + pub(crate) fn is_halt(&self) -> bool { + if let CodePtr::Local(LocalCodePtr::Halt) = self { + true + } else { + false } } } #[derive(Copy, Clone, Debug, PartialEq)] -pub enum LocalCodePtr { - DirEntry(usize), // offset. - InSituDirEntry(usize), - TopLevel(usize, usize), // chunk_num, offset. - UserGoalExpansion(usize), - UserTermExpansion(usize), +pub(crate) enum LocalCodePtr { + DirEntry(usize), // offset + Halt, + IndexingBuf(usize, usize, usize), // DirEntry offset, first internal offset, second internal offset + // TopLevel(usize, usize), // chunk_num, offset } impl LocalCodePtr { - pub(crate) - fn assign_if_local(&mut self, cp: CodePtr) { + pub(crate) fn assign_if_local(&mut self, cp: CodePtr) { match cp { CodePtr::Local(local) => *self = local, _ => {} } } - pub(crate) - fn is_reset_cont_marker(&self, code_repo: &CodeRepo, last_call: bool) -> bool { + #[inline] + pub(crate) fn abs_loc(&self) -> usize { + match self { + LocalCodePtr::DirEntry(ref p) => *p, + LocalCodePtr::IndexingBuf(ref p, ..) => *p, + LocalCodePtr::Halt => unreachable!(), + } + } + + pub(crate) fn is_reset_cont_marker(&self, code_repo: &CodeRepo, last_call: bool) -> bool { match code_repo.lookup_instr(last_call, &CodePtr::Local(*self)) { - Some(line) => { - match line.as_ref() { - Line::Control(ControlInstruction::CallClause(ref ct, ..)) => { - if let ClauseType::System(SystemClauseType::ResetContinuationMarker) = *ct { - return true; - } + Some(line) => match line.as_ref() { + Line::Control(ControlInstruction::CallClause(ref ct, ..)) => { + if let ClauseType::System(SystemClauseType::ResetContinuationMarker) = *ct { + return true; } - _ => {} } - } + _ => {} + }, None => {} } false } - pub(crate) - fn as_functor(&self, heap: &mut HeapTemplate) -> Addr { + pub(crate) fn as_functor(&self, heap: &mut HeapTemplate) -> Addr { let addr = Addr::HeapCell(heap.h()); match self { LocalCodePtr::DirEntry(p) => { - heap.append(functor!( - "dir_entry", - [integer(*p)] - )); + heap.append(functor!("dir_entry", [integer(*p)])); } - LocalCodePtr::InSituDirEntry(p) => { - heap.append(functor!( - "in_situ_dir_entry", - [integer(*p)] - )); + LocalCodePtr::Halt => { + heap.append(functor!("halt")); } + /* LocalCodePtr::TopLevel(chunk_num, offset) => { heap.append(functor!( "top_level", [integer(*chunk_num), integer(*offset)] )); } - LocalCodePtr::UserGoalExpansion(p) => { + */ + LocalCodePtr::IndexingBuf(p, o, i) => { heap.append(functor!( - "user_goal_expansion", - [integer(*p)] - )); - } - LocalCodePtr::UserTermExpansion(p) => { - heap.append(functor!( - "user_term_expansion", - [integer(*p)] + "indexed_buf", + [integer(*p), integer(*o), integer(*i)] )); } } @@ -651,61 +557,29 @@ impl LocalCodePtr { } } -impl PartialOrd for CodePtr { - fn partial_cmp(&self, other: &CodePtr) -> Option { - match (self, other) { - (&CodePtr::Local(ref l1), &CodePtr::Local(ref l2)) => { - l1.partial_cmp(l2) - } - _ => { - Some(Ordering::Greater) - } - } - } -} - -impl PartialOrd for LocalCodePtr { - fn partial_cmp(&self, other: &LocalCodePtr) -> Option { - match (self, other) { - (&LocalCodePtr::InSituDirEntry(p1), &LocalCodePtr::InSituDirEntry(ref p2)) - | (&LocalCodePtr::DirEntry(p1), &LocalCodePtr::DirEntry(ref p2)) - | (&LocalCodePtr::UserTermExpansion(p1), &LocalCodePtr::UserTermExpansion(ref p2)) - | (&LocalCodePtr::UserGoalExpansion(p1), &LocalCodePtr::UserGoalExpansion(ref p2)) - | (&LocalCodePtr::TopLevel(_, p1), &LocalCodePtr::TopLevel(_, ref p2)) => { - p1.partial_cmp(p2) - } - (_, &LocalCodePtr::TopLevel(_, _)) => { - Some(Ordering::Less) - } - _ => { - Some(Ordering::Greater) - } - } - } -} - impl Default for CodePtr { + #[inline] fn default() -> Self { CodePtr::Local(LocalCodePtr::default()) } } impl Default for LocalCodePtr { + #[inline] fn default() -> Self { - LocalCodePtr::TopLevel(0, 0) + LocalCodePtr::DirEntry(0) } } impl Add for LocalCodePtr { type Output = LocalCodePtr; + #[inline] fn add(self, rhs: usize) -> Self::Output { match self { - LocalCodePtr::InSituDirEntry(p) => LocalCodePtr::InSituDirEntry(p + rhs), LocalCodePtr::DirEntry(p) => LocalCodePtr::DirEntry(p + rhs), - LocalCodePtr::TopLevel(cn, p) => LocalCodePtr::TopLevel(cn, p + rhs), - LocalCodePtr::UserTermExpansion(p) => LocalCodePtr::UserTermExpansion(p + rhs), - LocalCodePtr::UserGoalExpansion(p) => LocalCodePtr::UserGoalExpansion(p + rhs), + LocalCodePtr::Halt => unreachable!(), + LocalCodePtr::IndexingBuf(p, o, i) => LocalCodePtr::IndexingBuf(p, o, i + rhs), } } } @@ -713,30 +587,36 @@ impl Add for LocalCodePtr { impl Sub for LocalCodePtr { type Output = Option; + #[inline] fn sub(self, rhs: usize) -> Self::Output { match self { - LocalCodePtr::InSituDirEntry(p) => - p.checked_sub(rhs).map(LocalCodePtr::InSituDirEntry), - LocalCodePtr::DirEntry(p) => - p.checked_sub(rhs).map(LocalCodePtr::DirEntry), - LocalCodePtr::TopLevel(cn, p) => - p.checked_sub(rhs).map(|r| LocalCodePtr::TopLevel(cn, r)), - LocalCodePtr::UserTermExpansion(p) => - p.checked_sub(rhs).map(LocalCodePtr::UserTermExpansion), - LocalCodePtr::UserGoalExpansion(p) => - p.checked_sub(rhs).map(LocalCodePtr::UserGoalExpansion), + LocalCodePtr::DirEntry(p) => p.checked_sub(rhs).map(LocalCodePtr::DirEntry), + LocalCodePtr::Halt => unreachable!(), + LocalCodePtr::IndexingBuf(p, o, i) => i + .checked_sub(rhs) + .map(|r| LocalCodePtr::IndexingBuf(p, o, r)), + } + } +} + +impl SubAssign for LocalCodePtr { + #[inline] + fn sub_assign(&mut self, rhs: usize) { + match self { + LocalCodePtr::DirEntry(ref mut p) => *p -= rhs, + LocalCodePtr::Halt | LocalCodePtr::IndexingBuf(..) => unreachable!(), } } } impl AddAssign for LocalCodePtr { + #[inline] fn add_assign(&mut self, rhs: usize) { match self { - &mut LocalCodePtr::InSituDirEntry(ref mut p) - | &mut LocalCodePtr::UserGoalExpansion(ref mut p) - | &mut LocalCodePtr::UserTermExpansion(ref mut p) - | &mut LocalCodePtr::DirEntry(ref mut p) - | &mut LocalCodePtr::TopLevel(_, ref mut p) => *p += rhs, + &mut LocalCodePtr::DirEntry(ref mut p) /* | + &mut LocalCodePtr::TopLevel(_, ref mut p) */ => *p += rhs, + &mut LocalCodePtr::IndexingBuf(_, _, ref mut i) => *i += rhs, + &mut LocalCodePtr::Halt => unreachable!(), } } } @@ -746,9 +626,11 @@ impl Add for CodePtr { fn add(self, rhs: usize) -> Self::Output { match self { - p @ CodePtr::REPL(..) - | p @ CodePtr::VerifyAttrInterrupt(_) - | p @ CodePtr::DynamicTransaction(..) => p, + p @ CodePtr::REPL(..) | p @ CodePtr::VerifyAttrInterrupt(_) => { + // | + // p @ CodePtr::DynamicTransaction(..) => { + p + } CodePtr::Local(local) => CodePtr::Local(local + rhs), CodePtr::BuiltInClause(_, local) | CodePtr::CallN(_, local, _) => { CodePtr::Local(local + rhs) @@ -767,186 +649,245 @@ impl AddAssign for CodePtr { } } -pub type HeapVarDict = IndexMap, Addr>; -pub type AllocVarDict = IndexMap, VarData>; - -#[derive(Debug, Clone)] -pub struct DynamicPredicateInfo { - pub(super) clauses_subsection_p: usize, // a LocalCodePtr::DirEntry value. -} - -impl Default for DynamicPredicateInfo { - fn default() -> Self { - DynamicPredicateInfo { - clauses_subsection_p: 0, +impl SubAssign for CodePtr { + #[inline] + fn sub_assign(&mut self, rhs: usize) { + match self { + CodePtr::Local(ref mut local) => *local -= rhs, + _ => unreachable!(), } } } -pub type InSituCodeDir = IndexMap; +pub(crate) type HeapVarDict = IndexMap, Addr>; +pub(crate) type AllocVarDict = IndexMap, VarData>; -// key type: module name, predicate indicator. -pub type DynamicCodeDir = IndexMap<(ClauseName, ClauseName, usize), DynamicPredicateInfo>; +pub(crate) type GlobalVarDir = IndexMap)>; -pub type GlobalVarDir = IndexMap)>; - -#[derive(Debug)] -pub(crate) struct ModuleStub { - pub(crate) atom_tbl: TabledData, - pub(crate) in_situ_code_dir: InSituCodeDir, -} - -impl ModuleStub { - pub(crate) fn new(atom_tbl: TabledData) -> Self { - ModuleStub { - atom_tbl, - in_situ_code_dir: InSituCodeDir::new(), - } - } -} - -pub(crate) type ModuleStubDir = IndexMap; pub(crate) type StreamAliasDir = IndexMap; pub(crate) type StreamDir = BTreeSet; +pub(crate) type MetaPredicateDir = IndexMap>; + +pub(crate) type ExtensiblePredicates = IndexMap; + +pub(crate) type LocalExtensiblePredicates = + IndexMap<(CompilationTarget, PredicateKey), PredicateSkeleton>; + #[derive(Debug)] -pub struct IndexStore { - pub(super) atom_tbl: TabledData, +pub(crate) struct IndexStore { pub(super) code_dir: CodeDir, - pub(super) dynamic_code_dir: DynamicCodeDir, + pub(super) extensible_predicates: ExtensiblePredicates, + pub(super) local_extensible_predicates: LocalExtensiblePredicates, pub(super) global_variables: GlobalVarDir, - pub(super) in_situ_code_dir: InSituCodeDir, - pub(super) in_situ_module_dir: ModuleStubDir, - pub(super) module_dir: ModuleDir, + pub(super) meta_predicates: MetaPredicateDir, pub(super) modules: ModuleDir, pub(super) op_dir: OpDir, pub(super) streams: StreamDir, pub(super) stream_aliases: StreamAliasDir, } +impl Default for IndexStore { + #[inline] + fn default() -> Self { + index_store!(CodeDir::new(), default_op_dir(), ModuleDir::new()) + } +} + impl IndexStore { - pub fn predicate_exists( - &self, - name: ClauseName, - module: ClauseName, - arity: usize, - op_spec: Option, - ) -> bool { - match self.modules.get(&module) { - Some(module) => match ClauseType::from(name, arity, op_spec) { - ClauseType::Named(name, arity, _) => module.code_dir.contains_key(&(name, arity)), - ClauseType::Op(name, spec, ..) => { - module.code_dir.contains_key(&(name, spec.arity())) + pub(crate) fn get_predicate_skeleton_mut( + &mut self, + compilation_target: &CompilationTarget, + key: &PredicateKey, + ) -> Option<&mut PredicateSkeleton> { + match (key.0.as_str(), key.1) { + ("term_expansion", 2) => self.extensible_predicates.get_mut(key), + _ => match compilation_target { + CompilationTarget::User => self.extensible_predicates.get_mut(key), + CompilationTarget::Module(ref module_name) => { + if let Some(module) = self.modules.get_mut(module_name) { + module.extensible_predicates.get_mut(key) + } else { + None + } } - _ => true, - }, - None => match ClauseType::from(name, arity, op_spec) { - ClauseType::Named(name, arity, _) => self.code_dir.contains_key(&(name, arity)), - ClauseType::Op(name, spec, ..) => self.code_dir.contains_key(&(name, spec.arity())), - _ => true, }, } } - pub fn add_term_and_goal_expansion_indices(&mut self) { - self.code_dir.insert((clause_name!("term_expansion"), 2), - CodeIndex(Rc::new(RefCell::new( - (IndexPtr::UserTermExpansion, - clause_name!("user")) - )))); - self.code_dir.insert((clause_name!("goal_expansion"), 2), - CodeIndex(Rc::new(RefCell::new( - (IndexPtr::UserGoalExpansion, - clause_name!("user")) - )))); + pub(crate) fn get_local_predicate_skeleton_mut( + &mut self, + src_compilation_target: &CompilationTarget, + local_compilation_target: CompilationTarget, + key: PredicateKey, + ) -> Option<&mut PredicateSkeleton> { + match (key.0.as_str(), key.1) { + ("term_expansion", 2) => self + .local_extensible_predicates + .get_mut(&(local_compilation_target, key)), + _ => match src_compilation_target { + CompilationTarget::User => self + .local_extensible_predicates + .get_mut(&(local_compilation_target, key)), + CompilationTarget::Module(ref module_name) => { + if let Some(module) = self.modules.get_mut(module_name) { + module + .local_extensible_predicates + .get_mut(&(local_compilation_target, key)) + } else { + None + } + } + }, + } } - #[inline] - pub fn remove_clause_subsection(&mut self, module: ClauseName, name: ClauseName, arity: usize) { - self.dynamic_code_dir.swap_remove(&(module, name, arity)); - } - - #[inline] - pub fn get_clause_subsection( + pub(crate) fn get_local_predicate_skeleton( + &self, + src_compilation_target: &CompilationTarget, + local_compilation_target: CompilationTarget, + key: PredicateKey, + ) -> Option<&PredicateSkeleton> { + match (key.0.as_str(), key.1) { + ("term_expansion", 2) => self + .local_extensible_predicates + .get(&(local_compilation_target, key)), + _ => match src_compilation_target { + CompilationTarget::User => self + .local_extensible_predicates + .get(&(local_compilation_target, key)), + CompilationTarget::Module(ref module_name) => { + if let Some(module) = self.modules.get(module_name) { + module + .local_extensible_predicates + .get(&(local_compilation_target, key)) + } else { + None + } + } + }, + } + } + + pub(crate) fn get_predicate_skeleton( + &self, + compilation_target: &CompilationTarget, + key: &PredicateKey, + ) -> Option<&PredicateSkeleton> { + match (key.0.as_str(), key.1) { + ("term_expansion", 2) => self.extensible_predicates.get(key), + _ => match compilation_target { + CompilationTarget::User => self.extensible_predicates.get(key), + CompilationTarget::Module(ref module_name) => { + if let Some(module) = self.modules.get(module_name) { + module.extensible_predicates.get(key) + } else { + None + } + } + }, + } + } + + pub(crate) fn remove_predicate_skeleton( + &mut self, + compilation_target: &CompilationTarget, + key: &PredicateKey, + ) -> Option { + match (key.0.as_str(), key.1) { + ("term_expansion", 2) => self.extensible_predicates.remove(key), + _ => match compilation_target { + CompilationTarget::User => self.extensible_predicates.remove(key), + CompilationTarget::Module(ref module_name) => { + if let Some(module) = self.modules.get_mut(module_name) { + module.extensible_predicates.remove(key) + } else { + None + } + } + }, + } + } + + pub(crate) fn get_predicate_code_index( &self, - module: ClauseName, name: ClauseName, arity: usize, - ) -> Option { - self.dynamic_code_dir.get(&(module, name, arity)).cloned() + module: ClauseName, + op_spec: Option, + ) -> Option { + if module.as_str() == "user" { + match ClauseType::from(name, arity, op_spec) { + ClauseType::Named(name, arity, _) => self.code_dir.get(&(name, arity)).cloned(), + ClauseType::Op(name, spec, ..) => self.code_dir.get(&(name, spec.arity())).cloned(), + _ => None, + } + } else { + self.modules.get(&module).and_then(|module| { + match ClauseType::from(name, arity, op_spec) { + ClauseType::Named(name, arity, _) => { + module.code_dir.get(&(name, arity)).cloned() + } + ClauseType::Op(name, spec, ..) => { + module.code_dir.get(&(name, spec.arity())).cloned() + } + _ => None, + } + }) + } } - #[inline] - pub(crate) fn take_in_situ_module_dir(&mut self) -> ModuleStubDir { - mem::replace(&mut self.in_situ_module_dir, ModuleStubDir::new()) + pub(crate) fn get_meta_predicate_spec( + &self, + name: ClauseName, + arity: usize, + compilation_target: &CompilationTarget, + ) -> Option<&Vec> { + match compilation_target { + CompilationTarget::User => self.meta_predicates.get(&(name, arity)), + CompilationTarget::Module(ref module_name) => match self.modules.get(module_name) { + Some(ref module) => module + .meta_predicates + .get(&(name.clone(), arity)) + .or_else(|| self.meta_predicates.get(&(name, arity))), + None => self.meta_predicates.get(&(name, arity)), + }, + } } - #[inline] - pub fn take_in_situ_code_dir(&mut self) -> InSituCodeDir { - mem::replace(&mut self.in_situ_code_dir, InSituCodeDir::new()) - } - - #[inline] - pub fn take_module(&mut self, name: ClauseName) -> Option { - self.modules.swap_remove(&name) - } - - #[inline] - pub fn insert_module(&mut self, module: Module) { - self.modules.insert(module.module_decl.name.clone(), module); + pub(crate) fn is_dynamic_predicate(&self, module_name: ClauseName, key: PredicateKey) -> bool { + match module_name.as_str() { + "user" => self + .extensible_predicates + .get(&key) + .map(|skeleton| skeleton.is_dynamic) + .unwrap_or(false), + _ => match self.modules.get(&module_name) { + Some(ref module) => module + .extensible_predicates + .get(&key) + .map(|skeleton| skeleton.is_dynamic) + .unwrap_or(false), + None => false, + }, + } } #[inline] pub(super) fn new() -> Self { - IndexStore { - atom_tbl: TabledData::new(Rc::new("user".to_string())), - code_dir: CodeDir::new(), - module_dir: ModuleDir::new(), - dynamic_code_dir: DynamicCodeDir::new(), - global_variables: GlobalVarDir::new(), - in_situ_code_dir: InSituCodeDir::new(), - in_situ_module_dir: ModuleStubDir::new(), - op_dir: default_op_dir(), - modules: ModuleDir::new(), - stream_aliases: StreamAliasDir::new(), - streams: StreamDir::new(), - } - } - - #[inline] - pub(super) fn copy_and_swap(&mut self, other: &mut IndexStore) { - self.code_dir = other.code_dir.clone(); - self.op_dir = other.op_dir.clone(); - - mem::swap(&mut self.code_dir, &mut other.code_dir); - mem::swap(&mut self.op_dir, &mut other.op_dir); - mem::swap(&mut self.modules, &mut other.modules); - } - - #[inline] - fn get_internal( - &self, - name: ClauseName, - arity: usize, - in_mod: ClauseName, - ) -> Option { - self.modules - .get(&in_mod) - .and_then(|ref module| module.code_dir.get(&(name, arity))) - .cloned() + IndexStore::default() } pub(super) fn get_cleaner_sites(&self) -> (usize, usize) { let r_w_h = clause_name!("run_cleaners_with_handling"); let r_wo_h = clause_name!("run_cleaners_without_handling"); - let iso_ext = clause_name!("iso_ext"); let r_w_h = self - .get_internal(r_w_h, 0, iso_ext.clone()) + .get_predicate_code_index(r_w_h, 0, iso_ext.clone(), None) .and_then(|item| item.local()); let r_wo_h = self - .get_internal(r_wo_h, 1, iso_ext) + .get_predicate_code_index(r_wo_h, 1, iso_ext, None) .and_then(|item| item.local()); if let Some(r_w_h) = r_w_h { @@ -959,132 +900,9 @@ impl IndexStore { } } -pub type CodeDir = BTreeMap; -pub type TermDir = IndexMap)>; +pub(crate) type CodeDir = BTreeMap; -#[derive(Debug)] -pub struct TermDirQuantumEntry { - pub old_terms: (Predicate, VecDeque), - pub new_terms: (Predicate, VecDeque), - pub is_fresh: bool, -} - -impl TermDirQuantumEntry { - #[inline] - pub fn new() -> Self { - TermDirQuantumEntry { - old_terms: (Predicate::new(), VecDeque::new()), - new_terms: (Predicate::new(), VecDeque::new()), - is_fresh: false, - } - } - - pub fn from(preds: &Predicate, queue: &VecDeque) -> Self - { - let mut entry = TermDirQuantumEntry::new(); - entry.is_fresh = false; - - (entry.old_terms.0).0.extend(preds.0.iter().cloned()); - entry.old_terms.1.extend(queue.iter().cloned()); - - entry - } -} - -#[derive(Debug)] -pub struct TermDirQuantum(IndexMap); - -impl TermDirQuantum { - #[inline] - pub fn new() -> Self { - TermDirQuantum(IndexMap::new()) - } - - #[inline] - pub fn insert_or_refresh(&mut self, key: PredicateKey, mut entry: TermDirQuantumEntry) { - if let Some(prev_entry) = self.get_mut(&key) { - prev_entry.is_fresh = true; - } else { - entry.is_fresh = true; - self.0.insert(key, entry); - } - } - - #[inline] - pub fn insert(&mut self, key: PredicateKey, entry: TermDirQuantumEntry) { - self.0.insert(key, entry); - } - - #[inline] - pub fn get_mut(&mut self, key: &PredicateKey) -> Option<&mut TermDirQuantumEntry> { - self.0.get_mut(key) - } - - pub fn consolidate(self) -> TermDir { - let mut term_dir = TermDir::new(); - - for (key, entry) in self.0 { - let (preds, queue) = - term_dir.entry(key).or_insert((Predicate::new(), VecDeque::new())); - - preds.0.extend((entry.new_terms.0).0.into_iter()); - queue.extend(entry.new_terms.1.into_iter()); - } - - term_dir - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)] -pub enum CompileTimeHook { - GoalExpansion, - TermExpansion, - UserGoalExpansion, - UserTermExpansion, -} - -impl CompileTimeHook { - pub fn name(self) -> ClauseName { - match self { - CompileTimeHook::UserGoalExpansion | CompileTimeHook::GoalExpansion => { - clause_name!("goal_expansion") - } - CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => { - clause_name!("term_expansion") - } - } - } - - #[inline] - pub fn arity(self) -> usize { - match self { - CompileTimeHook::UserGoalExpansion | CompileTimeHook::GoalExpansion => 2, - CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => 2, - } - } - - #[inline] - pub fn user_scope(self) -> Self { - match self { - CompileTimeHook::UserGoalExpansion | CompileTimeHook::GoalExpansion => { - CompileTimeHook::UserGoalExpansion - } - CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => { - CompileTimeHook::UserTermExpansion - } - } - } - - #[inline] - pub fn has_module_scope(self) -> bool { - match self { - CompileTimeHook::UserTermExpansion | CompileTimeHook::UserGoalExpansion => false, - _ => true, - } - } -} - -pub enum RefOrOwned<'a, T: 'a> { +pub(crate) enum RefOrOwned<'a, T: 'a> { Borrowed(&'a T), Owned(T), } @@ -1092,22 +910,21 @@ pub enum RefOrOwned<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for RefOrOwned<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - &RefOrOwned::Borrowed(ref borrowed) => - write!(f, "Borrowed({:?})", borrowed), + &RefOrOwned::Borrowed(ref borrowed) => write!(f, "Borrowed({:?})", borrowed), &RefOrOwned::Owned(ref owned) => write!(f, "Owned({:?})", owned), } } } impl<'a, T> RefOrOwned<'a, T> { - pub fn as_ref(&'a self) -> &'a T { + pub(crate) fn as_ref(&'a self) -> &'a T { match self { &RefOrOwned::Borrowed(r) => r, &RefOrOwned::Owned(ref r) => r, } } - pub fn to_owned(self) -> T + pub(crate) fn to_owned(self) -> T where T: Clone, { diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index e8799566..ee48340a 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -1,5 +1,6 @@ -use crate::prolog_parser::ast::*; -use crate::prolog_parser::tabled_rc::*; +use prolog_parser::ast::*; +use prolog_parser::tabled_rc::*; +use prolog_parser::{clause_name, temp_v}; use crate::clause_types::*; use crate::forms::*; @@ -9,14 +10,16 @@ use crate::machine::copier::*; use crate::machine::heap::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; -use crate::machine::modules::*; +use crate::machine::partial_string::HeapPStrIter; use crate::machine::stack::*; use crate::machine::streams::*; use crate::rug::Integer; -use crate::downcast::Any; +use downcast::{ + downcast, downcast_methods, downcast_methods_core, downcast_methods_std, impl_downcast, Any, +}; -use crate::indexmap::{IndexMap, IndexSet}; +use indexmap::IndexMap; use std::cmp::Ordering; use std::convert::TryFrom; @@ -24,338 +27,35 @@ use std::fmt; use std::io::Write; use std::mem; use std::ops::{Index, IndexMut}; +use std::rc::Rc; #[derive(Debug)] -pub(crate) struct HeapPStrIter<'a> { - focus: Addr, - machine_st: &'a MachineState, - seen: IndexSet, -} - -impl<'a> HeapPStrIter<'a> { - #[inline] - 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 { - 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 { - 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 { - 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) -} - -#[derive(Debug)] -pub struct Ball { +pub(crate) struct Ball { pub(super) boundary: usize, pub(super) stub: Heap, } impl Ball { - pub(super) - fn new() -> Self { + pub(super) fn new() -> Self { Ball { boundary: 0, stub: Heap::new(), } } - pub(super) - fn reset(&mut self) { + pub(super) fn reset(&mut self) { self.boundary = 0; self.stub.clear(); } - pub(super) - fn take(&mut self) -> Ball { - let boundary = self.boundary; - self.boundary = 0; - - Ball { - boundary, - stub: self.stub.take(), - } - } - - pub(super) - fn copy_and_align(&self, h: usize) -> Heap { + pub(super) fn copy_and_align(&self, h: usize) -> Heap { let diff = self.boundary as i64 - h as i64; let mut stub = Heap::new(); for heap_value in self.stub.iter_from(0) { stub.push(match heap_value { - &HeapCellValue::Addr(addr) => { - HeapCellValue::Addr(addr - diff) - } - heap_value => { - heap_value.context_free_clone() - } + &HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr - diff), + heap_value => heap_value.context_free_clone(), }); } @@ -420,11 +120,7 @@ pub(super) struct CopyBallTerm<'a> { } impl<'a> CopyBallTerm<'a> { - pub(super) fn new( - stack: &'a mut Stack, - heap: &'a mut Heap, - stub: &'a mut Heap, - ) -> Self { + pub(super) fn new(stack: &'a mut Stack, heap: &'a mut Heap, stub: &'a mut Heap) -> Self { let hb = heap.h(); CopyBallTerm { @@ -479,12 +175,8 @@ impl<'a> CopierTarget for CopyBallTerm<'a> { let index = h - self.heap_boundary; self.stub[index].as_addr(h) } - Addr::StackCell(fr, sc) => { - self.stack.index_and_frame(fr)[sc] - } - addr => { - addr - } + Addr::StackCell(fr, sc) => self.stack.index_and_frame(fr)[sc], + addr => addr, } } @@ -523,9 +215,7 @@ impl Index for MachineState { impl IndexMut for MachineState { fn index_mut(&mut self, reg: RegType) -> &mut Self::Output { match reg { - RegType::Temp(temp) => { - &mut self.registers[temp] - } + RegType::Temp(temp) => &mut self.registers[temp], RegType::Perm(perm) => { let e = self.e; @@ -535,7 +225,7 @@ impl IndexMut for MachineState { } } -pub type Registers = Vec; +pub(crate) type Registers = Vec; #[derive(Debug, Clone, Copy)] pub(super) enum MachineMode { @@ -552,15 +242,12 @@ pub(super) enum HeapPtr { impl HeapPtr { #[inline] - pub(super) - fn read(&self, heap: &Heap) -> Addr { + pub(super) fn read(&self, heap: &Heap) -> Addr { match self { - &HeapPtr::HeapCell(h) => { - Addr::HeapCell(h) - } + &HeapPtr::HeapCell(h) => Addr::HeapCell(h), &HeapPtr::PStrChar(h, n) => { if let &HeapCellValue::PartialString(ref pstr, has_tail) = &heap[h] { - if let Some(c) = pstr.range_from(n ..).next() { + if let Some(c) = pstr.range_from(n..).next() { Addr::Char(c) } else if has_tail { Addr::HeapCell(h + 1) @@ -571,9 +258,7 @@ impl HeapPtr { unreachable!() } } - &HeapPtr::PStrLocation(h, n) => { - Addr::PStrLocation(h, n) - } + &HeapPtr::PStrLocation(h, n) => Addr::PStrLocation(h, n), } } } @@ -585,7 +270,14 @@ impl Default for HeapPtr { } #[derive(Debug)] -pub struct MachineState { +pub enum FirstOrNext { + First, + Next, +} + +// #[derive(Debug)] +pub(crate) struct MachineState { + pub(crate) atom_tbl: TabledData, pub(super) s: HeapPtr, pub(super) p: CodePtr, pub(super) b: usize, @@ -607,18 +299,89 @@ pub struct MachineState { pub(super) lifted_heap: Heap, pub(super) interms: Vec, // intermediate numbers. pub(super) last_call: bool, - pub(crate) heap_locs: HeapVarDict, pub(crate) flags: MachineFlags, - pub(crate) at_end_of_expansion: bool + pub(crate) cc: usize, + pub(crate) global_clock: usize, + pub(crate) dynamic_mode: FirstOrNext, + pub(crate) unify_fn: fn(&mut MachineState, Addr, Addr), + pub(crate) bind_fn: fn(&mut MachineState, Ref, Addr), +} + +impl fmt::Debug for MachineState { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("MachineState") + .field("atom_tbl", &self.atom_tbl) + .field("s", &self.s) + .field("p", &self.p) + .field("b", &self.b) + .field("b0", &self.b0) + .field("e", &self.e) + .field("num_of_args", &self.num_of_args) + .field("cp", &self.cp) + .field("attr_var_init", &self.attr_var_init) + .field("fail", &self.fail) + .field("heap", &self.heap) + .field("mode", &self.mode) + .field("stack", &self.stack) + .field("registers", &self.registers) + .field("trail", &self.trail) + .field("tr", &self.tr) + .field("hb", &self.hb) + .field("block", &self.block) + .field("ball", &self.ball) + .field("lifted_heap", &self.lifted_heap) + .field("interms", &self.interms) + .field("last_call", &self.last_call) + .field("flags", &self.flags) + .field("cc", &self.cc) + .field("global_clock", &self.global_clock) + .field("dynamic_mode", &self.dynamic_mode) + .field("unify_fn", + if self.unify_fn as usize == MachineState::unify as usize { + &"MachineState::unify" + } else if self.unify_fn as usize == MachineState::unify_with_occurs_check as usize { + &"MachineState::unify_with_occurs_check" + } else { + &"MachineState::unify_with_occurs_check_with_error" + }) + .field("bind_fn", + if self.bind_fn as usize == MachineState::bind as usize { + &"MachineState::bind" + } else if self.bind_fn as usize == MachineState::bind_with_occurs_check_wrapper as usize { + &"MachineState::bind_with_occurs_check" + } else { + &"MachineState::bind_with_occurs_check_with_error_wrapper" + }) + .finish() + } } impl MachineState { - pub(crate) - fn read_term( - &mut self, - mut stream: Stream, - indices: &mut IndexStore, - ) -> CallResult { + pub(crate) fn read_term(&mut self, mut stream: Stream, indices: &mut IndexStore) -> CallResult { + fn push_var_eq_functors<'a>( + heap: &mut Heap, + iter: impl Iterator, &'a Addr)>, + op_dir: &OpDir, + atom_tbl: TabledData, + ) -> Vec { + let mut list_of_var_eqs = vec![]; + + for (var, binding) in iter { + let var_atom = clause_name!(var.to_string(), atom_tbl); + + let h = heap.h(); + let spec = fetch_atom_op_spec(clause_name!("="), None, op_dir); + + heap.push(HeapCellValue::NamedStr(2, clause_name!("="), spec)); + heap.push(HeapCellValue::Atom(var_atom, None)); + heap.push(HeapCellValue::Addr(*binding)); + + list_of_var_eqs.push(Addr::Str(h)); + } + + list_of_var_eqs + } + self.check_stream_properties( &mut stream, StreamType::Text, @@ -628,7 +391,7 @@ impl MachineState { )?; if stream.past_end_of_stream() { - if EOFAction::Reset != stream.options.eof_action { + if EOFAction::Reset != stream.options().eof_action { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -638,74 +401,63 @@ impl MachineState { let mut orig_stream = stream.clone(); loop { - match self.read( - stream.clone(), - indices.atom_tbl.clone(), - &indices.op_dir, - ) { + match self.read(stream.clone(), self.atom_tbl.clone(), &indices.op_dir) { Ok(term_write_result) => { let term = self[temp_v!(2)]; - self.unify(Addr::HeapCell(term_write_result.heap_loc), term); + (self.unify_fn)(self, Addr::HeapCell(term_write_result.heap_loc), term); if self.fail { return Ok(()); } - let mut list_of_var_eqs = vec![]; - - for (var, binding) in term_write_result.var_dict.into_iter() { - let var_atom = clause_name!(var.to_string(), indices.atom_tbl); - - let h = self.heap.h(); - let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir); - - self.heap.push(HeapCellValue::NamedStr(2, clause_name!("="), spec)); - self.heap.push(HeapCellValue::Atom(var_atom, None)); - self.heap.push(HeapCellValue::Addr(binding)); - - list_of_var_eqs.push(Addr::Str(h)); - } - - let mut var_set: IndexMap = IndexMap::new(); - - for addr in self.acyclic_pre_order_iter(term) { - if let Some(var) = addr.as_var() { - if !var_set.contains_key(&var) { - var_set.insert(var, true); - } else { - var_set.insert(var, false); - } - } - } + let list_of_var_eqs = push_var_eq_functors( + &mut self.heap, + term_write_result.var_dict.iter(), + &indices.op_dir, + self.atom_tbl.clone(), + ); + let mut singleton_var_set: IndexMap = IndexMap::new(); let mut var_list = vec![]; - let mut singleton_var_list = vec![]; for addr in self.acyclic_pre_order_iter(term) { if let Some(var) = addr.as_var() { - if var_set.get(&var) == Some(&true) { - singleton_var_list.push(var.as_addr()); + if !singleton_var_set.contains_key(&var) { + singleton_var_set.insert(var, true); + var_list.push(addr); + } else { + singleton_var_set.insert(var, false); } - - var_list.push(var.as_addr()); } } + let singleton_var_list = push_var_eq_functors( + &mut self.heap, + term_write_result.var_dict.iter().filter(|(_, binding)| { + if let Some(r) = binding.as_var() { + *singleton_var_set.get(&r).unwrap_or(&false) + } else { + false + } + }), + &indices.op_dir, + self.atom_tbl.clone(), + ); + let singleton_addr = self[temp_v!(3)]; let singletons_offset = Addr::HeapCell(self.heap.to_list(singleton_var_list.into_iter())); - self.unify(singletons_offset, singleton_addr); + (self.unify_fn)(self, singletons_offset, singleton_addr); if self.fail { return Ok(()); } let vars_addr = self[temp_v!(4)]; - let vars_offset = - Addr::HeapCell(self.heap.to_list(var_list.into_iter())); + let vars_offset = Addr::HeapCell(self.heap.to_list(var_list.into_iter())); - self.unify(vars_offset, vars_addr); + (self.unify_fn)(self, vars_offset, vars_addr); if self.fail { return Ok(()); @@ -715,7 +467,7 @@ impl MachineState { let var_names_offset = Addr::HeapCell(self.heap.to_list(list_of_var_eqs.into_iter())); - return Ok(self.unify(var_names_offset, var_names_addr)); + return Ok((self.unify_fn)(self, var_names_offset, var_names_addr)); } Err(err) => { if let ParserError::UnexpectedEOF = err { @@ -723,10 +475,10 @@ impl MachineState { self[temp_v!(2)], &mut orig_stream, clause_name!("read_term"), - 3 + 3, )?; - if orig_stream.options.eof_action == EOFAction::Reset { + if orig_stream.options().eof_action == EOFAction::Reset { if self.fail == false { continue; } @@ -744,12 +496,10 @@ impl MachineState { } } - pub(crate) - fn write_term<'a>( + pub(crate) fn write_term<'a>( &'a self, op_dir: &'a OpDir, - ) -> Result>, MachineStub> - { + ) -> Result>, MachineStub> { let ignore_ops = self.store(self.deref(self[temp_v!(3)])); let numbervars = self.store(self.deref(self[temp_v!(4)])); let quoted = self.store(self.deref(self[temp_v!(5)])); @@ -758,7 +508,7 @@ impl MachineState { let mut printer = HCPrinter::new(&self, op_dir, PrinterOutputter::new()); if let &Addr::Con(h) = &ignore_ops { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { printer.ignore_ops = name.as_str() == "true"; } else { unreachable!() @@ -766,7 +516,7 @@ impl MachineState { } if let &Addr::Con(h) = &numbervars { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { printer.numbervars = name.as_str() == "true"; } else { unreachable!() @@ -774,7 +524,7 @@ impl MachineState { } if let &Addr::Con(h) = "ed { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { printer.quoted = name.as_str() == "true"; } else { unreachable!() @@ -810,9 +560,7 @@ impl MachineState { for addr in addrs { match addr { Addr::Str(s) => match &self.heap[s] { - &HeapCellValue::NamedStr(2, ref name, _) - if name.as_str() == "=" => - { + &HeapCellValue::NamedStr(2, ref name, _) if name.as_str() == "=" => { let atom = self.heap[s + 1].as_addr(s + 1); let var = self.heap[s + 2].as_addr(s + 2); @@ -836,11 +584,9 @@ impl MachineState { var_names.insert(var, atom); } - _ => { - } + _ => {} }, - _ => { - } + _ => {} } } @@ -854,14 +600,20 @@ impl MachineState { Ok(Some(printer)) } + pub(super) fn throw_undefined_error(&mut self, name: ClauseName, arity: usize) -> MachineStub { + let stub = MachineError::functor_stub(name.clone(), arity); + let h = self.heap.h(); + let key = ExistenceError::Procedure(name, arity); + + self.error_form(MachineError::existence_error(h, key), stub) + } + #[inline] - pub(crate) - fn heap_pstr_iter<'a>(&'a self, focus: Addr) -> HeapPStrIter<'a> { + pub(crate) fn heap_pstr_iter<'a>(&'a self, focus: Addr) -> HeapPStrIter<'a> { HeapPStrIter::new(self, focus) } - pub(super) - fn try_char_list(&self, addrs: Vec) -> Result { + pub(super) fn try_char_list(&self, addrs: Vec) -> Result { let mut chars = String::new(); let mut iter = addrs.iter(); @@ -881,91 +633,77 @@ impl MachineState { } } } - _ => { - } + _ => {} }; let h = self.heap.h(); - return Err( - MachineError::type_error(h, ValidType::Character, addr) - ); + return Err(MachineError::type_error(h, ValidType::Character, addr)); } Ok(chars) } - pub(super) - fn call_at_index(&mut self, arity: usize, p: LocalCodePtr) { + pub(super) fn read_predicate_key(&self, name: Addr, arity: Addr) -> (ClauseName, usize) { + let predicate_name = atom_from!(self, self.store(self.deref(name))); + let arity = self.store(self.deref(arity)); + + let arity = match Number::try_from((arity, &self.heap)) { + Ok(Number::Integer(n)) if &*n >= &0 && &*n <= &MAX_ARITY => n.to_usize().unwrap(), + Ok(Number::Fixnum(n)) if n >= 0 && n <= MAX_ARITY as isize => { + usize::try_from(n).unwrap() + } + _ => unreachable!(), + }; + + (predicate_name, arity) + } + + pub(super) fn call_at_index(&mut self, arity: usize, p: LocalCodePtr) { self.cp.assign_if_local(self.p.clone() + 1); self.num_of_args = arity; self.b0 = self.b; self.p = CodePtr::Local(p); } - pub(super) - fn execute_at_index(&mut self, arity: usize, p: LocalCodePtr) { + pub(super) fn execute_at_index(&mut self, arity: usize, p: LocalCodePtr) { self.num_of_args = arity; self.b0 = self.b; self.p = CodePtr::Local(p); } - pub(super) - fn module_lookup( + pub(super) fn module_lookup( &mut self, indices: &IndexStore, + call_policy: &mut Box, key: PredicateKey, module_name: ClauseName, - last_call: bool, + _last_call: bool, + current_input_stream: &mut Stream, + current_output_stream: &mut Stream, ) -> CallResult { - let (name, arity) = key; - - if let Some(ref idx) = indices.get_code_index((name.clone(), arity), module_name.clone()) { - match idx.0.borrow().0 { - IndexPtr::Index(compiled_tl_index) => { - if last_call { - self.execute_at_index(arity, dir_entry!(compiled_tl_index)); - } else { - self.call_at_index(arity, dir_entry!(compiled_tl_index)); - } - - return Ok(()); - } - IndexPtr::DynamicUndefined => { - self.fail = true; - return Ok(()); - } - IndexPtr::UserTermExpansion => { - if last_call { - self.execute_at_index(arity, LocalCodePtr::UserTermExpansion(0)); - } else { - self.call_at_index(arity, LocalCodePtr::UserTermExpansion(0)); - } - - return Ok(()); - } - IndexPtr::UserGoalExpansion => { - if last_call { - self.execute_at_index(arity, LocalCodePtr::UserGoalExpansion(0)); - } else { - self.call_at_index(arity, LocalCodePtr::UserGoalExpansion(0)); - } - - return Ok(()); - } - IndexPtr::InSituDirEntry(p) => { - if last_call { - self.execute_at_index(arity, LocalCodePtr::InSituDirEntry(p)); - } else { - self.call_at_index(arity, LocalCodePtr::InSituDirEntry(p)); - } - - return Ok(()); - } - _ => {} - } + if module_name.as_str() == "user" { + return call_policy.call_clause_type( + self, + key, + &indices.code_dir, + &indices.op_dir, + current_input_stream, + current_output_stream, + ); + } else if let Some(module) = indices.modules.get(&module_name) { + return call_policy.call_clause_type( + self, + key, + &module.code_dir, + &module.op_dir, + current_input_stream, + current_output_stream, + ); } + let (name, arity) = key; + let h = self.heap.h(); let stub = MachineError::functor_stub(name.clone(), arity); let err = MachineError::module_resolution_error(h, module_name, name, arity); @@ -974,58 +712,25 @@ impl MachineState { } } -fn try_in_situ_lookup(name: ClauseName, arity: usize, indices: &IndexStore) -> Option -{ - match indices.in_situ_code_dir.get(&(name.clone(), arity)) { - Some(p) => Some(LocalCodePtr::InSituDirEntry(*p)), - None => - match indices.code_dir.get(&(name, arity)) { - Some(ref idx) => { - if let IndexPtr::Index(p) = idx.0.borrow().0 { - Some(LocalCodePtr::DirEntry(p)) - } else { - None - } - } - _ => None, - }, - } -} - -fn try_in_situ( - machine_st: &mut MachineState, - name: ClauseName, - arity: usize, - indices: &IndexStore, - last_call: bool, -) -> CallResult { - if let Some(p) = try_in_situ_lookup(name.clone(), arity, indices) { - if last_call { - machine_st.execute_at_index(arity, p); - } else { - machine_st.call_at_index(arity, p); - } - - machine_st.p = CodePtr::Local(p); - Ok(()) - } else { - let stub = MachineError::functor_stub(name.clone(), arity); - let h = machine_st.heap.h(); - let key = ExistenceError::Procedure(name, arity); - - Err(machine_st.error_form(MachineError::existence_error(h, key), stub)) - } -} - pub(crate) type CallResult = Result<(), Vec>; pub(crate) trait CallPolicy: Any + fmt::Debug { - fn retry_me_else(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult { + fn retry_me_else( + &mut self, + machine_st: &mut MachineState, + offset: usize, + global_variables: &mut GlobalVarDir, + ) -> CallResult { let b = machine_st.b; - let n = machine_st.stack.index_or_frame(b).prelude.univ_prelude.num_cells; + let n = machine_st + .stack + .index_or_frame(b) + .prelude + .univ_prelude + .num_cells; - for i in 1 .. n + 1 { - machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1]; + for i in 1..n + 1 { + machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i - 1]; } machine_st.num_of_args = n; @@ -1037,21 +742,28 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { let old_tr = machine_st.stack.index_or_frame(b).prelude.tr; let curr_tr = machine_st.tr; - machine_st.unwind_trail(old_tr, curr_tr); + machine_st.unwind_trail(old_tr, curr_tr, global_variables); machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr; machine_st.trail.truncate(machine_st.tr); - machine_st.heap.truncate(machine_st.stack.index_or_frame(b).prelude.h); + machine_st + .heap + .truncate(machine_st.stack.index_or_frame(b).prelude.h); - let attr_var_init_queue_b = - machine_st.stack.index_or_frame(b).prelude.attr_var_init_queue_b; - let attr_var_init_bindings_b = - machine_st.stack.index_or_frame(b).prelude.attr_var_init_bindings_b; + let attr_var_init_queue_b = machine_st + .stack + .index_or_frame(b) + .prelude + .attr_var_init_queue_b; + let attr_var_init_bindings_b = machine_st + .stack + .index_or_frame(b) + .prelude + .attr_var_init_bindings_b; - machine_st.attr_var_init.backtrack( - attr_var_init_queue_b, - attr_var_init_bindings_b, - ); + machine_st + .attr_var_init + .backtrack(attr_var_init_queue_b, attr_var_init_bindings_b); machine_st.hb = machine_st.heap.h(); machine_st.p += 1; @@ -1059,12 +771,22 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { Ok(()) } - fn retry(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult { + fn retry( + &mut self, + machine_st: &mut MachineState, + offset: usize, + global_variables: &mut GlobalVarDir, + ) -> CallResult { let b = machine_st.b; - let n = machine_st.stack.index_or_frame(b).prelude.univ_prelude.num_cells; + let n = machine_st + .stack + .index_or_frame(b) + .prelude + .univ_prelude + .num_cells; - for i in 1 .. n + 1 { - machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1]; + for i in 1..n + 1 { + machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i - 1]; } machine_st.num_of_args = n; @@ -1076,31 +798,51 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { let old_tr = machine_st.stack.index_or_frame(b).prelude.tr; let curr_tr = machine_st.tr; - machine_st.unwind_trail(old_tr, curr_tr); + machine_st.unwind_trail(old_tr, curr_tr, global_variables); machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr; machine_st.trail.truncate(machine_st.tr); - machine_st.heap.truncate(machine_st.stack.index_or_frame(b).prelude.h); + machine_st + .heap + .truncate(machine_st.stack.index_or_frame(b).prelude.h); - let attr_var_init_queue_b = - machine_st.stack.index_or_frame(b).prelude.attr_var_init_queue_b; - let attr_var_init_bindings_b = - machine_st.stack.index_or_frame(b).prelude.attr_var_init_bindings_b; + let attr_var_init_queue_b = machine_st + .stack + .index_or_frame(b) + .prelude + .attr_var_init_queue_b; + let attr_var_init_bindings_b = machine_st + .stack + .index_or_frame(b) + .prelude + .attr_var_init_bindings_b; - machine_st.attr_var_init.backtrack(attr_var_init_queue_b, attr_var_init_bindings_b); + machine_st + .attr_var_init + .backtrack(attr_var_init_queue_b, attr_var_init_bindings_b); machine_st.hb = machine_st.heap.h(); - machine_st.p += offset; + machine_st.p = CodePtr::Local(dir_entry!(machine_st.p.local().abs_loc() + offset)); Ok(()) } - fn trust(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult { + fn trust( + &mut self, + machine_st: &mut MachineState, + offset: usize, + global_variables: &mut GlobalVarDir, + ) -> CallResult { let b = machine_st.b; - let n = machine_st.stack.index_or_frame(b).prelude.univ_prelude.num_cells; + let n = machine_st + .stack + .index_or_frame(b) + .prelude + .univ_prelude + .num_cells; - for i in 1 .. n + 1 { - machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1]; + for i in 1..n + 1 { + machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i - 1]; } machine_st.num_of_args = n; @@ -1110,37 +852,53 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { let old_tr = machine_st.stack.index_or_frame(b).prelude.tr; let curr_tr = machine_st.tr; - machine_st.unwind_trail(old_tr, curr_tr); + machine_st.unwind_trail(old_tr, curr_tr, global_variables); machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr; machine_st.trail.truncate(machine_st.tr); - machine_st.heap.truncate(machine_st.stack.index_or_frame(b).prelude.h); + machine_st + .heap + .truncate(machine_st.stack.index_or_frame(b).prelude.h); - let attr_var_init_queue_b = - machine_st.stack.index_or_frame(b).prelude.attr_var_init_queue_b; - let attr_var_init_bindings_b = - machine_st.stack.index_or_frame(b).prelude.attr_var_init_bindings_b; + let attr_var_init_queue_b = machine_st + .stack + .index_or_frame(b) + .prelude + .attr_var_init_queue_b; + let attr_var_init_bindings_b = machine_st + .stack + .index_or_frame(b) + .prelude + .attr_var_init_bindings_b; - machine_st.attr_var_init.backtrack( - attr_var_init_queue_b, - attr_var_init_bindings_b, - ); + machine_st + .attr_var_init + .backtrack(attr_var_init_queue_b, attr_var_init_bindings_b); machine_st.b = machine_st.stack.index_or_frame(b).prelude.b; machine_st.stack.truncate(b); machine_st.hb = machine_st.heap.h(); - machine_st.p += offset; + machine_st.p = CodePtr::Local(dir_entry!(machine_st.p.local().abs_loc() + offset)); Ok(()) } - fn trust_me(&mut self, machine_st: &mut MachineState) -> CallResult { + fn trust_me( + &mut self, + machine_st: &mut MachineState, + global_variables: &mut GlobalVarDir, + ) -> CallResult { let b = machine_st.b; - let n = machine_st.stack.index_or_frame(b).prelude.univ_prelude.num_cells; + let n = machine_st + .stack + .index_or_frame(b) + .prelude + .univ_prelude + .num_cells; - for i in 1 .. n + 1 { - machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1]; + for i in 1..n + 1 { + machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i - 1]; } machine_st.num_of_args = n; @@ -1150,21 +908,28 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { let old_tr = machine_st.stack.index_or_frame(b).prelude.tr; let curr_tr = machine_st.tr; - machine_st.unwind_trail(old_tr, curr_tr); + machine_st.unwind_trail(old_tr, curr_tr, global_variables); machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr; machine_st.trail.truncate(machine_st.tr); - machine_st.heap.truncate(machine_st.stack.index_or_frame(b).prelude.h); + machine_st + .heap + .truncate(machine_st.stack.index_or_frame(b).prelude.h); - let attr_var_init_queue_b = - machine_st.stack.index_or_frame(b).prelude.attr_var_init_queue_b; - let attr_var_init_bindings_b = - machine_st.stack.index_or_frame(b).prelude.attr_var_init_bindings_b; + let attr_var_init_queue_b = machine_st + .stack + .index_or_frame(b) + .prelude + .attr_var_init_queue_b; + let attr_var_init_bindings_b = machine_st + .stack + .index_or_frame(b) + .prelude + .attr_var_init_bindings_b; - machine_st.attr_var_init.backtrack( - attr_var_init_queue_b, - attr_var_init_bindings_b, - ); + machine_st + .attr_var_init + .backtrack(attr_var_init_queue_b, attr_var_init_bindings_b); machine_st.b = machine_st.stack.index_or_frame(b).prelude.b; machine_st.stack.truncate(b); @@ -1180,13 +945,12 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { machine_st: &mut MachineState, name: ClauseName, arity: usize, - idx: CodeIndex, - indices: &mut IndexStore, + idx: &CodeIndex, ) -> CallResult { if machine_st.last_call { - self.try_execute(machine_st, name, arity, idx, indices) + self.try_execute(machine_st, name, arity, idx) } else { - self.try_call(machine_st, name, arity, idx, indices) + self.try_call(machine_st, name, arity, idx) } } @@ -1195,27 +959,22 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { machine_st: &mut MachineState, name: ClauseName, arity: usize, - idx: CodeIndex, - indices: &IndexStore, + idx: &CodeIndex, ) -> CallResult { - match idx.0.borrow().0 { + match idx.get() { IndexPtr::DynamicUndefined => { machine_st.fail = true; + return Ok(()); } IndexPtr::Undefined => { - return try_in_situ(machine_st, name, arity, indices, false); + return Err(machine_st.throw_undefined_error(name, arity)); + } + IndexPtr::DynamicIndex(compiled_tl_index) => { + machine_st.dynamic_mode = FirstOrNext::First; + machine_st.call_at_index(arity, dir_entry!(compiled_tl_index)); } IndexPtr::Index(compiled_tl_index) => { - machine_st.call_at_index(arity, LocalCodePtr::DirEntry(compiled_tl_index)) - } - IndexPtr::UserTermExpansion => { - machine_st.call_at_index(arity, LocalCodePtr::UserTermExpansion(0)); - } - IndexPtr::UserGoalExpansion => { - machine_st.call_at_index(arity, LocalCodePtr::UserGoalExpansion(0)); - } - IndexPtr::InSituDirEntry(p) => { - machine_st.call_at_index(arity, LocalCodePtr::InSituDirEntry(p)); + machine_st.call_at_index(arity, dir_entry!(compiled_tl_index)); } } @@ -1227,26 +986,23 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { machine_st: &mut MachineState, name: ClauseName, arity: usize, - idx: CodeIndex, - indices: &IndexStore, + idx: &CodeIndex, ) -> CallResult { - match idx.0.borrow().0 { - IndexPtr::DynamicUndefined => - machine_st.fail = true, - IndexPtr::Undefined => - return try_in_situ(machine_st, name, arity, indices, true), + match idx.get() { + IndexPtr::DynamicUndefined => { + machine_st.fail = true; + return Ok(()); + } + IndexPtr::Undefined => { + return Err(machine_st.throw_undefined_error(name, arity)); + } + IndexPtr::DynamicIndex(compiled_tl_index) => { + machine_st.dynamic_mode = FirstOrNext::First; + machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index)); + } IndexPtr::Index(compiled_tl_index) => { machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index)) } - IndexPtr::UserTermExpansion => { - machine_st.execute_at_index(arity, LocalCodePtr::UserTermExpansion(0)); - } - IndexPtr::UserGoalExpansion => { - machine_st.execute_at_index(arity, LocalCodePtr::UserGoalExpansion(0)); - } - IndexPtr::InSituDirEntry(p) => { - machine_st.execute_at_index(arity, LocalCodePtr::InSituDirEntry(p)); - } } Ok(()) @@ -1256,7 +1012,8 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { &mut self, machine_st: &mut MachineState, ct: &BuiltInClauseType, - indices: &mut IndexStore, + _code_dir: &CodeDir, + op_dir: &OpDir, current_input_stream: &mut Stream, current_output_stream: &mut Stream, ) -> CallResult { @@ -1279,13 +1036,13 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { Addr::Con(h) if machine_st.heap.atom_at(h) => { if let HeapCellValue::Atom(ref atom, _) = &machine_st.heap[h] { match atom.as_str() { - ">" | "<" | "=" => { - } + ">" | "<" | "=" => {} _ => { let stub = MachineError::functor_stub(clause_name!("compare"), 3); - let err = MachineError::domain_error(DomainErrorType::Order, a1); + let err = + MachineError::domain_error(DomainErrorType::Order, a1); return Err(machine_st.error_form(err, stub)); } } @@ -1299,21 +1056,20 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { let err = MachineError::type_error(h, ValidType::Atom, a1); return Err(machine_st.error_form(err, stub)); } - _ => { - } + _ => {} } let atom = match machine_st.compare_term_test(&a2, &a3) { Some(Ordering::Greater) => { - let spec = fetch_atom_op_spec(clause_name!(">"), None, &indices.op_dir); + let spec = fetch_atom_op_spec(clause_name!(">"), None, op_dir); HeapCellValue::Atom(clause_name!(">"), spec) } Some(Ordering::Equal) => { - let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir); + let spec = fetch_atom_op_spec(clause_name!("="), None, op_dir); HeapCellValue::Atom(clause_name!("="), spec) } None | Some(Ordering::Less) => { - let spec = fetch_atom_op_spec(clause_name!("<"), None, &indices.op_dir); + let spec = fetch_atom_op_spec(clause_name!("<"), None, op_dir); HeapCellValue::Atom(clause_name!("<"), spec) } }; @@ -1321,7 +1077,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { let h = machine_st.heap.h(); machine_st.heap.push(atom); - machine_st.unify(a1, Addr::Con(h)); + (machine_st.unify_fn)(machine_st, a1, Addr::Con(h)); return_from_clause!(machine_st.last_call, machine_st) } @@ -1338,25 +1094,25 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { &BuiltInClauseType::Read => { match machine_st.read( current_input_stream.clone(), - indices.atom_tbl.clone(), - &indices.op_dir, + machine_st.atom_tbl.clone(), + op_dir, ) { Ok(offset) => { let addr = machine_st[temp_v!(1)]; - machine_st.unify(addr, Addr::HeapCell(offset.heap_loc)); + (machine_st.unify_fn)(machine_st, addr, Addr::HeapCell(offset.heap_loc)); } Err(ParserError::UnexpectedEOF) => { let addr = machine_st[temp_v!(1)]; - let eof = clause_name!("end_of_file".to_string(), - indices.atom_tbl); - let atom = machine_st.heap.to_unifiable( - HeapCellValue::Atom(eof, None) - ); - machine_st.unify(addr, atom); + let eof = clause_name!("end_of_file".to_string(), machine_st.atom_tbl); + + let atom = machine_st.heap.to_unifiable(HeapCellValue::Atom(eof, None)); + + (machine_st.unify_fn)(machine_st, addr, atom); } Err(e) => { let h = machine_st.heap.h(); let stub = MachineError::functor_stub(clause_name!("read"), 1); + let err = MachineError::syntax_error(h, e); let err = machine_st.error_form(err, stub); @@ -1382,7 +1138,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { return_from_clause!(machine_st.last_call, machine_st) } &BuiltInClauseType::Functor => { - machine_st.try_functor(&indices)?; + machine_st.try_functor(op_dir)?; return_from_clause!(machine_st.last_call, machine_st) } &BuiltInClauseType::NotEq => { @@ -1405,7 +1161,9 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { let mut list = machine_st.try_from_list(temp_v!(1), stub)?; list.sort_unstable_by(|a1, a2| { - machine_st.compare_term_test(a1, a2).unwrap_or(Ordering::Less) + machine_st + .compare_term_test(a1, a2) + .unwrap_or(Ordering::Less) }); machine_st.term_dedup(&mut list); @@ -1413,7 +1171,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { let heap_addr = Addr::HeapCell(machine_st.heap.to_list(list.into_iter())); let r2 = machine_st[temp_v!(2)]; - machine_st.unify(r2, heap_addr); + (machine_st.unify_fn)(machine_st, r2, heap_addr); return_from_clause!(machine_st.last_call, machine_st) } @@ -1430,14 +1188,16 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { } key_pairs.sort_by(|a1, a2| { - machine_st.compare_term_test(&a1.0, &a2.0).unwrap_or(Ordering::Less) + machine_st + .compare_term_test(&a1.0, &a2.0) + .unwrap_or(Ordering::Less) }); let key_pairs = key_pairs.into_iter().map(|kp| kp.1); let heap_addr = Addr::HeapCell(machine_st.heap.to_list(key_pairs)); let r2 = machine_st[temp_v!(2)]; - machine_st.unify(r2, heap_addr); + (machine_st.unify_fn)(machine_st, r2, heap_addr); return_from_clause!(machine_st.last_call, machine_st) } @@ -1446,31 +1206,69 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { let n2 = machine_st.get_number(at)?; let n2 = machine_st.heap.put_constant(n2.into()); - machine_st.unify(a1, n2); + (machine_st.unify_fn)(machine_st, a1, n2); return_from_clause!(machine_st.last_call, machine_st) } } } - fn compile_hook( + fn call_clause_type( &mut self, machine_st: &mut MachineState, - hook: &CompileTimeHook, + key: PredicateKey, + code_dir: &CodeDir, + op_dir: &OpDir, + current_input_stream: &mut Stream, + current_output_stream: &mut Stream, ) -> CallResult { - machine_st.cp = LocalCodePtr::TopLevel(0, 0); + let (name, arity) = key; - machine_st.num_of_args = hook.arity(); - machine_st.b0 = machine_st.b; + match ClauseType::from(name.clone(), arity, None) { + ClauseType::BuiltIn(built_in) => { + machine_st.setup_built_in_call(built_in.clone()); + self.call_builtin( + machine_st, + &built_in, + code_dir, + op_dir, + current_input_stream, + current_output_stream, + )?; + } + ClauseType::CallN => { + machine_st.handle_internal_call_n(arity); - machine_st.p = match hook { - CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => { - CodePtr::Local(LocalCodePtr::UserTermExpansion(0)) + if machine_st.fail { + return Ok(()); + } + + machine_st.p = CodePtr::CallN(arity, machine_st.p.local(), machine_st.last_call); } - CompileTimeHook::UserGoalExpansion | CompileTimeHook::GoalExpansion => { - CodePtr::Local(LocalCodePtr::UserGoalExpansion(0)) + ClauseType::Inlined(inlined) => { + machine_st.execute_inlined(&inlined); + + if machine_st.last_call { + machine_st.p = CodePtr::Local(machine_st.cp); + } } - }; + ClauseType::Op(..) | ClauseType::Named(..) => { + if let Some(idx) = code_dir.get(&(name.clone(), arity)) { + self.context_call(machine_st, name, arity, idx)?; + } else { + return Err(machine_st.throw_undefined_error(name, arity)); + } + } + ClauseType::System(_) => { + let name = functor!(clause_name(name)); + let stub = MachineError::functor_stub(clause_name!("call"), arity + 1); + + return Err(machine_st.error_form( + MachineError::type_error(machine_st.heap.h(), ValidType::Callable, name), + stub, + )); + } + } Ok(()) } @@ -1479,57 +1277,20 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { &mut self, machine_st: &mut MachineState, arity: usize, - indices: &mut IndexStore, + code_dir: &CodeDir, + op_dir: &OpDir, current_input_stream: &mut Stream, current_output_stream: &mut Stream, ) -> CallResult { - if let Some((name, arity)) = machine_st.setup_call_n(arity) { - match ClauseType::from(name.clone(), arity, None) { - ClauseType::BuiltIn(built_in) => { - machine_st.setup_built_in_call(built_in.clone()); - self.call_builtin( - machine_st, - &built_in, - indices, - current_input_stream, - current_output_stream, - )?; - } - ClauseType::CallN => { - machine_st.handle_internal_call_n(arity); - - if machine_st.fail { - return Ok(()); - } - - machine_st.p = CodePtr::CallN(arity, machine_st.p.local(), machine_st.last_call); - } - ClauseType::Inlined(inlined) => { - machine_st.execute_inlined(&inlined); - - if machine_st.last_call { - machine_st.p = CodePtr::Local(machine_st.cp); - } - } - ClauseType::Op(..) | ClauseType::Named(..) => { - let module = name.owning_module(); - - if let Some(idx) = indices.get_code_index((name.clone(), arity), module) { - self.context_call(machine_st, name, arity, idx, indices)?; - } else { - try_in_situ(machine_st, name, arity, indices, machine_st.last_call)?; - } - } - ClauseType::Hook(_) | ClauseType::System(_) => { - let name = functor!(clause_name(name)); - let stub = MachineError::functor_stub(clause_name!("call"), arity + 1); - - return Err(machine_st.error_form( - MachineError::type_error(machine_st.heap.h(), ValidType::Callable, name), - stub, - )); - } - }; + if let Some(key) = machine_st.setup_call_n(arity) { + self.call_clause_type( + machine_st, + key, + code_dir, + op_dir, + current_input_stream, + current_output_stream, + )?; } Ok(()) @@ -1542,31 +1303,52 @@ impl CallPolicy for CWILCallPolicy { machine_st: &mut MachineState, name: ClauseName, arity: usize, - idx: CodeIndex, - indices: &mut IndexStore, + idx: &CodeIndex, ) -> CallResult { self.prev_policy - .context_call(machine_st, name, arity, idx, indices)?; + .context_call(machine_st, name, arity, idx)?; //, indices)?; self.increment(machine_st) } - fn retry_me_else(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult { - self.prev_policy.retry_me_else(machine_st, offset)?; + fn retry_me_else( + &mut self, + machine_st: &mut MachineState, + offset: usize, + global_variables: &mut GlobalVarDir, + ) -> CallResult { + self.prev_policy + .retry_me_else(machine_st, offset, global_variables)?; self.increment(machine_st) } - fn retry(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult { - self.prev_policy.retry(machine_st, offset)?; + fn retry( + &mut self, + machine_st: &mut MachineState, + offset: usize, + global_variables: &mut GlobalVarDir, + ) -> CallResult { + self.prev_policy + .retry(machine_st, offset, global_variables)?; self.increment(machine_st) } - fn trust_me(&mut self, machine_st: &mut MachineState) -> CallResult { - self.prev_policy.trust_me(machine_st)?; + fn trust_me( + &mut self, + machine_st: &mut MachineState, + global_variables: &mut GlobalVarDir, + ) -> CallResult { + self.prev_policy.trust_me(machine_st, global_variables)?; self.increment(machine_st) } - fn trust(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult { - self.prev_policy.trust(machine_st, offset)?; + fn trust( + &mut self, + machine_st: &mut MachineState, + offset: usize, + global_variables: &mut GlobalVarDir, + ) -> CallResult { + self.prev_policy + .trust(machine_st, offset, global_variables)?; self.increment(machine_st) } @@ -1574,16 +1356,18 @@ impl CallPolicy for CWILCallPolicy { &mut self, machine_st: &mut MachineState, ct: &BuiltInClauseType, - indices: &mut IndexStore, + code_dir: &CodeDir, + op_dir: &OpDir, current_input_stream: &mut Stream, current_output_stream: &mut Stream, ) -> CallResult { self.prev_policy.call_builtin( machine_st, ct, - indices, + code_dir, + op_dir, current_input_stream, - current_output_stream + current_output_stream, )?; self.increment(machine_st) @@ -1593,14 +1377,16 @@ impl CallPolicy for CWILCallPolicy { &mut self, machine_st: &mut MachineState, arity: usize, - indices: &mut IndexStore, + code_dir: &CodeDir, + op_dir: &OpDir, current_input_stream: &mut Stream, current_output_stream: &mut Stream, ) -> CallResult { self.prev_policy.call_n( machine_st, arity, - indices, + code_dir, + op_dir, current_input_stream, current_output_stream, )?; @@ -1625,8 +1411,7 @@ pub(crate) struct CWILCallPolicy { } impl CWILCallPolicy { - pub(crate) - fn new_in_place(policy: &mut Box) { + pub(crate) fn new_in_place(policy: &mut Box) { let mut prev_policy: Box = Box::new(DefaultCallPolicy {}); mem::swap(&mut prev_policy, policy); @@ -1661,8 +1446,7 @@ impl CWILCallPolicy { Ok(()) } - pub(crate) - fn add_limit(&mut self, mut limit: Integer, b: usize) -> &Integer { + pub(crate) fn add_limit(&mut self, mut limit: Integer, b: usize) -> &Integer { limit += &self.count; match self.limits.last().cloned() { @@ -1673,8 +1457,7 @@ impl CWILCallPolicy { &self.count } - pub(crate) - fn remove_limit(&mut self, b: usize) -> &Integer { + pub(crate) fn remove_limit(&mut self, b: usize) -> &Integer { if let Some((_, bp)) = self.limits.last().cloned() { if bp == b { self.limits.pop(); @@ -1684,13 +1467,11 @@ impl CWILCallPolicy { &self.count } - pub(crate) - fn is_empty(&self) -> bool { + pub(crate) fn is_empty(&self) -> bool { self.limits.is_empty() } - pub(crate) - fn into_inner(&mut self) -> Box { + pub(crate) fn into_inner(&mut self) -> Box { let mut new_inner: Box = Box::new(DefaultCallPolicy {}); mem::swap(&mut self.prev_policy, &mut new_inner); new_inner @@ -1711,7 +1492,6 @@ fn cut_body(machine_st: &mut MachineState, addr: &Addr) -> bool { &Addr::CutPoint(b0) | &Addr::Usize(b0) => { if b > b0 { machine_st.b = b0; - machine_st.tidy_trail(); } } _ => { @@ -1799,7 +1579,6 @@ impl CutPolicy for SCCCutPolicy { Addr::Usize(b0) | Addr::CutPoint(b0) => { if b > b0 { machine_st.b = b0; - machine_st.tidy_trail(); } } _ => { diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index f7cda917..b1d8dde7 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -1,11 +1,12 @@ -use crate::prolog_parser::ast::*; -use crate::prolog_parser::tabled_rc::*; +use prolog_parser::ast::*; +use prolog_parser::tabled_rc::*; +use prolog_parser::{clause_name, perm_v, temp_v}; use crate::clause_types::*; use crate::forms::*; use crate::heap_iter::*; +use crate::indexing::*; use crate::instructions::*; -use crate::machine::INTERRUPT; use crate::machine::attributed_variables::*; use crate::machine::code_repo::CodeRepo; use crate::machine::copier::*; @@ -13,33 +14,23 @@ use crate::machine::heap::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::machine_state::*; +use crate::machine::partial_string::*; use crate::machine::stack::*; use crate::machine::streams::*; -use crate::ordered_float::*; +use crate::machine::INTERRUPT; use crate::rug::Integer; +use ordered_float::*; -use crate::indexmap::{IndexMap, IndexSet}; +use indexmap::{IndexMap, IndexSet}; use std::cmp::Ordering; use std::convert::TryFrom; use std::rc::Rc; -macro_rules! try_or_fail { - ($s:ident, $e:expr) => {{ - match $e { - Ok(val) => val, - Err(msg) => { - $s.throw_exception(msg); - return; - } - } - }}; -} - impl MachineState { - pub(crate) - fn new() -> Self { + pub(crate) fn new() -> Self { MachineState { + atom_tbl: TabledData::new(Rc::new("".to_owned())), s: HeapPtr::default(), p: CodePtr::default(), b: 0, @@ -61,56 +52,24 @@ impl MachineState { lifted_heap: Heap::new(), interms: vec![Number::default(); 256], last_call: false, - heap_locs: HeapVarDict::new(), flags: MachineFlags::default(), - at_end_of_expansion: false - } - } - - pub(crate) - fn with_small_heap() -> Self { - MachineState { - s: HeapPtr::default(), - p: CodePtr::default(), - b: 0, - b0: 0, - e: 0, - num_of_args: 0, - cp: LocalCodePtr::default(), - attr_var_init: AttrVarInitializer::new(0, 0), - fail: false, - heap: Heap::new(), - mode: MachineMode::Write, - stack: Stack::new(), - registers: vec![Addr::HeapCell(0); MAX_ARITY + 1], // self.registers[0] is never used. - trail: vec![], - tr: 0, - hb: 0, - block: 0, - ball: Ball::new(), - lifted_heap: Heap::new(), - interms: vec![Number::default(); 0], - last_call: false, - heap_locs: HeapVarDict::new(), - flags: MachineFlags::default(), - at_end_of_expansion: false + cc: 0, + global_clock: 0, + dynamic_mode: FirstOrNext::First, + unify_fn: MachineState::unify, + bind_fn: MachineState::bind, } } #[inline] - pub fn machine_flags(&self) -> MachineFlags { + pub(crate) fn machine_flags(&self) -> MachineFlags { self.flags } - pub(crate) - fn store(&self, addr: Addr) -> Addr { + pub(crate) fn store(&self, addr: Addr) -> Addr { match addr { - Addr::AttrVar(h) | Addr::HeapCell(h) => { - self.heap[h].as_addr(h) - } - Addr::StackCell(fr, sc) => { - self.stack.index_and_frame(fr)[sc] - } + Addr::AttrVar(h) | Addr::HeapCell(h) => self.heap[h].as_addr(h), + Addr::StackCell(fr, sc) => self.stack.index_and_frame(fr)[sc], Addr::PStrLocation(h, n) => { if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.heap[h] { if !pstr.at_end(n) { @@ -124,14 +83,11 @@ impl MachineState { unreachable!() } } - addr => { - addr - } + addr => addr, } } - pub(crate) - fn deref(&self, mut addr: Addr) -> Addr { + pub(crate) fn deref(&self, mut addr: Addr) -> Addr { loop { let value = self.store(addr); @@ -162,8 +118,7 @@ impl MachineState { } } - pub(super) - fn bind(&mut self, r1: Ref, a2: Addr) { + pub(super) fn bind(&mut self, r1: Ref, a2: Addr) { let t1 = self.store(r1.as_addr()); let t2 = self.store(a2); @@ -194,38 +149,81 @@ impl MachineState { Some(Ref::AttrVar(h)) => { self.bind_attr_var(h, t1); } - None => { - } + None => {} } } } - fn bind_with_occurs_check(&mut self, r: Ref, addr: Addr) { + #[inline] + pub(super) fn bind_with_occurs_check_with_error_wrapper(&mut self, r: Ref, addr: Addr) { + if self.bind_with_occurs_check(r, addr) { + let err = self.representation_error( + RepFlag::Term, + clause_name!("unify_with_occurs_check"), + 2, + ); + + self.throw_exception(err); + } + } + + #[inline] + pub(super) fn bind_with_occurs_check_wrapper(&mut self, r: Ref, addr: Addr) { + self.bind_with_occurs_check(r, addr); + } + + #[inline] + pub(super) fn bind_with_occurs_check(&mut self, r: Ref, addr: Addr) -> bool { if let Ref::StackCell(..) = r { // local variable optimization -- r cannot occur in the // data structure bound to addr, so don't bother // traversing it. self.bind(r, addr); - return; + return false; } - let mut fail = false; + let mut occurs_triggered = false; for addr in self.acyclic_pre_order_iter(addr) { if let Some(inner_r) = addr.as_var() { if r == inner_r { - fail = true; + occurs_triggered = true; break; } } } - self.fail = fail; + self.fail = occurs_triggered; self.bind(r, addr); + + return occurs_triggered; } - pub(super) - fn unify_with_occurs_check(&mut self, a1: Addr, a2: Addr) { + pub(super) fn unify_with_occurs_check_with_error(&mut self, a1: Addr, a2: Addr) { + let mut throw_error = false; + self.unify_with_occurs_check_loop(a1, a2, || throw_error = true); + + if throw_error { + let err = self.representation_error( + RepFlag::Term, + clause_name!("unify_with_occurs_check"), + 2, + ); + + self.throw_exception(err); + } + } + + pub(super) fn unify_with_occurs_check(&mut self, a1: Addr, a2: Addr) { + self.unify_with_occurs_check_loop(a1, a2, || {}) + } + + pub(super) fn unify_with_occurs_check_loop( + &mut self, + a1: Addr, + a2: Addr, + mut occurs_trigger: impl FnMut() + ) { let mut pdl = vec![a1, a2]; let mut tabu_list: IndexSet<(Addr, Addr)> = IndexSet::new(); @@ -247,13 +245,19 @@ impl MachineState { match (d1, d2) { (Addr::AttrVar(h), addr) | (addr, Addr::AttrVar(h)) => { - self.bind_with_occurs_check(Ref::AttrVar(h), addr) + if self.bind_with_occurs_check(Ref::AttrVar(h), addr) { + occurs_trigger(); + } } (Addr::HeapCell(h), addr) | (addr, Addr::HeapCell(h)) => { - self.bind_with_occurs_check(Ref::HeapCell(h), addr) + if self.bind_with_occurs_check(Ref::HeapCell(h), addr) { + occurs_trigger(); + } } (Addr::StackCell(fr, sc), addr) | (addr, Addr::StackCell(fr, sc)) => { - self.bind_with_occurs_check(Ref::StackCell(fr, sc), addr) + if self.bind_with_occurs_check(Ref::StackCell(fr, sc), addr) { + occurs_trigger(); + } } (Addr::Lis(a1), Addr::Str(a2)) | (Addr::Str(a2), Addr::Lis(a1)) => { if let &HeapCellValue::NamedStr(n2, ref f2, _) = &self.heap[a2] { @@ -270,10 +274,10 @@ impl MachineState { self.fail = true; } - (Addr::PStrLocation(h, n), Addr::Lis(l)) | - (Addr::Lis(l), Addr::PStrLocation(h, n)) => { + (Addr::PStrLocation(h, n), Addr::Lis(l)) + | (Addr::Lis(l), Addr::PStrLocation(h, n)) => { if let HeapCellValue::PartialString(ref pstr, _) = &self.heap[h] { - if let Some(c) = pstr.range_from(n ..).next() { + if let Some(c) = pstr.range_from(n..).next() { pdl.push(Addr::PStrLocation(h, n + c.len_utf8())); pdl.push(Addr::HeapCell(l + 1)); @@ -287,20 +291,22 @@ impl MachineState { } } (Addr::PStrLocation(h1, n1), Addr::PStrLocation(h2, n2)) => { - if let &HeapCellValue::PartialString(ref pstr1, has_tail_1) = &self.heap[h1] { - if let &HeapCellValue::PartialString(ref pstr2, has_tail_2) = &self.heap[h2] { + if let &HeapCellValue::PartialString(ref pstr1, has_tail_1) = &self.heap[h1] + { + if let &HeapCellValue::PartialString(ref pstr2, has_tail_2) = + &self.heap[h2] + { let pstr1_s = pstr1.as_str_from(n1); let pstr2_s = pstr2.as_str_from(n2); - let m_len = - if pstr1_s.starts_with(pstr2_s) { - pstr2_s.len() - } else if pstr2_s.starts_with(pstr1_s) { - pstr1_s.len() - } else { - self.fail = true; - return; - }; + let m_len = if pstr1_s.starts_with(pstr2_s) { + pstr2_s.len() + } else if pstr2_s.starts_with(pstr1_s) { + pstr1_s.len() + } else { + self.fail = true; + return; + }; if pstr1.at_end(n1 + m_len) { if has_tail_1 { @@ -364,34 +370,25 @@ impl MachineState { self.fail = true; } - (Addr::Con(c1), Addr::Con(c2)) => { - match (&self.heap[c1], &self.heap[c2]) { - ( - &HeapCellValue::Atom(ref n1, _), - &HeapCellValue::Atom(ref n2, _), - ) if n1.as_str() == n2.as_str() => { - } - ( - &HeapCellValue::DBRef(ref db_ref_1), - &HeapCellValue::DBRef(ref db_ref_2), - ) if db_ref_1 == db_ref_2 => { - } - ( - v1, - v2, - ) => { - if let Ok(n1) = Number::try_from(v1) { - if let Ok(n2) = Number::try_from(v2) { - if n1 == n2 { - continue; - } + (Addr::Con(c1), Addr::Con(c2)) => match (&self.heap[c1], &self.heap[c2]) { + (&HeapCellValue::Atom(ref n1, _), &HeapCellValue::Atom(ref n2, _)) + if n1.as_str() == n2.as_str() => {} + ( + &HeapCellValue::DBRef(ref db_ref_1), + &HeapCellValue::DBRef(ref db_ref_2), + ) if db_ref_1 == db_ref_2 => {} + (v1, v2) => { + if let Ok(n1) = Number::try_from(v1) { + if let Ok(n2) = Number::try_from(v2) { + if n1 == n2 { + continue; } } - - self.fail = true; } + + self.fail = true; } - } + }, (Addr::Con(h), Addr::Char(c)) | (Addr::Char(c), Addr::Con(h)) => { match &self.heap[h] { &HeapCellValue::Atom(ref name, _) if name.is_char() => { @@ -440,8 +437,7 @@ impl MachineState { } } - pub(super) - fn unify(&mut self, a1: Addr, a2: Addr) { + pub(super) fn unify(&mut self, a1: Addr, a2: Addr) { let mut pdl = vec![a1, a2]; let mut tabu_list: IndexSet<(Addr, Addr)> = IndexSet::new(); @@ -487,37 +483,39 @@ impl MachineState { self.fail = true; } - (Addr::PStrLocation(h, n), Addr::Lis(l)) | - (Addr::Lis(l), Addr::PStrLocation(h, n)) => { - if let HeapCellValue::PartialString(ref pstr, _) = &self.heap[h] { - if let Some(c) = pstr.range_from(n ..).next() { - pdl.push(Addr::PStrLocation(h, n + c.len_utf8())); - pdl.push(Addr::HeapCell(l + 1)); + (Addr::PStrLocation(h, n), Addr::Lis(l)) + | (Addr::Lis(l), Addr::PStrLocation(h, n)) => { + if let HeapCellValue::PartialString(ref pstr, _) = &self.heap[h] { + if let Some(c) = pstr.range_from(n..).next() { + pdl.push(Addr::PStrLocation(h, n + c.len_utf8())); + pdl.push(Addr::HeapCell(l + 1)); - pdl.push(Addr::Char(c)); - pdl.push(Addr::HeapCell(l)); - } else { - unreachable!() - } - } else { - unreachable!() - } + pdl.push(Addr::Char(c)); + pdl.push(Addr::HeapCell(l)); + } else { + unreachable!() + } + } else { + unreachable!() + } } (Addr::PStrLocation(h1, n1), Addr::PStrLocation(h2, n2)) => { - if let &HeapCellValue::PartialString(ref pstr1, has_tail_1) = &self.heap[h1] { - if let &HeapCellValue::PartialString(ref pstr2, has_tail_2) = &self.heap[h2] { + if let &HeapCellValue::PartialString(ref pstr1, has_tail_1) = &self.heap[h1] + { + if let &HeapCellValue::PartialString(ref pstr2, has_tail_2) = + &self.heap[h2] + { let pstr1_s = pstr1.as_str_from(n1); let pstr2_s = pstr2.as_str_from(n2); - let m_len = - if pstr1_s.starts_with(pstr2_s) { - pstr2_s.len() - } else if pstr2_s.starts_with(pstr1_s) { - pstr1_s.len() - } else { - self.fail = true; - return; - }; + let m_len = if pstr1_s.starts_with(pstr2_s) { + pstr2_s.len() + } else if pstr2_s.starts_with(pstr1_s) { + pstr1_s.len() + } else { + self.fail = true; + return; + }; if pstr1.at_end(n1 + m_len) { if has_tail_1 { @@ -577,34 +575,25 @@ impl MachineState { self.fail = true; } - (Addr::Con(c1), Addr::Con(c2)) => { - match (&self.heap[c1], &self.heap[c2]) { - ( - &HeapCellValue::Atom(ref n1, _), - &HeapCellValue::Atom(ref n2, _), - ) if n1.as_str() == n2.as_str() => { - } -( - &HeapCellValue::DBRef(ref db_ref_1), - &HeapCellValue::DBRef(ref db_ref_2), - ) if db_ref_1 == db_ref_2 => { - } - ( - v1, - v2, - ) => { - if let Ok(n1) = Number::try_from(v1) { - if let Ok(n2) = Number::try_from(v2) { - if n1 == n2 { - continue; - } + (Addr::Con(c1), Addr::Con(c2)) => match (&self.heap[c1], &self.heap[c2]) { + (&HeapCellValue::Atom(ref n1, _), &HeapCellValue::Atom(ref n2, _)) + if n1.as_str() == n2.as_str() => {} + ( + &HeapCellValue::DBRef(ref db_ref_1), + &HeapCellValue::DBRef(ref db_ref_2), + ) if db_ref_1 == db_ref_2 => {} + (v1, v2) => { + if let Ok(n1) = Number::try_from(v1) { + if let Ok(n2) = Number::try_from(v2) { + if n1 == n2 { + continue; } } - - self.fail = true; } + + self.fail = true; } - } + }, (Addr::Con(h), Addr::Char(c)) | (Addr::Char(c), Addr::Con(h)) => { match &self.heap[h] { &HeapCellValue::Atom(ref name, _) if name.is_char() => { @@ -653,8 +642,7 @@ impl MachineState { } } - pub(super) - fn trail(&mut self, r: TrailRef) { + pub(super) fn trail(&mut self, r: TrailRef) { match r { TrailRef::Ref(Ref::HeapCell(h)) => { if h < self.hb { @@ -686,6 +674,14 @@ impl MachineState { self.tr += 1; } } + TrailRef::BlackboardOffset(key_h, value_h) => { + self.trail.push(TrailRef::BlackboardOffset(key_h, value_h)); + self.tr += 1; + } + TrailRef::BlackboardEntry(key_h) => { + self.trail.push(TrailRef::BlackboardEntry(key_h)); + self.tr += 1; + } } } @@ -694,25 +690,27 @@ impl MachineState { HeapPtr::HeapCell(ref mut h) => { *h += rhs; } - &mut HeapPtr::PStrChar(h, ref mut n) | - &mut HeapPtr::PStrLocation(h, ref mut n) => { + &mut HeapPtr::PStrChar(h, ref mut n) | &mut HeapPtr::PStrLocation(h, ref mut n) => { match &self.heap[h] { &HeapCellValue::PartialString(ref pstr, _) => { - for c in pstr.range_from(*n ..).take(rhs) { + for c in pstr.range_from(*n..).take(rhs) { *n += c.len_utf8(); } self.s = HeapPtr::PStrLocation(h, *n); } - _ => { - } + _ => {} } } } } - pub(super) - fn unwind_trail(&mut self, a1: usize, a2: usize) { + pub(super) fn unwind_trail( + &mut self, + a1: usize, + a2: usize, + global_variables: &mut GlobalVarDir, + ) { // the sequence is reversed to respect the chronology of trail // additions, now that deleted attributes can be undeleted by // backtracking. @@ -733,48 +731,35 @@ impl MachineState { TrailRef::AttrVarListLink(h, l) => { self.heap[h] = HeapCellValue::Addr(Addr::Lis(l)); } - } - } - } + TrailRef::BlackboardOffset(key_h, value_h) => { + let key = atom_from!( + self, + self.store(self.deref(self.heap[key_h].as_addr(key_h))) + ); - pub(super) - fn tidy_trail(&mut self) { - if self.b == 0 { - return; - } + let value_addr = self.heap[value_h].as_addr(value_h); - let b = self.b; - let hb = self.hb; - let mut offset = 0; - - for i in self.stack.index_or_frame(b).prelude.tr .. self.tr { - match self.trail[i] { - TrailRef::Ref(Ref::AttrVar(tr_i)) - | TrailRef::Ref(Ref::HeapCell(tr_i)) - | TrailRef::AttrVarHeapLink(tr_i) - | TrailRef::AttrVarListLink(tr_i, _) => { - if tr_i >= hb { - offset += 1; - } else { - self.trail[i - offset] = self.trail[i]; + match global_variables.get_mut(&key) { + Some((_, ref mut loc)) => *loc = Some(value_addr), + None => unreachable!(), } } - TrailRef::Ref(Ref::StackCell(b, _)) => { - if b < self.b { - self.trail[i - offset] = self.trail[i]; - } else { - offset += 1; + TrailRef::BlackboardEntry(key_h) => { + let key = atom_from!( + self, + self.store(self.deref(self.heap[key_h].as_addr(key_h))) + ); + + match global_variables.get_mut(&key) { + Some((_, ref mut loc)) => *loc = None, + None => unreachable!(), } } } } - - self.tr -= offset; - self.trail.truncate(self.tr); } - pub(super) - fn match_partial_string(&mut self, addr: Addr, string: &String, has_tail: bool) { + pub(super) fn match_partial_string(&mut self, addr: Addr, string: &String, has_tail: bool) { let mut heap_pstr_iter = self.heap_pstr_iter(addr); match compare_pstr_to_string(&mut heap_pstr_iter, string) { @@ -809,81 +794,64 @@ impl MachineState { } } } - Some(prefix_len) => { - match heap_pstr_iter.focus() { - addr if addr.is_ref() => { - let h = self.heap.h(); + Some(prefix_len) => match heap_pstr_iter.focus() { + addr if addr.is_ref() => { + let h = self.heap.h(); - let pstr_addr = - if has_tail { - self.s = HeapPtr::HeapCell(h+1); - self.mode = MachineMode::Read; + let pstr_addr = if has_tail { + self.s = HeapPtr::HeapCell(h + 1); + self.mode = MachineMode::Read; - self.heap.allocate_pstr(&string[prefix_len ..]) - } else { - self.heap.put_complete_string(&string[prefix_len ..]) - }; + self.heap.allocate_pstr(&string[prefix_len..]) + } else { + self.heap.put_complete_string(&string[prefix_len..]) + }; - self.bind(addr.as_var().unwrap(), pstr_addr); - } - Addr::Lis(l) => { - let h = self.heap.h(); - - let pstr_addr = - if has_tail { - self.s = HeapPtr::HeapCell(h+1); - self.mode = MachineMode::Read; - - self.heap.allocate_pstr(&string[prefix_len ..]) - } else { - self.heap.put_complete_string(&string[prefix_len ..]) - }; - - self.unify(Addr::Lis(l), pstr_addr); - } - _ => { - self.fail = true; - } + self.bind(addr.as_var().unwrap(), pstr_addr); } - } + Addr::Lis(l) => { + let h = self.heap.h(); + + let pstr_addr = if has_tail { + self.s = HeapPtr::HeapCell(h + 1); + self.mode = MachineMode::Read; + + self.heap.allocate_pstr(&string[prefix_len..]) + } else { + self.heap.put_complete_string(&string[prefix_len..]) + }; + + (self.unify_fn)(self, Addr::Lis(l), pstr_addr); + } + _ => { + self.fail = true; + } + }, None => { self.fail = true; } } } - pub(super) - fn write_constant_to_var(&mut self, addr: Addr, c: &Constant) { + pub(super) fn write_constant_to_var(&mut self, addr: Addr, c: &Constant) { match self.store(self.deref(addr)) { Addr::Con(c1) => { match &self.heap[c1] { HeapCellValue::Atom(ref n1, _) => { self.fail = match c { - Constant::Atom(ref n2, _) => { - n1 != n2 - } + Constant::Atom(ref n2, _) => n1 != n2, Constant::Char(c) if n1.is_char() => { Some(*c) != n1.as_str().chars().next() } - _ => { - true - } + _ => true, }; } HeapCellValue::Integer(ref n1) => { self.fail = match c { - Constant::Fixnum(n2) => { - n1.to_isize() != Some(*n2) - } - Constant::Integer(ref n2) => { - n1 != n2 - } - Constant::Usize(n2) => { - n1.to_usize() != Some(*n2) - } - _ => { - true - } + Constant::Fixnum(n2) => n1.to_isize() != Some(*n2), + Constant::Integer(ref n2) => n1 != n2, + Constant::Usize(n2) => n1.to_usize() != Some(*n2), + _ => true, }; } HeapCellValue::Rational(ref r1) => { @@ -895,11 +863,7 @@ impl MachineState { } HeapCellValue::PartialString(..) => { if let Constant::String(ref s2) = c { - self.match_partial_string( - Addr::PStrLocation(c1, 0), - &s2, - false, - ); + self.match_partial_string(Addr::PStrLocation(c1, 0), &s2, false); } else { self.fail = true; } @@ -914,12 +878,8 @@ impl MachineState { Constant::Atom(ref n2, _) if n2.is_char() => { Some(ch) != n2.as_str().chars().next() } - Constant::Char(c) => { - *c != ch - } - _ => { - true - } + Constant::Char(c) => *c != ch, + _ => true, }; } Addr::EmptyList => { @@ -934,11 +894,7 @@ impl MachineState { } Addr::PStrLocation(h, n) => { if let Constant::String(ref s2) = c { - self.match_partial_string( - Addr::PStrLocation(h, n), - &s2, - false, - ) + self.match_partial_string(Addr::PStrLocation(h, n), &s2, false) } else { self.fail = true; }; @@ -958,8 +914,7 @@ impl MachineState { }; } - pub(super) - fn execute_arith_instr(&mut self, instr: &ArithmeticInstruction) { + pub(super) fn execute_arith_instr(&mut self, instr: &ArithmeticInstruction) { let stub = MachineError::functor_stub(clause_name!("is"), 2); match instr { @@ -1023,7 +978,7 @@ impl MachineState { let stub = MachineError::functor_stub(clause_name!("(rdiv)"), 2); let (r1, stub) = try_or_fail!(self, self.get_rational(a1, stub)); - let (r2, _) = try_or_fail!(self, self.get_rational(a2, stub)); + let (r2, _) = try_or_fail!(self, self.get_rational(a2, stub)); self.interms[t - 1] = Number::Rational(Rc::new(try_or_fail!(self, self.rdiv(r1, r2)))); @@ -1229,8 +1184,7 @@ impl MachineState { }; } - pub(super) - fn execute_fact_instr(&mut self, instr: &FactInstruction) { + pub(super) fn execute_fact_instr(&mut self, instr: &FactInstruction) { match instr { &FactInstruction::GetConstant(_, ref c, reg) => { let addr = self[reg]; @@ -1244,9 +1198,9 @@ impl MachineState { self.s = HeapPtr::PStrChar(h, n); self.mode = MachineMode::Read; } - addr @ Addr::AttrVar(_) | - addr @ Addr::StackCell(..) | - addr @ Addr::HeapCell(_) => { + addr @ Addr::AttrVar(_) + | addr @ Addr::StackCell(..) + | addr @ Addr::HeapCell(_) => { let h = self.heap.h(); self.heap.push(HeapCellValue::Addr(Addr::Lis(h + 1))); @@ -1305,7 +1259,7 @@ impl MachineState { let norm_addr = self[norm]; let reg_addr = self.registers[arg]; - self.unify(norm_addr, reg_addr); + (self.unify_fn)(self, norm_addr, reg_addr); } &FactInstruction::UnifyConstant(ref c) => { match self.mode { @@ -1343,26 +1297,24 @@ impl MachineState { MachineMode::Read => { let reg_addr = self[reg]; - self.unify(reg_addr, self.s.read(&self.heap)); + (self.unify_fn)(self, reg_addr, self.s.read(&self.heap)); self.increment_s_ptr(1); } MachineMode::Write => { - let addr = self.deref(self[reg]); + let addr = self.store(self.deref(self[reg])); let h = self.heap.h(); if let Addr::HeapCell(hc) = addr { - if hc < h { - let val = self.heap.clone(hc); + let val = self.heap.clone(hc); - self.heap.push(val); - self.increment_s_ptr(1); + self.heap.push(val); + self.increment_s_ptr(1); - return; - } + return; } self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); - self.bind(Ref::HeapCell(h), addr); + (self.bind_fn)(self, Ref::HeapCell(h), addr); } }; } @@ -1371,7 +1323,7 @@ impl MachineState { MachineMode::Read => { let reg_addr = self[reg]; - self.unify(reg_addr, self.s.read(&self.heap)); + (self.unify_fn)(self, reg_addr, self.s.read(&self.heap)); self.increment_s_ptr(1); } MachineMode::Write => { @@ -1397,88 +1349,197 @@ impl MachineState { }; } - pub(super) - fn execute_indexing_instr(&mut self, instr: &IndexingInstruction) { - match instr { - &IndexingInstruction::SwitchOnTerm(arg, v, c, l, s) => { - let addr = self[temp_v!(arg)]; - let addr = self.store(self.deref(addr)); - - let offset = match addr { - Addr::Stream(_) | Addr::TcpListener(_) => { - 0 - } - Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(..) => { - v - } - Addr::PStrLocation(..) => { - l - } - Addr::Char(_) | Addr::Con(_) | Addr::CutPoint(_) | - Addr::EmptyList | Addr::Fixnum(_) | Addr::Float(_) | Addr::Usize(_) => { - c - } - Addr::Lis(_) => { - l - } - Addr::Str(_) => { - s - } - }; - - match offset { - 0 => self.fail = true, - o => self.p += o, - }; + pub(super) fn execute_indexing_instr( + &mut self, + indexing_lines: &Vec, + code_repo: &CodeRepo, + ) { + fn dynamic_external_of_clause_is_valid( + machine_st: &mut MachineState, + code: &Code, + p: usize, + ) -> bool { + match &code[p] { + Line::Choice(ChoiceInstruction::DynamicInternalElse(..)) => { + machine_st.dynamic_mode = FirstOrNext::First; + return true; + } + _ => {} } - &IndexingInstruction::SwitchOnConstant(arg, _, ref hm) => { - let addr = self[temp_v!(arg)]; - let addr = self.store(self.deref(addr)); - let offset = - match addr.as_constant_index(&self) { - Some(c) => { - match hm.get(&c) { - Some(offset) => *offset, - _ => 0, - } - } - None => { - 0 - } - }; - - match offset { - 0 => self.fail = true, - o => self.p += o, - }; + match &code[p-1] { + &Line::Choice(ChoiceInstruction::DynamicInternalElse(birth, death, _)) => { + if birth < machine_st.cc && Death::Finite(machine_st.cc) <= death { + return true; + } else { + return false; + } + } + _ => {} } - &IndexingInstruction::SwitchOnStructure(arg, _, ref hm) => { - let a1 = self.registers[arg]; - let addr = self.store(self.deref(a1)); - let offset = match addr { - Addr::Str(s) => { - if let &HeapCellValue::NamedStr(arity, ref name, _) = &self.heap[s] { - match hm.get(&(name.clone(), arity)) { - Some(offset) => *offset, - _ => 0, - } - } else { - 0 - } - } - _ => { - 0 - } - }; + true + } - match offset { - 0 => self.fail = true, - o => self.p += o, - }; + let mut index = 0; + let addr = match &indexing_lines[0] { + &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(arg, ..)) => { + self.store(self.deref(self[temp_v!(arg)])) + } + _ => { + unreachable!() } }; + + loop { + match &indexing_lines[index] { + &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, c, l, s)) => { + let offset = match addr { + Addr::LoadStatePayload(_) | Addr::Stream(_) | Addr::TcpListener(_) => { + IndexingCodePtr::Fail + } + Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(..) => { + v + } + Addr::PStrLocation(..) => l, + Addr::Char(_) + | Addr::Con(_) + | Addr::CutPoint(_) + | Addr::EmptyList + | Addr::Fixnum(_) + | Addr::Float(_) + | Addr::Usize(_) => c, + Addr::Lis(_) => l, + Addr::Str(_) => s, + }; + + match offset { + IndexingCodePtr::Fail => { + self.fail = true; + break; + } + IndexingCodePtr::DynamicExternal(o) => { + // either points directly to a + // DynamicInternalElse, or just ahead of + // one. Or neither! + let p = self.p.local().abs_loc(); + + if !dynamic_external_of_clause_is_valid(self, &code_repo.code, p + o) { + self.fail = true; + } else { + self.p += o; + } + + break; + } + IndexingCodePtr::External(o) => { + self.p += o; + break; + } + IndexingCodePtr::Internal(o) => { + index += o; + } + }; + } + &IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref hm)) => { + let offset = match addr.as_constant_index(&self) { + Some(c) => match hm.get(&c) { + Some(offset) => *offset, + _ => IndexingCodePtr::Fail, + }, + None => IndexingCodePtr::Fail, + }; + + match offset { + IndexingCodePtr::Fail => { + self.fail = true; + break; + } + IndexingCodePtr::DynamicExternal(o) => { + // either points directly to a + // DynamicInternalElse, or just ahead of + // one. Or neither! + let p = self.p.local().abs_loc(); + + if !dynamic_external_of_clause_is_valid(self, &code_repo.code, p + o) { + self.fail = true; + } else { + self.p += o; + } + + break; + } + IndexingCodePtr::External(o) => { + self.p += o; + break; + } + IndexingCodePtr::Internal(o) => { + index += o; + } + }; + } + &IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref hm)) => { + let offset = match addr { + Addr::Str(s) => { + if let &HeapCellValue::NamedStr(arity, ref name, _) = &self.heap[s] { + match hm.get(&(name.clone(), arity)) { + Some(offset) => *offset, + _ => IndexingCodePtr::Fail, + } + } else { + IndexingCodePtr::Fail + } + } + _ => IndexingCodePtr::Fail, + }; + + match offset { + IndexingCodePtr::Fail => { + self.fail = true; + break; + } + IndexingCodePtr::DynamicExternal(o) => { + let p = self.p.local().abs_loc(); + + if !dynamic_external_of_clause_is_valid(self, &code_repo.code, p + o) { + self.fail = true; + } else { + self.p += o; + } + + break; + } + IndexingCodePtr::External(o) => { + self.p += o; + break; + } + IndexingCodePtr::Internal(o) => { + index += o; + } + } + } + &IndexingLine::IndexedChoice(_) => { + if let LocalCodePtr::DirEntry(p) = self.p.local() { + self.p = CodePtr::Local(LocalCodePtr::IndexingBuf(p, index, 0)); + } else { + unreachable!() + } + + break; + } + &IndexingLine::DynamicIndexedChoice(_) => { + self.dynamic_mode = FirstOrNext::First; + + if let LocalCodePtr::DirEntry(p) = self.p.local() { + self.p = CodePtr::Local(LocalCodePtr::IndexingBuf(p, index, 0)); + } else { + unreachable!() + } + + break; + } + } + } } pub(super) fn execute_query_instr(&mut self, instr: &QueryInstruction) { @@ -1493,25 +1554,25 @@ impl MachineState { self[reg] = Addr::Lis(self.heap.h()); } &QueryInstruction::PutPartialString(_, ref string, reg, has_tail) => { - let pstr_addr = - if has_tail { - if !string.is_empty() { - let pstr_addr = self.heap.allocate_pstr(&string); - self.heap.pop(); // the tail will be added by the next instruction. - pstr_addr - } else { - Addr::EmptyList - } + let pstr_addr = if has_tail { + if !string.is_empty() { + let pstr_addr = self.heap.allocate_pstr(&string); + self.heap.pop(); // the tail will be added by the next instruction. + pstr_addr } else { - self.heap.put_complete_string(&string) - }; + Addr::EmptyList + } + } else { + self.heap.put_complete_string(&string) + }; self[reg] = pstr_addr; } &QueryInstruction::PutStructure(ref ct, arity, reg) => { let h = self.heap.h(); - self.heap.push(HeapCellValue::NamedStr(arity, ct.name(), ct.spec())); + self.heap + .push(HeapCellValue::NamedStr(arity, ct.name(), ct.spec())); self[reg] = Addr::Str(h); } &QueryInstruction::PutUnsafeValue(n, arg) => { @@ -1524,7 +1585,7 @@ impl MachineState { let h = self.heap.h(); self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); - self.bind(Ref::HeapCell(h), addr); + (self.bind_fn)(self, Ref::HeapCell(h), addr); self.registers[arg] = self.heap[h].as_addr(h); } @@ -1566,7 +1627,7 @@ impl MachineState { } self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); - self.bind(Ref::HeapCell(h), addr); + (self.bind_fn)(self, Ref::HeapCell(h), addr); } &QueryInstruction::SetVariable(reg) => { let h = self.heap.h(); @@ -1580,7 +1641,7 @@ impl MachineState { &QueryInstruction::SetVoid(n) => { let h = self.heap.h(); - for i in h .. h + n { + for i in h..h + n { self.heap.push(HeapCellValue::Addr(Addr::HeapCell(i))); } } @@ -1600,8 +1661,7 @@ impl MachineState { ); } - pub(super) - fn handle_internal_call_n(&mut self, arity: usize) { + pub(super) fn handle_internal_call_n(&mut self, arity: usize) { let arity = arity + 1; let pred = self.registers[1]; @@ -1617,8 +1677,7 @@ impl MachineState { self.fail = true; } - pub(super) - fn setup_call_n(&mut self, arity: usize) -> Option { + pub(super) fn setup_call_n(&mut self, arity: usize) -> Option { let addr = self.store(self.deref(self.registers[arity])); let (name, narity) = match addr { @@ -1638,11 +1697,11 @@ impl MachineState { return None; } - for i in (1 .. arity).rev() { + for i in (1..arity).rev() { self.registers[i + narity] = self.registers[i]; } - for i in 1 .. narity + 1 { + for i in 1..narity + 1 { self.registers[i] = self.heap[a + i].as_addr(a + i); } @@ -1652,22 +1711,17 @@ impl MachineState { return None; } } - Addr::Con(h) => - match &self.heap[h] { - HeapCellValue::Atom(ref name, _) => { - (name.clone(), 0) - } - _ => { - self.fail = true; - return None; - } + Addr::Con(h) => match &self.heap[h] { + HeapCellValue::Atom(ref name, _) => (name.clone(), 0), + _ => { + self.fail = true; + return None; } + }, Addr::HeapCell(_) | Addr::StackCell(_, _) => { let stub = MachineError::functor_stub(clause_name!("call"), arity + 1); - let instantiation_error = self.error_form( - MachineError::instantiation_error(), - stub, - ); + let instantiation_error = + self.error_form(MachineError::instantiation_error(), stub); self.throw_exception(instantiation_error); return None; @@ -1697,13 +1751,22 @@ impl MachineState { let mut fail = false; let mut iter = self.pre_order_iter(addr); + let is_composite = |addr: &Addr| match *addr { + Addr::Str(_) | Addr::Lis(_) | Addr::PStrLocation(..) => true, + _ => false, + }; + loop { if let Some(addr) = iter.stack().last() { - if !seen.contains(addr) { - seen.insert(*addr); + if is_composite(addr) { + if !seen.contains(addr) { + seen.insert(*addr); + } else { + fail = true; + break; + } } else { - fail = true; - break; + iter.stack().pop(); } } @@ -1716,63 +1779,56 @@ impl MachineState { } // arg(+N, +Term, ?Arg) - pub(super) - fn try_arg(&mut self) -> CallResult { + pub(super) fn try_arg(&mut self) -> CallResult { let stub = MachineError::functor_stub(clause_name!("arg"), 3); let n = self.store(self.deref(self[temp_v!(1)])); match n { - Addr::HeapCell(_) | Addr::StackCell(..) => { // 8.5.2.3 a) - return Err(self.error_form(MachineError::instantiation_error(), stub)) + Addr::HeapCell(_) | Addr::StackCell(..) => { + // 8.5.2.3 a) + return Err(self.error_form(MachineError::instantiation_error(), stub)); } addr => { - let n = - match Number::try_from((addr, &self.heap)) { - Ok(Number::Fixnum(n)) => Integer::from(n), - Ok(Number::Integer(n)) => Integer::from(n.as_ref()), - _ => { - return Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - addr, - ), - stub, - )); - } - }; + let n = match Number::try_from((addr, &self.heap)) { + Ok(Number::Fixnum(n)) => Integer::from(n), + Ok(Number::Integer(n)) => Integer::from(n.as_ref()), + _ => { + return Err(self.error_form( + MachineError::type_error(self.heap.h(), ValidType::Integer, addr), + stub, + )); + } + }; - if n < 0 { // 8.5.2.3 e) + if n < 0 { + // 8.5.2.3 e) let n = Number::from(n); - let dom_err = MachineError::domain_error( - DomainErrorType::NotLessThanZero, - n, - ); + let dom_err = MachineError::domain_error(DomainErrorType::NotLessThanZero, n); return Err(self.error_form(dom_err, stub)); } - let n = - match n.to_usize() { - Some(n) => n, - None => { - self.fail = true; - return Ok(()); - } - }; + let n = match n.to_usize() { + Some(n) => n, + None => { + self.fail = true; + return Ok(()); + } + }; let term = self.store(self.deref(self[temp_v!(2)])); match term { - Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(_) => { // 8.5.2.3 b) - return Err(self.error_form(MachineError::instantiation_error(), stub)) + Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(_) => { + // 8.5.2.3 b) + return Err(self.error_form(MachineError::instantiation_error(), stub)); } Addr::Str(o) => match self.heap.clone(o) { HeapCellValue::NamedStr(arity, _, _) if 1 <= n && n <= arity => { let a3 = self[temp_v!(3)]; let h_a = Addr::HeapCell(o + n); - self.unify(a3, h_a); + (self.unify_fn)(self, a3, h_a); } _ => { self.fail = true; @@ -1783,7 +1839,7 @@ impl MachineState { let a3 = self[temp_v!(3)]; let h_a = Addr::HeapCell(l + n - 1); - self.unify(a3, h_a); + (self.unify_fn)(self, a3, h_a); } else { self.fail = true; } @@ -1793,7 +1849,7 @@ impl MachineState { let a3 = self[temp_v!(3)]; let h_a = if let HeapCellValue::PartialString(ref pstr, _) = &self.heap[h] { - if let Some(c) = pstr.range_from(offset ..).next() { + if let Some(c) = pstr.range_from(offset..).next() { if n == 1 { Addr::Char(c) } else { @@ -1806,20 +1862,17 @@ impl MachineState { unreachable!() }; - self.unify(a3, h_a); + (self.unify_fn)(self, a3, h_a); } else { self.fail = true; } } - _ => { // 8.5.2.3 d) + _ => { + // 8.5.2.3 d) return Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Compound, - term, - ), + MachineError::type_error(self.heap.h(), ValidType::Compound, term), stub, - )) + )); } } } @@ -1844,8 +1897,7 @@ impl MachineState { self.p += 1; } - pub(super) - fn compare_term(&mut self, qt: CompareTermQT) { + pub(super) fn compare_term(&mut self, qt: CompareTermQT) { let a1 = self[temp_v!(1)]; let a2 = self[temp_v!(2)]; @@ -1869,8 +1921,7 @@ impl MachineState { } // returns true on failure. - pub(super) - fn eq_test(&self, a1: Addr, a2: Addr) -> bool { + pub(super) fn eq_test(&self, a1: Addr, a2: Addr) -> bool { let mut iter = self.zipped_acyclic_pre_order_iter(a1, a2); while let Some((v1, v2)) = iter.next() { @@ -1888,8 +1939,7 @@ impl MachineState { unreachable!() } } - (Addr::PStrLocation(..), Addr::Lis(_)) | - (Addr::Lis(_), Addr::PStrLocation(..)) => { + (Addr::PStrLocation(..), Addr::Lis(_)) | (Addr::Lis(_), Addr::PStrLocation(..)) => { continue; } (pstr1 @ Addr::PStrLocation(..), pstr2 @ Addr::PStrLocation(..)) => { @@ -1918,40 +1968,32 @@ impl MachineState { (Addr::Lis(_), Addr::Lis(_)) => { continue; } - (Addr::Con(h1), Addr::Con(h2)) => { - match (&self.heap[h1], &self.heap[h2]) { - ( - &HeapCellValue::Atom(ref n1, ref spec_1), - &HeapCellValue::Atom(ref n2, ref spec_2), - ) => { - if n1 != n2 || spec_1 != spec_2 { - return true; - } - } - ( - &HeapCellValue::DBRef(ref db_ref_1), - &HeapCellValue::DBRef(ref db_ref_2), - ) => { - if db_ref_1 != db_ref_2 { - return true; - } - } - ( - v1, - v2, - ) => { - if let Ok(n1) = Number::try_from(v1) { - if let Ok(n2) = Number::try_from(v2) { - if n1 == n2 { - continue; - } - } - } - + (Addr::Con(h1), Addr::Con(h2)) => match (&self.heap[h1], &self.heap[h2]) { + ( + &HeapCellValue::Atom(ref n1, ref spec_1), + &HeapCellValue::Atom(ref n2, ref spec_2), + ) => { + if n1 != n2 || spec_1 != spec_2 { return true; } } - } + (&HeapCellValue::DBRef(ref db_ref_1), &HeapCellValue::DBRef(ref db_ref_2)) => { + if db_ref_1 != db_ref_2 { + return true; + } + } + (v1, v2) => { + if let Ok(n1) = Number::try_from(v1) { + if let Ok(n2) = Number::try_from(v2) { + if n1 == n2 { + continue; + } + } + } + + return true; + } + }, (Addr::Con(h), Addr::Char(c)) | (Addr::Char(c), Addr::Con(h)) => { match &self.heap[h] { &HeapCellValue::Atom(ref name, _) if name.is_char() => { @@ -1986,8 +2028,7 @@ impl MachineState { iter.first_to_expire != Ordering::Equal } - pub(super) - fn compare_term_test(&self, a1: &Addr, a2: &Addr) -> Option { + pub(super) fn compare_term_test(&self, a1: &Addr, a2: &Addr) -> Option { let mut iter = self.zipped_acyclic_pre_order_iter(*a1, *a2); while let Some((v1, v2)) = iter.next() { @@ -2018,294 +2059,224 @@ impl MachineState { unreachable!() } } - Some(TermOrderCategory::Integer) => { - match (v1, v2) { - ( - Addr::Con(h1), - Addr::Con(h2), - ) => { - if let Ok(n1) = Number::try_from(&self.heap[h1]) { - if let Ok(n2) = Number::try_from(&self.heap[h2]) { - if n1 != n2 { - return Some(n1.cmp(&n2)); - } - } else { - unreachable!() - } - } else { - unreachable!() - } - } - ( - Addr::Con(h1), - v2, - ) => { - if let Ok(n1) = Number::try_from(&self.heap[h1]) { - if let Ok(n2) = Number::try_from(&HeapCellValue::Addr(v2)) { - if n1 != n2 { - return Some(n1.cmp(&n2)); - } - } else { - unreachable!() - } - } else { - unreachable!() - } - } - ( - v1, - Addr::Con(h2), - ) => { - if let Ok(n1) = Number::try_from(&HeapCellValue::Addr(v1)) { - if let Ok(n2) = Number::try_from(&self.heap[h2]) { - if n1 != n2 { - return Some(n1.cmp(&n2)); - } - } else { - unreachable!() - } - } else { - unreachable!() - } - } - (v1, v2) => { - if let Ok(n1) = Number::try_from(&HeapCellValue::Addr(v1)) { - if let Ok(n2) = Number::try_from(&HeapCellValue::Addr(v2)) { - if n1 != n2 { - return Some(n1.cmp(&n2)); - } - } else { - unreachable!() + Some(TermOrderCategory::Integer) => match (v1, v2) { + (Addr::Con(h1), Addr::Con(h2)) => { + if let Ok(n1) = Number::try_from(&self.heap[h1]) { + if let Ok(n2) = Number::try_from(&self.heap[h2]) { + if n1 != n2 { + return Some(n1.cmp(&n2)); } } else { unreachable!() } + } else { + unreachable!() } } - } - Some(TermOrderCategory::Atom) => { - match (v1, v2) { - ( - Addr::Con(h1), - Addr::Con(h2), - ) => { - if let HeapCellValue::Atom(ref n1, _) = &self.heap[h1] { - if let HeapCellValue::Atom(ref n2, _) = &self.heap[h2] { - if n1 != n2 { - return Some(n1.cmp(&n2)); - } - } else { - unreachable!() + (Addr::Con(h1), v2) => { + if let Ok(n1) = Number::try_from(&self.heap[h1]) { + if let Ok(n2) = Number::try_from(&HeapCellValue::Addr(v2)) { + if n1 != n2 { + return Some(n1.cmp(&n2)); } } else { unreachable!() } - } - ( - Addr::Con(h1), - Addr::Char(c), - ) => { - if let HeapCellValue::Atom(ref n1, _) = &self.heap[h1] { - if n1.is_char() { - if n1.as_str().chars().next() != Some(c) { - return Some(n1.as_str().chars().next().cmp(&Some(c))); - } - } else { - return Some(Ordering::Greater); - } - } else { - unreachable!() - } - } - ( - Addr::Char(c), - Addr::Con(h1), - ) => { - if let HeapCellValue::Atom(ref n1, _) = &self.heap[h1] { - if n1.is_char() { - if n1.as_str().chars().next() != Some(c) { - return Some(Some(c).cmp(&n1.as_str().chars().next())); - } - } else { - return Some(Ordering::Less); - } - } else { - unreachable!() - } - } - ( - Addr::EmptyList, - Addr::Con(h), - ) => { - if let HeapCellValue::Atom(ref n1, _) = &self.heap[h] { - if "[]" != n1.as_str() { - return Some("[]".cmp(n1.as_str())); - } - } else { - unreachable!() - } - } - ( - Addr::Con(h), - Addr::EmptyList, - ) => { - if let HeapCellValue::Atom(ref n1, _) = &self.heap[h] { - if "[]" != n1.as_str() { - return Some(n1.as_str().cmp("[]")); - } - } else { - unreachable!() - } - } - ( - Addr::Char(c1), - Addr::Char(c2), - ) => { - if c1 != c2 { - return Some(c1.cmp(&c2)); - } - } - ( - Addr::Char(c), - Addr::EmptyList, - ) => { - return if c == '[' { - Some(Ordering::Less) - } else { - Some(c.cmp(&'[')) - }; - } - ( - Addr::EmptyList, - Addr::Char(c), - ) => { - return if c == '[' { - Some(Ordering::Greater) - } else { - Some('['.cmp(&c)) - }; - } - ( - Addr::EmptyList, - Addr::EmptyList, - ) => { - } - _ => { - return None; + } else { + unreachable!() } } - } - Some(TermOrderCategory::Compound) => { - match (v1, v2) { - ( - Addr::Lis(_), - Addr::Lis(_), - ) => { - } - ( - pstr1 @ Addr::PStrLocation(..), - pstr2 @ Addr::PStrLocation(..), - ) => { - let mut i1 = self.heap_pstr_iter(pstr1); - let mut i2 = self.heap_pstr_iter(pstr2); - - let ordering = compare_pstr_prefixes(&mut i1, &mut i2); - - if let Some(ordering) = ordering { - if ordering != Ordering::Equal { - return Some(ordering); - } - } else { - let (lstack, rstack) = iter.stack(); - - lstack.pop(); - lstack.pop(); - - rstack.pop(); - rstack.pop(); - - lstack.push(i1.focus()); - rstack.push(i2.focus()); - } - } - ( - Addr::Str(h1), - Addr::Str(h2), - ) => { - if let HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[h1] { - if let HeapCellValue::NamedStr(a2, ref n2, _) = &self.heap[h2] { - if a1 != a2 || n1.as_str() != n2.as_str() { - return Some(a1.cmp(&a2).then_with(|| n1.as_str().cmp(n2.as_str()))); - } - } else { - unreachable!() + (v1, Addr::Con(h2)) => { + if let Ok(n1) = Number::try_from(&HeapCellValue::Addr(v1)) { + if let Ok(n2) = Number::try_from(&self.heap[h2]) { + if n1 != n2 { + return Some(n1.cmp(&n2)); } } else { unreachable!() } - } - ( - Addr::Lis(_), - Addr::PStrLocation(..), - ) | - ( - Addr::PStrLocation(..), - Addr::Lis(_), - ) => { - } - ( - Addr::Lis(_), - Addr::Str(s), - ) => { - if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] { - if a1 != 2 || n1.as_str() != "." { - return Some(a1.cmp(&2).then_with(|| n1.as_str().cmp("."))); - } - } else { - unreachable!() - } - } - ( - Addr::Str(s), - Addr::Lis(_), - ) => { - if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] { - if a1 != 2 || n1.as_str() != "." { - return Some(2.cmp(&a1).then_with(|| ".".cmp(n1.as_str()))); - } - } else { - unreachable!() - } - } - ( - Addr::PStrLocation(..), - Addr::Str(s), - ) => { - if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] { - if a1 != 2 || n1.as_str() != "." { - return Some(a1.cmp(&2).then_with(|| n1.as_str().cmp("."))); - } - } else { - unreachable!() - } - } - ( - Addr::Str(s), - Addr::PStrLocation(..), - ) => { - if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] { - if a1 != 2 || n1.as_str() != "." { - return Some(2.cmp(&a1).then_with(|| ".".cmp(n1.as_str()))); - } - } else { - unreachable!() - } - } - _ => { - return None; + } else { + unreachable!() } } - } + (v1, v2) => { + if let Ok(n1) = Number::try_from(&HeapCellValue::Addr(v1)) { + if let Ok(n2) = Number::try_from(&HeapCellValue::Addr(v2)) { + if n1 != n2 { + return Some(n1.cmp(&n2)); + } + } else { + unreachable!() + } + } else { + unreachable!() + } + } + }, + Some(TermOrderCategory::Atom) => match (v1, v2) { + (Addr::Con(h1), Addr::Con(h2)) => { + if let HeapCellValue::Atom(ref n1, _) = &self.heap[h1] { + if let HeapCellValue::Atom(ref n2, _) = &self.heap[h2] { + if n1 != n2 { + return Some(n1.cmp(&n2)); + } + } else { + unreachable!() + } + } else { + unreachable!() + } + } + (Addr::Con(h1), Addr::Char(c)) => { + if let HeapCellValue::Atom(ref n1, _) = &self.heap[h1] { + if n1.is_char() { + if n1.as_str().chars().next() != Some(c) { + return Some(n1.as_str().chars().next().cmp(&Some(c))); + } + } else { + return Some(Ordering::Greater); + } + } else { + unreachable!() + } + } + (Addr::Char(c), Addr::Con(h1)) => { + if let HeapCellValue::Atom(ref n1, _) = &self.heap[h1] { + if n1.is_char() { + if n1.as_str().chars().next() != Some(c) { + return Some(Some(c).cmp(&n1.as_str().chars().next())); + } + } else { + return Some(Ordering::Less); + } + } else { + unreachable!() + } + } + (Addr::EmptyList, Addr::Con(h)) => { + if let HeapCellValue::Atom(ref n1, _) = &self.heap[h] { + if "[]" != n1.as_str() { + return Some("[]".cmp(n1.as_str())); + } + } else { + unreachable!() + } + } + (Addr::Con(h), Addr::EmptyList) => { + if let HeapCellValue::Atom(ref n1, _) = &self.heap[h] { + if "[]" != n1.as_str() { + return Some(n1.as_str().cmp("[]")); + } + } else { + unreachable!() + } + } + (Addr::Char(c1), Addr::Char(c2)) => { + if c1 != c2 { + return Some(c1.cmp(&c2)); + } + } + (Addr::Char(c), Addr::EmptyList) => { + return if c == '[' { + Some(Ordering::Less) + } else { + Some(c.cmp(&'[')) + }; + } + (Addr::EmptyList, Addr::Char(c)) => { + return if c == '[' { + Some(Ordering::Greater) + } else { + Some('['.cmp(&c)) + }; + } + (Addr::EmptyList, Addr::EmptyList) => {} + _ => { + return None; + } + }, + Some(TermOrderCategory::Compound) => match (v1, v2) { + (Addr::Lis(_), Addr::Lis(_)) => {} + (pstr1 @ Addr::PStrLocation(..), pstr2 @ Addr::PStrLocation(..)) => { + let mut i1 = self.heap_pstr_iter(pstr1); + let mut i2 = self.heap_pstr_iter(pstr2); + + let ordering = compare_pstr_prefixes(&mut i1, &mut i2); + + if let Some(ordering) = ordering { + if ordering != Ordering::Equal { + return Some(ordering); + } + } else { + let (lstack, rstack) = iter.stack(); + + lstack.pop(); + lstack.pop(); + + rstack.pop(); + rstack.pop(); + + lstack.push(i1.focus()); + rstack.push(i2.focus()); + } + } + (Addr::Str(h1), Addr::Str(h2)) => { + if let HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[h1] { + if let HeapCellValue::NamedStr(a2, ref n2, _) = &self.heap[h2] { + if a1 != a2 || n1.as_str() != n2.as_str() { + return Some( + a1.cmp(&a2).then_with(|| n1.as_str().cmp(n2.as_str())), + ); + } + } else { + unreachable!() + } + } else { + unreachable!() + } + } + (Addr::Lis(_), Addr::PStrLocation(..)) + | (Addr::PStrLocation(..), Addr::Lis(_)) => {} + (Addr::Lis(_), Addr::Str(s)) => { + if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] { + if a1 != 2 || n1.as_str() != "." { + return Some(a1.cmp(&2).then_with(|| n1.as_str().cmp("."))); + } + } else { + unreachable!() + } + } + (Addr::Str(s), Addr::Lis(_)) => { + if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] { + if a1 != 2 || n1.as_str() != "." { + return Some(2.cmp(&a1).then_with(|| ".".cmp(n1.as_str()))); + } + } else { + unreachable!() + } + } + (Addr::PStrLocation(..), Addr::Str(s)) => { + if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] { + if a1 != 2 || n1.as_str() != "." { + return Some(a1.cmp(&2).then_with(|| n1.as_str().cmp("."))); + } + } else { + unreachable!() + } + } + (Addr::Str(s), Addr::PStrLocation(..)) => { + if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] { + if a1 != 2 || n1.as_str() != "." { + return Some(2.cmp(&a1).then_with(|| ".".cmp(n1.as_str()))); + } + } else { + unreachable!() + } + } + _ => { + return None; + } + }, None => { return None; } @@ -2315,16 +2286,14 @@ impl MachineState { Some(iter.first_to_expire) } - pub(super) - fn reset_block(&mut self, addr: Addr) { + pub(super) fn reset_block(&mut self, addr: Addr) { match self.store(addr) { Addr::Usize(b) => self.block = b, _ => self.fail = true, }; } - pub(super) - fn execute_inlined(&mut self, inlined: &InlinedClauseType) { + pub(super) fn execute_inlined(&mut self, inlined: &InlinedClauseType) { match inlined { &InlinedClauseType::CompareNumber(cmp, ref at_1, ref at_2) => { let n1 = try_or_fail!(self, self.get_number(at_1)); @@ -2336,12 +2305,13 @@ impl MachineState { let d = self.store(self.deref(self[r1])); match d { - Addr::Con(h) => + Addr::Con(h) => { if let HeapCellValue::Atom(..) = &self.heap[h] { self.p += 1; } else { self.fail = true; - }, + } + } Addr::Char(_) => self.p += 1, Addr::EmptyList => self.p += 1, _ => self.fail = true, @@ -2351,12 +2321,12 @@ impl MachineState { let d = self.store(self.deref(self[r1])); match d { - Addr::Char(_) | - Addr::Con(_) | - Addr::EmptyList | - Addr::Fixnum(_) | - Addr::Float(_) | - Addr::Usize(_) => self.p += 1, + Addr::Char(_) + | Addr::Con(_) + | Addr::EmptyList + | Addr::Fixnum(_) + | Addr::Float(_) + | Addr::Usize(_) => self.p += 1, _ => self.fail = true, }; } @@ -2398,29 +2368,27 @@ impl MachineState { _ => self.fail = true, }; } - &InlinedClauseType::IsNumber(r1) => { - match self.store(self.deref(self[r1])) { - Addr::Float(_) => self.p += 1, - d => match Number::try_from((d, &self.heap)) { - Ok(Number::Fixnum(_)) => { + &InlinedClauseType::IsNumber(r1) => match self.store(self.deref(self[r1])) { + Addr::Float(_) => self.p += 1, + d => match Number::try_from((d, &self.heap)) { + Ok(Number::Fixnum(_)) => { + self.p += 1; + } + Ok(Number::Integer(_)) => { + self.p += 1; + } + Ok(Number::Rational(n)) => { + if n.denom() == &1 { self.p += 1; - } - Ok(Number::Integer(_)) => { - self.p += 1; - } - Ok(Number::Rational(n)) => { - if n.denom() == &1 { - self.p += 1; - } else { - self.fail = true; - } - } - _ => { + } else { self.fail = true; } } - } - } + _ => { + self.fail = true; + } + }, + }, &InlinedClauseType::IsRational(r1) => { let d = self.store(self.deref(self[r1])); @@ -2474,18 +2442,14 @@ impl MachineState { self.try_functor_unify_components(name, arity); } - fn try_functor_unify_components( - &mut self, - name: Addr, - arity: usize, - ) { + fn try_functor_unify_components(&mut self, name: Addr, arity: usize) { let a2 = self[temp_v!(2)]; let a3 = self[temp_v!(3)]; - self.unify(a2, name); + (self.unify_fn)(self, a2, name); if !self.fail { - self.unify(a3, Addr::Usize(arity)); + (self.unify_fn)(self, a3, Addr::Usize(arity)); } } @@ -2508,20 +2472,20 @@ impl MachineState { let f_a = if name.as_str() == "." && arity == 2 { Addr::Lis(self.heap.h()) } else { - self.heap.to_unifiable(HeapCellValue::NamedStr(arity, name, spec)) + self.heap + .to_unifiable(HeapCellValue::NamedStr(arity, name, spec)) }; let h = self.heap.h(); - for i in 0 .. arity { + for i in 0..arity { self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h + i))); } - self.bind(r, f_a); + (self.bind_fn)(self, r, f_a); } - pub(super) - fn try_functor(&mut self, indices: &IndexStore) -> CallResult { + pub(super) fn try_functor(&mut self, op_dir: &OpDir) -> CallResult { let stub = MachineError::functor_stub(clause_name!("functor"), 3); let a1 = self.store(self.deref(self[temp_v!(1)])); @@ -2529,18 +2493,17 @@ impl MachineState { Addr::Stream(_) => { self.fail = true; } - Addr::Char(_) | Addr::Con(_) | Addr::Fixnum(_) | - Addr::Float(_) | Addr::EmptyList | Addr::Usize(_) => { + Addr::Char(_) + | Addr::Con(_) + | Addr::Fixnum(_) + | Addr::Float(_) + | Addr::EmptyList + | Addr::Usize(_) => { self.try_functor_unify_components(a1, 0); } Addr::Str(o) => match self.heap.clone(o) { HeapCellValue::NamedStr(arity, name, spec) => { - let spec = fetch_op_spec_from_existing( - name.clone(), - arity, - spec, - &indices.op_dir, - ); + let spec = fetch_op_spec_from_existing(name.clone(), arity, spec, &op_dir); self.try_functor_compound_case(name, arity, spec) } @@ -2549,17 +2512,12 @@ impl MachineState { } }, Addr::Lis(_) | Addr::PStrLocation(..) => { - let spec = fetch_op_spec_from_existing( - clause_name!("."), - 2, - None, - &indices.op_dir, - ); + let spec = fetch_op_spec_from_existing(clause_name!("."), 2, None, &op_dir); self.try_functor_compound_case(clause_name!("."), 2, spec) } Addr::AttrVar(..) | Addr::HeapCell(_) | Addr::StackCell(..) => { - let name = self.store(self.deref(self[temp_v!(2)])); + let name = self.store(self.deref(self[temp_v!(2)])); let arity = self.store(self.deref(self[temp_v!(3)])); if name.is_ref() || arity.is_ref() { @@ -2567,35 +2525,22 @@ impl MachineState { return Err(self.error_form(MachineError::instantiation_error(), stub)); } - let arity = - match Number::try_from((arity, &self.heap)) { - Ok(Number::Fixnum(n)) => Some(n), - Ok(Number::Integer(n)) => n.to_isize(), - Ok(Number::Rational(n)) - if n.denom() == &1 => { - n.numer().to_isize() - }, - _ => - match arity { - arity => { - return Err( - self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - arity, - ), - stub, - ) - ); - } - } - }; + let arity = match Number::try_from((arity, &self.heap)) { + Ok(Number::Fixnum(n)) => Some(n), + Ok(Number::Integer(n)) => n.to_isize(), + Ok(Number::Rational(n)) if n.denom() == &1 => n.numer().to_isize(), + _ => match arity { + arity => { + return Err(self.error_form( + MachineError::type_error(self.heap.h(), ValidType::Integer, arity), + stub, + )); + } + }, + }; let arity = match arity { - Some(arity) => { - arity - } + Some(arity) => arity, None => { self.fail = true; return Ok(()); @@ -2609,18 +2554,23 @@ impl MachineState { } else if arity < 0 { // 8.5.1.3 g) let arity = Number::Integer(Rc::new(Integer::from(arity))); - let dom_err = MachineError::domain_error( - DomainErrorType::NotLessThanZero, - arity, - ); + let dom_err = + MachineError::domain_error(DomainErrorType::NotLessThanZero, arity); return Err(self.error_form(dom_err, stub)); } match name { - Addr::Char(_) | Addr::Con(_) | Addr::Fixnum(_) | Addr::Float(_) | - Addr::EmptyList | Addr::PStrLocation(..) | Addr::Usize(_) if arity == 0 => { - self.unify(a1, name); + Addr::Char(_) + | Addr::Con(_) + | Addr::Fixnum(_) + | Addr::Float(_) + | Addr::EmptyList + | Addr::PStrLocation(..) + | Addr::Usize(_) + if arity == 0 => + { + (self.unify_fn)(self, a1, name); } Addr::Con(h) => { if let HeapCellValue::Atom(name, spec) = self.heap.clone(h) { @@ -2628,27 +2578,23 @@ impl MachineState { name, arity as usize, spec, - &indices.op_dir, + &op_dir, a1.as_var().unwrap(), ); } else { // 8.5.1.3 e) return Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Atom, - name, - ), + MachineError::type_error(self.heap.h(), ValidType::Atom, name), stub, - )) + )); } } Addr::Char(c) => { self.try_functor_fabricate_struct( - clause_name!(c.to_string(), indices.atom_tbl), + clause_name!(c.to_string(), self.atom_tbl), arity as usize, None, - &indices.op_dir, + &op_dir, a1.as_var().unwrap(), ); } @@ -2668,8 +2614,7 @@ impl MachineState { Ok(()) } - pub(super) - fn term_dedup(&self, list: &mut Vec) { + pub(super) fn term_dedup(&self, list: &mut Vec) { let mut result = vec![]; for a2 in list.iter() { @@ -2685,20 +2630,14 @@ impl MachineState { *list = result; } - - pub(super) - fn integers_to_bytevec( - &self, - r: RegType, - caller: MachineStub, - ) -> Vec { - + pub(super) fn integers_to_bytevec(&self, r: RegType, caller: MachineStub) -> Vec { let mut bytes: Vec = Vec::new(); match self.try_from_list(r, caller) { - Err(_) => { unreachable!() } + Err(_) => { + unreachable!() + } Ok(addrs) => { - for addr in addrs { let addr = self.store(self.deref(addr)); @@ -2708,20 +2647,19 @@ impl MachineState { Ok(b) => { bytes.push(b); } - Err(_) => { } + Err(_) => {} } continue; } Ok(Number::Integer(n)) => { if let Some(b) = n.to_u8() { - bytes.push(b); + bytes.push(b); } continue; } - _ => { - } + _ => {} } } } @@ -2729,9 +2667,7 @@ impl MachineState { bytes } - - pub(super) - fn try_from_list( + pub(super) fn try_from_list( &self, r: RegType, caller: MachineStub, @@ -2739,24 +2675,16 @@ impl MachineState { let a1 = self.store(self.deref(self[r])); match a1 { - Addr::Lis(l) => { - self.try_from_inner_list(vec![], l, caller, a1) - } - Addr::PStrLocation(h, n) => { - self.try_from_partial_string(vec![], h, n, caller, a1) - } + Addr::Lis(l) => self.try_from_inner_list(vec![], l, caller, a1), + Addr::PStrLocation(h, n) => self.try_from_partial_string(vec![], h, n, caller, a1), Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) => { Err(self.error_form(MachineError::instantiation_error(), caller)) } - Addr::EmptyList => { - Ok(vec![]) - } - _ => { - Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::List, a1), - caller, - )) - } + Addr::EmptyList => Ok(vec![]), + _ => Err(self.error_form( + MachineError::type_error(self.heap.h(), ValidType::List, a1), + caller, + )), } } @@ -2772,31 +2700,27 @@ impl MachineState { loop { match &self.heap[l] { - HeapCellValue::Addr(ref addr) => - match self.store(self.deref(*addr)) { - Addr::Lis(hcp) => { - result.push(self.heap[hcp].as_addr(hcp)); - l = hcp + 1; - } - Addr::PStrLocation(h, n) => { - return self.try_from_partial_string(result, h, n, caller, a1); - } - Addr::EmptyList => { - break; - } - Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) => { - return Err(self.error_form( - MachineError::instantiation_error(), - caller, - )) - } - _ => { - return Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::List, a1), - caller, - )) - } - }, + HeapCellValue::Addr(ref addr) => match self.store(self.deref(*addr)) { + Addr::Lis(hcp) => { + result.push(self.heap[hcp].as_addr(hcp)); + l = hcp + 1; + } + Addr::PStrLocation(h, n) => { + return self.try_from_partial_string(result, h, n, caller, a1); + } + Addr::EmptyList => { + break; + } + Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) => { + return Err(self.error_form(MachineError::instantiation_error(), caller)) + } + _ => { + return Err(self.error_form( + MachineError::type_error(self.heap.h(), ValidType::List, a1), + caller, + )) + } + }, _ => { return Err(self.error_form( MachineError::type_error(self.heap.h(), ValidType::List, a1), @@ -2819,7 +2743,7 @@ impl MachineState { ) -> Result, MachineStub> { loop { if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.heap[h] { - chars.extend(pstr.range_from(n ..).map(Addr::Char)); + chars.extend(pstr.range_from(n..).map(Addr::Char)); if !has_tail { return Ok(chars); @@ -2861,39 +2785,27 @@ impl MachineState { Addr::HeapCell(_) | Addr::StackCell(..) => { Err(self.error_form(MachineError::instantiation_error(), stub)) } - Addr::Str(s) => { - match self.heap.clone(s) { - HeapCellValue::NamedStr(2, ref name, Some(_)) - if *name == clause_name!("-") => { - Ok(Addr::HeapCell(s + 1)) - } - _ => { - Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Pair, - self.heap[s].as_addr(s), - ), - stub, - )) - } + Addr::Str(s) => match self.heap.clone(s) { + HeapCellValue::NamedStr(2, ref name, Some(_)) if *name == clause_name!("-") => { + Ok(Addr::HeapCell(s + 1)) } - } - a => { - Err(self.error_form( + _ => Err(self.error_form( MachineError::type_error( self.heap.h(), ValidType::Pair, - a, + self.heap[s].as_addr(s), ), stub, - )) - } + )), + }, + a => Err(self.error_form( + MachineError::type_error(self.heap.h(), ValidType::Pair, a), + stub, + )), } } - pub(super) - fn copy_term(&mut self, attr_var_policy: AttrVarPolicy) { + pub(super) fn copy_term(&mut self, attr_var_policy: AttrVarPolicy) { let old_h = self.heap.h(); let a1 = self[temp_v!(1)]; @@ -2901,12 +2813,11 @@ impl MachineState { copy_term(CopyTerm::new(self), a1, attr_var_policy); - self.unify(Addr::HeapCell(old_h), a2); + (self.unify_fn)(self, Addr::HeapCell(old_h), a2); } // returns true on failure. - pub(super) - fn structural_eq_test(&self) -> bool { + pub(super) fn structural_eq_test(&self) -> bool { let a1 = self[temp_v!(1)]; let a2 = self[temp_v!(2)]; @@ -2926,21 +2837,13 @@ impl MachineState { | ( HeapCellValue::Addr(Addr::PStrLocation(..)), HeapCellValue::Addr(Addr::Lis(_)), - ) => { - } - ( - HeapCellValue::NamedStr(ar1, n1, _), - HeapCellValue::NamedStr(ar2, n2, _), - ) => { + ) => {} + (HeapCellValue::NamedStr(ar1, n1, _), HeapCellValue::NamedStr(ar2, n2, _)) => { if ar1 != ar2 || n1 != n2 { return true; } } - ( - HeapCellValue::Addr(Addr::Lis(_)), - HeapCellValue::Addr(Addr::Lis(_)), - ) => { - } + (HeapCellValue::Addr(Addr::Lis(_)), HeapCellValue::Addr(Addr::Lis(_))) => {} ( &HeapCellValue::Addr(v1 @ Addr::HeapCell(_)), &HeapCellValue::Addr(v2 @ Addr::AttrVar(_)), @@ -2976,19 +2879,18 @@ impl MachineState { | ( &HeapCellValue::Addr(v1 @ Addr::StackCell(..)), &HeapCellValue::Addr(v2 @ Addr::HeapCell(_)), - ) => - match (var_pairs.get(&v1), var_pairs.get(&v2)) { - (Some(ref v2_p), Some(ref v1_p)) if **v1_p == v1 && **v2_p == v2 => { - continue; - } - (Some(_), _) | (_, Some(_)) => { - return true; - } - (None, None) => { - var_pairs.insert(v1, v2); - var_pairs.insert(v2, v1); - } - }, + ) => match (var_pairs.get(&v1), var_pairs.get(&v2)) { + (Some(ref v2_p), Some(ref v1_p)) if **v1_p == v1 && **v2_p == v2 => { + continue; + } + (Some(_), _) | (_, Some(_)) => { + return true; + } + (None, None) => { + var_pairs.insert(v1, v2); + var_pairs.insert(v2, v1); + } + }, ( HeapCellValue::PartialString(ref pstr1, has_tail_1), HeapCellValue::PartialString(ref pstr2, has_tail_2), @@ -2997,8 +2899,8 @@ impl MachineState { return true; } - let pstr1_iter = pstr1.range_from(0 ..); - let pstr2_iter = pstr2.range_from(0 ..); + let pstr1_iter = pstr1.range_from(0..); + let pstr2_iter = pstr2.range_from(0..); for (c1, c2) in pstr1_iter.zip(pstr2_iter) { if c1 != c2 { @@ -3009,8 +2911,7 @@ impl MachineState { ( HeapCellValue::Addr(Addr::PStrLocation(..)), HeapCellValue::Addr(Addr::PStrLocation(..)), - ) => { - } + ) => {} ( HeapCellValue::Atom(ref n1, ref spec_1), HeapCellValue::Atom(ref n2, ref spec_2), @@ -3019,18 +2920,12 @@ impl MachineState { return true; } } - ( - HeapCellValue::DBRef(ref db_ref_1), - HeapCellValue::DBRef(ref db_ref_2), - ) => { + (HeapCellValue::DBRef(ref db_ref_1), HeapCellValue::DBRef(ref db_ref_2)) => { if db_ref_1 != db_ref_2 { return true; } } - ( - v1, - v2, - ) => { + (v1, v2) => { if let Ok(n1) = Number::try_from(v1) { if let Ok(n2) = Number::try_from(v2) { if n1 != n2 { @@ -3044,10 +2939,7 @@ impl MachineState { } match (v1, v2) { - ( - HeapCellValue::Addr(a1), - HeapCellValue::Addr(a2), - ) => { + (HeapCellValue::Addr(a1), HeapCellValue::Addr(a2)) => { if a1 != a2 { return true; } @@ -3064,8 +2956,7 @@ impl MachineState { } // returns true on failure. - pub(super) - fn ground_test(&self) -> bool { + pub(super) fn ground_test(&self) -> bool { let a = self.store(self.deref(self[temp_v!(1)])); for v in self.acyclic_pre_order_iter(a) { @@ -3080,33 +2971,30 @@ impl MachineState { false } - pub(super) - fn setup_built_in_call(&mut self, ct: BuiltInClauseType) { + pub(super) fn setup_built_in_call(&mut self, ct: BuiltInClauseType) { self.num_of_args = ct.arity(); self.b0 = self.b; self.p = CodePtr::BuiltInClause(ct, self.p.local()); } - pub(super) - fn allocate(&mut self, num_cells: usize) { + pub(super) fn allocate(&mut self, num_cells: usize) { let e = self.stack.allocate_and_frame(num_cells); let and_frame = self.stack.index_and_frame_mut(e); - and_frame.prelude.e = self.e; + and_frame.prelude.e = self.e; and_frame.prelude.cp = self.cp; self.e = e; self.p += 1; } - pub(super) - fn deallocate(&mut self) { + pub(super) fn deallocate(&mut self) { let e = self.e; let frame = self.stack.index_and_frame(e); self.cp = frame.prelude.cp; - self.e = frame.prelude.e; + self.e = frame.prelude.e; if e > self.b { self.stack.truncate(e); @@ -3136,17 +3024,22 @@ impl MachineState { lco: bool, use_default_cp: bool, ) { - let interrupted = INTERRUPT.load(std::sync::atomic::Ordering::Relaxed); + let interrupted = INTERRUPT.load(std::sync::atomic::Ordering::Relaxed); - match INTERRUPT.compare_exchange(interrupted, false, std::sync::atomic::Ordering::Relaxed, std::sync::atomic::Ordering::Relaxed) { + match INTERRUPT.compare_exchange( + interrupted, + false, + std::sync::atomic::Ordering::Relaxed, + std::sync::atomic::Ordering::Relaxed, + ) { Ok(interruption) => { if interruption { self.throw_interrupt_exception(); return; } - }, - Err(_) => unreachable!() - } + } + Err(_) => unreachable!(), + } let mut default_call_policy: Box = Box::new(DefaultCallPolicy {}); @@ -3164,16 +3057,23 @@ impl MachineState { call_policy.call_builtin( self, ct, - indices, + &indices.code_dir, + &indices.op_dir, current_input_stream, current_output_stream, ) ), &ClauseType::CallN => try_or_fail!( self, - call_policy.call_n(self, arity, indices, current_input_stream, current_output_stream) + call_policy.call_n( + self, + arity, + &indices.code_dir, + &indices.op_dir, + current_input_stream, + current_output_stream, + ) ), - &ClauseType::Hook(ref hook) => try_or_fail!(self, call_policy.compile_hook(self, hook)), &ClauseType::Inlined(ref ct) => { self.execute_inlined(ct); @@ -3184,7 +3084,7 @@ impl MachineState { &ClauseType::Named(ref name, _, ref idx) | &ClauseType::Op(ref name, _, ref idx) => { try_or_fail!( self, - call_policy.context_call(self, name.clone(), arity, idx.clone(), indices) + call_policy.context_call(self, name.clone(), arity, idx) ) } &ClauseType::System(ref ct) => try_or_fail!( @@ -3204,8 +3104,7 @@ impl MachineState { self.last_call = false; } - pub(super) - fn execute_ctrl_instr( + pub(super) fn execute_ctrl_instr( &mut self, indices: &mut IndexStore, code_repo: &CodeRepo, @@ -3242,16 +3141,127 @@ impl MachineState { self.b0 = self.b; self.p += offset; } + &ControlInstruction::RevJmpBy(offset) => { + self.p -= offset; + } &ControlInstruction::Proceed => { self.p = CodePtr::Local(self.cp); } }; } + pub(super) fn execute_dynamic_indexed_choice_instr( + &mut self, + code_repo: &CodeRepo, + call_policy: &mut Box, + global_variables: &mut GlobalVarDir, + ) { + let p = self.p.local(); + + match code_repo.find_living_dynamic(p, self.cc) { + Some((offset, oi, ii, is_next_clause)) => { + self.p = CodePtr::Local(LocalCodePtr::IndexingBuf( + p.abs_loc(), oi, ii, + )); + + match self.dynamic_mode { + FirstOrNext::First if !is_next_clause => { + self.p = CodePtr::Local(LocalCodePtr::DirEntry( + p.abs_loc() + offset, + )); + } + FirstOrNext::First => { + // there's a leading DynamicElse that sets self.cc. + // self.cc = self.global_clock; + + match code_repo.find_living_dynamic( + LocalCodePtr::IndexingBuf(p.abs_loc(), oi, ii + 1), + self.cc, + ) { + Some(_) => { + self.registers[self.num_of_args + 1] = Addr::Usize(self.cc); + self.num_of_args += 1; + + self.execute_indexed_choice_instr( + &IndexedChoiceInstruction::Try(offset), + call_policy, + global_variables, + ); + + self.num_of_args -= 1; + } + None => { + self.p = CodePtr::Local(LocalCodePtr::DirEntry( + p.abs_loc() + offset, + )); + } + } + } + FirstOrNext::Next => { + let n = self + .stack + .index_or_frame(self.b) + .prelude + .univ_prelude + .num_cells; + + self.cc = match self.stack.index_or_frame(self.b)[n - 1] { + Addr::Usize(cc) => cc, + _ => unreachable!(), + }; + + if is_next_clause { + match code_repo.find_living_dynamic( + LocalCodePtr::IndexingBuf(p.abs_loc(), oi, ii + 1), + self.cc, + ) { + Some(_) => { + try_or_fail!( + self, + call_policy.retry( + self, + offset, + global_variables, + ) + ) + } + None => { + try_or_fail!( + self, + call_policy.trust( + self, + offset, + global_variables, + ) + ) + } + } + } else { + try_or_fail!( + self, + call_policy.trust( + self, + offset, + global_variables, + ) + ) + } + } + } + + self.dynamic_mode = FirstOrNext::Next; + } + None => { + self.fail = true; + } + } + } + pub(super) fn execute_indexed_choice_instr( &mut self, instr: &IndexedChoiceInstruction, call_policy: &mut Box, + global_variables: &mut GlobalVarDir, ) { match instr { &IndexedChoiceInstruction::Try(offset) => { @@ -3265,28 +3275,26 @@ impl MachineState { or_frame.prelude.b = self.b; or_frame.prelude.bp = self.p.local() + 1; or_frame.prelude.tr = self.tr; - or_frame.prelude.h = self.heap.h(); + or_frame.prelude.h = self.heap.h(); or_frame.prelude.b0 = self.b0; - or_frame.prelude.attr_var_init_queue_b = - self.attr_var_init.attr_var_queue.len(); - or_frame.prelude.attr_var_init_bindings_b = - self.attr_var_init.bindings.len(); + or_frame.prelude.attr_var_init_queue_b = self.attr_var_init.attr_var_queue.len(); + or_frame.prelude.attr_var_init_bindings_b = self.attr_var_init.bindings.len(); self.b = b; - for i in 1 .. n + 1 { - self.stack.index_or_frame_mut(b)[i-1] = self.registers[i]; + for i in 1..n + 1 { + self.stack.index_or_frame_mut(b)[i - 1] = self.registers[i]; } self.hb = self.heap.h(); - self.p += offset; + self.p = CodePtr::Local(dir_entry!(self.p.local().abs_loc() + offset)); } &IndexedChoiceInstruction::Retry(l) => { - try_or_fail!(self, call_policy.retry(self, l)); + try_or_fail!(self, call_policy.retry(self, l, global_variables)); } &IndexedChoiceInstruction::Trust(l) => { - try_or_fail!(self, call_policy.trust(self, l)); + try_or_fail!(self, call_policy.trust(self, l, global_variables)); } }; } @@ -3294,9 +3302,187 @@ impl MachineState { pub(super) fn execute_choice_instr( &mut self, instr: &ChoiceInstruction, + code_repo: &CodeRepo, call_policy: &mut Box, + global_variables: &mut GlobalVarDir, ) { match instr { + &ChoiceInstruction::DynamicElse(..) => { + if let FirstOrNext::First = self.dynamic_mode { + self.cc = self.global_clock; + } + + let p = self.p.local().abs_loc(); + + match code_repo.find_living_dynamic_else(p, self.cc) { + Some((p, next_i)) => { + self.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); + + match self.dynamic_mode { + FirstOrNext::First if next_i == 0 => { + self.p = CodePtr::Local(LocalCodePtr::DirEntry(p + 1)); + } + FirstOrNext::First => { + self.cc = self.global_clock; + + match code_repo.find_living_dynamic_else(p + next_i, self.cc) { + Some(_) => { + self.registers[self.num_of_args + 1] = Addr::Usize(self.cc); + self.num_of_args += 1; + + self.execute_choice_instr( + &ChoiceInstruction::TryMeElse(next_i), + code_repo, + call_policy, + global_variables, + ); + + self.num_of_args -= 1; + } + None => { + self.p += 1; + } + } + } + FirstOrNext::Next => { + let n = self + .stack + .index_or_frame(self.b) + .prelude + .univ_prelude + .num_cells; + + self.cc = match self.stack.index_or_frame(self.b)[n - 1] { + Addr::Usize(cc) => cc, + _ => unreachable!(), + }; + + if next_i > 0 { + match code_repo.find_living_dynamic_else(p + next_i, self.cc) { + Some(_) => { + try_or_fail!( + self, + call_policy.retry_me_else( + self, + next_i, + global_variables, + ) + ) + } + None => { + try_or_fail!( + self, + call_policy.trust_me( + self, + global_variables, + ) + ) + } + } + } else { + try_or_fail!( + self, + call_policy.trust_me( + self, + global_variables, + ) + ) + } + } + } + } + None => { + self.fail = true; + } + } + + self.dynamic_mode = FirstOrNext::Next; + } + &ChoiceInstruction::DynamicInternalElse(..) => { + let p = self.p.local().abs_loc(); + + match code_repo.find_living_dynamic_else(p, self.cc) { + Some((p, next_i)) => { + self.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); + + match self.dynamic_mode { + FirstOrNext::First if next_i == 0 => { + self.p = CodePtr::Local(LocalCodePtr::DirEntry(p + 1)); + } + FirstOrNext::First => { + match code_repo.find_living_dynamic_else(p + next_i, self.cc) { + Some(_) => { + self.registers[self.num_of_args + 1] = Addr::Usize(self.cc); + self.num_of_args += 1; + + self.execute_choice_instr( + &ChoiceInstruction::TryMeElse(next_i), + code_repo, + call_policy, + global_variables, + ); + + self.num_of_args -= 1; + } + None => { + self.p += 1; + } + } + } + FirstOrNext::Next => { + let n = self + .stack + .index_or_frame(self.b) + .prelude + .univ_prelude + .num_cells; + + self.cc = match self.stack.index_or_frame(self.b)[n - 1] { + Addr::Usize(cc) => cc, + _ => unreachable!(), + }; + + if next_i > 0 { + match code_repo.find_living_dynamic_else(p + next_i, self.cc) { + Some(_) => { + try_or_fail!( + self, + call_policy.retry_me_else( + self, + next_i, + global_variables, + ) + ) + } + None => { + try_or_fail!( + self, + call_policy.trust_me( + self, + global_variables, + ) + ) + } + } + } else { + try_or_fail!( + self, + call_policy.trust_me( + self, + global_variables, + ) + ) + } + } + } + } + None => { + self.fail = true; + } + } + + self.dynamic_mode = FirstOrNext::Next; + } &ChoiceInstruction::TryMeElse(offset) => { let n = self.num_of_args; let b = self.stack.allocate_or_frame(n); @@ -3308,17 +3494,15 @@ impl MachineState { or_frame.prelude.b = self.b; or_frame.prelude.bp = self.p.local() + offset; or_frame.prelude.tr = self.tr; - or_frame.prelude.h = self.heap.h(); + or_frame.prelude.h = self.heap.h(); or_frame.prelude.b0 = self.b0; - or_frame.prelude.attr_var_init_queue_b = - self.attr_var_init.attr_var_queue.len(); - or_frame.prelude.attr_var_init_bindings_b = - self.attr_var_init.attr_var_queue.len(); + or_frame.prelude.attr_var_init_queue_b = self.attr_var_init.attr_var_queue.len(); + or_frame.prelude.attr_var_init_bindings_b = self.attr_var_init.attr_var_queue.len(); self.b = b; - for i in 1 .. n + 1 { - self.stack.index_or_frame_mut(b)[i-1] = self.registers[i]; + for i in 1..n + 1 { + self.stack.index_or_frame_mut(b)[i - 1] = self.registers[i]; } self.hb = self.heap.h(); @@ -3326,17 +3510,23 @@ impl MachineState { } &ChoiceInstruction::DefaultRetryMeElse(offset) => { let mut call_policy = DefaultCallPolicy {}; - try_or_fail!(self, call_policy.retry_me_else(self, offset)) + try_or_fail!( + self, + call_policy.retry_me_else(self, offset, global_variables) + ) } - &ChoiceInstruction::DefaultTrustMe => { + &ChoiceInstruction::DefaultTrustMe(_) => { let mut call_policy = DefaultCallPolicy {}; - try_or_fail!(self, call_policy.trust_me(self)) + try_or_fail!(self, call_policy.trust_me(self, global_variables)) } &ChoiceInstruction::RetryMeElse(offset) => { - try_or_fail!(self, call_policy.retry_me_else(self, offset)) + try_or_fail!( + self, + call_policy.retry_me_else(self, offset, global_variables) + ) } - &ChoiceInstruction::TrustMe => { - try_or_fail!(self, call_policy.trust_me(self)) + &ChoiceInstruction::TrustMe(_) => { + try_or_fail!(self, call_policy.trust_me(self, global_variables)) } } } @@ -3353,7 +3543,6 @@ impl MachineState { if b > b0 { self.b = b0; - self.tidy_trail(); if b > self.e { self.stack.truncate(b); @@ -3372,7 +3561,7 @@ impl MachineState { let b0 = self[perm_v!(1)]; let a = self[r]; - self.unify(a, b0); + (self.unify_fn)(self, a, b0); self.p += 1; } &CutInstruction::Cut(r) => { @@ -3382,30 +3571,4 @@ impl MachineState { } } } - - pub fn reset(&mut self) { - self.stack.drop_in_place(); - - self.hb = 0; - self.e = 0; - self.b = 0; - self.b0 = 0; - self.s = HeapPtr::default(); - self.tr = 0; - self.p = CodePtr::default(); - self.cp = LocalCodePtr::default(); - self.attr_var_init.reset(); - self.num_of_args = 0; - - self.fail = false; - self.trail.clear(); - self.heap.clear(); - self.mode = MachineMode::Write; - self.registers = vec![Addr::HeapCell(0); MAX_ARITY + 1]; // self.registers[0] is never used. - self.block = 0; - - self.ball.reset(); - self.heap_locs.clear(); - self.lifted_heap.clear(); - } } diff --git a/src/machine/mod.rs b/src/machine/mod.rs index daaf4e81..3deee1bb 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -1,30 +1,35 @@ -use crate::prolog_parser::ast::*; -use crate::prolog_parser::tabled_rc::*; +use prolog_parser::ast::*; +use prolog_parser::tabled_rc::*; +use prolog_parser::{clause_name, temp_v}; + +use lazy_static::lazy_static; use crate::clause_types::*; use crate::forms::*; -use crate::heap_print::*; use crate::instructions::*; use crate::machine::heap::*; +use crate::machine::loader::*; +use crate::machine::term_stream::{LiveTermStream, LoadStatePayload, TermStream}; use crate::read::*; mod attributed_variables; pub(super) mod code_repo; -pub mod code_walker; -pub mod compile; +pub(crate) mod code_walker; +#[macro_use] +pub(crate) mod loader; +mod compile; mod copier; -mod dynamic_database; -pub mod heap; -pub mod machine_errors; -pub mod machine_indices; +pub(crate) mod heap; +mod load_state; +pub(crate) mod machine_errors; +pub(crate) mod machine_indices; pub(super) mod machine_state; -pub mod modules; -pub mod partial_string; +pub(crate) mod partial_string; +mod preprocessor; mod raw_block; mod stack; pub(crate) mod streams; -pub(super) mod term_expansion; -pub mod toplevel; +mod term_stream; #[macro_use] mod arithmetic_ops; @@ -32,29 +37,24 @@ mod arithmetic_ops; mod machine_state_impl; mod system_calls; -use crate::machine::attributed_variables::*; use crate::machine::code_repo::*; use crate::machine::compile::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::machine_state::*; -use crate::machine::modules::*; -use crate::machine::streams::*; -use crate::machine::toplevel::*; +pub use crate::machine::streams::Stream; -use crate::indexmap::IndexMap; +use indexmap::IndexMap; -use std::collections::VecDeque; -use std::convert::TryFrom; +//use std::convert::TryFrom; +use prolog_parser::ast::ClauseName; use std::fs::File; use std::mem; -use std::ops::Index; use std::path::PathBuf; -use std::rc::Rc; use std::sync::atomic::AtomicBool; #[derive(Debug)] -pub struct MachinePolicies { +pub(crate) struct MachinePolicies { call_policy: Box, cut_policy: Box, } @@ -80,6 +80,32 @@ impl Default for MachinePolicies { } } +#[derive(Debug)] +pub(super) struct LoadContext { + pub(super) path: PathBuf, + pub(super) stream: Stream, + pub(super) module: ClauseName, +} + +impl LoadContext { + #[inline] + fn new(path: &str, stream: Stream) -> Self { + let mut path_buf = PathBuf::from(path); + + if path_buf.is_relative() { + let mut current_dir = current_dir(); + current_dir.push(path_buf); + path_buf = current_dir; + } + + LoadContext { + path: path_buf, + stream, + module: clause_name!("user"), + } + } +} + #[derive(Debug)] pub struct Machine { pub(super) machine_st: MachineState, @@ -87,243 +113,99 @@ pub struct Machine { pub(super) policies: MachinePolicies, pub(super) indices: IndexStore, pub(super) code_repo: CodeRepo, - pub(super) toplevel_idx: usize, - pub(super) current_input_stream: Stream, - pub(super) current_output_stream: Stream, + pub(super) user_input: Stream, + pub(super) user_output: Stream, + pub(super) load_contexts: Vec, } -impl Index for CodeRepo { - type Output = Line; - - fn index(&self, ptr: LocalCodePtr) -> &Self::Output { - match ptr { - LocalCodePtr::InSituDirEntry(p) => &self.in_situ_code[p], - LocalCodePtr::TopLevel(_, p) => &self.cached_query[p], - LocalCodePtr::DirEntry(p) => &self.code[p], - LocalCodePtr::UserGoalExpansion(p) => &self.goal_expanders[p], - LocalCodePtr::UserTermExpansion(p) => &self.term_expanders[p], - } - } -} - -impl Index for Machine { - type Output = Line; - - fn index(&self, ptr: LocalCodePtr) -> &Self::Output { - &self.code_repo[ptr] - } -} - -impl SubModuleUser for IndexStore { - fn atom_tbl(&self) -> TabledData { - self.atom_tbl.clone() - } - - fn op_dir(&mut self) -> &mut OpDir { - &mut self.op_dir - } - - fn get_code_index(&self, key: PredicateKey, module_name: ClauseName) -> Option { - match module_name.as_str() { - "user" => { - self.code_dir.get(&key).cloned() - } - _ => { - match self.in_situ_module_dir.get(&module_name) { - Some(ref module_stub) => { - match module_stub.in_situ_code_dir.get(&key) { - Some(p) => { - return Some(CodeIndex::new( - IndexPtr::InSituDirEntry(*p), - module_name.clone() - )); - } - None => { - } - } - } - None => { - } - }; - - self.modules - .get(&module_name) - .and_then(|ref module| { - module.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) { - if let Some(ref code_idx) = self.code_dir.get(&(name.clone(), arity)) { - if !code_idx.is_undefined() { - match (name.as_str(), arity) { - ("term_expansion", 2) => { - } - ("goal_expansion", 2) => { - } - _ => { - println!("Warning: overwriting {}/{}", &name, arity); - } - } - } - - let (p, module_name) = idx.0.borrow().clone(); - set_code_index!(code_idx, p, module_name); - return; - } - - self.code_dir.insert((name.clone(), arity), idx.clone()); - } - - fn use_qualified_module( - &mut self, - code_repo: &mut CodeRepo, - _: MachineFlags, - submodule: &Module, - exports: &Vec, - ) -> Result<(), SessionError> { - use_qualified_module(self, submodule, exports)?; - submodule - .dump_expansions(code_repo) - .map_err(SessionError::from) - } - - fn use_module( - &mut self, - code_repo: &mut CodeRepo, - _: MachineFlags, - submodule: &Module, - ) -> Result<(), SessionError> { - use_module(self, submodule)?; - - if !submodule.inserted_expansions { - submodule - .dump_expansions(code_repo) - .map_err(SessionError::from) - } else { - Ok(()) - } - } +#[inline] +fn current_dir() -> PathBuf { + std::env::current_dir().unwrap_or(PathBuf::from("./")) } include!(concat!(env!("OUT_DIR"), "/libraries.rs")); -static TOPLEVEL: &str = include_str!("../toplevel.pl"); - impl Machine { - fn compile_special_forms(&mut self) - { - let verify_attrs_src = ListingSource::User; + fn run_module_predicate(&mut self, module_name: ClauseName, key: PredicateKey) { + if let Some(module) = self.indices.modules.get(&module_name) { + if let Some(ref code_index) = module.code_dir.get(&key) { + let p = code_index.local().unwrap(); - match compile_special_form( - self, - Stream::from(VERIFY_ATTRS), - verify_attrs_src, - ) - { - Ok(p) => { - self.machine_st.attr_var_init.verify_attrs_loc = p; + self.machine_st.cp = LocalCodePtr::Halt; + self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); + + return self.run_query(); } - Err(_) => - panic!("Machine::compile_special_forms() failed at VERIFY_ATTRS"), } - let project_attrs_src = ListingSource::User; - - match compile_special_form( - self, - Stream::from(PROJECT_ATTRS), - project_attrs_src, - ) - { - Ok(p) => { - self.machine_st.attr_var_init.project_attrs_loc = p; - } - Err(e) => - panic!("Machine::compile_special_forms() failed at PROJECT_ATTRS: {}", e), - } + unreachable!(); } - fn compile_top_level(&mut self) -> Result<(), SessionError> - { - self.toplevel_idx = self.code_repo.code.len(); + pub fn load_file(&mut self, path: String, stream: Stream) { + self.machine_st[temp_v!(1)] = + Addr::Stream(self.machine_st.heap.push(HeapCellValue::Stream(stream))); - let top_lvl_src = ListingSource::User; + self.machine_st[temp_v!(2)] = Addr::Con(self.machine_st.heap.push(HeapCellValue::Atom( + clause_name!(path, self.machine_st.atom_tbl), + None, + ))); - compile_user_module( - self, - Stream::from(TOPLEVEL), - true, - top_lvl_src, - ); - - if let Some(module) = self.indices.take_module(clause_name!("$toplevel")) { - self.indices.use_module( - &mut self.code_repo, - self.machine_st.flags, - &module, - )?; - - Ok(self.indices.insert_module(module)) - } else { - let err = ExistenceError::ModuleSource(ModuleSource::File( - clause_name!("$toplevel"), - )); - - Err(SessionError::ExistenceError(err)) - } + self.run_module_predicate(clause_name!("loader"), (clause_name!("file_load"), 2)); } - fn compile_scryerrc(&mut self) { - let mut path = match dirs_next::home_dir() { - Some(path) => path, - None => return, - }; + fn load_top_level(&mut self) { + let mut path_buf = current_dir(); + path_buf.push("toplevel.pl"); - path.push(".scryerrc"); + let path = path_buf.to_str().unwrap().to_string(); - if path.is_file() { - let file_src = match File::open(&path) { - Ok(file_handle) => Stream::from_file_as_input( - clause_name!(".scryerrc"), - file_handle, - ), - Err(_) => return, - }; + self.load_file(path, Stream::from(include_str!("../toplevel.pl"))); - let rc_src = ListingSource::from_file_and_path( - clause_name!(".scryerrc"), - path.to_path_buf(), + if let Some(toplevel) = self.indices.modules.get(&clause_name!("$toplevel")) { + load_module( + &mut self.indices.code_dir, + &mut self.indices.op_dir, + &mut self.indices.meta_predicates, + &CompilationTarget::User, + toplevel, ); - - compile_user_module(self, file_src, true, rc_src); + } else { + unreachable!() } } - #[cfg(test)] - pub fn reset(&mut self) { - self.current_input_stream = readline::input_stream(); - self.policies.cut_policy = Box::new(DefaultCutPolicy {}); - self.machine_st.reset(); - } + fn load_special_forms(&mut self) { + let mut path_buf = current_dir(); + path_buf.push("machine/attributed_variables.pl"); - pub fn run_init_code(&mut self, code: Code) -> bool { - let old_machine_st = self.sink_to_snapshot(); - self.machine_st.reset(); + bootstrapping_compile( + Stream::from(include_str!("attributed_variables.pl")), + self, + ListingSource::from_file_and_path(clause_name!("attributed_variables"), path_buf), + ) + .unwrap(); - self.code_repo.cached_query = code; - self.run_query(); + let mut path_buf = current_dir(); + path_buf.push("machine/project_attributes.pl"); - let result = self.machine_st.fail; - self.absorb_snapshot(old_machine_st); + bootstrapping_compile( + Stream::from(include_str!("project_attributes.pl")), + self, + ListingSource::from_file_and_path(clause_name!("project_attributes"), path_buf), + ) + .unwrap(); - !result + if let Some(module) = self.indices.modules.get(&clause_name!("$atts")) { + if let Some(code_index) = module.code_dir.get(&(clause_name!("driver"), 2)) { + self.machine_st.attr_var_init.verify_attrs_loc = code_index.local().unwrap(); + } + } + + if let Some(module) = self.indices.modules.get(&clause_name!("$project_atts")) { + if let Some(code_index) = module.code_dir.get(&(clause_name!("driver"), 2)) { + self.machine_st.attr_var_init.project_attrs_loc = code_index.local().unwrap(); + } + } } pub fn run_top_level(&mut self) { @@ -336,17 +218,70 @@ impl Machine { } let list_addr = Addr::HeapCell(self.machine_st.heap.to_list(arg_pstrs.into_iter())); + self.machine_st[temp_v!(1)] = list_addr; - loop { - self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(self.toplevel_idx)); - self.run_query(); + self.run_module_predicate(clause_name!("$toplevel"), (clause_name!("$repl"), 1)); + } + + pub(crate) fn configure_modules(&mut self) { + fn update_call_n_indices(loader: &Module, target_code_dir: &mut CodeDir) { + for arity in 1..66 { + let key = (clause_name!("call"), arity); + + match loader.code_dir.get(&key) { + Some(src_code_index) => { + let target_code_index = target_code_dir + .entry(key.clone()) + .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)); + + target_code_index.set(src_code_index.get()); + } + None => { + unreachable!(); + } + } + } + } + + if let Some(loader) = self.indices.modules.swap_remove(&clause_name!("loader")) { + if let Some(builtins) = self.indices.modules.get_mut(&clause_name!("builtins")) { + // Import loader's exports into the builtins module so they will be + // implicitly included in every further module. + load_module( + &mut builtins.code_dir, + &mut builtins.op_dir, + &mut builtins.meta_predicates, + &CompilationTarget::Module(clause_name!("builtins")), + &loader, + ); + + for export in &loader.module_decl.exports { + builtins.module_decl.exports.push(export.clone()); + } + + for arity in 10..66 { + builtins + .module_decl + .exports + .push(ModuleExport::PredicateKey((clause_name!("call"), arity))); + } + } + + for (_, target_module) in self.indices.modules.iter_mut() { + update_call_n_indices(&loader, &mut target_module.code_dir); + } + + update_call_n_indices(&loader, &mut self.indices.code_dir); + + self.indices.modules.insert(clause_name!("loader"), loader); + } else { + unreachable!() } } - pub fn new(current_input_stream: Stream, current_output_stream: Stream) -> Self - { - use crate::ref_thread_local::RefThreadLocal; + pub fn new(user_input: Stream, user_output: Stream) -> Self { + use ref_thread_local::RefThreadLocal; let mut wam = Machine { machine_st: MachineState::new(), @@ -354,191 +289,91 @@ impl Machine { policies: MachinePolicies::new(), indices: IndexStore::new(), code_repo: CodeRepo::new(), - toplevel_idx: 0, - current_input_stream, - current_output_stream, + user_input, + user_output, + load_contexts: vec![], }; - let atom_tbl = wam.indices.atom_tbl.clone(); + let mut lib_path = current_dir(); - wam.indices.add_term_and_goal_expansion_indices(); + lib_path.pop(); + lib_path.push("lib"); - compile_listing( + bootstrapping_compile( + Stream::from(LIBRARIES.borrow()["ops_and_meta_predicates"]), &mut wam, + ListingSource::from_file_and_path( + clause_name!("ops_and_meta_predicates.pl"), + lib_path.clone(), + ), + ) + .unwrap(); + + bootstrapping_compile( Stream::from(LIBRARIES.borrow()["builtins"]), - default_index_store!(atom_tbl.clone()), - true, - ListingSource::User, - ); - - wam.compile_special_forms(); - - compile_user_module( &mut wam, - Stream::from(LIBRARIES.borrow()["error"]), - true, - ListingSource::User, - ); + ListingSource::from_file_and_path(clause_name!("builtins.pl"), lib_path.clone()), + ) + .unwrap(); - compile_user_module( - &mut wam, - Stream::from(LIBRARIES.borrow()["pairs"]), - true, - ListingSource::User, - ); - - compile_user_module( - &mut wam, - Stream::from(LIBRARIES.borrow()["lists"]), - true, - ListingSource::User, - ); - - compile_user_module( - &mut wam, - Stream::from(LIBRARIES.borrow()["iso_ext"]), - true, - ListingSource::User, - ); - - compile_user_module( - &mut wam, - Stream::from(LIBRARIES.borrow()["si"]), - true, - ListingSource::User, - ); - - compile_user_module( - &mut wam, - Stream::from(LIBRARIES.borrow()["charsio"]), - true, - ListingSource::User, - ); - - if wam.compile_top_level().is_err() { - panic!("Loading '$toplevel' module failed"); + if let Some(builtins) = wam.indices.modules.get(&clause_name!("builtins")) { + load_module( + &mut wam.indices.code_dir, + &mut wam.indices.op_dir, + &mut wam.indices.meta_predicates, + &CompilationTarget::User, + builtins, + ); + } else { + unreachable!() } - wam.compile_scryerrc(); + lib_path.pop(); // remove the "lib" at the end + + bootstrapping_compile( + Stream::from(include_str!("../loader.pl")), + &mut wam, + ListingSource::from_file_and_path(clause_name!("loader.pl"), lib_path.clone()), + ) + .unwrap(); + + wam.configure_modules(); + + if let Some(loader) = wam.indices.modules.get(&clause_name!("loader")) { + load_module( + &mut wam.indices.code_dir, + &mut wam.indices.op_dir, + &mut wam.indices.meta_predicates, + &CompilationTarget::User, + loader, + ); + } else { + unreachable!() + } + + wam.load_special_forms(); + wam.load_top_level(); wam.configure_streams(); wam } - pub fn configure_streams(&mut self) { - self.current_input_stream.options.alias = Some(clause_name!("user_input")); + pub(crate) fn configure_streams(&mut self) { + self.user_input.options_mut().alias = Some(clause_name!("user_input")); - self.indices.stream_aliases.insert( - clause_name!("user_input"), - self.current_input_stream.clone(), - ); - - self.indices.streams.insert( - self.current_input_stream.clone() - ); - - self.current_output_stream.options.alias = Some(clause_name!("user_output")); - - self.indices.stream_aliases.insert( - clause_name!("user_output"), - self.current_output_stream.clone(), - ); - - self.indices.streams.insert( - self.current_output_stream.clone() - ); - } - - #[inline] - pub fn machine_flags(&self) -> MachineFlags { - self.machine_st.flags - } - - pub fn check_toplevel_code(&self, indices: &IndexStore) -> Result<(), SessionError> { - for (key, idx) in &indices.code_dir { - match ClauseType::from(key.0.clone(), key.1, None) { - ClauseType::Named(..) | ClauseType::Op(..) => {} - _ => { - // ensure we don't try to overwrite the name/arity of a builtin. - let err_str = format!("{}/{}", key.0, key.1); - let err_str = clause_name!(err_str, self.indices.atom_tbl()); - - return Err(SessionError::CannotOverwriteBuiltIn(err_str)); - } - }; - - if let Some(ref existing_idx) = self.indices.code_dir.get(&key) { - // ensure we don't try to overwrite an existing predicate from a different module. - if !existing_idx.is_undefined() && !idx.is_undefined() { - // allow the overwriting of user-level predicates by all other predicates. - if existing_idx.module_name().as_str() == "user" { - continue; - } - - if existing_idx.module_name() != idx.module_name() { - let err_str = format!( - "{}/{} from module {}", - key.0, - key.1, - existing_idx.module_name().as_str() - ); - let err_str = clause_name!(err_str, self.indices.atom_tbl()); - - return Err(SessionError::CannotOverwriteImport(err_str)); - } - } - } - } - - Ok(()) - } - - pub(crate) fn add_batched_code_dir(&mut self, code_dir: CodeDir) { - // error detection has finished, so update the master index of keys. - for (key, idx) in code_dir { - if let Some(ref master_idx) = self.indices.code_dir.get(&key) { - // ensure we don't double borrow if master_idx == idx. - // we don't need to modify anything in that case. - if !Rc::ptr_eq(&master_idx.0, &idx.0) { - set_code_index!(master_idx, idx.0.borrow().0, idx.module_name()); - } - - continue; - } - - self.indices.code_dir.insert(key, idx); - } - } - - #[inline] - pub(crate) fn add_batched_ops(&mut self, op_dir: OpDir) { - self.indices.op_dir.extend(op_dir.into_iter()); - } - - pub(crate) fn add_in_situ_module_dir(&mut self, module_dir: ModuleDir) { - for (module_name, module_skeleton) in module_dir { - match self.indices.modules.get_mut(&module_name) { - Some(ref mut module) => { - for (key, idx) in module_skeleton.code_dir { - if let Some(existing_idx) = module.code_dir.get(&key) { - set_code_index!(existing_idx, idx.0.borrow().0, module_name.clone()); - } else { - module.code_dir.insert(key, idx); - } - } - } - None => { - self.add_module(module_skeleton); - } - } - } - } - - #[inline] - pub fn add_module(&mut self, module: Module) { self.indices - .modules - .insert(module.module_decl.name.clone(), module); + .stream_aliases + .insert(clause_name!("user_input"), self.user_input.clone()); + + self.indices.streams.insert(self.user_input.clone()); + + self.user_output.options_mut().alias = Some(clause_name!("user_output")); + + self.indices + .stream_aliases + .insert(clause_name!("user_output"), self.user_output.clone()); + + self.indices.streams.insert(self.user_output.clone()); } fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) { @@ -552,307 +387,133 @@ impl Machine { return; } - fn extract_module_export_list(&mut self) -> Result, ParserError> - { - let mut export_list = self.machine_st[temp_v!(2)].clone(); - let mut exports = vec![]; - - while let Addr::Lis(l) = self.machine_st.store(self.machine_st.deref(export_list)) { - match &self.machine_st.heap[l] { - &HeapCellValue::Addr(Addr::Str(s)) => { - match &self.machine_st.heap[s] { - HeapCellValue::NamedStr(arity, ref name, _) - if *arity == 2 && name.as_str() == "/" => { - let name = match &self.machine_st.heap[s+1] { - &HeapCellValue::Atom(ref name, _) => - name.clone(), - _ => - unreachable!() - }; - - let arity = match &self.machine_st.heap[s+2] { - &HeapCellValue::Integer(ref arity) => - arity.to_usize().unwrap(), - &HeapCellValue::Addr(Addr::Fixnum(n)) => - usize::try_from(n).unwrap(), - _ => - unreachable!() - }; - - exports.push(ModuleExport::PredicateKey((name, arity))); - } - HeapCellValue::NamedStr(arity, ref name, _) - if *arity == 3 && name.as_str() == "op" => { - let name = match &self.machine_st.heap[s+3] { - &HeapCellValue::Atom(ref name, _) => - name.clone(), - _ => - unreachable!() - }; - - let spec = match &self.machine_st.heap[s+2] { - &HeapCellValue::Atom(ref name, _) => - name.clone(), - _ => - unreachable!() - }; - - let prec = match &self.machine_st.heap[s+1] { - &HeapCellValue::Integer(ref arity) => - arity.to_usize().unwrap(), - &HeapCellValue::Addr(Addr::Fixnum(n)) => - usize::try_from(n).unwrap(), - _ => - unreachable!() - }; - - exports.push(ModuleExport::OpDecl(to_op_decl( - prec, - spec.as_str(), - name, - )?)); - } - _ => unreachable!() - } - } - _ => unreachable!() - } - - export_list = self.machine_st.heap[l+1].as_addr(l+1); - } - - Ok(exports) - } - - fn use_module(&mut self, to_src: ToSource) - where ToSource: Fn(ClauseName) -> ModuleSource - { - // the term expander will overwrite the cached query, so save it here. - let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]); - - let module_spec = self.machine_st[temp_v!(1)].clone(); - let name = { - let addr = self.machine_st.store(self.machine_st.deref(module_spec)); - - match self.machine_st.heap.index_addr(&addr).as_ref() { - HeapCellValue::Atom(name, _) => - name.clone(), - HeapCellValue::Addr(Addr::Char(c)) => - clause_name!(c.to_string(), self.indices.atom_tbl), - HeapCellValue::Addr(addr @ Addr::PStrLocation(..)) => { - let mut heap_pstr_iter = - self.machine_st.heap_pstr_iter(*addr); - clause_name!( - heap_pstr_iter.to_string(), - self.indices.atom_tbl - ) - } - _ => unreachable!(), - } - }; - - let load_result = match to_src(name) { - ModuleSource::Library(name) => - if let Some(module) = self.indices.take_module(name.clone()) { - self.indices.remove_module(clause_name!("user"), &module); - self.indices.modules.insert(name.clone(), module); - - Ok(name) - } else { - load_library(self, name, false) - }, - ModuleSource::File(name) => - load_module_from_file(self, PathBuf::from(name.as_str()), false) - }; - - let result = load_result.and_then(|name| { - let module = self.indices.take_module(name.clone()).unwrap(); - - if !module.is_impromptu_module { - self.indices.use_module(&mut self.code_repo, self.machine_st.flags, &module)?; - } - - Ok(self.indices.insert_module(module)) - }); - - self.code_repo.cached_query = cached_query; - - if let Err(e) = result { - self.throw_session_error(e, (clause_name!("use_module"), 1)); - } - } - - fn use_qualified_module(&mut self, to_src: ToSource) - where ToSource: Fn(ClauseName) -> ModuleSource - { - // the term expander will overwrite the cached query, so save it here. - let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]); - - let module_spec = self.machine_st[temp_v!(1)].clone(); - let name = { - let addr = self.machine_st.store(self.machine_st.deref(module_spec)); - - match self.machine_st.heap.index_addr(&addr).as_ref() { - HeapCellValue::Atom(name, _) => - name.clone(), - HeapCellValue::Addr(Addr::Char(c)) => - clause_name!(c.to_string(), self.indices.atom_tbl), - _ => - unreachable!(), - } - }; - - let exports = match self.extract_module_export_list() { - Ok(exports) => exports, - Err(e) => { - self.throw_session_error(SessionError::from(e), (clause_name!("use_module"), 2)); - return; - } - }; - - let load_result = match to_src(name) { - ModuleSource::Library(name) => - if let Some(module) = self.indices.take_module(name.clone()) { - self.indices.remove_module(clause_name!("user"), &module); - self.indices.modules.insert(name.clone(), module); - - Ok(name) - } else { - load_library(self, name, false) - }, - ModuleSource::File(name) => - load_module_from_file(self, PathBuf::from(name.as_str()), false) - }; - - let result = load_result.and_then(|name| { - let module = self.indices.take_module(name.clone()).unwrap(); - - if !module.is_impromptu_module { - self.indices.use_qualified_module(&mut self.code_repo, - self.machine_st.flags, - &module, - &exports)?; - } - - Ok(self.indices.insert_module(module)) - }); - - self.code_repo.cached_query = cached_query; - - if let Err(e) = result { - self.throw_session_error(e, (clause_name!("use_module"), 2)); - } - } - fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) { match code_ptr { - REPLCodePtr::CompileBatch => { - let user_src = ListingSource::User; - - let src = readline::input_stream(); - readline::set_prompt(false); - - if let EvalSession::Error(e) = compile_user_module(self, src, false, user_src) { - self.throw_session_error(e, (clause_name!("repl"), 0)); - } + REPLCodePtr::AddDiscontiguousPredicate => { + self.add_discontiguous_predicate(); + } + REPLCodePtr::AddDynamicPredicate => { + self.add_dynamic_predicate(); + } + REPLCodePtr::AddMultifilePredicate => { + self.add_multifile_predicate(); + } + REPLCodePtr::AddGoalExpansionClause => { + self.add_goal_expansion_clause(); + } + REPLCodePtr::AddTermExpansionClause => { + self.add_term_expansion_clause(); + } + REPLCodePtr::ClauseToEvacuable => { + self.clause_to_evacuable(); + } + REPLCodePtr::ScopedClauseToEvacuable => { + self.scoped_clause_to_evacuable(); + } + REPLCodePtr::ConcludeLoad => { + self.conclude_load(); + } + REPLCodePtr::PopLoadContext => { + self.pop_load_context(); + } + REPLCodePtr::PushLoadContext => { + self.push_load_context(); + } + REPLCodePtr::PopLoadStatePayload => { + self.pop_load_state_payload(); + } + REPLCodePtr::UseModule => { + self.use_module(); + } + REPLCodePtr::LoadCompiledLibrary => { + self.load_compiled_library(); + } + REPLCodePtr::DeclareModule => { + self.declare_module(); + } + REPLCodePtr::PushLoadStatePayload => { + self.push_load_state_payload(); + } + REPLCodePtr::LoadContextSource => { + self.load_context_source(); + } + REPLCodePtr::LoadContextFile => { + self.load_context_file(); + } + REPLCodePtr::LoadContextDirectory => { + self.load_context_directory(); + } + REPLCodePtr::LoadContextModule => { + self.load_context_module(); + } + REPLCodePtr::LoadContextStream => { + self.load_context_stream(); + } + REPLCodePtr::MetaPredicateProperty => { + self.meta_predicate_property(); + } + REPLCodePtr::BuiltInProperty => { + self.builtin_property(); + } + REPLCodePtr::MultifileProperty => { + self.multifile_property(); + } + REPLCodePtr::DiscontiguousProperty => { + self.discontiguous_property(); + } + REPLCodePtr::DynamicProperty => { + self.dynamic_property(); + } + REPLCodePtr::Assertz => { + self.compile_assert(AppendOrPrepend::Append); + } + REPLCodePtr::Asserta => { + self.compile_assert(AppendOrPrepend::Prepend); + } + REPLCodePtr::Retract => { + self.retract_clause(); + } + REPLCodePtr::AbolishClause => { + self.abolish_clause(); + } + REPLCodePtr::IsConsistentWithTermQueue => { + self.is_consistent_with_term_queue(); + } + REPLCodePtr::FlushTermQueue => { + self.flush_term_queue(); + } + REPLCodePtr::RemoveModuleExports => { + self.remove_module_exports(); + } + REPLCodePtr::AddNonCountedBacktracking => { + self.add_non_counted_backtracking(); } - REPLCodePtr::UseModule => - self.use_module(ModuleSource::Library), - REPLCodePtr::UseModuleFromFile => - self.use_module(ModuleSource::File), - REPLCodePtr::UseQualifiedModule => - self.use_qualified_module(ModuleSource::Library), - REPLCodePtr::UseQualifiedModuleFromFile => - self.use_qualified_module(ModuleSource::File) } self.machine_st.p = CodePtr::Local(p); } - fn sink_to_snapshot(&mut self) -> MachineState { - let mut snapshot = MachineState::with_small_heap(); - - snapshot.hb = self.machine_st.hb; - snapshot.e = self.machine_st.e; - snapshot.b = self.machine_st.b; - snapshot.b0 = self.machine_st.b0; - snapshot.s = self.machine_st.s.clone(); - snapshot.tr = self.machine_st.tr; - snapshot.num_of_args = self.machine_st.num_of_args; - - snapshot.fail = self.machine_st.fail; - snapshot.trail = mem::replace(&mut self.machine_st.trail, vec![]); - snapshot.heap = self.machine_st.heap.take(); - snapshot.mode = self.machine_st.mode; - snapshot.stack = self.machine_st.stack.take(); - snapshot.registers = mem::replace(&mut self.machine_st.registers, vec![]); - snapshot.block = self.machine_st.block; - - snapshot.ball = self.machine_st.ball.take(); - snapshot.lifted_heap = self.machine_st.lifted_heap.take(); - - snapshot - } - - fn absorb_snapshot(&mut self, mut snapshot: MachineState) { - self.machine_st.hb = snapshot.hb; - self.machine_st.e = snapshot.e; - self.machine_st.b = snapshot.b; - self.machine_st.b0 = snapshot.b0; - self.machine_st.s = snapshot.s; - self.machine_st.tr = snapshot.tr; - self.machine_st.num_of_args = snapshot.num_of_args; - - self.machine_st.fail = snapshot.fail; - self.machine_st.trail = mem::replace(&mut snapshot.trail, vec![]); - - self.inner_heap = self.machine_st.heap.take(); - self.inner_heap.truncate(0); - - self.machine_st.heap = snapshot.heap.take(); - self.machine_st.mode = snapshot.mode; - self.machine_st.stack = snapshot.stack; - self.machine_st.registers = mem::replace(&mut snapshot.registers, vec![]); - self.machine_st.block = snapshot.block; - - self.machine_st.ball = snapshot.ball.take(); - self.machine_st.lifted_heap = snapshot.lifted_heap.take(); - } - - pub(super) fn run_query(&mut self) { - self.machine_st.cp = LocalCodePtr::TopLevel(0, self.code_repo.size_of_cached_query()); - let end_ptr = CodePtr::Local(self.machine_st.cp); - - while self.machine_st.p < end_ptr { + pub(crate) fn run_query(&mut self) { + while !self.machine_st.p.is_halt() { self.machine_st.query_stepper( &mut self.indices, &mut self.policies, &mut self.code_repo, - &mut self.current_input_stream, - &mut self.current_output_stream, + &mut self.user_input, + &mut self.user_output, ); match self.machine_st.p { - CodePtr::Local(LocalCodePtr::TopLevel(_, p)) if p > 0 => { - } CodePtr::REPL(code_ptr, p) => { - self.handle_toplevel_command(code_ptr, p) - } - CodePtr::DynamicTransaction(trans_type, p) => { - // self.code_repo.cached_query is about to be overwritten by the term expander, - // so hold onto it locally and restore it after the compiler has finished. - self.machine_st.fail = false; - let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]); + self.handle_toplevel_command(code_ptr, p); - self.dynamic_transaction(trans_type, p); - self.code_repo.cached_query = cached_query; - - if let CodePtr::Local(LocalCodePtr::TopLevel(_, 0)) = self.machine_st.p { - break; + if self.machine_st.fail { + self.machine_st.backtrack(); } } - _ => - break + _ => { + break; + } }; } } @@ -865,39 +526,54 @@ impl MachineState { indices: &mut IndexStore, policies: &mut MachinePolicies, code_repo: &CodeRepo, - current_input_stream: &mut Stream, - current_output_stream: &mut Stream, + user_input: &mut Stream, + user_output: &mut Stream, ) { match instr { - &Line::Arithmetic(ref arith_instr) => { - self.execute_arith_instr(arith_instr) - } + &Line::Arithmetic(ref arith_instr) => self.execute_arith_instr(arith_instr), &Line::Choice(ref choice_instr) => { - self.execute_choice_instr(choice_instr, &mut policies.call_policy) + self.execute_choice_instr( + choice_instr, + code_repo, + &mut policies.call_policy, + &mut indices.global_variables, + ) } &Line::Cut(ref cut_instr) => { self.execute_cut_instr(cut_instr, &mut policies.cut_policy) } - &Line::Control(ref control_instr) => { - self.execute_ctrl_instr( - indices, - code_repo, - &mut policies.call_policy, - &mut policies.cut_policy, - current_input_stream, - current_output_stream, - control_instr, - ) - } + &Line::Control(ref control_instr) => self.execute_ctrl_instr( + indices, + code_repo, + &mut policies.call_policy, + &mut policies.cut_policy, + user_input, + user_output, + control_instr, + ), &Line::Fact(ref fact_instr) => { self.execute_fact_instr(&fact_instr); self.p += 1; } - &Line::Indexing(ref indexing_instr) => { - self.execute_indexing_instr(&indexing_instr) + &Line::IndexingCode(ref indexing_lines) => { + self.execute_indexing_instr( + indexing_lines, + code_repo, + ) } &Line::IndexedChoice(ref choice_instr) => { - self.execute_indexed_choice_instr(choice_instr, &mut policies.call_policy) + self.execute_indexed_choice_instr( + choice_instr, + &mut policies.call_policy, + &mut indices.global_variables, + ) + } + &Line::DynamicIndexedChoice(_) => { + self.execute_dynamic_indexed_choice_instr( + code_repo, + &mut policies.call_policy, + &mut indices.global_variables, + ) } &Line::Query(ref query_instr) => { self.execute_query_instr(&query_instr); @@ -911,8 +587,8 @@ impl MachineState { indices: &mut IndexStore, policies: &mut MachinePolicies, code_repo: &CodeRepo, - current_input_stream: &mut Stream, - current_output_stream: &mut Stream, + user_input: &mut Stream, + user_output: &mut Stream, ) { let instr = match code_repo.lookup_instr(self.last_call, &self.p) { Some(instr) => instr, @@ -924,45 +600,26 @@ impl MachineState { indices, policies, code_repo, - current_input_stream, - current_output_stream, + user_input, + user_output, ); } fn backtrack(&mut self) { - if self.b > 0 { - let b = self.b; + let b = self.b; - self.b0 = self.stack.index_or_frame(b).prelude.b0; - self.p = CodePtr::Local(self.stack.index_or_frame(b).prelude.bp); + self.b0 = self.stack.index_or_frame(b).prelude.b0; + self.p = CodePtr::Local(self.stack.index_or_frame(b).prelude.bp); - if let CodePtr::Local(LocalCodePtr::TopLevel(_, p)) = self.p { - self.fail = p == 0; - } else { - self.fail = false; - } - } else { - self.p = CodePtr::Local(LocalCodePtr::TopLevel(0, 0)); - } + self.fail = false; } fn check_machine_index(&mut self, code_repo: &CodeRepo) -> bool { match self.p { - CodePtr::Local(LocalCodePtr::DirEntry(p)) if p < code_repo.code.len() => {} - CodePtr::Local(LocalCodePtr::UserTermExpansion(p)) - if p < code_repo.term_expanders.len() => {} - CodePtr::Local(LocalCodePtr::UserTermExpansion(_)) => self.fail = true, - CodePtr::Local(LocalCodePtr::UserGoalExpansion(p)) - if p < code_repo.goal_expanders.len() => {} - CodePtr::Local(LocalCodePtr::UserGoalExpansion(_)) => self.fail = true, - CodePtr::Local(LocalCodePtr::InSituDirEntry(p)) if p < code_repo.in_situ_code.len() => { - } - CodePtr::Local(_) | CodePtr::REPL(..) => return false, - CodePtr::DynamicTransaction(..) => { - // prevent use of dynamic transactions from - // succeeding in expansions. self.fail will be toggled - // back to false later. - self.fail = true; + CodePtr::Local(LocalCodePtr::DirEntry(p)) + | CodePtr::Local(LocalCodePtr::IndexingBuf(p, ..)) + if p < code_repo.code.len() => {} + CodePtr::Local(LocalCodePtr::Halt) | CodePtr::REPL(..) => { return false; } _ => {} @@ -977,8 +634,8 @@ impl MachineState { indices: &mut IndexStore, policies: &mut MachinePolicies, code_repo: &mut CodeRepo, - current_input_stream: &mut Stream, - current_output_stream: &mut Stream, + user_input: &mut Stream, + user_output: &mut Stream, ) -> bool { loop { let instr = match code_repo.lookup_instr(self.last_call, &self.p) { @@ -999,8 +656,8 @@ impl MachineState { indices, policies, code_repo, - current_input_stream, - current_output_stream, + user_input, + user_output, ); if self.fail { @@ -1025,17 +682,11 @@ impl MachineState { indices: &mut IndexStore, policies: &mut MachinePolicies, code_repo: &mut CodeRepo, - current_input_stream: &mut Stream, - current_output_stream: &mut Stream, + user_input: &mut Stream, + user_output: &mut Stream, ) { loop { - self.execute_instr( - indices, - policies, - code_repo, - current_input_stream, - current_output_stream, - ); + self.execute_instr(indices, policies, code_repo, user_input, user_output); if self.fail { self.backtrack(); @@ -1055,8 +706,8 @@ impl MachineState { indices, policies, code_repo, - current_input_stream, - current_output_stream, + user_input, + user_output, ) { if self.fail { break; diff --git a/src/machine/modules.rs b/src/machine/modules.rs deleted file mode 100644 index 42576032..00000000 --- a/src/machine/modules.rs +++ /dev/null @@ -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, - 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, - ) { - 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, - ) { - 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)> - { - 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; - fn op_dir(&mut self) -> &mut OpDir; - fn remove_code_index(&mut self, _: PredicateKey); - fn get_code_index(&self, _: PredicateKey, _: ClauseName) -> Option; - - fn insert_dir_entry(&mut self, _: ClauseName, _: usize, _: CodeIndex); - - fn get_op_module_name(&mut self, name: ClauseName, fixity: Fixity) -> Option { - 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, - ) -> Result<(), SessionError>; - - fn use_module( - &mut self, - _: &mut CodeRepo, - _: MachineFlags, - _: &Module - ) -> Result<(), SessionError>; -} - -pub fn use_qualified_module( - user: &mut User, - submodule: &Module, - exports: &Vec, -) -> 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: &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 { - self.atom_tbl.clone() - } - - fn op_dir(&mut self) -> &mut OpDir { - &mut self.op_dir - } - - fn get_code_index(&self, key: PredicateKey, _: ClauseName) -> Option { - 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, - ) -> 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(()) - } -} diff --git a/src/machine/partial_string.rs b/src/machine/partial_string.rs index 1413b37c..bdaacc78 100644 --- a/src/machine/partial_string.rs +++ b/src/machine/partial_string.rs @@ -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: 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) -> PStrIter { + pub(crate) fn range_from(&self, index: RangeFrom) -> 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, +} + +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 { + 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 { + 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 { + 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) +} diff --git a/src/machine/preprocessor.rs b/src/machine/preprocessor.rs new file mode 100644 index 00000000..62a446f8 --- /dev/null +++ b/src/machine/preprocessor.rs @@ -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(terms: I, mut term: Term, sym: ClauseName) -> Term +where + I: DoubleEndedIterator, +{ + 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 { + 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>, + atom_tbl: TabledData, +) -> Result { + 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 { + 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 +{ + 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, +) -> Result { + 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, +) -> Result, 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>, + atom_tbl: TabledData, +) -> Result { + 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>) -> Result { + 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>) -> Result { + 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); + +fn setup_qualified_import( + mut terms: Vec>, + atom_tbl: TabledData, +) -> Result { + 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>, + load_state: &LoadState<'a>, +) -> Result<(ClauseName, ClauseName, Vec), CompilationError> { + fn get_name_and_meta_specs( + name: ClauseName, + terms: &mut [Box], + ) -> Result<(ClauseName, Vec), 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) -> Result { + 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, 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) -> 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) { + 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>, +) -> Result { + 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>, + fixity: Option, +) -> 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>, + fixity: Option, +) -> 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>, +} + +impl Preprocessor { + pub(super) fn new(flags: MachineFlags) -> Self { + Preprocessor { + flags, + queue: VecDeque::new(), + } + } + + fn setup_fact(&mut self, term: Term) -> Result { + match term { + Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => Ok(term), + _ => Err(CompilationError::InadmissibleFact), + } + } + + fn compute_head(&self, term: &Term) -> Vec { + 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, 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) { + // 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) { + 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) { + 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 { + 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 { + 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>, + cut_context: CutContext, + ) -> Result, 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>, + cut_context: CutContext, + ) -> Result { + 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>, + cut_context: CutContext, + ) -> Result { + 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 { + 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>( + &mut self, + load_state: &mut LoadState<'a>, + terms: I, + cut_context: CutContext, + ) -> Result, 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, 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) + } +} diff --git a/src/machine/project_attributes.pl b/src/machine/project_attributes.pl index 0d7a82d0..cee4f1ce 100644 --- a/src/machine/project_attributes.pl +++ b/src/machine/project_attributes.pl @@ -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]). diff --git a/src/machine/stack.rs b/src/machine/stack.rs index 4bd3802b..8240d2a8 100644 --- a/src/machine/stack.rs +++ b/src/machine/stack.rs @@ -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() -> usize { } #[derive(Debug)] -pub struct Stack { +pub(crate) struct Stack { buf: RawBlock, _marker: PhantomData, } @@ -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::() + num_cells * mem::size_of::() } } @@ -104,23 +102,23 @@ impl IndexMut 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 for OrFrame { @@ -156,24 +154,27 @@ impl IndexMut for OrFrame { } impl OrFrame { - pub fn size_of(num_cells: usize) -> usize { + pub(crate) fn size_of(num_cells: usize) -> usize { prelude_size::() + num_cells * mem::size_of::() } } 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::() + idx * mem::size_of::(); 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::() + idx * mem::size_of::(); 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::()); } 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::()); debug_assert!(if self.buf.top.is_null() { diff --git a/src/machine/streams.rs b/src/machine/streams.rs index 1375cb65..e1401b0e 100644 --- a/src/machine/streams.rs +++ b/src/machine/streams.rs @@ -1,36 +1,36 @@ -use crate::prolog_parser::ast::*; +use prolog_parser::ast::*; +use prolog_parser::clause_name; -use crate::read::PrologStream; -use crate::read::readline::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::machine_state::*; +use crate::read::readline::*; +use crate::read::PrologStream; -use std::cmp::Ordering; use std::cell::RefCell; +use std::cmp::Ordering; use std::error::Error; use std::fmt; use std::fs::File; +use std::hash::{Hash, Hasher}; use std::io; use std::io::{stdout, Cursor, ErrorKind, Read, Seek, SeekFrom, Write}; -use std::hash::{Hash, Hasher}; use std::mem; use std::net::{Shutdown, TcpStream}; use std::ops::DerefMut; use std::rc::Rc; -use crate::native_tls::TlsStream; +use native_tls::TlsStream; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum StreamType { +pub(crate) enum StreamType { Binary, Text, } impl StreamType { #[inline] - pub(crate) - fn as_str(&self) -> &'static str { + pub(crate) fn as_str(&self) -> &'static str { match self { StreamType::Binary => "binary_stream", StreamType::Text => "text_stream", @@ -38,8 +38,7 @@ impl StreamType { } #[inline] - pub(crate) - fn as_property_str(&self) -> &'static str { + pub(crate) fn as_property_str(&self) -> &'static str { match self { StreamType::Binary => "binary", StreamType::Text => "text", @@ -47,8 +46,7 @@ impl StreamType { } #[inline] - pub(crate) - fn other(self) -> StreamType { + pub(crate) fn other(self) -> StreamType { match self { StreamType::Binary => StreamType::Text, StreamType::Text => StreamType::Binary, @@ -57,23 +55,22 @@ impl StreamType { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum EOFAction { +pub(crate) enum EOFAction { EOFCode, Error, Reset, } #[derive(Debug, PartialEq)] -pub enum AtEndOfStream { +pub(crate) enum AtEndOfStream { Not, At, - Past + Past, } impl AtEndOfStream { #[inline] - pub(crate) - fn as_str(&self) -> &'static str { + pub(crate) fn as_str(&self) -> &'static str { match self { AtEndOfStream::Not => "not", AtEndOfStream::Past => "past", @@ -84,8 +81,7 @@ impl AtEndOfStream { impl EOFAction { #[inline] - pub(crate) - fn as_str(&self) -> &'static str { + pub(crate) fn as_str(&self) -> &'static str { match self { EOFAction::EOFCode => "eof_code", EOFAction::Error => "error", @@ -120,7 +116,7 @@ enum StreamInstance { StaticStr(Cursor<&'static str>), Stdout, TcpStream(ClauseName, TcpStream), - TlsStream(ClauseName, TlsStream) + TlsStream(ClauseName, TlsStream), } impl StreamInstance { @@ -141,31 +137,18 @@ impl StreamInstance { if index == buf.len() { Ok(buf.len()) } else { - stream.read(&mut buf[index ..]) - .map(|bytes_read| bytes_read + index) + stream + .read(&mut buf[index..]) + .map(|bytes_read| bytes_read + index) } } - StreamInstance::InputFile(_, ref mut file) => { - file.read(buf) - } - StreamInstance::TcpStream(_, ref mut tcp_stream) => { - tcp_stream.read(buf) - } - StreamInstance::TlsStream(_, ref mut tls_stream) => { - tls_stream.read(buf) - } - StreamInstance::ReadlineStream(ref mut rl_stream) => { - rl_stream.read(buf) - } - StreamInstance::StaticStr(ref mut src) => { - src.read(buf) - } - StreamInstance::Bytes(ref mut cursor) => { - cursor.read(buf) - } - StreamInstance::OutputFile(..) | - StreamInstance::Stdout | - StreamInstance::Null => { + StreamInstance::InputFile(_, ref mut file) => file.read(buf), + StreamInstance::TcpStream(_, ref mut tcp_stream) => tcp_stream.read(buf), + StreamInstance::TlsStream(_, ref mut tls_stream) => tls_stream.read(buf), + StreamInstance::ReadlineStream(ref mut rl_stream) => rl_stream.read(buf), + StreamInstance::StaticStr(ref mut src) => src.read(buf), + StreamInstance::Bytes(ref mut cursor) => cursor.read(buf), + StreamInstance::OutputFile(..) | StreamInstance::Stdout | StreamInstance::Null => { Err(std::io::Error::new( ErrorKind::PermissionDenied, StreamError::ReadFromOutputStream, @@ -179,13 +162,12 @@ impl Drop for StreamInstance { fn drop(&mut self) { match self { StreamInstance::TcpStream(_, ref mut tcp_stream) => { - discard_result!(tcp_stream.shutdown(Shutdown::Both)); + tcp_stream.shutdown(Shutdown::Both).unwrap(); } StreamInstance::TlsStream(_, ref mut tls_stream) => { - discard_result!(tls_stream.shutdown()); - } - _ => { + tls_stream.shutdown().unwrap(); } + _ => {} } } } @@ -193,39 +175,48 @@ impl Drop for StreamInstance { impl fmt::Debug for StreamInstance { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { - &StreamInstance::Bytes(ref bytes) => - write!(fmt, "Bytes({:?})", bytes), - &StreamInstance::StaticStr(_) => - write!(fmt, "StaticStr(_)"), // Hacky solution. - &StreamInstance::InputFile(_, ref file) => - write!(fmt, "InputFile({:?})", file), - &StreamInstance::OutputFile(_, ref file, _) => - write!(fmt, "OutputFile({:?})", file), - &StreamInstance::Null => - write!(fmt, "Null"), - &StreamInstance::PausedPrologStream(ref put_back, ref stream) => - write!(fmt, "PausedPrologStream({:?}, {:?})", put_back, stream), - &StreamInstance::ReadlineStream(ref readline_stream) => - write!(fmt, "ReadlineStream({:?})", readline_stream), - &StreamInstance::Stdout => - write!(fmt, "Stdout"), - &StreamInstance::TcpStream(_, ref tcp_stream) => - write!(fmt, "TcpStream({:?})", tcp_stream), - &StreamInstance::TlsStream(_, ref tls_stream) => - write!(fmt, "TlsStream({:?})", tls_stream), + &StreamInstance::Bytes(ref bytes) => write!(fmt, "Bytes({:?})", bytes), + &StreamInstance::StaticStr(_) => write!(fmt, "StaticStr(_)"), // Hacky solution. + &StreamInstance::InputFile(_, ref file) => write!(fmt, "InputFile({:?})", file), + &StreamInstance::OutputFile(_, ref file, _) => write!(fmt, "OutputFile({:?})", file), + &StreamInstance::Null => write!(fmt, "Null"), + &StreamInstance::PausedPrologStream(ref put_back, ref stream) => { + write!(fmt, "PausedPrologStream({:?}, {:?})", put_back, stream) + } + &StreamInstance::ReadlineStream(ref readline_stream) => { + write!(fmt, "ReadlineStream({:?})", readline_stream) + } + &StreamInstance::Stdout => write!(fmt, "Stdout"), + &StreamInstance::TcpStream(_, ref tcp_stream) => { + write!(fmt, "TcpStream({:?})", tcp_stream) + } + &StreamInstance::TlsStream(_, ref tls_stream) => { + write!(fmt, "TlsStream({:?})", tls_stream) + } } } } +#[derive(Debug)] +pub(crate) struct InnerStream { + options: StreamOptions, + stream_inst: StreamInstance, + past_end_of_stream: bool, + lines_read: usize, +} + #[derive(Debug, Clone)] -struct WrappedStreamInstance(Rc>); +struct WrappedStreamInstance(Rc>); impl WrappedStreamInstance { #[inline] - fn new(stream_inst: StreamInstance) -> Self { - WrappedStreamInstance( - Rc::new(RefCell::new((false, stream_inst))) - ) + fn new(stream_inst: StreamInstance, past_end_of_stream: bool) -> Self { + WrappedStreamInstance(Rc::new(RefCell::new(InnerStream { + options: StreamOptions::default(), + stream_inst, + past_end_of_stream, + lines_read: 0, + }))) } } @@ -294,11 +285,11 @@ impl fmt::Display for StreamError { impl Error for StreamError {} #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct StreamOptions { - pub stream_type: StreamType, - pub reposition: bool, - pub alias: Option, - pub eof_action: EOFAction, +pub(crate) struct StreamOptions { + pub(crate) stream_type: StreamType, + pub(crate) reposition: bool, + pub(crate) alias: Option, + pub(crate) eof_action: EOFAction, } impl Default for StreamOptions { @@ -315,7 +306,6 @@ impl Default for StreamOptions { #[derive(Debug, Clone, Hash)] pub struct Stream { - pub options: StreamOptions, stream_inst: WrappedStreamInstance, } @@ -362,8 +352,7 @@ impl From<&'static str> for Stream { impl Stream { #[inline] - pub(crate) - fn as_ptr(&self) -> *const u8 { + pub(crate) fn as_ptr(&self) -> *const u8 { let rc = self.stream_inst.0.clone(); let ptr = Rc::into_raw(rc); @@ -375,158 +364,172 @@ impl Stream { ptr as *const u8 } - #[inline] - pub(crate) - fn position(&mut self) -> Option { - match self.stream_inst.0.borrow_mut().1 { - StreamInstance::InputFile(_, ref mut file) => { - file.seek(SeekFrom::Current(0)).ok() - } - _ => { - None - } + pub fn bytes(&self) -> Option>> { + // if Ref had an and_then function this could be simplified + let val = std::cell::Ref::map(self.stream_inst.0.borrow(), |inner_stream| { + &inner_stream.stream_inst + }); + match std::ops::Deref::deref(&val) { + StreamInstance::Bytes(_) => Some(std::cell::Ref::map( + std::cell::Ref::clone(&val), + |instance| match instance { + StreamInstance::Bytes(cursor) => cursor.get_ref(), + _ => unreachable!(), + }, + )), + _ => None, } } #[inline] - pub(crate) - fn set_position(&mut self, position: u64) { + pub(crate) fn lines_read(&mut self) -> usize { + self.stream_inst.0.borrow_mut().lines_read + } + + #[inline] + pub(crate) fn add_lines_read(&mut self, incr_num_lines_read: usize) { + self.stream_inst.0.borrow_mut().lines_read += incr_num_lines_read; + } + + #[inline] + pub(crate) fn options(&self) -> std::cell::Ref<'_, StreamOptions> { + std::cell::Ref::map(self.stream_inst.0.borrow(), |inner_stream| { + &inner_stream.options + }) + } + + #[inline] + pub(crate) fn options_mut(&mut self) -> std::cell::RefMut<'_, StreamOptions> { + std::cell::RefMut::map(self.stream_inst.0.borrow_mut(), |inner_stream| { + &mut inner_stream.options + }) + } + + #[inline] + pub(crate) fn position(&mut self) -> Option<(u64, usize)> { + // returns lines_read, position. + let result = match self.stream_inst.0.borrow_mut().stream_inst { + StreamInstance::InputFile(_, ref mut file) => file.seek(SeekFrom::Current(0)).ok(), + StreamInstance::TcpStream(..) + | StreamInstance::TlsStream(..) + | StreamInstance::ReadlineStream(..) + | StreamInstance::StaticStr(..) + | StreamInstance::PausedPrologStream(..) + | StreamInstance::Bytes(..) => Some(0), + _ => None, + }; + + result.map(|position| (position, self.stream_inst.0.borrow().lines_read)) + } + + #[inline] + pub(crate) fn set_position(&mut self, position: u64) { match self.stream_inst.0.borrow_mut().deref_mut() { - (past_end_of_stream, StreamInstance::InputFile(_, ref mut file)) => { + InnerStream { + past_end_of_stream, + stream_inst: StreamInstance::InputFile(_, ref mut file), + .. + } => { file.seek(SeekFrom::Start(position)).unwrap(); if let Ok(metadata) = file.metadata() { *past_end_of_stream = position > metadata.len(); } } - _ => { - } + _ => {} } } #[inline] - pub(crate) - fn past_end_of_stream(&self) -> bool { - self.stream_inst.0.borrow_mut().0 + pub(crate) fn past_end_of_stream(&self) -> bool { + self.stream_inst.0.borrow_mut().past_end_of_stream } #[inline] - pub(crate) - fn at_end_of_stream(&mut self) -> bool { + pub(crate) fn at_end_of_stream(&mut self) -> bool { self.position_relative_to_end() == AtEndOfStream::At } #[inline] - pub(crate) - fn set_past_end_of_stream(&mut self) { - self.stream_inst.0.borrow_mut().0 = true; + pub(crate) fn set_past_end_of_stream(&mut self) { + self.stream_inst.0.borrow_mut().past_end_of_stream = true; } #[inline] - pub(crate) - fn position_relative_to_end(&mut self) -> AtEndOfStream { + pub(crate) fn position_relative_to_end(&mut self) -> AtEndOfStream { if self.past_end_of_stream() { return AtEndOfStream::Past; } match self.stream_inst.0.borrow_mut().deref_mut() { - (past_end_of_stream, StreamInstance::InputFile(_, ref mut file)) => { - match file.metadata() { - Ok(metadata) => { - if let Ok(position) = file.seek(SeekFrom::Current(0)) { - return match position.cmp(&metadata.len()) { - Ordering::Equal => { - AtEndOfStream::At - } - Ordering::Less => { - AtEndOfStream::Not - } - Ordering::Greater => { - *past_end_of_stream = true; //self.set_past_end_of_stream(); - AtEndOfStream::Past - } - }; - } else { - *past_end_of_stream = true; //self.set_past_end_of_stream(); - AtEndOfStream::Past - } - } - _ => { - *past_end_of_stream = true; //self.set_past_end_of_stream(); + InnerStream { + past_end_of_stream, + stream_inst: StreamInstance::InputFile(_, ref mut file), + .. + } => match file.metadata() { + Ok(metadata) => { + if let Ok(position) = file.seek(SeekFrom::Current(0)) { + return match position.cmp(&metadata.len()) { + Ordering::Equal => AtEndOfStream::At, + Ordering::Less => AtEndOfStream::Not, + Ordering::Greater => { + *past_end_of_stream = true; + AtEndOfStream::Past + } + }; + } else { + *past_end_of_stream = true; AtEndOfStream::Past } } - } - _ => { - AtEndOfStream::Not - } + _ => { + *past_end_of_stream = true; + AtEndOfStream::Past + } + }, + _ => AtEndOfStream::Not, } } #[inline] - pub(crate) - fn file_name(&self) -> Option { - match self.stream_inst.0.borrow().1 { - StreamInstance::InputFile(ref name, _) => { - Some(name.clone()) - } - StreamInstance::OutputFile(ref name, ..) => { - Some(name.clone()) - } - StreamInstance::TcpStream(ref name, _) => { - Some(name.clone()) - } - _ => { - None - } + pub(crate) fn file_name(&self) -> Option { + match self.stream_inst.0.borrow().stream_inst { + StreamInstance::InputFile(ref name, _) => Some(name.clone()), + StreamInstance::OutputFile(ref name, ..) => Some(name.clone()), + StreamInstance::TcpStream(ref name, _) => Some(name.clone()), + _ => None, } } #[inline] - pub(crate) - fn mode(&self) -> &'static str { - match self.stream_inst.0.borrow().1 { - StreamInstance::Bytes(_) | - StreamInstance::PausedPrologStream(..) | - StreamInstance::ReadlineStream(_) | - StreamInstance::StaticStr(_) | - StreamInstance::InputFile(..) => { - "read" - } - StreamInstance::TcpStream(..) | - StreamInstance::TlsStream(..) => { - "read_append" - } - StreamInstance::OutputFile(_, _, true) => { - "append" - } - StreamInstance::Stdout | - StreamInstance::OutputFile(_, _, false) => { - "write" - } - StreamInstance::Null => { - "" - } + pub(crate) fn mode(&self) -> &'static str { + match self.stream_inst.0.borrow().stream_inst { + StreamInstance::Bytes(_) + | StreamInstance::PausedPrologStream(..) + | StreamInstance::ReadlineStream(_) + | StreamInstance::StaticStr(_) + | StreamInstance::InputFile(..) => "read", + StreamInstance::TcpStream(..) | StreamInstance::TlsStream(..) => "read_append", + StreamInstance::OutputFile(_, _, true) => "append", + StreamInstance::Stdout | StreamInstance::OutputFile(_, _, false) => "write", + StreamInstance::Null => "", } } #[inline] fn from_inst(stream_inst: StreamInstance) -> Self { Stream { - options: StreamOptions::default(), - stream_inst: WrappedStreamInstance::new(stream_inst) + stream_inst: WrappedStreamInstance::new(stream_inst, false), } } #[inline] - pub(crate) - fn stdout() -> Self { + pub fn stdout() -> Self { Stream::from_inst(StreamInstance::Stdout) } #[inline] - pub(crate) - fn from_tcp_stream(address: ClauseName, tcp_stream: TcpStream) -> Self { + pub(crate) fn from_tcp_stream(address: ClauseName, tcp_stream: TcpStream) -> Self { tcp_stream.set_read_timeout(None).unwrap(); tcp_stream.set_write_timeout(None).unwrap(); @@ -534,59 +537,44 @@ impl Stream { } #[inline] - pub(crate) - fn from_tls_stream(address: ClauseName, tls_stream: TlsStream) -> Self { + pub(crate) fn from_tls_stream(address: ClauseName, tls_stream: TlsStream) -> Self { Stream::from_inst(StreamInstance::TlsStream(address, tls_stream)) } #[inline] - pub(crate) - fn from_file_as_output(name: ClauseName, file: File, in_append_mode: bool) -> Self { + pub(crate) fn from_file_as_output(name: ClauseName, file: File, in_append_mode: bool) -> Self { Stream::from_inst(StreamInstance::OutputFile(name, file, in_append_mode)) } #[inline] - pub(crate) - fn from_file_as_input(name: ClauseName, file: File) -> Self { + pub(crate) fn from_file_as_input(name: ClauseName, file: File) -> Self { Stream::from_inst(StreamInstance::InputFile(name, file)) } #[inline] - pub(crate) - fn is_stdout(&self) -> bool { - match self.stream_inst.0.borrow().1 { - StreamInstance::Stdout => { - true - } - _ => { - false - } + pub(crate) fn is_stdout(&self) -> bool { + match self.stream_inst.0.borrow().stream_inst { + StreamInstance::Stdout => true, + _ => false, } } #[inline] - pub(crate) - fn is_stdin(&self) -> bool { - match self.stream_inst.0.borrow().1 { - StreamInstance::ReadlineStream(_) => { - true - } - _ => { - false - } + pub(crate) fn is_stdin(&self) -> bool { + match self.stream_inst.0.borrow().stream_inst { + StreamInstance::ReadlineStream(_) => true, + _ => false, } } #[inline] - pub(crate) - fn close(&mut self) { - self.stream_inst.0.borrow_mut().1 = StreamInstance::Null; + pub(crate) fn close(&mut self) { + self.stream_inst.0.borrow_mut().stream_inst = StreamInstance::Null; } #[inline] - pub(crate) - fn is_null_stream(&self) -> bool { - if let StreamInstance::Null = self.stream_inst.0.borrow().1 { + pub(crate) fn is_null_stream(&self) -> bool { + if let StreamInstance::Null = self.stream_inst.0.borrow().stream_inst { true } else { false @@ -594,64 +582,54 @@ impl Stream { } #[inline] - pub(crate) - fn is_input_stream(&self) -> bool { - match self.stream_inst.0.borrow().1 { - StreamInstance::TcpStream(..) | - StreamInstance::TlsStream(..) | - StreamInstance::Bytes(_) | - StreamInstance::PausedPrologStream(..) | - StreamInstance::ReadlineStream(_) | - StreamInstance::StaticStr(_) | - StreamInstance::InputFile(..) => { - true - } - _ => { - false - } + pub(crate) fn is_input_stream(&self) -> bool { + match self.stream_inst.0.borrow().stream_inst { + StreamInstance::TcpStream(..) + | StreamInstance::TlsStream(..) + | StreamInstance::Bytes(_) + | StreamInstance::PausedPrologStream(..) + | StreamInstance::ReadlineStream(_) + | StreamInstance::StaticStr(_) + | StreamInstance::InputFile(..) => true, + _ => false, } } #[inline] - pub(crate) - fn is_output_stream(&self) -> bool { - match self.stream_inst.0.borrow().1 { + pub(crate) fn is_output_stream(&self) -> bool { + match self.stream_inst.0.borrow().stream_inst { StreamInstance::Stdout - | StreamInstance::TcpStream(..) - | StreamInstance::TlsStream(..) - | StreamInstance::Bytes(_) - | StreamInstance::OutputFile(..) => { - true - } - _ => { - false - } + | StreamInstance::TcpStream(..) + | StreamInstance::TlsStream(..) + | StreamInstance::Bytes(_) + | StreamInstance::OutputFile(..) => true, + _ => false, } } fn unpause_stream(&mut self) { - let stream_inst = - match self.stream_inst.0.borrow_mut().1 { - StreamInstance::PausedPrologStream(ref put_back, ref mut stream_inst) - if put_back.is_empty() => { - mem::replace(&mut **stream_inst, StreamInstance::Null) - } - _ => { - return; - } - }; + let stream_inst = match self.stream_inst.0.borrow_mut().stream_inst { + StreamInstance::PausedPrologStream(ref put_back, ref mut stream_inst) + if put_back.is_empty() => + { + mem::replace(&mut **stream_inst, StreamInstance::Null) + } + _ => { + return; + } + }; - self.stream_inst.0.borrow_mut().1 = stream_inst; + self.stream_inst.0.borrow_mut().stream_inst = stream_inst; } // returns true on success. #[inline] - pub(super) - fn reset(&mut self) -> bool { - self.stream_inst.0.borrow_mut().0 = false; + pub(super) fn reset(&mut self) -> bool { + self.stream_inst.0.borrow_mut().lines_read = 0; + self.stream_inst.0.borrow_mut().past_end_of_stream = false; loop { - match self.stream_inst.0.borrow_mut().1 { + match self.stream_inst.0.borrow_mut().stream_inst { StreamInstance::Bytes(ref mut cursor) => { cursor.set_position(0); return true; @@ -676,9 +654,8 @@ impl Stream { } #[inline] - pub(crate) - fn peek_byte(&mut self) -> std::io::Result { - match self.stream_inst.0.borrow_mut().1 { + pub(crate) fn peek_byte(&mut self) -> std::io::Result { + match self.stream_inst.0.borrow_mut().stream_inst { StreamInstance::Bytes(ref mut cursor) => { let mut b = [0u8; 1]; let pos = cursor.position(); @@ -688,12 +665,7 @@ impl Stream { cursor.set_position(pos); Ok(b[0]) } - _ => { - Err(std::io::Error::new( - ErrorKind::UnexpectedEof, - "end of file", - )) - } + _ => Err(std::io::Error::new(ErrorKind::UnexpectedEof, "end of file")), } } StreamInstance::InputFile(_, ref mut file) => { @@ -704,37 +676,30 @@ impl Stream { file.seek(SeekFrom::Current(-1))?; Ok(b[0]) } - _ => { - Err(std::io::Error::new( - ErrorKind::UnexpectedEof, - StreamError::PeekByteFailed, - )) - } + _ => Err(std::io::Error::new( + ErrorKind::UnexpectedEof, + StreamError::PeekByteFailed, + )), } } - StreamInstance::ReadlineStream(ref mut stream) => { - stream.peek_byte() - } + StreamInstance::ReadlineStream(ref mut stream) => stream.peek_byte(), StreamInstance::TcpStream(_, ref mut tcp_stream) => { let mut b = [0u8; 1]; tcp_stream.peek(&mut b)?; Ok(b[0]) } - _ => { - Err(std::io::Error::new( - ErrorKind::PermissionDenied, - StreamError::PeekByteFromNonPeekableStream, - )) - } + _ => Err(std::io::Error::new( + ErrorKind::PermissionDenied, + StreamError::PeekByteFromNonPeekableStream, + )), } } #[inline] - pub(crate) - fn peek_char(&mut self) -> std::io::Result { - use crate::unicode_reader::CodePoints; + pub(crate) fn peek_char(&mut self) -> std::io::Result { + use unicode_reader::CodePoints; - match self.stream_inst.0.borrow_mut().1 { + match self.stream_inst.0.borrow_mut().stream_inst { StreamInstance::InputFile(_, ref mut file) => { let c = { let mut iter = CodePoints::from(&*file); @@ -744,18 +709,16 @@ impl Stream { } else { return Err(std::io::Error::new( ErrorKind::UnexpectedEof, - StreamError::PeekCharFailed + StreamError::PeekCharFailed, )); } }; - file.seek(SeekFrom::Current(- (c.len_utf8() as i64)))?; + file.seek(SeekFrom::Current(-(c.len_utf8() as i64)))?; Ok(c) } - StreamInstance::ReadlineStream(ref mut stream) => { - stream.peek_char() - } + StreamInstance::ReadlineStream(ref mut stream) => stream.peek_char(), StreamInstance::TcpStream(_, ref tcp_stream) => { let c = { let mut buf = [0u8; 8]; @@ -768,45 +731,40 @@ impl Stream { } else { return Err(std::io::Error::new( ErrorKind::UnexpectedEof, - StreamError::PeekCharFailed + StreamError::PeekCharFailed, )); } }; Ok(c) } - _ => { - Err(std::io::Error::new( - ErrorKind::PermissionDenied, - StreamError::PeekCharFromNonPeekableStream, - )) - } + _ => Err(std::io::Error::new( + ErrorKind::PermissionDenied, + StreamError::PeekCharFromNonPeekableStream, + )), } } #[inline] - pub(crate) - fn pause_stream(&mut self, buf: Vec>) -> io::Result<()> { - match self.stream_inst.0.borrow_mut().1 { + pub(crate) fn pause_stream(&mut self, buf: Vec>) -> io::Result<()> { + match self.stream_inst.0.borrow_mut().stream_inst { StreamInstance::PausedPrologStream(ref mut inner_buf, _) => { inner_buf.extend(parser_top_to_bytes(buf)?.into_iter()); return Ok(()); } - _ => { - } + _ => {} } if !buf.is_empty() { let stream_inst = mem::replace( - &mut self.stream_inst.0.borrow_mut().1, + &mut self.stream_inst.0.borrow_mut().stream_inst, StreamInstance::Null, ); - self.stream_inst.0.borrow_mut().1 = - StreamInstance::PausedPrologStream( - parser_top_to_bytes(buf)?, - Box::new(stream_inst), - ); + self.stream_inst.0.borrow_mut().stream_inst = StreamInstance::PausedPrologStream( + parser_top_to_bytes(buf)?, + Box::new(stream_inst), + ); } Ok(()) @@ -815,28 +773,27 @@ impl Stream { impl MachineState { #[inline] - pub(crate) - fn eof_action( + pub(crate) fn eof_action( &mut self, result: Addr, stream: &mut Stream, caller: ClauseName, arity: usize, ) -> CallResult { - match stream.options.eof_action { + let eof_action = stream.options().eof_action; + + match eof_action { EOFAction::Error => { stream.set_past_end_of_stream(); return Err(self.open_past_eos_error(stream.clone(), caller, arity)); } EOFAction::EOFCode => { - let end_of_stream = - if stream.options.stream_type == StreamType::Binary { - Addr::Fixnum(-1) - } else { - self.heap.to_unifiable( - HeapCellValue::Atom(clause_name!("end_of_file"), None) - ) - }; + let end_of_stream = if stream.options().stream_type == StreamType::Binary { + Addr::Fixnum(-1) + } else { + self.heap + .to_unifiable(HeapCellValue::Atom(clause_name!("end_of_file"), None)) + }; stream.set_past_end_of_stream(); Ok(self.unify(result, end_of_stream)) @@ -851,114 +808,106 @@ impl MachineState { } } - pub(crate) - fn to_stream_options( + pub(crate) fn to_stream_options( &self, alias: Addr, eof_action: Addr, reposition: Addr, stream_type: Addr, ) -> StreamOptions { - let alias = - match self.store(self.deref(alias)) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - Some(name.clone()) - } else { - unreachable!() - } - } - _ => { - None - } - }; - - let eof_action = - match self.store(self.deref(eof_action)) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - match name.as_str() { - "eof_code" => EOFAction::EOFCode, - "error" => EOFAction::Error, - "reset" => EOFAction::Reset, - _ => unreachable!(), - } - } else { - unreachable!() - } - } - _ => { + let alias = match self.store(self.deref(alias)) { + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + Some(name.clone()) + } else { unreachable!() } - }; + } + _ => None, + }; - let reposition = - match self.store(self.deref(reposition)) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - name.as_str() == "true" - } else { - unreachable!() + let eof_action = match self.store(self.deref(eof_action)) { + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + match name.as_str() { + "eof_code" => EOFAction::EOFCode, + "error" => EOFAction::Error, + "reset" => EOFAction::Reset, + _ => unreachable!(), } - } - _ => { + } else { unreachable!() } - }; + } + _ => { + unreachable!() + } + }; - let stream_type = - match self.store(self.deref(stream_type)) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - match name.as_str() { - "text" => StreamType::Text, - "binary" => StreamType::Binary, - _ => unreachable!() - } - } else { - unreachable!() - } - } - _ => { + let reposition = match self.store(self.deref(reposition)) { + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + name.as_str() == "true" + } else { unreachable!() } - }; + } + _ => { + unreachable!() + } + }; + + let stream_type = match self.store(self.deref(stream_type)) { + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + match name.as_str() { + "text" => StreamType::Text, + "binary" => StreamType::Binary, + _ => unreachable!(), + } + } else { + unreachable!() + } + } + _ => { + unreachable!() + } + }; let mut options = StreamOptions::default(); options.stream_type = stream_type; - options.reposition = reposition; + options.reposition = reposition; options.alias = alias; options.eof_action = eof_action; options } - pub(crate) - fn get_stream_or_alias( + pub(crate) fn get_stream_or_alias( &mut self, addr: Addr, indices: &IndexStore, caller: &'static str, arity: usize, - ) -> Result - { + ) -> Result { Ok(match self.store(self.deref(addr)) { Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, ref spec) = self.heap.clone(h) { + if let HeapCellValue::Atom(ref atom, ref spec) = self.heap.clone(h) { match indices.stream_aliases.get(atom) { - Some(stream) if !stream.is_null_stream() => { - stream.clone() - } + Some(stream) if !stream.is_null_stream() => stream.clone(), _ => { let stub = MachineError::functor_stub(clause_name!(caller), arity); - let addr = self.heap.to_unifiable( - HeapCellValue::Atom(atom.clone(), spec.clone()) - ); + let addr = self + .heap + .to_unifiable(HeapCellValue::Atom(atom.clone(), spec.clone())); return Err(self.error_form( - MachineError::existence_error(self.heap.h(), ExistenceError::Stream(addr)), + MachineError::existence_error( + self.heap.h(), + ExistenceError::Stream(addr), + ), stub, )); } @@ -970,11 +919,7 @@ impl MachineState { Addr::Stream(h) => { if let HeapCellValue::Stream(ref stream) = &self.heap[h] { if stream.is_null_stream() { - return Err(self.open_permission_error( - Addr::Stream(h), - caller, - arity, - )); + return Err(self.open_permission_error(Addr::Stream(h), caller, arity)); } else { stream.clone() } @@ -986,10 +931,7 @@ impl MachineState { let stub = MachineError::functor_stub(clause_name!(caller), arity); if addr.is_ref() { - return Err(self.error_form( - MachineError::instantiation_error(), - stub, - )); + return Err(self.error_form(MachineError::instantiation_error(), stub)); } else { return Err(self.error_form( MachineError::domain_error(DomainErrorType::StreamOrAlias, addr), @@ -1000,31 +942,24 @@ impl MachineState { }) } - pub(crate) - fn open_parsing_stream( + pub(crate) fn open_parsing_stream( &self, stream: Stream, stub_name: &'static str, stub_arity: usize, ) -> Result { match parsing_stream(stream) { - Ok(parsing_stream) => { - Ok(parsing_stream) - } + Ok(parsing_stream) => Ok(parsing_stream), Err(e) => { let stub = MachineError::functor_stub(clause_name!(stub_name), stub_arity); - let err = MachineError::session_error( - self.heap.h(), - SessionError::from(e), - ); + let err = MachineError::session_error(self.heap.h(), SessionError::from(e)); Err(self.error_form(err, stub)) } } } - pub(crate) - fn stream_permission_error( + pub(crate) fn stream_permission_error( &self, perm: Permission, err_string: &'static str, @@ -1033,23 +968,15 @@ impl MachineState { arity: usize, ) -> MachineStub { let stub = MachineError::functor_stub(caller, arity); - let payload = vec![ - HeapCellValue::Stream(stream) - ]; + let payload = vec![HeapCellValue::Stream(stream)]; - let err = MachineError::permission_error( - self.heap.h(), - perm, - err_string, - payload, - ); + let err = MachineError::permission_error(self.heap.h(), perm, err_string, payload); return self.error_form(err, stub); } #[inline] - pub(crate) - fn open_past_eos_error( + pub(crate) fn open_past_eos_error( &self, stream: Stream, caller: ClauseName, @@ -1064,26 +991,20 @@ impl MachineState { ) } - pub(crate) - fn open_permission_error( + pub(crate) fn open_permission_error( &self, culprit: T, stub_name: &'static str, stub_arity: usize, ) -> MachineStub { let stub = MachineError::functor_stub(clause_name!(stub_name), stub_arity); - let err = MachineError::permission_error( - self.heap.h(), - Permission::Open, - "source_sink", - culprit, - ); + let err = + MachineError::permission_error(self.heap.h(), Permission::Open, "source_sink", culprit); return self.error_form(err, stub); } - pub(crate) - fn occupied_alias_permission_error( + pub(crate) fn occupied_alias_permission_error( &self, alias: ClauseName, stub_name: &'static str, @@ -1100,8 +1021,7 @@ impl MachineState { return self.error_form(err, stub); } - pub(crate) - fn reposition_error( + pub(crate) fn reposition_error( &self, stub_name: &'static str, stub_arity: usize, @@ -1119,9 +1039,7 @@ impl MachineState { return self.error_form(err, stub); } - - pub(crate) - fn check_stream_properties( + pub(crate) fn check_stream_properties( &mut self, stream: &mut Stream, expected_type: StreamType, @@ -1129,19 +1047,21 @@ impl MachineState { caller: ClauseName, arity: usize, ) -> CallResult { - let opt_err = - if input.is_some() && !stream.is_input_stream() { - Some("stream") // 8.14.2.3 g) - } else if input.is_none() && !stream.is_output_stream() { - Some("stream") // 8.14.2.3 g) - } else if stream.options.stream_type != expected_type { - Some(expected_type.other().as_str()) // 8.14.2.3 h) - } else { - None - }; + let opt_err = if input.is_some() && !stream.is_input_stream() { + Some("stream") // 8.14.2.3 g) + } else if input.is_none() && !stream.is_output_stream() { + Some("stream") // 8.14.2.3 g) + } else if stream.options().stream_type != expected_type { + Some(expected_type.other().as_str()) // 8.14.2.3 h) + } else { + None + }; - let permission = - if input.is_some() { Permission::InputStream } else { Permission::OutputStream }; + let permission = if input.is_some() { + Permission::InputStream + } else { + Permission::OutputStream + }; if let Some(err_string) = opt_err { return Err(self.stream_permission_error( @@ -1155,12 +1075,7 @@ impl MachineState { if let Some(input) = input { if stream.past_end_of_stream() { - self.eof_action( - input, - stream, - caller, - arity, - )?; + self.eof_action(input, stream, caller, arity)?; } } @@ -1171,7 +1086,7 @@ impl MachineState { impl Read for Stream { #[inline] fn read(&mut self, buf: &mut [u8]) -> std::io::Result { - let bytes_read = self.stream_inst.0.borrow_mut().1.read(buf)?; + let bytes_read = self.stream_inst.0.borrow_mut().stream_inst.read(buf)?; self.unpause_stream(); Ok(bytes_read) } @@ -1179,62 +1094,38 @@ impl Read for Stream { impl Write for Stream { fn write(&mut self, buf: &[u8]) -> std::io::Result { - match self.stream_inst.0.borrow_mut().1 { - StreamInstance::OutputFile(_, ref mut file, _) => { - file.write(buf) - } - StreamInstance::TcpStream(_, ref mut tcp_stream) => { - tcp_stream.write(buf) - } - StreamInstance::TlsStream(_, ref mut tls_stream) => { - tls_stream.write(buf) - } - StreamInstance::Bytes(ref mut cursor) => { - cursor.write(buf) - } - StreamInstance::Stdout => { - stdout().write(buf) - } - StreamInstance::PausedPrologStream(..) | - StreamInstance::StaticStr(_) | - StreamInstance::ReadlineStream(_) | - StreamInstance::InputFile(..) | - StreamInstance::Null => { - Err(std::io::Error::new( - ErrorKind::PermissionDenied, - StreamError::WriteToInputStream, - )) - } + match self.stream_inst.0.borrow_mut().stream_inst { + StreamInstance::OutputFile(_, ref mut file, _) => file.write(buf), + StreamInstance::TcpStream(_, ref mut tcp_stream) => tcp_stream.write(buf), + StreamInstance::TlsStream(_, ref mut tls_stream) => tls_stream.write(buf), + StreamInstance::Bytes(ref mut cursor) => cursor.write(buf), + StreamInstance::Stdout => stdout().write(buf), + StreamInstance::PausedPrologStream(..) + | StreamInstance::StaticStr(_) + | StreamInstance::ReadlineStream(_) + | StreamInstance::InputFile(..) + | StreamInstance::Null => Err(std::io::Error::new( + ErrorKind::PermissionDenied, + StreamError::WriteToInputStream, + )), } } fn flush(&mut self) -> std::io::Result<()> { - match self.stream_inst.0.borrow_mut().1 { - StreamInstance::OutputFile(_, ref mut file, _) => { - file.flush() - } - StreamInstance::TcpStream(_, ref mut tcp_stream) => { - tcp_stream.flush() - } - StreamInstance::TlsStream(_, ref mut tls_stream) => { - tls_stream.flush() - } - StreamInstance::Bytes(ref mut cursor) => { - cursor.flush() - } - StreamInstance::Stdout => { - stdout().flush() - } - StreamInstance::PausedPrologStream(..) | - StreamInstance::StaticStr(_) | - StreamInstance::ReadlineStream(_) | - StreamInstance::InputFile(..) | - StreamInstance::Null => { - Err(std::io::Error::new( - ErrorKind::PermissionDenied, - StreamError::FlushToInputStream, - )) - } + match self.stream_inst.0.borrow_mut().stream_inst { + StreamInstance::OutputFile(_, ref mut file, _) => file.flush(), + StreamInstance::TcpStream(_, ref mut tcp_stream) => tcp_stream.flush(), + StreamInstance::TlsStream(_, ref mut tls_stream) => tls_stream.flush(), + StreamInstance::Bytes(ref mut cursor) => cursor.flush(), + StreamInstance::Stdout => stdout().flush(), + StreamInstance::PausedPrologStream(..) + | StreamInstance::StaticStr(_) + | StreamInstance::ReadlineStream(_) + | StreamInstance::InputFile(..) + | StreamInstance::Null => Err(std::io::Error::new( + ErrorKind::PermissionDenied, + StreamError::FlushToInputStream, + )), } } } diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index da31e966..1ffa227e 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -1,65 +1,77 @@ -use crate::prolog_parser::ast::*; -use crate::prolog_parser::parser::*; -use crate::prolog_parser::tabled_rc::*; +use prolog_parser::ast::*; +use prolog_parser::parser::*; +use prolog_parser::{ + alpha_char, binary_digit_char, clause_name, decimal_digit_char, exponent_char, graphic_char, + graphic_token_char, hexadecimal_digit_char, layout_char, meta_char, new_line_char, + octal_digit_char, prolog_char, sign_char, solo_char, symbolic_control_char, + symbolic_hexadecimal_char, temp_v, +}; + +use lazy_static::lazy_static; use crate::clause_types::*; use crate::forms::*; use crate::heap_print::*; use crate::instructions::*; +use crate::machine; use crate::machine::code_repo::CodeRepo; -use crate::machine::copier::*; use crate::machine::code_walker::*; +use crate::machine::copier::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::machine_state::*; +use crate::machine::preprocessor::to_op_decl; use crate::machine::streams::*; -use crate::machine::toplevel::to_op_decl; -use crate::ordered_float::OrderedFloat; + use crate::read::readline; use crate::rug::Integer; +use ordered_float::OrderedFloat; -use crate::indexmap::IndexSet; +use indexmap::IndexSet; -use crate::ref_thread_local::RefThreadLocal; +use ref_thread_local::RefThreadLocal; use std::cmp; -use std::fs; use std::collections::BTreeSet; use std::convert::TryFrom; +use std::env; +use std::fs; use std::io::{ErrorKind, Read, Write}; use std::iter::{once, FromIterator}; use std::net::{TcpListener, TcpStream}; +use std::num::NonZeroU32; use std::ops::Sub; use std::rc::Rc; -use std::num::NonZeroU32; -use std::env; +use chrono::{offset::Local, DateTime}; +use cpu_time::ProcessTime; use std::time::{Duration, SystemTime}; -use crate::cpu_time::ProcessTime; -use crate::chrono::{offset::Local,DateTime}; -use crate::crossterm::event::{read, Event, KeyCode, KeyEvent, KeyModifiers}; -use crate::crossterm::terminal::{enable_raw_mode, disable_raw_mode}; +use crossterm::event::{read, Event, KeyCode, KeyEvent, KeyModifiers}; +use crossterm::terminal::{disable_raw_mode, enable_raw_mode}; -use crate::ring::rand::{SecureRandom, SystemRandom}; -use crate::ring::{digest,hkdf,pbkdf2,aead,signature::{self,KeyPair}}; -use crate::ripemd160::{Ripemd160, Digest}; -use crate::sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512}; -use crate::blake2::{Blake2s, Blake2b}; +use blake2::{Blake2b, Blake2s}; +use ring::rand::{SecureRandom, SystemRandom}; +use ring::{ + aead, digest, hkdf, pbkdf2, + signature::{self, KeyPair}, +}; +use ripemd160::{Digest, Ripemd160}; +use sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512}; -use crate::openssl::ec::{EcGroup, EcPoint}; -use crate::openssl::bn::{BigNum, BigNumContext}; -use crate::openssl::nid::Nid; +use openssl::bn::{BigNum, BigNumContext}; +use openssl::ec::{EcGroup, EcPoint}; +use openssl::nid::Nid; use sodiumoxide::crypto::scalarmult::curve25519::*; -use crate::native_tls::TlsConnector; +use native_tls::TlsConnector; -extern crate select; -use roxmltree; use base64; +use roxmltree; +use select; -pub fn get_key() -> KeyEvent { +pub(crate) fn get_key() -> KeyEvent { let key; enable_raw_mode().expect("failed to enable raw mode"); loop { @@ -70,8 +82,8 @@ pub fn get_key() -> KeyEvent { KeyCode::Char(_) | KeyCode::Enter | KeyCode::Tab => { key = key_; break; - }, - _ => () + } + _ => (), } } } @@ -123,15 +135,9 @@ impl BrentAlgState { addr @ Addr::HeapCell(_) | addr @ Addr::StackCell(..) | addr @ Addr::AttrVar(_) => { CycleSearchResult::PartialList(self.steps, addr.as_var().unwrap()) } - Addr::PStrLocation(h, n) => { - CycleSearchResult::PStrLocation(self.steps, h, n) - } - Addr::EmptyList => { - CycleSearchResult::ProperList(self.steps) - } - _ => { - CycleSearchResult::NotList - } + Addr::PStrLocation(h, n) => CycleSearchResult::PStrLocation(self.steps, h, n), + Addr::EmptyList => CycleSearchResult::ProperList(self.steps), + _ => CycleSearchResult::NotList, } } } @@ -147,50 +153,37 @@ impl MachineState { // a step in Brent's algorithm. fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option { match self.store(self.deref(brent_st.hare)) { - Addr::EmptyList => { - Some(CycleSearchResult::ProperList(brent_st.steps)) - } + Addr::EmptyList => Some(CycleSearchResult::ProperList(brent_st.steps)), addr @ Addr::HeapCell(_) | addr @ Addr::StackCell(..) | addr @ Addr::AttrVar(_) => { Some(CycleSearchResult::PartialList( brent_st.steps, addr.as_var().unwrap(), )) } - Addr::PStrLocation(h, n) => { - match &self.heap[h] { - HeapCellValue::PartialString(ref pstr, _) => { - if let Some(c) = pstr.range_from(n ..).next() { - brent_st.step(Addr::PStrLocation(h, n + c.len_utf8())) - } else { - unreachable!() - } - } - _ => { + Addr::PStrLocation(h, n) => match &self.heap[h] { + HeapCellValue::PartialString(ref pstr, _) => { + if let Some(c) = pstr.range_from(n..).next() { + brent_st.step(Addr::PStrLocation(h, n + c.len_utf8())) + } else { unreachable!() } } - } - Addr::Lis(l) => { - brent_st.step(Addr::HeapCell(l + 1)) - } - _ => { - Some(CycleSearchResult::NotList) - } + _ => { + unreachable!() + } + }, + Addr::Lis(l) => brent_st.step(Addr::HeapCell(l + 1)), + _ => Some(CycleSearchResult::NotList), } } - pub(super) - fn detect_cycles_with_max(&self, max_steps: usize, addr: Addr) -> CycleSearchResult { + pub(super) fn detect_cycles_with_max(&self, max_steps: usize, addr: Addr) -> CycleSearchResult { let hare = match self.store(self.deref(addr)) { - Addr::Lis(offset) if max_steps > 0 => { - Addr::Lis(offset) - } + Addr::Lis(offset) if max_steps > 0 => Addr::Lis(offset), Addr::Lis(offset) => { return CycleSearchResult::UntouchedList(offset); } - Addr::PStrLocation(h, n) if max_steps > 0 => { - Addr::PStrLocation(h, n) - } + Addr::PStrLocation(h, n) if max_steps > 0 => Addr::PStrLocation(h, n), Addr::PStrLocation(h, _) => { return CycleSearchResult::UntouchedList(h); } @@ -229,19 +222,14 @@ impl MachineState { } } - pub(super) - fn detect_cycles(&self, addr: Addr) -> CycleSearchResult { + pub(super) fn detect_cycles(&self, addr: Addr) -> CycleSearchResult { let addr = self.store(self.deref(addr)); let hare = match addr { - Addr::Lis(offset) => { - Addr::Lis(offset) - } + Addr::Lis(offset) => Addr::Lis(offset), Addr::EmptyList => { return CycleSearchResult::EmptyList; } - Addr::PStrLocation(h, n) => { - Addr::PStrLocation(h, n) - } + Addr::PStrLocation(h, n) => Addr::PStrLocation(h, n), Addr::Con(h) => { if let HeapCellValue::PartialString(..) = &self.heap[h] { Addr::PStrLocation(h, 0) @@ -274,33 +262,23 @@ impl MachineState { } fn skip_max_list_result(&mut self, max_steps: Option) { - let search_result = - if let Some(max_steps) = max_steps { - if max_steps == -1 { - self.detect_cycles(self[temp_v!(3)]) - } else { - self.detect_cycles_with_max( - max_steps as usize, - self[temp_v!(3)], - ) - } - } else { + let search_result = if let Some(max_steps) = max_steps { + if max_steps == -1 { self.detect_cycles(self[temp_v!(3)]) - }; + } else { + self.detect_cycles_with_max(max_steps as usize, self[temp_v!(3)]) + } + } else { + self.detect_cycles(self[temp_v!(3)]) + }; match search_result { CycleSearchResult::PStrLocation(steps, h, n) => { self.finalize_skip_max_list(steps, Addr::PStrLocation(h, n)); } - CycleSearchResult::UntouchedList(l) => { - self.finalize_skip_max_list(0, Addr::Lis(l)) - } - CycleSearchResult::EmptyList => { - self.finalize_skip_max_list(0, Addr::EmptyList) - } - CycleSearchResult::PartialList(n, r) => { - self.finalize_skip_max_list(n, r.as_addr()) - } + CycleSearchResult::UntouchedList(l) => self.finalize_skip_max_list(0, Addr::Lis(l)), + CycleSearchResult::EmptyList => self.finalize_skip_max_list(0, Addr::EmptyList), + CycleSearchResult::PartialList(n, r) => self.finalize_skip_max_list(n, r.as_addr()), CycleSearchResult::ProperList(steps) => { self.finalize_skip_max_list(steps, Addr::EmptyList) } @@ -311,8 +289,7 @@ impl MachineState { }; } - pub(super) - fn skip_max_list(&mut self) -> CallResult { + pub(super) fn skip_max_list(&mut self) -> CallResult { let max_steps = self.store(self.deref(self[temp_v!(2)])); match max_steps { @@ -321,12 +298,11 @@ impl MachineState { return Err(self.error_form(MachineError::instantiation_error(), stub)); } addr => { - let max_steps_n = - match Number::try_from((max_steps, &self.heap)) { - Ok(Number::Integer(n)) => n.to_isize(), - Ok(Number::Fixnum(n)) => Some(n), - _ => None, - }; + let max_steps_n = match Number::try_from((max_steps, &self.heap)) { + Ok(Number::Integer(n)) => n.to_isize(), + Ok(Number::Fixnum(n)) => Some(n), + _ => None, + }; if max_steps_n.map(|i| i >= -1).unwrap_or(false) { let n = self.store(self.deref(self[temp_v!(1)])); @@ -335,7 +311,7 @@ impl MachineState { Ok(Number::Integer(n)) => { if n.as_ref() == &0 { let xs0 = self[temp_v!(3)]; - let xs = self[temp_v!(4)]; + let xs = self[temp_v!(4)]; self.unify(xs0, xs); } else { @@ -345,7 +321,7 @@ impl MachineState { Ok(Number::Fixnum(n)) => { if n == 0 { let xs0 = self[temp_v!(3)]; - let xs = self[temp_v!(4)]; + let xs = self[temp_v!(4)]; self.unify(xs0, xs); } else { @@ -358,16 +334,10 @@ impl MachineState { } } else { let stub = MachineError::functor_stub(clause_name!("$skip_max_list"), 4); - return Err( - self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - addr - ), - stub, - ) - ); + return Err(self.error_form( + MachineError::type_error(self.heap.h(), ValidType::Integer, addr), + stub, + )); } } } @@ -383,10 +353,7 @@ impl MachineState { ) -> Result { if file_spec.as_str().is_empty() { let stub = MachineError::functor_stub(clause_name!("open"), 4); - let err = MachineError::domain_error( - DomainErrorType::SourceSink, - self[temp_v!(1)], - ); + let err = MachineError::domain_error(DomainErrorType::SourceSink, self[temp_v!(1)]); return Err(self.error_form(err, stub)); } @@ -394,86 +361,72 @@ impl MachineState { // 8.11.5.3l) if let Some(ref alias) = &options.alias { if indices.stream_aliases.contains_key(alias) { - return Err(self.occupied_alias_permission_error( - alias.clone(), - "open", - 4, - )); + return Err(self.occupied_alias_permission_error(alias.clone(), "open", 4)); } } - let mode = - atom_from!(self, indices, self.store(self.deref(self[temp_v!(2)]))); - + let mode = atom_from!(self, self.store(self.deref(self[temp_v!(2)]))); let mut open_options = fs::OpenOptions::new(); - let (is_input_file, in_append_mode) = - match mode.as_str() { - "read" => { - open_options.read(true).write(false).create(false); - (true, false) - } - "write" => { - open_options.read(false).write(true).truncate(true).create(true); - (false, false) - } - "append" => { - open_options.read(false).write(true).create(true).append(true); - (false, true) - } - _ => { - let stub = MachineError::functor_stub(clause_name!("open"), 4); - let err = MachineError::domain_error( - DomainErrorType::IOMode, - self[temp_v!(2)], - ); + let (is_input_file, in_append_mode) = match mode.as_str() { + "read" => { + open_options.read(true).write(false).create(false); + (true, false) + } + "write" => { + open_options + .read(false) + .write(true) + .truncate(true) + .create(true); + (false, false) + } + "append" => { + open_options + .read(false) + .write(true) + .create(true) + .append(true); + (false, true) + } + _ => { + let stub = MachineError::functor_stub(clause_name!("open"), 4); + let err = MachineError::domain_error(DomainErrorType::IOMode, self[temp_v!(2)]); - // 8.11.5.3h) - return Err(self.error_form(err, stub)); - } - }; + // 8.11.5.3h) + return Err(self.error_form(err, stub)); + } + }; - let file = - match open_options.open(file_spec.as_str()) { - Ok(file) => { - file - } - Err(err) => { - match err.kind() { - ErrorKind::NotFound => { - // 8.11.5.3j) - let stub = MachineError::functor_stub( - clause_name!("open"), - 4, - ); + let file = match open_options.open(file_spec.as_str()) { + Ok(file) => file, + Err(err) => { + match err.kind() { + ErrorKind::NotFound => { + // 8.11.5.3j) + let stub = MachineError::functor_stub(clause_name!("open"), 4); - let err = MachineError::existence_error( - self.heap.h(), - ExistenceError::SourceSink(self[temp_v!(1)]), - ); + let err = MachineError::existence_error( + self.heap.h(), + ExistenceError::SourceSink(self[temp_v!(1)]), + ); - return Err(self.error_form(err, stub)); - } - ErrorKind::PermissionDenied => { - // 8.11.5.3k) - return Err(self.open_permission_error(self[temp_v!(1)], "open", 4)); - } - _ => { - let stub = MachineError::functor_stub( - clause_name!("open"), - 4, - ); + return Err(self.error_form(err, stub)); + } + ErrorKind::PermissionDenied => { + // 8.11.5.3k) + return Err(self.open_permission_error(self[temp_v!(1)], "open", 4)); + } + _ => { + let stub = MachineError::functor_stub(clause_name!("open"), 4); - let err = MachineError::syntax_error( - self.heap.h(), - ParserError::IO(err), - ); + let err = MachineError::syntax_error(self.heap.h(), ParserError::IO(err)); - return Err(self.error_form(err, stub)); - } + return Err(self.error_form(err, stub)); } } - }; + } + }; Ok(if is_input_file { Stream::from_file_as_input(file_spec, file) @@ -496,11 +449,8 @@ impl MachineState { fn copy_findall_solution(&mut self, lh_offset: usize, copy_target: Addr) -> usize { let threshold = self.lifted_heap.h() - lh_offset; - let mut copy_ball_term = CopyBallTerm::new( - &mut self.stack, - &mut self.heap, - &mut self.lifted_heap, - ); + let mut copy_ball_term = + CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut self.lifted_heap); copy_ball_term.push(HeapCellValue::Addr(Addr::Lis(threshold + 1))); copy_ball_term.push(HeapCellValue::Addr(Addr::HeapCell(threshold + 3))); @@ -517,7 +467,7 @@ impl MachineState { } else { self.p.local() + 1 }; - + Ok(self.p = CodePtr::REPL(repl_code_ptr, p)) } @@ -531,7 +481,8 @@ impl MachineState { self.lifted_heap.truncate(lh_offset); } else { let threshold = self.lifted_heap.h() - lh_offset; - self.lifted_heap.push(HeapCellValue::Addr(addr_constr(threshold))); + self.lifted_heap + .push(HeapCellValue::Addr(addr_constr(threshold))); } } _ => self.fail = true, @@ -560,16 +511,16 @@ impl MachineState { let spec = get_clause_spec( name.clone(), *arity, - composite_op!(&indices.op_dir), + &CompositeOpDir::new(&indices.op_dir, None), ); - let addr = self.heap.to_unifiable(HeapCellValue::DBRef( - DBRef::NamedPred( + let addr = self + .heap + .to_unifiable(HeapCellValue::DBRef(DBRef::NamedPred( name.clone(), *arity, spec, - ) - )); + ))); self.bind(r, addr); @@ -593,17 +544,13 @@ impl MachineState { let a2 = self[temp_v!(2)]; if let Some(r) = a2.as_var() { - let addr = self.heap.to_unifiable( - HeapCellValue::DBRef( - DBRef::Op( - *priority, - *spec, - name.clone(), - op_dir.clone(), - SharedOpDesc::new(*priority, *spec) - ), - ), - ); + let addr = self.heap.to_unifiable(HeapCellValue::DBRef(DBRef::Op( + *priority, + *spec, + name.clone(), + op_dir.clone(), + SharedOpDesc::new(*priority, *spec), + ))); self.bind(r, addr); } else { @@ -621,8 +568,7 @@ impl MachineState { n: &Integer, stub: &'static str, arity: usize, - ) -> Result - { + ) -> Result { let c = n.to_u32().and_then(std::char::from_u32); if let Some(c) = c { @@ -664,28 +610,18 @@ impl MachineState { string.push('.'); - let mut stream = - match parsing_stream(std::io::Cursor::new(string)) { - Ok(stream) => { - stream - } - Err(e) => { - let err = MachineError::session_error( - self.heap.h(), - SessionError::from(e), - ); + let mut stream = match parsing_stream(std::io::Cursor::new(string)) { + Ok(stream) => stream, + Err(e) => { + let err = MachineError::session_error(self.heap.h(), SessionError::from(e)); - return Err(self.error_form(err, stub)); - } - }; + return Err(self.error_form(err, stub)); + } + }; - let mut parser = Parser::new( - &mut stream, - indices.atom_tbl.clone(), - self.machine_flags(), - ); + let mut parser = Parser::new(&mut stream, self.atom_tbl.clone(), self.machine_flags()); - match parser.read_term(composite_op!(&indices.op_dir)) { + match parser.read_term(&CompositeOpDir::new(&indices.op_dir, None)) { Err(err) => { let h = self.heap.h(); let err = MachineError::syntax_error(h, err); @@ -694,19 +630,19 @@ impl MachineState { } Ok(Term::Constant(_, Constant::Rational(n))) => { let addr = self.heap.put_constant(Constant::Rational(n)); - self.unify(nx, addr); + (self.unify_fn)(self, nx, addr); } Ok(Term::Constant(_, Constant::Float(n))) => { let addr = self.heap.put_constant(Constant::Float(n)); - self.unify(nx, addr); + (self.unify_fn)(self, nx, addr); } Ok(Term::Constant(_, Constant::Integer(n))) => { let addr = self.heap.put_constant(Constant::Integer(n)); - self.unify(nx, addr); + (self.unify_fn)(self, nx, addr); } Ok(Term::Constant(_, Constant::Fixnum(n))) => { let addr = self.heap.put_constant(Constant::Fixnum(n)); - self.unify(nx, addr); + (self.unify_fn)(self, nx, addr); } _ => { let err = ParserError::ParseBigInt(0, 0); @@ -732,7 +668,7 @@ impl MachineState { let attr_goals = Addr::HeapCell(self.heap.to_list(attr_goals.into_iter())); let target = self[temp_v!(1)]; - self.unify(attr_goals, target); + (self.unify_fn)(self, attr_goals, target); } fn call_continuation_chunk(&mut self, chunk: Addr, return_p: LocalCodePtr) -> LocalCodePtr { @@ -743,7 +679,7 @@ impl MachineState { match &self.heap[s] { HeapCellValue::NamedStr(arity, ..) => { let num_cells = arity - 1; - let p_functor = self.heap[s+1].as_addr(s+1); + let p_functor = self.heap[s + 1].as_addr(s + 1); let cp = self.heap.to_local_code_ptr(&p_functor).unwrap(); let prev_e = self.e; @@ -751,37 +687,36 @@ impl MachineState { let e = self.stack.allocate_and_frame(num_cells); let and_frame = self.stack.index_and_frame_mut(e); - and_frame.prelude.e = prev_e; + and_frame.prelude.e = prev_e; and_frame.prelude.cp = return_p; self.p = CodePtr::Local(cp + 1); // adjust cut point to occur after call_continuation. if num_cells > 0 { - if let Addr::CutPoint(_) = self.heap[s+2].as_addr(s+2) { + if let Addr::CutPoint(_) = self.heap[s + 2].as_addr(s + 2) { and_frame[1] = Addr::CutPoint(self.b); } else { - and_frame[1] = self.heap[s+2].as_addr(s+2); + and_frame[1] = self.heap[s + 2].as_addr(s + 2); } } - for index in s+3 .. s+2+num_cells { - and_frame[index - (s+1)] = self.heap[index].as_addr(index); + for index in s + 3..s + 2 + num_cells { + and_frame[index - (s + 1)] = self.heap[index].as_addr(index); } self.e = e; self.p.local() } - _ => unreachable!() + _ => unreachable!(), } } - _ => unreachable!() + _ => unreachable!(), } } - pub(super) - fn system_call( + pub(super) fn system_call( &mut self, ct: &SystemClauseType, code_repo: &CodeRepo, @@ -792,79 +727,43 @@ impl MachineState { current_output_stream: &mut Stream, ) -> CallResult { match ct { - &SystemClauseType::AbolishClause => { - let p = self.cp; - let trans_type = DynamicTransactionType::Abolish; - - self.p = CodePtr::DynamicTransaction(trans_type, p); - return Ok(()); - } - &SystemClauseType::AbolishModuleClause => { - let p = self.cp; - let trans_type = DynamicTransactionType::ModuleAbolish; - - self.p = CodePtr::DynamicTransaction(trans_type, p); - return Ok(()); - } &SystemClauseType::BindFromRegister => { let reg = self.store(self.deref(self[temp_v!(2)])); - let n = - match Number::try_from((reg, &self.heap)) { - Ok(Number::Integer(n)) => { - n.to_usize() - } - Ok(Number::Fixnum(n)) => { - usize::try_from(n).ok() - } - _ => { - unreachable!() - } - }; + let n = match Number::try_from((reg, &self.heap)) { + Ok(Number::Integer(n)) => n.to_usize(), + Ok(Number::Fixnum(n)) => usize::try_from(n).ok(), + _ => { + unreachable!() + } + }; if let Some(n) = n { if n <= MAX_ARITY { let target = self[temp_v!(n)]; - let addr = self[temp_v!(1)]; + let addr = self[temp_v!(1)]; - self.unify(addr, target); + (self.unify_fn)(self, addr, target); return return_from_clause!(self.last_call, self); } } self.fail = true; } - &SystemClauseType::AssertDynamicPredicateToFront => { - let p = self.cp; - let trans_type = DynamicTransactionType::Assert(DynamicAssertPlace::Front); - - self.p = CodePtr::DynamicTransaction(trans_type, p); - return Ok(()); - } - &SystemClauseType::AssertDynamicPredicateToBack => { - let p = self.cp; - let trans_type = DynamicTransactionType::Assert(DynamicAssertPlace::Back); - - self.p = CodePtr::DynamicTransaction(trans_type, p); - return Ok(()); - } &SystemClauseType::CurrentHostname => { match hostname::get().ok() { - Some(host) => { - match host.into_string().ok() { - Some(host) => { - let hostname = self.heap.to_unifiable( - HeapCellValue::Atom(clause_name!(host, indices.atom_tbl), None) - ); + Some(host) => match host.into_string().ok() { + Some(host) => { + let hostname = self.heap.to_unifiable(HeapCellValue::Atom( + clause_name!(host, self.atom_tbl), + None, + )); - self.unify(self[temp_v!(1)], hostname); - return return_from_clause!(self.last_call, self); - } - None => { - } + (self.unify_fn)(self, self[temp_v!(1)], hostname); + return return_from_clause!(self.last_call, self); } - } - None => { - } + None => {} + }, + None => {} } self.fail = true; @@ -878,7 +777,7 @@ impl MachineState { match addr { addr if addr.is_ref() => { let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream)); - self.unify(stream, addr); + (self.unify_fn)(self, stream, addr); } Addr::Stream(other_stream) => { if let HeapCellValue::Stream(ref other_stream) = &self.heap[other_stream] { @@ -888,15 +787,9 @@ impl MachineState { } } addr => { - let stub = MachineError::functor_stub( - clause_name!("current_input"), - 1, - ); + let stub = MachineError::functor_stub(clause_name!("current_input"), 1); - let err = MachineError::domain_error( - DomainErrorType::Stream, - addr, - ); + let err = MachineError::domain_error(DomainErrorType::Stream, addr); return Err(self.error_form(err, stub)); } @@ -909,7 +802,7 @@ impl MachineState { match addr { addr if addr.is_ref() => { let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream)); - self.unify(stream, addr); + (self.unify_fn)(self, stream, addr); } Addr::Stream(other_stream) => { if let HeapCellValue::Stream(ref other_stream) = &self.heap[other_stream] { @@ -919,15 +812,9 @@ impl MachineState { } } addr => { - let stub = MachineError::functor_stub( - clause_name!("current_input"), - 1, - ); + let stub = MachineError::functor_stub(clause_name!("current_input"), 1); - let err = MachineError::domain_error( - DomainErrorType::Stream, - addr, - ); + let err = MachineError::domain_error(DomainErrorType::Stream, addr); return Err(self.error_form(err, stub)); } @@ -942,10 +829,16 @@ impl MachineState { for entry in entries { if let Ok(entry) = entry { match entry.file_name().into_string() { - Ok(name) => { files.push(self.heap.put_complete_string(&name)); } + Ok(name) => { + files.push(self.heap.put_complete_string(&name)); + } _ => { - let stub = MachineError::functor_stub(clause_name!("directory_files"), 2); - let err = MachineError::representation_error(RepFlag::Character); + let stub = MachineError::functor_stub( + clause_name!("directory_files"), + 2, + ); + let err = + MachineError::representation_error(RepFlag::Character); let err = self.error_form(err, stub); return Err(err); @@ -956,7 +849,7 @@ impl MachineState { } let files_list = Addr::HeapCell(self.heap.to_list(files.into_iter())); - self.unify(self[temp_v!(2)], files_list); + (self.unify_fn)(self, self[temp_v!(2)], files_list); } &SystemClauseType::FileSize => { let file = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); @@ -964,33 +857,39 @@ impl MachineState { let len = self.heap.to_unifiable(HeapCellValue::Integer(Rc::new(len))); - self.unify(self[temp_v!(2)], len); + (self.unify_fn)(self, self[temp_v!(2)], len); } &SystemClauseType::FileExists => { let file = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - if !std::path::Path::new(&file).exists() || !fs::metadata(&file).unwrap().is_file() { + if !std::path::Path::new(&file).exists() || !fs::metadata(&file).unwrap().is_file() + { self.fail = true; return Ok(()); } } &SystemClauseType::DirectoryExists => { let directory = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - if !std::path::Path::new(&directory).exists() || !fs::metadata(&directory).unwrap().is_dir() { + if !std::path::Path::new(&directory).exists() + || !fs::metadata(&directory).unwrap().is_dir() + { self.fail = true; return Ok(()); } } &SystemClauseType::DirectorySeparator => { - let addr = self.heap.put_constant(Constant::Char(std::path::MAIN_SEPARATOR)); - self.unify(self[temp_v!(1)], addr); + let addr = self + .heap + .put_constant(Constant::Char(std::path::MAIN_SEPARATOR)); + (self.unify_fn)(self, self[temp_v!(1)], addr); } &SystemClauseType::MakeDirectory => { let directory = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); match fs::create_dir(directory) { - Ok(_) => { } - _ => { self.fail = true; - return Ok(()); + Ok(_) => {} + _ => { + self.fail = true; + return Ok(()); } } } @@ -998,33 +897,37 @@ impl MachineState { let file = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); match fs::remove_file(file) { - Ok(_) => { } - _ => { self.fail = true; - return Ok(()); + Ok(_) => {} + _ => { + self.fail = true; + return Ok(()); } } } &SystemClauseType::WorkingDirectory => { if let Ok(dir) = env::current_dir() { - let current = - match dir.to_str() { - Some(d) => { d } - _ => { let stub = MachineError::functor_stub(clause_name!("working_directory"), 2); - let err = MachineError::representation_error(RepFlag::Character); - let err = self.error_form(err, stub); + let current = match dir.to_str() { + Some(d) => d, + _ => { + let stub = + MachineError::functor_stub(clause_name!("working_directory"), 2); + let err = MachineError::representation_error(RepFlag::Character); + let err = self.error_form(err, stub); + + return Err(err); + } + }; - return Err(err); - } - }; let chars = self.heap.put_complete_string(current); - self.unify(self[temp_v!(1)], chars); + (self.unify_fn)(self, self[temp_v!(1)], chars); let next = self.heap_pstr_iter(self[temp_v!(2)]).to_string(); match env::set_current_dir(std::path::Path::new(&next)) { - Ok(_) => { } - _ => { self.fail = true; - return Ok(()); + Ok(_) => {} + _ => { + self.fail = true; + return Ok(()); } } } else { @@ -1037,19 +940,19 @@ impl MachineState { match fs::canonicalize(path) { Ok(canonical) => { - let cs = - match canonical.to_str() { - Some(s) => { s } - _ => { - let stub = MachineError::functor_stub(clause_name!("path_canonical"), 2); - let err = MachineError::representation_error(RepFlag::Character); - let err = self.error_form(err, stub); + let cs = match canonical.to_str() { + Some(s) => s, + _ => { + let stub = + MachineError::functor_stub(clause_name!("path_canonical"), 2); + let err = MachineError::representation_error(RepFlag::Character); + let err = self.error_form(err, stub); - return Err(err); - } - }; + return Err(err); + } + }; let chars = self.heap.put_complete_string(cs); - self.unify(self[temp_v!(2)], chars); + (self.unify_fn)(self, self[temp_v!(2)], chars); } _ => { self.fail = true; @@ -1074,15 +977,16 @@ impl MachineState { }; if let Ok(md) = fs::metadata(file) { - if let Ok(time) = - match which { - "modification" => { md.modified() } - "access" => { md.accessed() } - "creation" => { md.created() } - _ => { unreachable!() } - } { + if let Ok(time) = match which { + "modification" => md.modified(), + "access" => md.accessed(), + "creation" => md.created(), + _ => { + unreachable!() + } + } { let chars = self.systemtime_to_timestamp(time); - self.unify(self[temp_v!(3)], chars); + (self.unify_fn)(self, self[temp_v!(3)], chars); } else { self.fail = true; return Ok(()); @@ -1092,11 +996,6 @@ impl MachineState { return Ok(()); } } - &SystemClauseType::AtEndOfExpansion => { - if self.cp == LocalCodePtr::TopLevel(0, 0) { - self.at_end_of_expansion = true; - } - } &SystemClauseType::AtomChars => { let a1 = self[temp_v!(1)]; @@ -1106,29 +1005,25 @@ impl MachineState { let list_of_chars = Addr::HeapCell(self.heap.to_list(iter)); let a2 = self[temp_v!(2)]; - self.unify(a2, list_of_chars); + (self.unify_fn)(self, a2, list_of_chars); } Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(name, _) = self.heap.clone(h) { - let s = self.heap.put_complete_string(name.as_str()); + if let HeapCellValue::Atom(name, _) = self.heap.clone(h) { + let s = self.heap.put_complete_string(name.as_str()); let a2 = self[temp_v!(2)]; - self.unify(s, a2); + (self.unify_fn)(self, s, a2); } else { unreachable!() } } Addr::EmptyList => { let a2 = self[temp_v!(2)]; - let chars = vec![ - Addr::Char('['), - Addr::Char(']'), - ]; + let chars = vec![Addr::Char('['), Addr::Char(']')]; - let list_of_chars = - Addr::HeapCell(self.heap.to_list(chars.into_iter())); + let list_of_chars = Addr::HeapCell(self.heap.to_list(chars.into_iter())); - self.unify(a2, list_of_chars); + (self.unify_fn)(self, a2, list_of_chars); } addr if addr.is_ref() => { let mut iter = self.heap_pstr_iter(self[temp_v!(2)]); @@ -1137,22 +1032,19 @@ impl MachineState { match iter.focus() { Addr::EmptyList => { if &string == "[]" { - self.unify(addr, Addr::EmptyList); + (self.unify_fn)(self, addr, Addr::EmptyList); } else { - let chars = clause_name!(string, indices.atom_tbl); - let atom = self.heap.to_unifiable( - HeapCellValue::Atom(chars, None) - ); + let chars = clause_name!(string, self.atom_tbl); + let atom = + self.heap.to_unifiable(HeapCellValue::Atom(chars, None)); - self.unify(addr, atom); + (self.unify_fn)(self, addr, atom); } } focus => { if let Addr::Lis(l) = focus { - let stub = MachineError::functor_stub( - clause_name!("atom_chars"), - 2, - ); + let stub = + MachineError::functor_stub(clause_name!("atom_chars"), 2); let err = MachineError::type_error( self.heap.h(), @@ -1179,34 +1071,28 @@ impl MachineState { let list_of_codes = Addr::HeapCell(self.heap.to_list(iter)); let a2 = self[temp_v!(2)]; - self.unify(a2, list_of_codes); + (self.unify_fn)(self, a2, list_of_codes); } Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(name, _) = self.heap.clone(h) { + if let HeapCellValue::Atom(name, _) = self.heap.clone(h) { let a2 = self.store(self.deref(self[temp_v!(2)])); - let iter = name - .as_str() - .chars() - .map(|c| Addr::Fixnum(c as isize)); + let iter = name.as_str().chars().map(|c| Addr::Fixnum(c as isize)); let list_of_codes = Addr::HeapCell(self.heap.to_list(iter)); - self.unify(a2, list_of_codes); + (self.unify_fn)(self, a2, list_of_codes); } else { unreachable!() } } Addr::EmptyList => { - let chars = vec![ - Addr::Fixnum('[' as isize), - Addr::Fixnum(']' as isize), - ]; + let chars = vec![Addr::Fixnum('[' as isize), Addr::Fixnum(']' as isize)]; let list_of_codes = Addr::HeapCell(self.heap.to_list(chars.into_iter())); let a2 = self[temp_v!(2)]; - self.unify(a2, list_of_codes); + (self.unify_fn)(self, a2, list_of_codes); } addr if addr.is_ref() => { let stub = MachineError::functor_stub(clause_name!("atom_codes"), 2); @@ -1253,9 +1139,10 @@ impl MachineState { } } - let string = self.heap.to_unifiable( - HeapCellValue::Atom(clause_name!(chars, indices.atom_tbl), None) - ); + let string = self.heap.to_unifiable(HeapCellValue::Atom( + clause_name!(chars, self.atom_tbl), + None, + )); self.bind(addr.as_var().unwrap(), string); } @@ -1281,7 +1168,7 @@ impl MachineState { clause_name!("[]") } Addr::Char(c) => { - clause_name!(c.to_string(), indices.atom_tbl) + clause_name!(c.to_string(), self.atom_tbl) } _ => { unreachable!() @@ -1293,7 +1180,7 @@ impl MachineState { let a2 = self[temp_v!(2)]; - self.unify(a2, len); + (self.unify_fn)(self, a2, len); } &SystemClauseType::CallContinuation => { let stub = MachineError::functor_stub(clause_name!("call_continuation"), 1); @@ -1324,22 +1211,17 @@ impl MachineState { Err(e) => { return Err(e); } - Ok(addrs) => { - match self.try_char_list(addrs) { - Ok(string) => { - let stub = MachineError::functor_stub(clause_name!("number_chars"), 2); - self.parse_number_from_string(string, indices, stub)?; - } - Err(err) => { - let stub = MachineError::functor_stub( - clause_name!("number_chars"), - 2, - ); - - return Err(self.error_form(err, stub)); - } + Ok(addrs) => match self.try_char_list(addrs) { + Ok(string) => { + let stub = MachineError::functor_stub(clause_name!("number_chars"), 2); + self.parse_number_from_string(string, indices, stub)?; } - } + Err(err) => { + let stub = MachineError::functor_stub(clause_name!("number_chars"), 2); + + return Err(self.error_form(err, stub)); + } + }, } } &SystemClauseType::CreatePartialString => { @@ -1362,13 +1244,13 @@ impl MachineState { } let pstr = self.heap.allocate_pstr(atom.as_str()); - self.unify(self[temp_v!(2)], pstr); + (self.unify_fn)(self, self[temp_v!(2)], pstr); if !self.fail { let h = self.heap.h(); let pstr_tail = self.heap[h - 1].as_addr(h - 1); - self.unify(self[temp_v!(3)], pstr_tail); + (self.unify_fn)(self, self[temp_v!(3)], pstr_tail); } } &SystemClauseType::IsPartialString => { @@ -1382,24 +1264,20 @@ impl MachineState { self.fail = true; return Ok(()); } - _ => { - } + _ => {} } let mut heap_pstr_iter = self.heap_pstr_iter(addr); while let Some(_) = heap_pstr_iter.next() {} - self.fail = - match heap_pstr_iter.focus() { - Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) | - Addr::EmptyList => { - false - } - _ => { - true - } - }; + self.fail = match heap_pstr_iter.focus() { + Addr::AttrVar(_) + | Addr::HeapCell(_) + | Addr::StackCell(..) + | Addr::EmptyList => false, + _ => true, + }; } &SystemClauseType::PartialStringTail => { let pstr = self.store(self.deref(self[temp_v!(1)])); @@ -1410,14 +1288,14 @@ impl MachineState { let tail = self.heap[h + 1].as_addr(h + 1); let target = self[temp_v!(2)]; - self.unify(tail, target); + (self.unify_fn)(self, tail, target); } else { self.fail = true; return Ok(()); } } Addr::Lis(h) => { - self.unify(Addr::HeapCell(h + 1), self[temp_v!(2)]); + (self.unify_fn)(self, Addr::HeapCell(h + 1), self[temp_v!(2)]); } Addr::EmptyList => { self.fail = true; @@ -1441,7 +1319,7 @@ impl MachineState { )?; if stream.past_end_of_stream() { - if EOFAction::Reset != stream.options.eof_action { + if EOFAction::Reset != stream.options().eof_action { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -1450,52 +1328,47 @@ impl MachineState { if stream.at_end_of_stream() { stream.set_past_end_of_stream(); - self.unify(self[temp_v!(2)], Addr::Fixnum(-1)); + (self.unify_fn)(self, self[temp_v!(2)], Addr::Fixnum(-1)); return return_from_clause!(self.last_call, self); } - let addr = - match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => { - addr - } - addr => { - match Number::try_from((addr, &self.heap)) { - Ok(Number::Integer(n)) => { - if let Some(nb) = n.to_u8() { - Addr::Usize(nb as usize) - } else { - return Err(self.type_error( - ValidType::InByte, - addr, - clause_name!("peek_byte"), - 2, - )); - } - } - Ok(Number::Fixnum(n)) => { - if let Ok(nb) = u8::try_from(n) { - Addr::Usize(nb as usize) - } else { - return Err(self.type_error( - ValidType::InByte, - addr, - clause_name!("peek_byte"), - 2, - )); - } - } - _ => { - return Err(self.type_error( - ValidType::InByte, - addr, - clause_name!("peek_byte"), - 2, - )); - } + let addr = match self.store(self.deref(self[temp_v!(2)])) { + addr if addr.is_ref() => addr, + addr => match Number::try_from((addr, &self.heap)) { + Ok(Number::Integer(n)) => { + if let Some(nb) = n.to_u8() { + Addr::Usize(nb as usize) + } else { + return Err(self.type_error( + ValidType::InByte, + addr, + clause_name!("peek_byte"), + 2, + )); } } - }; + Ok(Number::Fixnum(n)) => { + if let Ok(nb) = u8::try_from(n) { + Addr::Usize(nb as usize) + } else { + return Err(self.type_error( + ValidType::InByte, + addr, + clause_name!("peek_byte"), + 2, + )); + } + } + _ => { + return Err(self.type_error( + ValidType::InByte, + addr, + clause_name!("peek_byte"), + 2, + )); + } + }, + }; loop { match stream.peek_byte().map_err(|e| e.kind()) { @@ -1522,7 +1395,7 @@ impl MachineState { 2, )?; - if EOFAction::Reset != stream.options.eof_action { + if EOFAction::Reset != stream.options().eof_action { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -1544,7 +1417,7 @@ impl MachineState { )?; if stream.past_end_of_stream() { - if EOFAction::Reset != stream.options.eof_action { + if EOFAction::Reset != stream.options().eof_action { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -1553,52 +1426,45 @@ impl MachineState { if stream.at_end_of_stream() { let end_of_file = clause_name!("end_of_file"); - let end_of_file = self.heap.to_unifiable( - HeapCellValue::Atom(end_of_file, None), - ); + let end_of_file = self + .heap + .to_unifiable(HeapCellValue::Atom(end_of_file, None)); stream.set_past_end_of_stream(); - self.unify(self[temp_v!(2)], end_of_file); + (self.unify_fn)(self, self[temp_v!(2)], end_of_file); return return_from_clause!(self.last_call, self); } - let addr = - match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => { - addr - } - Addr::Con(h) if self.heap.atom_at(h) => { - match &self.heap[h] { - HeapCellValue::Atom(ref atom, _) if atom.is_char() => { - if let Some(c) = atom.as_str().chars().next() { - Addr::Char(c) - } else { - unreachable!() - } - } - culprit => { - return Err(self.type_error( - ValidType::InCharacter, - culprit.as_addr(h), - clause_name!("peek_char"), - 2, - )); - } + let addr = match self.store(self.deref(self[temp_v!(2)])) { + addr if addr.is_ref() => addr, + Addr::Con(h) if self.heap.atom_at(h) => match &self.heap[h] { + HeapCellValue::Atom(ref atom, _) if atom.is_char() => { + if let Some(c) = atom.as_str().chars().next() { + Addr::Char(c) + } else { + unreachable!() } } - Addr::Char(d) => { - Addr::Char(d) - } culprit => { return Err(self.type_error( ValidType::InCharacter, - culprit, + culprit.as_addr(h), clause_name!("peek_char"), 2, )); } - }; + }, + Addr::Char(d) => Addr::Char(d), + culprit => { + return Err(self.type_error( + ValidType::InCharacter, + culprit, + clause_name!("peek_char"), + 2, + )); + } + }; loop { match stream.peek_char().map_err(|e| e.kind()) { @@ -1625,19 +1491,19 @@ impl MachineState { 2, )?; - if EOFAction::Reset != stream.options.eof_action { + if EOFAction::Reset != stream.options().eof_action { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); } - }/* - _ => { - let stub = MachineError::functor_stub(clause_name!("peek_char"), 2); - let err = MachineError::representation_error(RepFlag::Character); - let err = self.error_form(err, stub); + } /* + _ => { + let stub = MachineError::functor_stub(clause_name!("peek_char"), 2); + let err = MachineError::representation_error(RepFlag::Character); + let err = self.error_form(err, stub); - return Err(err); - }*/ + return Err(err); + }*/ } } } @@ -1654,7 +1520,7 @@ impl MachineState { )?; if stream.past_end_of_stream() { - if EOFAction::Reset != stream.options.eof_action { + if EOFAction::Reset != stream.options().eof_action { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -1663,64 +1529,59 @@ impl MachineState { if stream.at_end_of_stream() { let end_of_file = clause_name!("end_of_file"); - let end_of_file = self.heap.to_unifiable( - HeapCellValue::Atom(end_of_file, None), - ); + let end_of_file = self + .heap + .to_unifiable(HeapCellValue::Atom(end_of_file, None)); stream.set_past_end_of_stream(); - self.unify(self[temp_v!(2)], end_of_file); + (self.unify_fn)(self, self[temp_v!(2)], end_of_file); return return_from_clause!(self.last_call, self); } - let addr = - match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => { - addr - } - addr => { - match Number::try_from((addr, &self.heap)) { - Ok(Number::Integer(n)) => { - let n = n.to_u32().and_then(|n| { - std::char::from_u32(n).and_then(|_| Some(n)) - }); + let addr = match self.store(self.deref(self[temp_v!(2)])) { + addr if addr.is_ref() => addr, + addr => match Number::try_from((addr, &self.heap)) { + Ok(Number::Integer(n)) => { + let n = n + .to_u32() + .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n))); - if let Some(n) = n { - Addr::Fixnum(n as isize) - } else { - return Err(self.representation_error( - RepFlag::InCharacterCode, - clause_name!("peek_code"), - 2, - )); - } - } - Ok(Number::Fixnum(n)) => { - let n = u32::try_from(n).ok().and_then(|n| { - std::char::from_u32(n).and_then(|_| Some(n)) - }); - - if let Some(n) = n { - Addr::Fixnum(n as isize) - } else { - return Err(self.representation_error( - RepFlag::InCharacterCode, - clause_name!("peek_code"), - 2, - )); - } - } - _ => { - return Err(self.type_error( - ValidType::Integer, - self[temp_v!(2)], - clause_name!("peek_code"), - 2, - )); - } + if let Some(n) = n { + Addr::Fixnum(n as isize) + } else { + return Err(self.representation_error( + RepFlag::InCharacterCode, + clause_name!("peek_code"), + 2, + )); } } - }; + Ok(Number::Fixnum(n)) => { + let n = u32::try_from(n) + .ok() + .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n))); + + if let Some(n) = n { + Addr::Fixnum(n as isize) + } else { + return Err(self.representation_error( + RepFlag::InCharacterCode, + clause_name!("peek_code"), + 2, + )); + } + } + _ => { + return Err(self.type_error( + ValidType::Integer, + self[temp_v!(2)], + clause_name!("peek_code"), + 2, + )); + } + }, + }; loop { let result = stream.peek_char(); @@ -1749,19 +1610,12 @@ impl MachineState { 2, )?; - if EOFAction::Reset != stream.options.eof_action { + if EOFAction::Reset != stream.options().eof_action { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); } - }/* - _ => { - let stub = MachineError::functor_stub(clause_name!("get_char"), 2); - let err = MachineError::representation_error(RepFlag::Character); - let err = self.error_form(err, stub); - - return Err(err); - }*/ + } } } } @@ -1771,67 +1625,54 @@ impl MachineState { let n = self.store(self.deref(n)); - let string = - match Number::try_from((n, &self.heap)) { - Ok(Number::Float(OrderedFloat(n))) => { - format!("{0:<20?}", n) - } - Ok(Number::Fixnum(n)) => { - n.to_string() - } - Ok(Number::Integer(n)) => { - n.to_string() - } - Ok(Number::Rational(r)) => { - // n has already been confirmed as an integer, and - // internally, Rational is assumed reduced, so its denominator - // must be 1. - r.numer().to_string() - } - _ => { - unreachable!() - } - }; + let string = match Number::try_from((n, &self.heap)) { + Ok(Number::Float(OrderedFloat(n))) => { + format!("{0:<20?}", n) + } + Ok(Number::Fixnum(n)) => n.to_string(), + Ok(Number::Integer(n)) => n.to_string(), + Ok(Number::Rational(r)) => { + // n has already been confirmed as an integer, and + // internally, Rational is assumed reduced, so its denominator + // must be 1. + r.numer().to_string() + } + _ => { + unreachable!() + } + }; let chars = string.trim().chars().map(|c| Addr::Char(c)); let char_list = Addr::HeapCell(self.heap.to_list(chars)); - self.unify(char_list, chs); + (self.unify_fn)(self, char_list, chs); } &SystemClauseType::NumberToCodes => { let n = self[temp_v!(1)]; let chs = self[temp_v!(2)]; - let string = - match Number::try_from((n, &self.heap)) { - Ok(Number::Float(OrderedFloat(n))) => { - format!("{0:<20?}", n) - } - Ok(Number::Fixnum(n)) => { - n.to_string() - } - Ok(Number::Integer(n)) => { - n.to_string() - } - Ok(Number::Rational(r)) => { - // n has already been confirmed as an integer, and - // internally, Rational is assumed reduced, so its - // denominator must be 1. - r.numer().to_string() - } - _ => { - unreachable!() - } - }; + let string = match Number::try_from((n, &self.heap)) { + Ok(Number::Float(OrderedFloat(n))) => { + format!("{0:<20?}", n) + } + Ok(Number::Fixnum(n)) => n.to_string(), + Ok(Number::Integer(n)) => n.to_string(), + Ok(Number::Rational(r)) => { + // n has already been confirmed as an integer, and + // internally, Rational is assumed reduced, so its + // denominator must be 1. + r.numer().to_string() + } + _ => { + unreachable!() + } + }; - let codes = string - .trim() - .chars() - .map(|c| Addr::Fixnum(c as isize)); + let codes = string.trim().chars().map(|c| Addr::Fixnum(c as isize)); let codes_list = Addr::HeapCell(self.heap.to_list(codes)); - self.unify(codes_list, chs); + (self.unify_fn)(self, codes_list, chs); } &SystemClauseType::CodesToNumber => { let stub = MachineError::functor_stub(clause_name!("number_codes"), 2); @@ -1840,76 +1681,54 @@ impl MachineState { Err(e) => { return Err(e); } - Ok(addrs) => { - match self.try_char_list(addrs) { - Ok(chars) => { - let stub = MachineError::functor_stub(clause_name!("number_codes"), 2); - self.parse_number_from_string(chars, indices, stub)?; - } - Err(err) => { - let stub = MachineError::functor_stub( - clause_name!("number_codes"), - 2, - ); - - return Err(self.error_form(err, stub)); - } + Ok(addrs) => match self.try_char_list(addrs) { + Ok(chars) => { + let stub = MachineError::functor_stub(clause_name!("number_codes"), 2); + self.parse_number_from_string(chars, indices, stub)?; } - } + Err(err) => { + let stub = MachineError::functor_stub(clause_name!("number_codes"), 2); + + return Err(self.error_form(err, stub)); + } + }, } } - &SystemClauseType::ModuleAssertDynamicPredicateToFront => { - let p = self.cp; - let trans_type = DynamicTransactionType::ModuleAssert(DynamicAssertPlace::Front); - - self.p = CodePtr::DynamicTransaction(trans_type, p); - return Ok(()); - } - &SystemClauseType::ModuleAssertDynamicPredicateToBack => { - let p = self.cp; - let trans_type = DynamicTransactionType::ModuleAssert(DynamicAssertPlace::Back); - - self.p = CodePtr::DynamicTransaction(trans_type, p); - return Ok(()); - } &SystemClauseType::LiftedHeapLength => { let a1 = self[temp_v!(1)]; let lh_len = Addr::Usize(self.lifted_heap.h()); - self.unify(a1, lh_len); + (self.unify_fn)(self, a1, lh_len); } &SystemClauseType::CharCode => { let a1 = self[temp_v!(1)]; match self.store(self.deref(a1)) { Addr::Con(h) if self.heap.atom_at(h) => { - let c = - if let HeapCellValue::Atom(name, _) = &self.heap[h] { - if name.is_char() { - name.as_str().chars().next().unwrap() - } else { - self.fail = true; - return Ok(()); - } + let c = if let HeapCellValue::Atom(name, _) = &self.heap[h] { + if name.is_char() { + name.as_str().chars().next().unwrap() } else { - unreachable!() - }; + self.fail = true; + return Ok(()); + } + } else { + unreachable!() + }; let a2 = self[temp_v!(2)]; - self.unify(Addr::Fixnum(c as isize), a2); + (self.unify_fn)(self, Addr::Fixnum(c as isize), a2); } Addr::Char(c) => { let a2 = self[temp_v!(2)]; - self.unify(Addr::Fixnum(c as isize), a2); + (self.unify_fn)(self, Addr::Fixnum(c as isize), a2); } addr if addr.is_ref() => { let a2 = self[temp_v!(2)]; let a2 = self.store(self.deref(a2)); let c = match Number::try_from((a2, &self.heap)) { - Ok(Number::Integer(n)) => { - self.int_to_char(&n, "char_code", 2)? - } + Ok(Number::Integer(n)) => self.int_to_char(&n, "char_code", 2)?, Ok(Number::Fixnum(n)) => { self.int_to_char(&Integer::from(n), "char_code", 2)? } @@ -1919,7 +1738,7 @@ impl MachineState { } }; - self.unify(Addr::Char(c), addr); + (self.unify_fn)(self, Addr::Char(c), addr); } _ => { unreachable!(); @@ -1935,45 +1754,41 @@ impl MachineState { Addr::Con(h) if self.heap.atom_at(h) => { if let HeapCellValue::Atom(name, _) = &self.heap[h] { name.as_str().chars().next().unwrap() - } - else { + } else { unreachable!() } } - _ => unreachable!() + _ => unreachable!(), }; let chars = match a2 { Addr::Con(h) if self.heap.atom_at(h) => { if let HeapCellValue::Atom(name, _) = &self.heap[h] { name.as_str().to_string() - } - else { + } else { unreachable!() } } - Addr::Char(c) => { - c.to_string() - } - _ => unreachable!() + Addr::Char(c) => c.to_string(), + _ => unreachable!(), }; self.fail = true; // This predicate fails by default. macro_rules! macro_check { ($id:ident, $name:tt) => { - if $id!(c) && chars == $name { - self.fail = false; + if $id!(c) && chars == $name { + self.fail = false; - return return_from_clause!(self.last_call, self); - } - } + return return_from_clause!(self.last_call, self); + } + }; } macro_rules! method_check { ($id:ident, $name:tt) => { - if c.$id() && chars == $name { - self.fail = false; + if c.$id() && chars == $name { + self.fail = false; - return return_from_clause!(self.last_call, self); - } - } + return return_from_clause!(self.last_call, self); + } + }; } macro_check!(symbolic_control_char, "symbolic_control"); // macro_check!(space_char, "space"); @@ -2035,12 +1850,10 @@ impl MachineState { self.copy_term(AttrVarPolicy::StripAttributes); } &SystemClauseType::FetchGlobalVar => { - let key = self[temp_v!(1)]; - - let key = match self.store(self.deref(key)) { + let (key_h, key) = match self.store(self.deref(self[temp_v!(1)])) { Addr::Con(h) if self.heap.atom_at(h) => { if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { - atom.clone() + (h, atom.clone()) } else { unreachable!() } @@ -2053,61 +1866,29 @@ impl MachineState { let addr = self[temp_v!(2)]; match indices.global_variables.get_mut(&key) { - Some((ref mut ball, None)) => { - let h = self.heap.h(); - let stub = ball.copy_and_align(h); + Some((ref ball, ref mut loc)) => { + match loc { + Some(ref value_addr) => { + (self.unify_fn)(self, addr, *value_addr); + } + loc @ None if !ball.stub.is_empty() => { + let h = self.heap.h(); + let stub = ball.copy_and_align(h); - self.heap.extend(stub.into_iter()); - self.unify(addr, Addr::HeapCell(h)); - } - Some((_, Some(h))) => { - self.unify(addr, Addr::HeapCell(*h)) + self.heap.extend(stub.into_iter()); + (self.unify_fn)(self, addr, Addr::HeapCell(h)); + + if !self.fail { + *loc = Some(Addr::HeapCell(h)); + self.trail(TrailRef::BlackboardEntry(key_h)); + } + } + _ => self.fail = true, + } } None => self.fail = true, }; } - &SystemClauseType::FetchGlobalVarWithOffset => { - let key = self[temp_v!(1)]; - - let key = match self.store(self.deref(key)) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { - atom.clone() - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - }; - - let addr = self[temp_v!(2)]; - - match indices.global_variables.get_mut(&key) { - Some((ref mut ball, ref mut offset @ None)) => { - let h = self.heap.h(); - let stub = ball.copy_and_align(h); - - self.heap.extend(stub.into_iter()); - self.unify(addr, Addr::HeapCell(h)); - - *offset = Some(h); - } - Some((_, Some(h))) => { - let offset = self[temp_v!(3)]; - - self.unify(offset, Addr::Usize(*h)); - - if !self.fail { - self.unify(addr, Addr::HeapCell(*h)); - } - } - None => { - self.fail = true - } - }; - } &SystemClauseType::PutCode => { let mut stream = self.get_stream_or_alias(self[temp_v!(1)], indices, "put_code", 2)?; @@ -2136,7 +1917,9 @@ impl MachineState { } } Ok(Number::Fixnum(n)) => { - if let Some(c) = u32::try_from(n).ok().and_then(|c| char::try_from(c).ok()) { + if let Some(c) = + u32::try_from(n).ok().and_then(|c| char::try_from(c).ok()) + { write!(&mut stream, "{}", c).unwrap(); return return_from_clause!(self.last_call, self); } @@ -2154,9 +1937,7 @@ impl MachineState { } let stub = MachineError::functor_stub(clause_name!("put_code"), 2); - let err = MachineError::representation_error( - RepFlag::CharacterCode, - ); + let err = MachineError::representation_error(RepFlag::CharacterCode); return Err(self.error_form(err, stub)); } @@ -2183,34 +1964,27 @@ impl MachineState { } addr => { match self.store(self.deref(self[temp_v!(2)])) { - Addr::Con(h) if self.heap.atom_at(h) => { - match &self.heap[h] { - HeapCellValue::Atom(ref atom, _) if atom.is_char() => { - if let Some(c) = atom.as_str().chars().next() { - write!(&mut stream, "{}", c).unwrap(); - return return_from_clause!(self.last_call, self); - } else { - unreachable!() - } - } - _ => { + Addr::Con(h) if self.heap.atom_at(h) => match &self.heap[h] { + HeapCellValue::Atom(ref atom, _) if atom.is_char() => { + if let Some(c) = atom.as_str().chars().next() { + write!(&mut stream, "{}", c).unwrap(); + return return_from_clause!(self.last_call, self); + } else { + unreachable!() } } - } + _ => {} + }, Addr::Char(c) => { write!(&mut stream, "{}", c).unwrap(); return return_from_clause!(self.last_call, self); } - _ => { - } + _ => {} } let stub = MachineError::functor_stub(clause_name!("put_char"), 2); - let err = MachineError::type_error( - self.heap.h(), - ValidType::Character, - addr, - ); + let err = + MachineError::type_error(self.heap.h(), ValidType::Character, addr); return Err(self.error_form(err, stub)); } @@ -2223,10 +1997,9 @@ impl MachineState { let mut bytes = Vec::new(); let string = self.heap_pstr_iter(self[temp_v!(2)]).to_string(); - if stream.options.stream_type == StreamType::Binary { + if stream.options().stream_type == StreamType::Binary { for c in string.chars() { if c as u32 > 255 { - let stub = MachineError::functor_stub(clause_name!("$put_chars"), 2); let err = MachineError::type_error( @@ -2249,14 +2022,11 @@ impl MachineState { return return_from_clause!(self.last_call, self); } _ => { - let stub = MachineError::functor_stub( - clause_name!("$put_chars"), - 2, - ); + let stub = MachineError::functor_stub(clause_name!("$put_chars"), 2); - let addr = self.heap.to_unifiable( - HeapCellValue::Stream(stream.clone()), - ); + let addr = self + .heap + .to_unifiable(HeapCellValue::Stream(stream.clone())); return Err(self.error_form( MachineError::existence_error( @@ -2343,8 +2113,7 @@ impl MachineState { } } } - _ => { - } + _ => {} } let stub = MachineError::functor_stub(clause_name!("put_byte"), 2); @@ -2371,62 +2140,52 @@ impl MachineState { )?; if stream.past_end_of_stream() { - self.eof_action( - self[temp_v!(2)], - &mut stream, - clause_name!("get_byte"), - 2, - )?; + self.eof_action(self[temp_v!(2)], &mut stream, clause_name!("get_byte"), 2)?; - if EOFAction::Reset != stream.options.eof_action { + if EOFAction::Reset != stream.options().eof_action { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); } } - let addr = - match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => { - addr - } - addr => { - match Number::try_from((addr, &self.heap)) { - Ok(Number::Integer(n)) => { - if let Some(nb) = n.to_u8() { - Addr::Usize(nb as usize) - } else { - return Err(self.type_error( - ValidType::InByte, - addr, - clause_name!("get_byte"), - 2, - )); - } - } - Ok(Number::Fixnum(n)) => { - if let Ok(nb) = u8::try_from(n) { - Addr::Usize(nb as usize) - } else { - return Err(self.type_error( - ValidType::InByte, - addr, - clause_name!("get_byte"), - 2, - )); - } - } - _ => { - return Err(self.type_error( - ValidType::InByte, - addr, - clause_name!("get_byte"), - 2, - )); - } + let addr = match self.store(self.deref(self[temp_v!(2)])) { + addr if addr.is_ref() => addr, + addr => match Number::try_from((addr, &self.heap)) { + Ok(Number::Integer(n)) => { + if let Some(nb) = n.to_u8() { + Addr::Usize(nb as usize) + } else { + return Err(self.type_error( + ValidType::InByte, + addr, + clause_name!("get_byte"), + 2, + )); } } - }; + Ok(Number::Fixnum(n)) => { + if let Ok(nb) = u8::try_from(n) { + Addr::Usize(nb as usize) + } else { + return Err(self.type_error( + ValidType::InByte, + addr, + clause_name!("get_byte"), + 2, + )); + } + } + _ => { + return Err(self.type_error( + ValidType::InByte, + addr, + clause_name!("get_byte"), + 2, + )); + } + }, + }; loop { let mut b = [0u8; 1]; @@ -2445,7 +2204,7 @@ impl MachineState { } _ => { stream.set_past_end_of_stream(); - self.unify(self[temp_v!(2)], Addr::Fixnum(-1)); + (self.unify_fn)(self, self[temp_v!(2)], Addr::Fixnum(-1)); return return_from_clause!(self.last_call, self); } } @@ -2464,7 +2223,7 @@ impl MachineState { )?; if stream.past_end_of_stream() { - if EOFAction::Reset != stream.options.eof_action { + if EOFAction::Reset != stream.options().eof_action { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -2473,58 +2232,47 @@ impl MachineState { if stream.at_end_of_stream() { let end_of_file = clause_name!("end_of_file"); - let end_of_file = self.heap.to_unifiable( - HeapCellValue::Atom(end_of_file, None), - ); + let end_of_file = self + .heap + .to_unifiable(HeapCellValue::Atom(end_of_file, None)); stream.set_past_end_of_stream(); - self.unify(self[temp_v!(2)], end_of_file); + (self.unify_fn)(self, self[temp_v!(2)], end_of_file); return return_from_clause!(self.last_call, self); } - let mut iter = self.open_parsing_stream( - stream.clone(), - "get_char", - 2, - )?; + let mut iter = self.open_parsing_stream(stream.clone(), "get_char", 2)?; - let addr = - match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => { - addr - } - Addr::Con(h) if self.heap.atom_at(h) => { - match &self.heap[h] { - HeapCellValue::Atom(ref atom, _) if atom.is_char() => { - if let Some(c) = atom.as_str().chars().next() { - Addr::Char(c) - } else { - unreachable!() - } - } - culprit => { - return Err(self.type_error( - ValidType::InCharacter, - culprit.as_addr(h), - clause_name!("get_char"), - 2, - )); - } + let addr = match self.store(self.deref(self[temp_v!(2)])) { + addr if addr.is_ref() => addr, + Addr::Con(h) if self.heap.atom_at(h) => match &self.heap[h] { + HeapCellValue::Atom(ref atom, _) if atom.is_char() => { + if let Some(c) = atom.as_str().chars().next() { + Addr::Char(c) + } else { + unreachable!() } } - Addr::Char(d) => { - Addr::Char(d) - } culprit => { return Err(self.type_error( ValidType::InCharacter, - culprit, + culprit.as_addr(h), clause_name!("get_char"), 2, )); } - }; + }, + Addr::Char(d) => Addr::Char(d), + culprit => { + return Err(self.type_error( + ValidType::InCharacter, + culprit, + clause_name!("get_char"), + 2, + )); + } + }; loop { let result = iter.next(); @@ -2549,19 +2297,19 @@ impl MachineState { 2, )?; - if EOFAction::Reset != stream.options.eof_action { + if EOFAction::Reset != stream.options().eof_action { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); } - }/* - _ => { - let stub = MachineError::functor_stub(clause_name!("get_char"), 2); - let err = MachineError::representation_error(RepFlag::Character); - let err = self.error_form(err, stub); + } /* + _ => { + let stub = MachineError::functor_stub(clause_name!("get_char"), 2); + let err = MachineError::representation_error(RepFlag::Character); + let err = self.error_form(err, stub); - return Err(err); - }*/ + return Err(err); + }*/ } } } @@ -2569,23 +2317,23 @@ impl MachineState { let stream = self.get_stream_or_alias(self[temp_v!(1)], indices, "get_n_chars", 3)?; - let num = - match Number::try_from((self[temp_v!(2)], &self.heap)) { - Ok(Number::Fixnum(n)) => { - usize::try_from(n).unwrap() + let num = match Number::try_from((self[temp_v!(2)], &self.heap)) { + Ok(Number::Fixnum(n)) => usize::try_from(n).unwrap(), + Ok(Number::Integer(n)) => match n.to_usize() { + Some(u) => u, + _ => { + self.fail = true; + return Ok(()); } - Ok(Number::Integer(n)) => { - match n.to_usize() { - Some(u) => { u } - _ => { self.fail = true; return Ok(()); } - } - } - _ => { unreachable!() } - }; + }, + _ => { + unreachable!() + } + }; let mut string = String::new(); - if stream.options.stream_type == StreamType::Binary { + if stream.options().stream_type == StreamType::Binary { let mut buf = vec![]; let mut chunk = stream.take(num as u64); chunk.read_to_end(&mut buf).ok(); @@ -2593,26 +2341,23 @@ impl MachineState { string.push(c as char); } } else { - let mut iter = self.open_parsing_stream( - stream.clone(), - "get_n_chars", - 2, - )?; + let mut iter = self.open_parsing_stream(stream.clone(), "get_n_chars", 2)?; for _ in 0..num { - let result = iter.next(); + let result = iter.next(); - match result { - Some(Ok(c)) => { + match result { + Some(Ok(c)) => { string.push(c); - } - _ => { break; - } - } - } + } + _ => { + break; + } + } + } }; let string = self.heap.put_complete_string(&string); - self.unify(self[temp_v!(3)], string); + (self.unify_fn)(self, self[temp_v!(3)], string); } &SystemClauseType::GetCode => { let mut stream = @@ -2627,7 +2372,7 @@ impl MachineState { )?; if stream.past_end_of_stream() { - if EOFAction::Reset != stream.options.eof_action { + if EOFAction::Reset != stream.options().eof_action { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -2636,70 +2381,61 @@ impl MachineState { if stream.at_end_of_stream() { let end_of_file = clause_name!("end_of_file"); - let end_of_file = self.heap.to_unifiable( - HeapCellValue::Atom(end_of_file, None), - ); + let end_of_file = self + .heap + .to_unifiable(HeapCellValue::Atom(end_of_file, None)); stream.set_past_end_of_stream(); - self.unify(self[temp_v!(2)], end_of_file); + (self.unify_fn)(self, self[temp_v!(2)], end_of_file); return return_from_clause!(self.last_call, self); } - let addr = - match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => { - addr - } - addr => { - match Number::try_from((addr, &self.heap)) { - Ok(Number::Integer(n)) => { - let n = n.to_u32().and_then(|n| { - std::char::from_u32(n).and_then(|_| Some(n)) - }); + let addr = match self.store(self.deref(self[temp_v!(2)])) { + addr if addr.is_ref() => addr, + addr => match Number::try_from((addr, &self.heap)) { + Ok(Number::Integer(n)) => { + let n = n + .to_u32() + .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n))); - if let Some(n) = n { - Addr::Fixnum(n as isize) - } else { - return Err(self.representation_error( - RepFlag::InCharacterCode, - clause_name!("get_code"), - 2, - )); - } - } - Ok(Number::Fixnum(n)) => { - let n = u32::try_from(n).ok().and_then(|n| { - std::char::from_u32(n).and_then(|_| Some(n)) - }); - - if let Some(n) = n { - Addr::Fixnum(n as isize) - } else { - return Err(self.representation_error( - RepFlag::InCharacterCode, - clause_name!("get_code"), - 2, - )); - } - } - _ => { - return Err(self.type_error( - ValidType::Integer, - self[temp_v!(2)], - clause_name!("get_code"), - 2, - )); - } + if let Some(n) = n { + Addr::Fixnum(n as isize) + } else { + return Err(self.representation_error( + RepFlag::InCharacterCode, + clause_name!("get_code"), + 2, + )); } } - }; + Ok(Number::Fixnum(n)) => { + let n = u32::try_from(n) + .ok() + .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n))); - let mut iter = self.open_parsing_stream( - stream.clone(), - "get_code", - 2, - )?; + if let Some(n) = n { + Addr::Fixnum(n as isize) + } else { + return Err(self.representation_error( + RepFlag::InCharacterCode, + clause_name!("get_code"), + 2, + )); + } + } + _ => { + return Err(self.type_error( + ValidType::Integer, + self[temp_v!(2)], + clause_name!("get_code"), + 2, + )); + } + }, + }; + + let mut iter = self.open_parsing_stream(stream.clone(), "get_code", 2)?; loop { let result = iter.next(); @@ -2724,19 +2460,12 @@ impl MachineState { 2, )?; - if EOFAction::Reset != stream.options.eof_action { + if EOFAction::Reset != stream.options().eof_action { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); } - }/* - _ => { - let stub = MachineError::functor_stub(clause_name!("get_char"), 2); - let err = MachineError::representation_error(RepFlag::Character); - let err = self.error_form(err, stub); - - return Err(err); - }*/ + } } } } @@ -2766,24 +2495,28 @@ impl MachineState { } } &SystemClauseType::NextStream => { - let prev_stream = - match self.store(self.deref(self[temp_v!(1)])) { - Addr::Stream(h) => { - if let HeapCellValue::Stream(ref stream) = &self.heap[h] { - stream.clone() - } else { - unreachable!() - } - } - _ => { + let prev_stream = match self.store(self.deref(self[temp_v!(1)])) { + Addr::Stream(h) => { + if let HeapCellValue::Stream(ref stream) = &self.heap[h] { + stream.clone() + } else { unreachable!() } - }; + } + _ => { + unreachable!() + } + }; - let mut next_stream = None; + let mut next_stream = None; let mut null_streams = BTreeSet::new(); - for stream in indices.streams.range(prev_stream.clone() ..).skip(1).cloned() { + for stream in indices + .streams + .range(prev_stream.clone()..) + .skip(1) + .cloned() + { if !stream.is_null_stream() { next_stream = Some(stream); break; @@ -2811,9 +2544,7 @@ impl MachineState { if !stream.is_output_stream() { let stub = MachineError::functor_stub(clause_name!("flush_output"), 1); - let addr = vec![ - HeapCellValue::Stream(stream) - ]; + let addr = vec![HeapCellValue::Stream(stream)]; let err = MachineError::permission_error( self.heap.h(), @@ -2830,14 +2561,11 @@ impl MachineState { &SystemClauseType::GetSingleChar => { let ctrl_c = KeyEvent { code: KeyCode::Char('c'), - modifiers: KeyModifiers::CONTROL + modifiers: KeyModifiers::CONTROL, }; let key = get_key(); if key == ctrl_c { - let stub = MachineError::functor_stub( - clause_name!("get_single_char"), - 1 - ); + let stub = MachineError::functor_stub(clause_name!("get_single_char"), 1); let err = MachineError::interrupt_error(); let err = self.error_form(err, stub); @@ -2847,117 +2575,26 @@ impl MachineState { KeyCode::Enter => '\n', KeyCode::Tab => '\t', KeyCode::Char(c) => c, - _ => unreachable!() + _ => unreachable!(), }; let a1 = self[temp_v!(1)]; - self.unify(Addr::Char(c), a1); - } - &SystemClauseType::GetModuleClause => { - let module = self[temp_v!(3)]; - let head = self[temp_v!(1)]; - - let module = match self.store(self.deref(module)) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(module, _) = &self.heap[h] { - module.clone() - } else { - unreachable!() - } - } - _ => { - self.fail = true; - return Ok(()); - } - }; - - let subsection = match self.store(self.deref(head)) { - Addr::Str(s) => match &self.heap[s] { - &HeapCellValue::NamedStr(arity, ref name, ..) => { - indices.get_clause_subsection(module, name.clone(), arity) - } - _ => { - unreachable!() - } - }, - Addr::Con(h) => { - if let HeapCellValue::Atom(name, _) = &self.heap[h] { - indices.get_clause_subsection(module, name.clone(), 0) - } else { - unreachable!() - } - } - - _ => { - unreachable!() - } - }; - - match subsection { - Some(dynamic_predicate_info) => { - self.execute_at_index( - 2, - dir_entry!(dynamic_predicate_info.clauses_subsection_p), - ); - - return Ok(()); - } - None => { - self.fail = true; - } - } - } - &SystemClauseType::ModuleHeadIsDynamic => { - let module = self[temp_v!(2)]; - let head = self[temp_v!(1)]; - - let module = match self.store(self.deref(module)) { - Addr::Con(h) if self.heap.atom_at(h) => - if let HeapCellValue::Atom(module, _) = &self.heap[h] { - module.clone() - } else { - unreachable!() - } - _ => { - self.fail = true; - return Ok(()); - } - }; - - self.fail = !match self.store(self.deref(head)) { - Addr::Str(s) => match &self.heap[s] { - &HeapCellValue::NamedStr(arity, ref name, ..) => { - indices.get_clause_subsection(module, name.clone(), arity) - .is_some() - } - _ => unreachable!(), - }, - Addr::Con(h) => { - if let HeapCellValue::Atom(name, _) = &self.heap[h] { - indices.get_clause_subsection(module, name.clone(), 0) - .is_some() - } else { - unreachable!() - } - } - _ => unreachable!(), - }; + (self.unify_fn)(self, Addr::Char(c), a1); } &SystemClauseType::HeadIsDynamic => { - let head = self[temp_v!(1)]; + let module_name = atom_from!(self, self.store(self.deref(self[temp_v!(1)]))); - self.fail = !match self.store(self.deref(head)) { + self.fail = !match self.store(self.deref(self[temp_v!(2)])) { Addr::Str(s) => match &self.heap[s] { - &HeapCellValue::NamedStr(arity, ref name, ..) => indices - .get_clause_subsection(name.owning_module(), name.clone(), arity) - .is_some(), + &HeapCellValue::NamedStr(arity, ref name, ..) => { + indices.is_dynamic_predicate(module_name, (name.clone(), arity)) + } _ => unreachable!(), }, Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(name, _) = &self.heap[h] { - indices.get_clause_subsection(name.owning_module(), name.clone(), 0) - .is_some() + if let HeapCellValue::Atom(name, _) = &self.heap[h] { + indices.is_dynamic_predicate(module_name, (name.clone(), 0)) } else { unreachable!() } @@ -2968,8 +2605,7 @@ impl MachineState { }; } &SystemClauseType::Close => { - let mut stream = - self.get_stream_or_alias(self[temp_v!(1)], indices, "close", 2)?; + let mut stream = self.get_stream_or_alias(self[temp_v!(1)], indices, "close", 2)?; if !stream.is_input_stream() { stream.flush().unwrap(); // 8.11.6.1b) @@ -2978,15 +2614,19 @@ impl MachineState { indices.streams.remove(&stream); if stream == *current_input_stream { - *current_input_stream = indices.stream_aliases.get( - &clause_name!("user_input") - ).cloned().unwrap(); + *current_input_stream = indices + .stream_aliases + .get(&clause_name!("user_input")) + .cloned() + .unwrap(); indices.streams.insert(current_input_stream.clone()); } else if stream == *current_output_stream { - *current_output_stream = indices.stream_aliases.get( - &clause_name!("user_output") - ).cloned().unwrap(); + *current_output_stream = indices + .stream_aliases + .get(&clause_name!("user_output")) + .cloned() + .unwrap(); indices.streams.insert(current_output_stream.clone()); } @@ -2994,36 +2634,34 @@ impl MachineState { if !stream.is_stdin() && !stream.is_stdout() { stream.close(); - if let Some(alias) = stream.options.alias { - indices.stream_aliases.remove(&alias); + if let Some(ref alias) = stream.options().alias { + indices.stream_aliases.remove(alias); } } } - &SystemClauseType::CopyToLiftedHeap => { - match self.store(self.deref(self[temp_v!(1)])) { - Addr::Usize(lh_offset) => { - let copy_target = self[temp_v!(2)]; + &SystemClauseType::CopyToLiftedHeap => match self.store(self.deref(self[temp_v!(1)])) { + Addr::Usize(lh_offset) => { + let copy_target = self[temp_v!(2)]; - let old_threshold = self.copy_findall_solution(lh_offset, copy_target); - let new_threshold = self.lifted_heap.h() - lh_offset; + let old_threshold = self.copy_findall_solution(lh_offset, copy_target); + let new_threshold = self.lifted_heap.h() - lh_offset; - self.lifted_heap[old_threshold] = - HeapCellValue::Addr(Addr::HeapCell(new_threshold)); + self.lifted_heap[old_threshold] = + HeapCellValue::Addr(Addr::HeapCell(new_threshold)); - for addr in self.lifted_heap.iter_mut_from(old_threshold + 1) { - match addr { - HeapCellValue::Addr(ref mut addr) => { - *addr -= self.heap.h() + lh_offset; - } - _ => {} + for addr in self.lifted_heap.iter_mut_from(old_threshold + 1) { + match addr { + HeapCellValue::Addr(ref mut addr) => { + *addr -= self.heap.h() + lh_offset; } + _ => {} } } - _ => { - self.fail = true; - } } - } + _ => { + self.fail = true; + } + }, &SystemClauseType::DeleteAttribute => { let ls0 = self.store(self.deref(self[temp_v!(1)])); @@ -3041,7 +2679,7 @@ impl MachineState { let trail_ref = match old_addr { Addr::HeapCell(h) => TrailRef::AttrVarHeapLink(h), Addr::Lis(l) => TrailRef::AttrVarListLink(l1 + 1, l), - _ => unreachable!() + _ => unreachable!(), }; self.heap[l1 + 1] = HeapCellValue::Addr(tail); @@ -3101,31 +2739,37 @@ impl MachineState { match self.store(self.deref(self[temp_v!(2 + narity)])) { Addr::Str(a) => { if let HeapCellValue::NamedStr(arity, name, _) = self.heap.clone(a) { - for i in (arity + 1 .. arity + narity + 1).rev() { + for i in (arity + 1..arity + narity + 1).rev() { self.registers[i] = self.registers[i - arity]; } - for i in 1 .. arity + 1 { + for i in 1..arity + 1 { self.registers[i] = self.heap[a + i].as_addr(a + i); } return self.module_lookup( indices, + call_policy, (name, arity + narity), module_name, true, + current_input_stream, + current_output_stream, ); } else { unreachable!() } } Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(name, _) = self.heap.clone(h) { + if let HeapCellValue::Atom(name, _) = self.heap.clone(h) { return self.module_lookup( indices, + call_policy, (name.clone(), narity), module_name, true, + current_input_stream, + current_output_stream, ); } else { unreachable!() @@ -3134,11 +2778,8 @@ impl MachineState { addr => { let stub = MachineError::functor_stub(clause_name!("(:)"), 2); - let type_error = MachineError::type_error( - self.heap.h(), - ValidType::Callable, - addr, - ); + let type_error = + MachineError::type_error(self.heap.h(), ValidType::Callable, addr); let type_error = self.error_form(type_error, stub); return Err(type_error); @@ -3156,10 +2797,10 @@ impl MachineState { Addr::AttrVar(h) => { self.attr_var_init.attr_var_queue.push(h); } - _ => { - } + _ => {} } } + /* &SystemClauseType::ExpandGoal => { self.p = CodePtr::Local(LocalCodePtr::UserGoalExpansion(0)); return Ok(()); @@ -3168,13 +2809,14 @@ impl MachineState { self.p = CodePtr::Local(LocalCodePtr::UserTermExpansion(0)); return Ok(()); } + */ &SystemClauseType::GetNextDBRef => { let a1 = self[temp_v!(1)]; match self.store(self.deref(a1)) { addr @ Addr::HeapCell(_) - | addr @ Addr::StackCell(..) - | addr @ Addr::AttrVar(_) => { + | addr @ Addr::StackCell(..) + | addr @ Addr::AttrVar(_) => { let mut iter = indices.code_dir.iter(); while let Some(((name, arity), _)) = iter.next() { @@ -3185,15 +2827,13 @@ impl MachineState { let spec = get_clause_spec( name.clone(), *arity, - composite_op!(&indices.op_dir), + &CompositeOpDir::new(&indices.op_dir, None), ); let db_ref = DBRef::NamedPred(name.clone(), *arity, spec); let r = addr.as_var().unwrap(); - let addr = self.heap.to_unifiable( - HeapCellValue::DBRef(db_ref) - ); + let addr = self.heap.to_unifiable(HeapCellValue::DBRef(db_ref)); self.bind(r, addr); @@ -3202,19 +2842,17 @@ impl MachineState { self.fail = true; } - Addr::Con(h) => { - match self.heap.clone(h) { - HeapCellValue::DBRef(DBRef::Op(..)) => { - self.fail = true; - } - HeapCellValue::DBRef(ref db_ref) => { - self.get_next_db_ref(indices, db_ref); - } - _ => { - self.fail = true; - } + Addr::Con(h) => match self.heap.clone(h) { + HeapCellValue::DBRef(DBRef::Op(..)) => { + self.fail = true; } - } + HeapCellValue::DBRef(ref db_ref) => { + self.get_next_db_ref(indices, db_ref); + } + _ => { + self.fail = true; + } + }, _ => { self.fail = true; } @@ -3225,8 +2863,8 @@ impl MachineState { match self.store(self.deref(a1)) { addr @ Addr::HeapCell(_) - | addr @ Addr::StackCell(..) - | addr @ Addr::AttrVar(_) => { + | addr @ Addr::StackCell(..) + | addr @ Addr::AttrVar(_) => { let mut unossified_op_dir = OssifiedOpDir::new(); unossified_op_dir.extend(indices.op_dir.iter().filter_map( @@ -3258,9 +2896,7 @@ impl MachineState { ); let r = addr.as_var().unwrap(); - let addr = self.heap.to_unifiable( - HeapCellValue::DBRef(db_ref) - ); + let addr = self.heap.to_unifiable(HeapCellValue::DBRef(db_ref)); self.bind(r, addr); } @@ -3270,19 +2906,17 @@ impl MachineState { } } } - Addr::Con(h) => { - match self.heap.clone(h) { - HeapCellValue::DBRef(DBRef::NamedPred(..)) => { - self.fail = true; - } - HeapCellValue::DBRef(ref db_ref) => { - self.get_next_db_ref(indices, db_ref); - } - _ => { - self.fail = true; - } + Addr::Con(h) => match self.heap.clone(h) { + HeapCellValue::DBRef(DBRef::NamedPred(..)) => { + self.fail = true; } - } + HeapCellValue::DBRef(ref db_ref) => { + self.get_next_db_ref(indices, db_ref); + } + _ => { + self.fail = true; + } + }, _ => { self.fail = true; } @@ -3292,27 +2926,23 @@ impl MachineState { let a1 = self[temp_v!(1)]; match self.store(self.deref(a1)) { - Addr::Con(h) => { - match self.heap.clone(h) { - HeapCellValue::DBRef(DBRef::NamedPred(name, arity, spec)) => { - let a2 = self[temp_v!(2)]; - let a3 = self[temp_v!(3)]; + Addr::Con(h) => match self.heap.clone(h) { + HeapCellValue::DBRef(DBRef::NamedPred(name, arity, spec)) => { + let a2 = self[temp_v!(2)]; + let a3 = self[temp_v!(3)]; - let atom = self.heap.to_unifiable( - HeapCellValue::Atom(name, spec) - ); + let atom = self.heap.to_unifiable(HeapCellValue::Atom(name, spec)); - self.unify(a2, atom); + (self.unify_fn)(self, a2, atom); - if !self.fail { - self.unify(a3, Addr::Usize(arity)); - } - } - _ => { - self.fail = true; + if !self.fail { + (self.unify_fn)(self, a3, Addr::Usize(arity)); } } - } + _ => { + self.fail = true; + } + }, _ => { self.fail = true; } @@ -3322,56 +2952,54 @@ impl MachineState { let a1 = self[temp_v!(1)]; match self.store(self.deref(a1)) { - Addr::Con(h) => { - match self.heap.clone(h) { - HeapCellValue::DBRef(DBRef::Op( - priority, - spec, - name, - _, - shared_op_desc, - )) => { - let prec = self[temp_v!(2)]; - let specifier = self[temp_v!(3)]; - let op = self[temp_v!(4)]; + Addr::Con(h) => match self.heap.clone(h) { + HeapCellValue::DBRef(DBRef::Op( + priority, + spec, + name, + _, + shared_op_desc, + )) => { + let prec = self[temp_v!(2)]; + let specifier = self[temp_v!(3)]; + let op = self[temp_v!(4)]; - let spec = match spec { - FX => "fx", - FY => "fy", - XF => "xf", - YF => "yf", - XFX => "xfx", - XFY => "xfy", - YFX => "yfx", - _ => { - self.fail = true; - return Ok(()); - } - }; - - let a3 = self.heap.to_unifiable( - HeapCellValue::Atom(clause_name!(spec), None) - ); - - let a4 = self.heap.to_unifiable( - HeapCellValue::Atom(name, Some(shared_op_desc)) - ); - - self.unify(Addr::Usize(priority), prec); - - if !self.fail { - self.unify(a3, specifier); + let spec = match spec { + FX => "fx", + FY => "fy", + XF => "xf", + YF => "yf", + XFX => "xfx", + XFY => "xfy", + YFX => "yfx", + _ => { + self.fail = true; + return Ok(()); } + }; - if !self.fail { - self.unify(a4, op); - } + let a3 = self + .heap + .to_unifiable(HeapCellValue::Atom(clause_name!(spec), None)); + + let a4 = self + .heap + .to_unifiable(HeapCellValue::Atom(name, Some(shared_op_desc))); + + (self.unify_fn)(self, Addr::Usize(priority), prec); + + if !self.fail { + (self.unify_fn)(self, a3, specifier); } - _ => { - self.fail = true; + + if !self.fail { + (self.unify_fn)(self, a4, op); } } - } + _ => { + self.fail = true; + } + }, _ => { self.fail = true; } @@ -3390,11 +3018,11 @@ impl MachineState { let a2 = ProcessTime::now().as_duration().as_secs_f64(); let addr = self.heap.put_constant(Constant::Float(OrderedFloat(a2))); - self.unify(a1, addr); + (self.unify_fn)(self, a1, addr); } &SystemClauseType::CurrentTime => { let str = self.systemtime_to_timestamp(SystemTime::now()); - self.unify(self[temp_v!(1)], str); + (self.unify_fn)(self, self[temp_v!(1)], str); } &SystemClauseType::OpDeclaration => { let priority = self[temp_v!(1)]; @@ -3403,59 +3031,54 @@ impl MachineState { let priority = self.store(self.deref(priority)); - let priority = - match Number::try_from((priority, &self.heap)) { - Ok(Number::Integer(n)) => { - n.to_usize().unwrap() - } - Ok(Number::Fixnum(n)) => { - usize::try_from(n).unwrap() - } - _ => { - unreachable!(); - } - }; + let priority = match Number::try_from((priority, &self.heap)) { + Ok(Number::Integer(n)) => n.to_usize().unwrap(), + Ok(Number::Fixnum(n)) => usize::try_from(n).unwrap(), + _ => { + unreachable!(); + } + }; let specifier = match self.store(self.deref(specifier)) { - Addr::Con(h) if self.heap.atom_at(h) => + Addr::Con(h) if self.heap.atom_at(h) => { if let HeapCellValue::Atom(ref specifier, _) = &self.heap[h] { specifier.clone() } else { unreachable!() - }, - _ => - unreachable!(), + } + } + _ => unreachable!(), }; let op = match self.store(self.deref(op)) { - Addr::Char(c) => - clause_name!(c.to_string(), indices.atom_tbl), - Addr::Con(h) if self.heap.atom_at(h) => + Addr::Char(c) => clause_name!(c.to_string(), self.atom_tbl), + Addr::Con(h) if self.heap.atom_at(h) => { if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { name.clone() } else { unreachable!() - }, - _ => - unreachable!(), + } + } + _ => unreachable!(), }; - let module = op.owning_module(); - let result = to_op_decl(priority, specifier.as_str(), op) .map_err(SessionError::from) - .and_then(|op_decl| { - if op_decl.0 == 0 { + .and_then(|mut op_decl| { + if op_decl.prec == 0 { Ok(op_decl.remove(&mut indices.op_dir)) } else { - let spec = get_desc(op_decl.name(), composite_op!(&indices.op_dir)); - op_decl.submit(module, spec, &mut indices.op_dir) + let spec = get_op_desc( + op_decl.name.clone(), + &CompositeOpDir::new(&indices.op_dir, None), + ); + + op_decl.submit(spec, &mut indices.op_dir) } }); match result { - Ok(()) => { - } + Ok(()) => {} Err(e) => { // 8.14.3.3 l) let e = MachineError::session_error(self.heap.h(), e); @@ -3472,50 +3095,39 @@ impl MachineState { let reposition = self[temp_v!(6)]; let stream_type = self[temp_v!(7)]; - let options = - self.to_stream_options(alias, eof_action, reposition, stream_type); + let options = self.to_stream_options(alias, eof_action, reposition, stream_type); - let mut stream = - match self.store(self.deref(self[temp_v!(1)])) { - Addr::Con(h) if self.heap.atom_at(h) => { - match &self.heap[h] { - &HeapCellValue::Atom(ref atom, _) => { - self.stream_from_file_spec(atom.clone(), indices, &options)? - } - _ => { - unreachable!() - } - } - } - Addr::PStrLocation(h, n) => { - match &self.heap[h] { - &HeapCellValue::PartialString(_, true) => { - let mut heap_pstr_iter = - self.heap_pstr_iter(Addr::PStrLocation(h, n)); - - let file_spec = - clause_name!( - heap_pstr_iter.to_string(), - indices.atom_tbl.clone() - ); - - self.stream_from_file_spec(file_spec, indices, &options)? - } - _ => { - self.stream_from_file_spec(clause_name!(""), indices, &options)? - } - } + let mut stream = match self.store(self.deref(self[temp_v!(1)])) { + Addr::Con(h) if self.heap.atom_at(h) => match &self.heap[h] { + &HeapCellValue::Atom(ref atom, _) => { + self.stream_from_file_spec(atom.clone(), indices, &options)? } _ => { - self.stream_from_file_spec(clause_name!(""), indices, &options)? + unreachable!() } - }; + }, + Addr::Char(c) => { + let atom = clause_name!(c.to_string(), self.atom_tbl); + self.stream_from_file_spec(atom, indices, &options)? + } + Addr::PStrLocation(h, n) => match &self.heap[h] { + &HeapCellValue::PartialString(_, true) => { + let mut heap_pstr_iter = self.heap_pstr_iter(Addr::PStrLocation(h, n)); - stream.options = options; + let file_spec = clause_name!(heap_pstr_iter.to_string(), self.atom_tbl); + + self.stream_from_file_spec(file_spec, indices, &options)? + } + _ => self.stream_from_file_spec(clause_name!(""), indices, &options)?, + }, + _ => self.stream_from_file_spec(clause_name!(""), indices, &options)?, + }; + + *stream.options_mut() = options; indices.streams.insert(stream.clone()); - if let Some(ref alias) = &stream.options.alias { + if let Some(ref alias) = &stream.options().alias { indices.stream_aliases.insert(alias.clone(), stream.clone()); } @@ -3539,27 +3151,23 @@ impl MachineState { } &SystemClauseType::GetAttributedVariableList => { let attr_var = self.store(self.deref(self[temp_v!(1)])); - let attr_var_list = - match attr_var { - Addr::AttrVar(h) => { - h + 1 - } - attr_var @ Addr::HeapCell(_) | - attr_var @ Addr::StackCell(..) => { - // create an AttrVar in the heap. - let h = self.heap.h(); + let attr_var_list = match attr_var { + Addr::AttrVar(h) => h + 1, + attr_var @ Addr::HeapCell(_) | attr_var @ Addr::StackCell(..) => { + // create an AttrVar in the heap. + let h = self.heap.h(); - self.heap.push(HeapCellValue::Addr(Addr::AttrVar(h))); - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h + 1))); + self.heap.push(HeapCellValue::Addr(Addr::AttrVar(h))); + self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h + 1))); - self.bind(Ref::AttrVar(h), attr_var); - h + 1 - } - _ => { - self.fail = true; - return Ok(()); - } - }; + self.bind(Ref::AttrVar(h), attr_var); + h + 1 + } + _ => { + self.fail = true; + return Ok(()); + } + }; let list_addr = self[temp_v!(2)]; self.bind(Ref::HeapCell(attr_var_list), list_addr); @@ -3568,32 +3176,23 @@ impl MachineState { let addr = self[temp_v!(1)]; let value = Addr::Usize(self.attr_var_init.attr_var_queue.len()); - self.unify(addr, value); + (self.unify_fn)(self, addr, value); } &SystemClauseType::GetAttrVarQueueBeyond => { let addr = self[temp_v!(1)]; let addr = self.store(self.deref(addr)); - let b = - match addr { - Addr::Usize(b) => { - Some(b) - } + let b = match addr { + Addr::Usize(b) => Some(b), + _ => match Number::try_from((addr, &self.heap)) { + Ok(Number::Integer(n)) => n.to_usize(), + Ok(Number::Fixnum(n)) => usize::try_from(n).ok(), _ => { - match Number::try_from((addr, &self.heap)) { - Ok(Number::Integer(n)) => { - n.to_usize() - } - Ok(Number::Fixnum(n)) => { - usize::try_from(n).ok() - } - _ => { - self.fail = true; - return Ok(()); - } - } + self.fail = true; + return Ok(()); } - }; + }, + }; if let Some(b) = b { let iter = self.gather_attr_vars_created_since(b); @@ -3601,7 +3200,7 @@ impl MachineState { let var_list_addr = Addr::HeapCell(self.heap.to_list(iter)); let list_addr = self[temp_v!(2)]; - self.unify(var_list_addr, list_addr); + (self.unify_fn)(self, var_list_addr, list_addr); } } &SystemClauseType::GetContinuationChunk => { @@ -3617,22 +3216,21 @@ impl MachineState { let p_functor = self.store(self.deref(self[temp_v!(2)])); let p = self.heap.to_local_code_ptr(&p_functor).unwrap(); - let num_cells = - match code_repo.lookup_instr(self.last_call, &CodePtr::Local(p)) { - Some(line) => { - let perm_vars = match line.as_ref() { - Line::Control(ref ctrl_instr) => ctrl_instr.perm_vars(), - _ => None - }; + let num_cells = match code_repo.lookup_instr(self.last_call, &CodePtr::Local(p)) { + Some(line) => { + let perm_vars = match line.as_ref() { + Line::Control(ref ctrl_instr) => ctrl_instr.perm_vars(), + _ => None, + }; - perm_vars.unwrap() - } - _ => unreachable!() - }; + perm_vars.unwrap() + } + _ => unreachable!(), + }; let mut addrs = vec![]; - for index in 1 .. num_cells + 1 { + for index in 1..num_cells + 1 { addrs.push(self.stack.index_and_frame(e)[index]); } @@ -3647,7 +3245,7 @@ impl MachineState { self.heap.push(HeapCellValue::Addr(p_functor)); self.heap.extend(addrs.into_iter().map(HeapCellValue::Addr)); - self.unify(self[temp_v!(3)], chunk); + (self.unify_fn)(self, self[temp_v!(3)], chunk); } &SystemClauseType::GetLiftedHeapFromOffsetDiff => { let lh_offset = self[temp_v!(1)]; @@ -3658,8 +3256,8 @@ impl MachineState { let solutions = self[temp_v!(2)]; let diff = self[temp_v!(3)]; - self.unify(solutions, Addr::EmptyList); - self.unify(diff, Addr::EmptyList); + (self.unify_fn)(self, solutions, Addr::EmptyList); + (self.unify_fn)(self, diff, Addr::EmptyList); } else { let h = self.heap.h(); let mut last_index = h; @@ -3687,14 +3285,14 @@ impl MachineState { addr_opt.map(|addr| { let diff = self[temp_v!(3)]; - self.unify(diff, addr); + (self.unify_fn)(self, diff, addr); }); } self.lifted_heap.truncate(lh_offset); let solutions = self[temp_v!(2)]; - self.unify(Addr::HeapCell(h), solutions); + (self.unify_fn)(self, Addr::HeapCell(h), solutions); } } _ => { @@ -3709,7 +3307,7 @@ impl MachineState { Addr::Usize(lh_offset) => { if lh_offset >= self.lifted_heap.h() { let solutions = self[temp_v!(2)]; - self.unify(solutions, Addr::EmptyList); + (self.unify_fn)(self, solutions, Addr::EmptyList); } else { let h = self.heap.h(); @@ -3727,7 +3325,7 @@ impl MachineState { self.lifted_heap.truncate(lh_offset); let solutions = self[temp_v!(2)]; - self.unify(Addr::HeapCell(h), solutions); + (self.unify_fn)(self, Addr::HeapCell(h), solutions); } } _ => { @@ -3740,25 +3338,25 @@ impl MachineState { match self.flags.double_quotes { DoubleQuotes::Chars => { - let atom = self.heap.to_unifiable( - HeapCellValue::Atom(clause_name!("chars"), None) - ); + let atom = self + .heap + .to_unifiable(HeapCellValue::Atom(clause_name!("chars"), None)); - self.unify(a1, atom); + (self.unify_fn)(self, a1, atom); } - DoubleQuotes::Atom => { - let atom = self.heap.to_unifiable( - HeapCellValue::Atom(clause_name!("atom"), None) - ); + DoubleQuotes::Atom => { + let atom = self + .heap + .to_unifiable(HeapCellValue::Atom(clause_name!("atom"), None)); - self.unify(a1, atom); + (self.unify_fn)(self, a1, atom); } DoubleQuotes::Codes => { - let atom = self.heap.to_unifiable( - HeapCellValue::Atom(clause_name!("codes"), None) - ); + let atom = self + .heap + .to_unifiable(HeapCellValue::Atom(clause_name!("codes"), None)); - self.unify(a1, atom); + (self.unify_fn)(self, a1, atom); } } } @@ -3782,8 +3380,7 @@ impl MachineState { } } } - None => { - } + None => {} }; self.fail = true; @@ -3800,7 +3397,9 @@ impl MachineState { // denominator must be 1. r.numer().to_i32().unwrap() } - _ => { unreachable!() } + _ => { + unreachable!() + } }; std::process::exit(code); @@ -3835,42 +3434,33 @@ impl MachineState { CWILCallPolicy::new_in_place(call_policy); } - let n = - match Number::try_from((a2, &self.heap)) { - Ok(Number::Integer(n)) => { - Integer::from(&*n.clone()) - } - Ok(Number::Fixnum(n)) => { - Integer::from(n) - } - _ => { - let stub = MachineError::functor_stub( - clause_name!("call_with_inference_limit"), - 3, - ); + let n = match Number::try_from((a2, &self.heap)) { + Ok(Number::Integer(n)) => Integer::from(&*n.clone()), + Ok(Number::Fixnum(n)) => Integer::from(n), + _ => { + let stub = MachineError::functor_stub( + clause_name!("call_with_inference_limit"), + 3, + ); - return Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - a2, - ), - stub, - )); - } - }; + return Err(self.error_form( + MachineError::type_error(self.heap.h(), ValidType::Integer, a2), + stub, + )); + } + }; match a1 { Addr::Usize(bp) | Addr::CutPoint(bp) => { match call_policy.downcast_mut::().ok() { Some(call_policy) => { let count = call_policy.add_limit(n, bp).clone(); - let count = self.heap.to_unifiable( - HeapCellValue::Integer(Rc::new(count)) - ); + let count = self + .heap + .to_unifiable(HeapCellValue::Integer(Rc::new(count))); let a3 = self[temp_v!(3)]; - self.unify(a3, count); + (self.unify_fn)(self, a3, count); } None => { panic!( @@ -3890,7 +3480,7 @@ impl MachineState { match module { Addr::Con(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { self.fail = !indices.modules.contains_key(name); } else { unreachable!() @@ -3901,86 +3491,40 @@ impl MachineState { } }; } - &SystemClauseType::ModuleOf => { - let module = self.store(self.deref(self[temp_v!(2)])); - - match module { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(name, _) = self.heap.clone(h) { - let module = self.heap.to_unifiable( - HeapCellValue::Atom( - name.owning_module(), - None - ), - ); - - let target = self[temp_v!(1)]; - - self.unify(target, module); - } else { - unreachable!() - } - } - Addr::Str(s) => match self.heap.clone(s) { - HeapCellValue::NamedStr(_, name, ..) => { - let module = self.heap.to_unifiable( - HeapCellValue::Atom( - name.owning_module(), - None - ), - ); - - let target = self[temp_v!(1)]; - - self.unify(target, module); - } - HeapCellValue::Addr(addr) if addr.is_ref() => { - let err = MachineError::uninstantiation_error(addr); - let stub = MachineError::functor_stub( - clause_name!("$module_of"), - 2, - ); - - return Err(self.error_form(err, stub)); - } - _ => { - unreachable!() - } - }, - _ => { - self.fail = true; - } - }; - } &SystemClauseType::NoSuchPredicate => { - let head = self[temp_v!(1)]; + let module_name = atom_from!(self, self.store(self.deref(self[temp_v!(1)]))); - self.fail = match self.store(self.deref(head)) { + self.fail = match self.store(self.deref(self[temp_v!(2)])) { Addr::Str(s) => match &self.heap[s] { &HeapCellValue::NamedStr(arity, ref name, ref spec) => { - let module = name.owning_module(); - indices.predicate_exists(name.clone(), module, arity, spec.clone()) + CLAUSE_TYPE_FORMS.borrow().get(&(name.as_str(), arity)).is_some() || + indices.get_predicate_code_index( + name.clone(), + arity, + module_name, + spec.clone(), + ) + .is_some() } _ => { unreachable!() } }, Addr::Con(h) if self.heap.atom_at(h) => { - if let &HeapCellValue::Atom(ref name, ref spec) = &self.heap[h] { - let module = name.owning_module(); - let spec = fetch_atom_op_spec( - name.clone(), - spec.clone(), - &indices.op_dir, - ); + if let &HeapCellValue::Atom(ref name, ref spec) = &self.heap[h] { + let spec = + fetch_atom_op_spec(name.clone(), spec.clone(), &indices.op_dir); - indices.predicate_exists(name.clone(), module, 0, spec) + CLAUSE_TYPE_FORMS.borrow().get(&(name.as_str(), 0)).is_some() || + indices.get_predicate_code_index(name.clone(), 0, module_name, spec) + .is_some() } else { unreachable!() } } head => { - let err = MachineError::type_error(self.heap.h(), ValidType::Callable, head); + let err = + MachineError::type_error(self.heap.h(), ValidType::Callable, head); let stub = MachineError::functor_stub(clause_name!("clause"), 2); return Err(self.error_form(err, stub)); @@ -3988,7 +3532,7 @@ impl MachineState { }; } &SystemClauseType::RedoAttrVarBinding => { - let var = self.store(self.deref(self[temp_v!(1)])); + let var = self.store(self.deref(self[temp_v!(1)])); let value = self.store(self.deref(self[temp_v!(2)])); match var { @@ -4000,6 +3544,7 @@ impl MachineState { } } } + /* &SystemClauseType::ResetGlobalVarAtKey => { let key = self[temp_v!(1)]; @@ -4053,34 +3598,34 @@ impl MachineState { indices.global_variables.insert(key, (ball, None)); } } - }, + } + */ &SystemClauseType::ResetAttrVarState => { self.attr_var_init.reset(); } &SystemClauseType::RemoveCallPolicyCheck => { - let restore_default = - match call_policy.downcast_mut::().ok() { - Some(call_policy) => { - let a1 = self.store(self.deref(self[temp_v!(1)])); + let restore_default = match call_policy.downcast_mut::().ok() { + Some(call_policy) => { + let a1 = self.store(self.deref(self[temp_v!(1)])); - match a1 { - Addr::Usize(bp) | Addr::CutPoint(bp) => { - if call_policy.is_empty() && bp == self.b { - Some(call_policy.into_inner()) - } else { - None - } - } - _ => { - panic!("remove_call_policy_check: expected Usize in A1."); + match a1 { + Addr::Usize(bp) | Addr::CutPoint(bp) => { + if call_policy.is_empty() && bp == self.b { + Some(call_policy.into_inner()) + } else { + None } } + _ => { + panic!("remove_call_policy_check: expected Usize in A1."); + } } - None => panic!( - "remove_call_policy_check: requires \\ + } + None => panic!( + "remove_call_policy_check: requires \\ CWILCallPolicy." - ), - }; + ), + }; if let Some(new_policy) = restore_default { *call_policy = new_policy; @@ -4094,13 +3639,13 @@ impl MachineState { match a1 { Addr::Usize(bp) | Addr::CutPoint(bp) => { let count = call_policy.remove_limit(bp).clone(); - let count = self.heap.to_unifiable( - HeapCellValue::Integer(Rc::new(count)), - ); + let count = self + .heap + .to_unifiable(HeapCellValue::Integer(Rc::new(count))); let a2 = self[temp_v!(2)]; - self.unify(a2, count); + (self.unify_fn)(self, a2, count); } _ => { panic!("remove_inference_counter: expected Usize in A1."); @@ -4116,6 +3661,7 @@ impl MachineState { &SystemClauseType::REPL(repl_code_ptr) => { return self.repl_redirect(repl_code_ptr); } + /* &SystemClauseType::ModuleRetractClause => { let p = self.cp; let trans_type = DynamicTransactionType::ModuleRetract; @@ -4130,11 +3676,12 @@ impl MachineState { self.p = CodePtr::DynamicTransaction(trans_type, p); return Ok(()); } + */ &SystemClauseType::ReturnFromVerifyAttr => { let e = self.e; let frame_len = self.stack.index_and_frame(e).prelude.univ_prelude.num_cells; - for i in 1 .. frame_len - 1 { + for i in 1..frame_len - 1 { self[RegType::Temp(i)] = self.stack.index_and_frame(e)[i]; } @@ -4168,22 +3715,17 @@ impl MachineState { return Ok(()); } } - &SystemClauseType::SetCutPointByDefault(r) => { - deref_cut(self, r) - } + &SystemClauseType::SetCutPointByDefault(r) => deref_cut(self, r), &SystemClauseType::SetInput => { let addr = self.store(self.deref(self[temp_v!(1)])); let stream = self.get_stream_or_alias(addr, indices, "set_input", 1)?; if !stream.is_input_stream() { - let stub = MachineError::functor_stub( - clause_name!("set_input"), - 1, - ); + let stub = MachineError::functor_stub(clause_name!("set_input"), 1); - let user_alias = self.heap.to_unifiable( - HeapCellValue::Atom(clause_name!("user"), None), - ); + let user_alias = self + .heap + .to_unifiable(HeapCellValue::Atom(clause_name!("user"), None)); let err = MachineError::permission_error( self.heap.h(), @@ -4202,14 +3744,11 @@ impl MachineState { let stream = self.get_stream_or_alias(addr, indices, "set_output", 1)?; if !stream.is_output_stream() { - let stub = MachineError::functor_stub( - clause_name!("set_input"), - 1, - ); + let stub = MachineError::functor_stub(clause_name!("set_input"), 1); - let user_alias = self.heap.to_unifiable( - HeapCellValue::Atom(clause_name!("user"), None), - ); + let user_alias = self + .heap + .to_unifiable(HeapCellValue::Atom(clause_name!("user"), None)); let err = MachineError::permission_error( self.heap.h(), @@ -4223,29 +3762,26 @@ impl MachineState { *current_output_stream = stream; } - &SystemClauseType::SetDoubleQuotes => { - match self[temp_v!(1)] { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { - self.flags.double_quotes = - match atom.as_str() { - "atom" => DoubleQuotes::Atom, - "chars" => DoubleQuotes::Chars, - "codes" => DoubleQuotes::Codes, - _ => { - self.fail = true; - return Ok(()); - } - }; - } else { - unreachable!() - } - } - _ => { - self.fail = true; + &SystemClauseType::SetDoubleQuotes => match self[temp_v!(1)] { + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { + self.flags.double_quotes = match atom.as_str() { + "atom" => DoubleQuotes::Atom, + "chars" => DoubleQuotes::Chars, + "codes" => DoubleQuotes::Codes, + _ => { + self.fail = true; + return Ok(()); + } + }; + } else { + unreachable!() } } - } + _ => { + self.fail = true; + } + }, &SystemClauseType::InferenceLevel => { let a1 = self[temp_v!(1)]; let a2 = self.store(self.deref(self[temp_v!(2)])); @@ -4255,17 +3791,17 @@ impl MachineState { let prev_b = self.stack.index_or_frame(self.b).prelude.b; if prev_b <= bp { - let a2 = self.heap.to_unifiable( - HeapCellValue::Atom(clause_name!("!"), None) - ); + let a2 = self + .heap + .to_unifiable(HeapCellValue::Atom(clause_name!("!"), None)); - self.unify(a1, a2); + (self.unify_fn)(self, a1, a2); } else { - let a2 = self.heap.to_unifiable( - HeapCellValue::Atom(clause_name!("true"), None) - ); + let a2 = self + .heap + .to_unifiable(HeapCellValue::Atom(clause_name!("true"), None)); - self.unify(a1, a2); + (self.unify_fn)(self, a1, a2); } } _ => { @@ -4324,59 +3860,13 @@ impl MachineState { let a1 = self[temp_v!(1)]; let a2 = Addr::Usize(self.b); - self.unify(a1, a2); - } - &SystemClauseType::GetClause => { - let head = self[temp_v!(1)]; - - let subsection = match self.store(self.deref(head)) { - Addr::Str(s) => match &self.heap[s] { - &HeapCellValue::NamedStr(arity, ref name, ..) => { - indices.get_clause_subsection( - name.owning_module(), - name.clone(), - arity, - ) - } - _ => { - unreachable!() - } - }, - Addr::Con(h) if self.heap.atom_at(h) => { - if let &HeapCellValue::Atom(ref name, _) = &self.heap[h] { - indices.get_clause_subsection( - name.owning_module(), - name.clone(), - 0, - ) - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - }; - - match subsection { - Some(dynamic_predicate_info) => { - self.execute_at_index( - 2, - dir_entry!(dynamic_predicate_info.clauses_subsection_p), - ); - - return Ok(()); - } - _ => { - unreachable!() - } - } + (self.unify_fn)(self, a1, a2); } &SystemClauseType::GetCutPoint => { let a1 = self[temp_v!(1)]; let a2 = Addr::CutPoint(self.b0); - self.unify(a1, a2); + (self.unify_fn)(self, a1, a2); } &SystemClauseType::InstallNewBlock => { self.install_new_block(temp_v!(1)); @@ -4393,17 +3883,18 @@ impl MachineState { return Ok(()); } - let cp = (self.stack.index_and_frame(self.e).prelude.cp - 1).unwrap(); + let cp = + (self.stack.index_and_frame(self.e).prelude.cp - 1).unwrap(); let e = self.stack.index_and_frame(self.e).prelude.e; let e = Addr::Usize(e); let p = cp.as_functor(&mut self.heap); - self.unify(self[temp_v!(2)], e); + (self.unify_fn)(self, self[temp_v!(2)], e); if !self.fail { - self.unify(self[temp_v!(3)], p); + (self.unify_fn)(self, self[temp_v!(3)], p); } } else { unreachable!() @@ -4427,10 +3918,10 @@ impl MachineState { let e = Addr::Usize(e); - self.unify(self[temp_v!(2)], e); + (self.unify_fn)(self, self[temp_v!(2)], e); if !self.fail { - self.unify(self[temp_v!(3)], p); + (self.unify_fn)(self, self[temp_v!(3)], p); } } _ => { @@ -4442,9 +3933,7 @@ impl MachineState { let addr = self.store(self.deref(self[temp_v!(1)])); let p = match self.heap.to_local_code_ptr(&addr) { - Some(p) => { - p + 1 - } + Some(p) => p + 1, None => { self.fail = true; return Ok(()); @@ -4467,19 +3956,15 @@ impl MachineState { let n = n.and_then(std::char::from_u32); self.fail = match n { - Some(c) => { - non_quoted_token(once(c)) - } - None => { - true - } + Some(c) => non_quoted_token(once(c)), + None => true, }; } Addr::Char(c) => { self.fail = non_quoted_token(once(c)); } Addr::Con(h) => { - if let HeapCellValue::Atom(atom, _) = &self.heap[h] { + if let HeapCellValue::Atom(atom, _) = &self.heap[h] { self.fail = non_quoted_token(atom.as_str().chars()); } } @@ -4496,8 +3981,7 @@ impl MachineState { readline::set_prompt(false); match result { - Ok(()) => { - } + Ok(()) => {} Err(e) => { *current_input_stream = readline::input_stream(); return Err(e); @@ -4507,12 +3991,7 @@ impl MachineState { &SystemClauseType::ReadTerm => { readline::set_prompt(false); - let stream = self.get_stream_or_alias( - self[temp_v!(1)], - indices, - "read_term", - 3, - )?; + let stream = self.get_stream_or_alias(self[temp_v!(1)], indices, "read_term", 3)?; self.read_term(stream, indices)?; } @@ -4521,27 +4000,22 @@ impl MachineState { let chars = heap_pstr_iter.to_string(); if let Addr::EmptyList = heap_pstr_iter.focus() { - let term_write_result = - match self.read( - Stream::from(chars), - indices.atom_tbl.clone(), - &indices.op_dir, - ) { - Ok(term_write_result) => { - term_write_result - } - Err(e) => { - let stub = MachineError::functor_stub( - clause_name!("read_term_from_chars"), - 2, - ); + let term_write_result = match self.read( + Stream::from(chars), + self.atom_tbl.clone(), + &indices.op_dir, + ) { + Ok(term_write_result) => term_write_result, + Err(e) => { + let stub = + MachineError::functor_stub(clause_name!("read_term_from_chars"), 2); - let h = self.heap.h(); - let e = MachineError::session_error(h, SessionError::from(e)); + let h = self.heap.h(); + let e = MachineError::session_error(h, SessionError::from(e)); - return Err(self.error_form(e, stub)); - } - }; + return Err(self.error_form(e, stub)); + } + }; let result = Addr::HeapCell(term_write_result.heap_loc); @@ -4559,9 +4033,9 @@ impl MachineState { self.reset_block(addr); } &SystemClauseType::ResetContinuationMarker => { - self[temp_v!(3)] = self.heap.to_unifiable( - HeapCellValue::Atom(clause_name!("none"), None) - ); + self[temp_v!(3)] = self + .heap + .to_unifiable(HeapCellValue::Atom(clause_name!("none"), None)); let h = self.heap.h(); @@ -4574,31 +4048,24 @@ impl MachineState { &SystemClauseType::SetSeed => { let seed = self.store(self.deref(self[temp_v!(1)])); - let seed = - match Number::try_from((seed, &self.heap)) { - Ok(Number::Fixnum(n)) => { - Integer::from(n) - } - Ok(Number::Integer(n)) => { - Integer::from(n.as_ref()) - } - Ok(Number::Rational(n)) - if n.denom() == &1 => { - n.numer().clone() - } - _ => { - self.fail = true; - return Ok(()); - } - }; + let seed = match Number::try_from((seed, &self.heap)) { + Ok(Number::Fixnum(n)) => Integer::from(n), + Ok(Number::Integer(n)) => Integer::from(n.as_ref()), + Ok(Number::Rational(n)) if n.denom() == &1 => n.numer().clone(), + _ => { + self.fail = true; + return Ok(()); + } + }; let mut rand = RANDOM_STATE.borrow_mut(); rand.seed(&seed); } - &SystemClauseType::SkipMaxList => + &SystemClauseType::SkipMaxList => { if let Err(err) = self.skip_max_list() { return Err(err); - }, + } + } &SystemClauseType::Sleep => { let time = self.store(self.deref(self[temp_v!(1)])); @@ -4619,64 +4086,50 @@ impl MachineState { let addr = self.store(self.deref(self[temp_v!(1)])); let port = self.store(self.deref(self[temp_v!(2)])); - let socket_atom = - match addr { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - name.clone() - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - }; - - let port = - match port { - Addr::Fixnum(n) => { - n.to_string() - } - Addr::Usize(n) => { - n.to_string() - } - Addr::Con(h) => { - match &self.heap[h] { - HeapCellValue::Atom(ref name, _) => { - name.as_str().to_string() - } - HeapCellValue::Integer(ref n) => { - n.to_string() - } - _ => { - unreachable!() - } - } - } - _ => { - unreachable!() - } - }; - - let socket_addr = - format!( - "{}:{}", - if socket_atom.as_str() == "" { - "127.0.0.1" + let socket_atom = match addr { + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + name.clone() } else { - socket_atom.as_str() - }, - port, - ); + unreachable!() + } + } + _ => { + unreachable!() + } + }; + + let port = match port { + Addr::Fixnum(n) => n.to_string(), + Addr::Usize(n) => n.to_string(), + Addr::Con(h) => match &self.heap[h] { + HeapCellValue::Atom(ref name, _) => name.as_str().to_string(), + HeapCellValue::Integer(ref n) => n.to_string(), + _ => { + unreachable!() + } + }, + _ => { + unreachable!() + } + }; + + let socket_addr = format!( + "{}:{}", + if socket_atom.as_str() == "" { + "127.0.0.1" + } else { + socket_atom.as_str() + }, + port, + ); let alias = self[temp_v!(4)]; let eof_action = self[temp_v!(5)]; let reposition = self[temp_v!(6)]; let stream_type = self[temp_v!(7)]; - let options = - self.to_stream_options(alias, eof_action, reposition, stream_type); + let options = self.to_stream_options(alias, eof_action, reposition, stream_type); if options.reposition { return Err(self.reposition_error("socket_client_open", 3)); @@ -4692,121 +4145,111 @@ impl MachineState { } } - let stream = - match TcpStream::connect(&socket_addr).map_err(|e| e.kind()) { - Ok(tcp_stream) => { - let socket_addr = clause_name!(socket_addr, indices.atom_tbl.clone()); + let stream = match TcpStream::connect(&socket_addr).map_err(|e| e.kind()) { + Ok(tcp_stream) => { + let socket_addr = clause_name!(socket_addr, self.atom_tbl); - - let mut stream = - { let tls = match self.store(self.deref(self[temp_v!(8)])) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { - atom.as_str() - } else { - unreachable!() - } - } - _ => { + let mut stream = { + let tls = match self.store(self.deref(self[temp_v!(8)])) { + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { + atom.as_str() + } else { unreachable!() } - }; - match tls { - "false" => { Stream::from_tcp_stream(socket_addr, tcp_stream) } - "true" => { let connector = TlsConnector::new().unwrap(); - let stream = match connector.connect(socket_atom.as_str(), tcp_stream) { - Ok(tls_stream) => { tls_stream } - Err(_) => { return Err(self.open_permission_error(addr, "socket_client_open", 3)); } - }; - - Stream::from_tls_stream(socket_addr, stream) - } - _ => { unreachable!() } } - }; - stream.options = options; + _ => { + unreachable!() + } + }; - if let Some(ref alias) = &stream.options.alias { - indices.stream_aliases.insert(alias.clone(), stream.clone()); + match tls { + "false" => Stream::from_tcp_stream(socket_addr, tcp_stream), + "true" => { + let connector = TlsConnector::new().unwrap(); + let stream = + match connector.connect(socket_atom.as_str(), tcp_stream) { + Ok(tls_stream) => tls_stream, + Err(_) => { + return Err(self.open_permission_error( + addr, + "socket_client_open", + 3, + )); + } + }; + + Stream::from_tls_stream(socket_addr, stream) + } + _ => { + unreachable!() + } } + }; - indices.streams.insert(stream.clone()); + *stream.options_mut() = options; - self.heap.to_unifiable(HeapCellValue::Stream(stream)) + if let Some(ref alias) = &stream.options().alias { + indices.stream_aliases.insert(alias.clone(), stream.clone()); } - Err(ErrorKind::PermissionDenied) => { - return Err(self.open_permission_error(addr, "socket_client_open", 3)); - } - Err(ErrorKind::NotFound) => { - let stub = MachineError::functor_stub( - clause_name!("socket_client_open"), - 3, - ); - let err = MachineError::existence_error( - self.heap.h(), - ExistenceError::SourceSink(addr), - ); + indices.streams.insert(stream.clone()); - return Err(self.error_form(err, stub)); - } - Err(_) => { - // for now, just fail. expand to meaningful error messages later. - self.fail = true; - return Ok(()); - } - }; + self.heap.to_unifiable(HeapCellValue::Stream(stream)) + } + Err(ErrorKind::PermissionDenied) => { + return Err(self.open_permission_error(addr, "socket_client_open", 3)); + } + Err(ErrorKind::NotFound) => { + let stub = + MachineError::functor_stub(clause_name!("socket_client_open"), 3); + + let err = MachineError::existence_error( + self.heap.h(), + ExistenceError::SourceSink(addr), + ); + + return Err(self.error_form(err, stub)); + } + Err(_) => { + // for now, just fail. expand to meaningful error messages later. + self.fail = true; + return Ok(()); + } + }; let stream_addr = self.store(self.deref(self[temp_v!(3)])); self.bind(stream_addr.as_var().unwrap(), stream); } &SystemClauseType::SocketServerOpen => { let addr = self.store(self.deref(self[temp_v!(1)])); - let socket_atom = - match addr { - Addr::EmptyList => { - "127.0.0.1".to_string() - } - Addr::Con(h) if self.heap.atom_at(h) => { - match &self.heap[h] { - HeapCellValue::Atom(ref name, _) => { - name.as_str().to_string() - } - _ => { - unreachable!() - } - } - } + let socket_atom = match addr { + Addr::EmptyList => "127.0.0.1".to_string(), + Addr::Con(h) if self.heap.atom_at(h) => match &self.heap[h] { + HeapCellValue::Atom(ref name, _) => name.as_str().to_string(), _ => { unreachable!() } - }; + }, + _ => { + unreachable!() + } + }; - let port = - match self.store(self.deref(self[temp_v!(2)])) { - Addr::Fixnum(n) => { - n.to_string() - } - Addr::Usize(n) => { - n.to_string() - } - Addr::Con(h) => { - match &self.heap[h] { - HeapCellValue::Integer(ref n) => { - n.to_string() - } - _ => { - unreachable!() - } - } - } - addr if addr.is_ref() => { - "0".to_string() - } + let port = match self.store(self.deref(self[temp_v!(2)])) { + Addr::Fixnum(n) => n.to_string(), + Addr::Usize(n) => n.to_string(), + Addr::Con(h) => match &self.heap[h] { + HeapCellValue::Integer(ref n) => n.to_string(), _ => { unreachable!() } - }; + }, + addr if addr.is_ref() => "0".to_string(), + _ => { + unreachable!() + } + }; let had_zero_port = &port == "0"; @@ -4823,7 +4266,8 @@ impl MachineState { if let Some(port) = port { ( - self.heap.to_unifiable(HeapCellValue::TcpListener(tcp_listener)), + self.heap + .to_unifiable(HeapCellValue::TcpListener(tcp_listener)), port as usize, ) } else { @@ -4844,7 +4288,7 @@ impl MachineState { self.bind(addr.as_var().unwrap(), tcp_listener); if had_zero_port { - self.unify(self[temp_v!(2)], Addr::Usize(port)); + (self.unify_fn)(self, self[temp_v!(2)], Addr::Usize(port)); } } &SystemClauseType::SocketServerAccept => { @@ -4853,8 +4297,7 @@ impl MachineState { let reposition = self[temp_v!(6)]; let stream_type = self[temp_v!(7)]; - let options = - self.to_stream_options(alias, eof_action, reposition, stream_type); + let options = self.to_stream_options(alias, eof_action, reposition, stream_type); if options.reposition { return Err(self.reposition_error("socket_server_accept", 4)); @@ -4871,58 +4314,55 @@ impl MachineState { } match self.store(self.deref(self[temp_v!(1)])) { - Addr::TcpListener(h) => { - match &mut self.heap[h] { - HeapCellValue::TcpListener(ref mut tcp_listener) => { - match tcp_listener.accept().ok() { - Some((tcp_stream, socket_addr)) => { - let client = - clause_name!(format!("{}", socket_addr), indices.atom_tbl); + Addr::TcpListener(h) => match &mut self.heap[h] { + HeapCellValue::TcpListener(ref mut tcp_listener) => { + match tcp_listener.accept().ok() { + Some((tcp_stream, socket_addr)) => { + let client = + clause_name!(format!("{}", socket_addr), self.atom_tbl); - let mut tcp_stream = - Stream::from_tcp_stream(client.clone(), tcp_stream); + let mut tcp_stream = + Stream::from_tcp_stream(client.clone(), tcp_stream); - tcp_stream.options = options; + *tcp_stream.options_mut() = options; - if let Some(ref alias) = &tcp_stream.options.alias { - indices.stream_aliases.insert( - alias.clone(), - tcp_stream.clone(), - ); - } - - indices.streams.insert(tcp_stream.clone()); - - let tcp_stream = - self.heap.to_unifiable(HeapCellValue::Stream(tcp_stream)); - - let client = - self.heap.to_unifiable(HeapCellValue::Atom(client, None)); - - let client_addr = self.store(self.deref(self[temp_v!(2)])); - let stream_addr = self.store(self.deref(self[temp_v!(3)])); - - self.bind(client_addr.as_var().unwrap(), client); - self.bind(stream_addr.as_var().unwrap(), tcp_stream); - } - None => { - self.fail = true; - return Ok(()); + if let Some(ref alias) = &tcp_stream.options().alias { + indices + .stream_aliases + .insert(alias.clone(), tcp_stream.clone()); } + + indices.streams.insert(tcp_stream.clone()); + + let tcp_stream = + self.heap.to_unifiable(HeapCellValue::Stream(tcp_stream)); + + let client = + self.heap.to_unifiable(HeapCellValue::Atom(client, None)); + + let client_addr = self.store(self.deref(self[temp_v!(2)])); + let stream_addr = self.store(self.deref(self[temp_v!(3)])); + + self.bind(client_addr.as_var().unwrap(), client); + self.bind(stream_addr.as_var().unwrap(), tcp_stream); + } + None => { + self.fail = true; + return Ok(()); } } - culprit => { - let culprit = culprit.as_addr(h); - - return Err(self.type_error( - ValidType::TcpListener, - culprit, - clause_name!("socket_server_accept"), - 4, - )); - } } - } + culprit => { + let culprit = culprit.as_addr(h); + + return Err(self.type_error( + ValidType::TcpListener, + culprit, + clause_name!("socket_server_accept"), + 4, + )); + } + }, culprit => { return Err(self.type_error( ValidType::TcpListener, @@ -4950,14 +4390,10 @@ impl MachineState { } } &SystemClauseType::SetStreamPosition => { - let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], - indices, - "set_stream_position", - 2, - )?; + let mut stream = + self.get_stream_or_alias(self[temp_v!(1)], indices, "set_stream_position", 2)?; - if !stream.options.reposition { + if !stream.options().reposition { let stub = MachineError::functor_stub(clause_name!("set_stream_position"), 2); let err = MachineError::permission_error( @@ -4972,140 +4408,112 @@ impl MachineState { let position = self.store(self.deref(self[temp_v!(2)])); - let position = - match Number::try_from((position, &self.heap)) { - Ok(Number::Fixnum(n)) => { - n as u64 + let position = match Number::try_from((position, &self.heap)) { + Ok(Number::Fixnum(n)) => n as u64, + Ok(Number::Integer(n)) => { + if let Some(n) = n.to_u64() { + n + } else { + self.fail = true; + return Ok(()); } - Ok(Number::Integer(n)) => { - if let Some(n) = n.to_u64() { - n - } else { - self.fail = true; - return Ok(()); - } - } - _ => { - unreachable!() - } - }; + } + _ => { + unreachable!() + } + }; stream.set_position(position); } &SystemClauseType::StreamProperty => { - let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], - indices, - "stream_property", - 2, - )?; + let mut stream = + self.get_stream_or_alias(self[temp_v!(1)], indices, "stream_property", 2)?; - let property = - match self.store(self.deref(self[temp_v!(2)])) { - Addr::Con(h) if self.heap.atom_at(h) => { - match &self.heap[h] { - HeapCellValue::Atom(ref name, _) => { - match name.as_str() { - "file_name" => { - if let Some(file_name) = stream.file_name() { - HeapCellValue::Atom( - file_name, - None, - ) - } else { - self.fail = true; - return Ok(()); - } - } - "mode" => { - HeapCellValue::Atom( - clause_name!(stream.mode()), - None, - ) - } - "direction" => { - HeapCellValue::Atom( - if stream.is_input_stream() && stream.is_output_stream() { - clause_name!("input_output") - } else if stream.is_input_stream() { - clause_name!("input") - } else { - clause_name!("output") - }, - None, - ) - } - "alias" => { - if let Some(alias) = &stream.options.alias { - HeapCellValue::Atom( - alias.clone(), - None, - ) - } else { - self.fail = true; - return Ok(()); - } - } - "position" => { - if let Some(position) = stream.position() { - HeapCellValue::Addr(Addr::Usize(position as usize)) - } else { - self.fail = true; - return Ok(()); - } - } - "end_of_stream" => { - let end_of_stream_pos = stream.position_relative_to_end(); - - HeapCellValue::Atom( - clause_name!(end_of_stream_pos.as_str()), - None, - ) - } - "eof_action" => { - HeapCellValue::Atom( - clause_name!(stream.options.eof_action.as_str()), - None, - ) - } - "reposition" => { - HeapCellValue::Atom( - clause_name!(if stream.options.reposition { - "true" - } else { - "false" - }), - None, - ) - } - "type" => { - HeapCellValue::Atom( - clause_name!(stream.options.stream_type.as_property_str()), - None, - ) - } - _ => { - unreachable!() - } - } - } - _ => { - unreachable!() + let property = match self.store(self.deref(self[temp_v!(2)])) { + Addr::Con(h) if self.heap.atom_at(h) => match &self.heap[h] { + HeapCellValue::Atom(ref name, _) => match name.as_str() { + "file_name" => { + if let Some(file_name) = stream.file_name() { + HeapCellValue::Atom(file_name, None) + } else { + self.fail = true; + return Ok(()); } } - } + "mode" => HeapCellValue::Atom(clause_name!(stream.mode()), None), + "direction" => HeapCellValue::Atom( + if stream.is_input_stream() && stream.is_output_stream() { + clause_name!("input_output") + } else if stream.is_input_stream() { + clause_name!("input") + } else { + clause_name!("output") + }, + None, + ), + "alias" => { + if let Some(alias) = &stream.options().alias { + HeapCellValue::Atom(alias.clone(), None) + } else { + self.fail = true; + return Ok(()); + } + } + "position" => { + if let Some((position, lines_read)) = stream.position() { + let h = self.heap.h(); + + let position_term = functor!( + "position_and_lines_read", + [integer(position), integer(lines_read)] + ); + + self.heap.extend(position_term.into_iter()); + + HeapCellValue::Addr(Addr::HeapCell(h)) + } else { + self.fail = true; + return Ok(()); + } + } + "end_of_stream" => { + let end_of_stream_pos = stream.position_relative_to_end(); + HeapCellValue::Atom(clause_name!(end_of_stream_pos.as_str()), None) + } + "eof_action" => HeapCellValue::Atom( + clause_name!(stream.options().eof_action.as_str()), + None, + ), + "reposition" => HeapCellValue::Atom( + clause_name!(if stream.options().reposition { + "true" + } else { + "false" + }), + None, + ), + "type" => HeapCellValue::Atom( + clause_name!(stream.options().stream_type.as_property_str()), + None, + ), + _ => { + unreachable!() + } + }, _ => { unreachable!() } - }; + }, + _ => { + unreachable!() + } + }; let property = self.heap.to_unifiable(property); - self.unify(self[temp_v!(3)], property); + (self.unify_fn)(self, self[temp_v!(3)], property); } &SystemClauseType::StoreGlobalVar => { - let key = self[temp_v!(1)]; - - let key = match self.store(self.deref(key)) { + let key = match self.store(self.deref(self[temp_v!(1)])) { Addr::Con(h) if self.heap.atom_at(h) => { if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { atom.clone() @@ -5131,13 +4539,11 @@ impl MachineState { indices.global_variables.insert(key, (ball, None)); } - &SystemClauseType::StoreGlobalVarWithOffset => { - let key = self[temp_v!(1)]; - - let key = match self.store(self.deref(key)) { + &SystemClauseType::StoreBacktrackableGlobalVar => { + let (key_h, key) = match self.store(self.deref(self[temp_v!(1)])) { Addr::Con(h) if self.heap.atom_at(h) => { if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { - atom.clone() + (h, atom.clone()) } else { unreachable!() } @@ -5147,36 +4553,38 @@ impl MachineState { } }; - let value = self[temp_v!(2)]; - let mut ball = Ball::new(); - let h = self.heap.h(); + let new_value = self.store(self.deref(self[temp_v!(2)])); - ball.boundary = h; - - copy_term( - CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut ball.stub), - value.clone(), - AttrVarPolicy::DeepCopy, - ); - - let stub = ball.copy_and_align(h); - self.heap.extend(stub.into_iter()); - - indices.global_variables.insert(key, (ball, Some(h))); - - self.unify(value, Addr::HeapCell(h)); - } - &SystemClauseType::Succeed => { + match indices.global_variables.get_mut(&key) { + Some((_, ref mut loc)) => { + match loc { + Some(ref mut value) => { + let old_value_loc = self.heap.push(HeapCellValue::Addr(*value)); + self.trail(TrailRef::BlackboardOffset(key_h, old_value_loc)); + *value = new_value; + } + loc @ None => { + self.trail(TrailRef::BlackboardEntry(key_h)); + *loc = Some(new_value); + } + } + } + None => { + self.trail(TrailRef::BlackboardEntry(key_h)); + indices.global_variables.insert(key, (Ball::new(), Some(new_value))); + } + } } + &SystemClauseType::Succeed => {} &SystemClauseType::TermAttributedVariables => { let seen_vars = self.attr_vars_of_term(self[temp_v!(1)]); let outcome = Addr::HeapCell(self.heap.to_list(seen_vars.into_iter())); - self.unify(self[temp_v!(2)], outcome); + (self.unify_fn)(self, self[temp_v!(2)], outcome); } &SystemClauseType::TermVariables => { let a1 = self[temp_v!(1)]; - let mut seen_set = IndexSet::new(); + let mut seen_set = IndexSet::new(); let mut seen_vars = vec![]; for addr in self.acyclic_pre_order_iter(a1) { @@ -5187,14 +4595,12 @@ impl MachineState { } let outcome = Addr::HeapCell(self.heap.to_list(seen_vars.into_iter())); - self.unify(self[temp_v!(2)], outcome); + (self.unify_fn)(self, self[temp_v!(2)], outcome); } &SystemClauseType::TruncateLiftedHeapTo => { match self.store(self.deref(self[temp_v!(1)])) { - Addr::Usize(lh_offset) => - self.lifted_heap.truncate(lh_offset), - _ => - self.fail = true, + Addr::Usize(lh_offset) => self.lifted_heap.truncate(lh_offset), + _ => self.fail = true, } } &SystemClauseType::UnifyWithOccursCheck => { @@ -5226,8 +4632,10 @@ impl MachineState { self.fail = self.structural_eq_test(); } &SystemClauseType::WAMInstructions => { - let name = self[temp_v!(1)]; - let arity = self[temp_v!(2)]; + let module_name = atom_from!(self, self.store(self.deref(self[temp_v!(1)]))); + + let name = self[temp_v!(2)]; + let arity = self[temp_v!(3)]; let name = match self.store(self.deref(name)) { Addr::Con(h) if self.heap.atom_at(h) => { @@ -5244,23 +4652,40 @@ impl MachineState { let arity = self.store(self.deref(arity)); - let arity = - match Number::try_from((arity, &self.heap)) { - Ok(Number::Fixnum(n)) => { - Integer::from(n) - } - Ok(Number::Integer(n)) => { - Integer::from(n.as_ref()) - } - _ => { - unreachable!() - } - }; + let arity = match Number::try_from((arity, &self.heap)) { + Ok(Number::Fixnum(n)) => Integer::from(n), + Ok(Number::Integer(n)) => Integer::from(n.as_ref()), + _ => { + unreachable!() + } + }; - let first_idx = match indices - .code_dir - .get(&(name.clone(), arity.to_usize().unwrap())) - { + let key = (name.clone(), arity.to_usize().unwrap()); + + let first_idx = match module_name.as_str() { + "user" => indices.code_dir.get(&key), + _ => match indices.modules.get(&module_name) { + Some(module) => module.code_dir.get(&key), + None => { + let stub = MachineError::functor_stub(key.0, key.1); + let h = self.heap.h(); + + let err = MachineError::session_error( + h, + SessionError::from(CompilationError::InvalidModuleResolution( + module_name, + )), + ); + + let err = self.error_form(err, stub); + + self.throw_exception(err); + return Ok(()); + } + }, + }; + + let first_idx = match first_idx { Some(ref idx) if idx.local().is_some() => { if let Some(idx) = idx.local() { idx @@ -5287,31 +4712,31 @@ impl MachineState { let mut h = self.heap.h(); let mut functors = vec![]; + let mut functor_list = vec![]; - walk_code( - &code_repo.code, - first_idx, - |instr| { - let section = instr.to_functor(h); - functors.push(Addr::HeapCell(h)); + walk_code(&code_repo.code, first_idx, |instr| { + let old_len = functors.len(); + instr.enqueue_functors(h, &mut functors); + let new_len = functors.len(); - h += section.len(); - self.heap.extend(section.into_iter()); - }, - ); + for index in old_len..new_len { + functor_list.push(Addr::HeapCell(h)); + h += functors[index].len(); + } + }); - let listing = Addr::HeapCell(self.heap.to_list(functors.into_iter())); - let listing_var = self[temp_v!(3)]; + for functor in functors { + self.heap.extend(functor.into_iter()); + } - self.unify(listing, listing_var); + let listing = Addr::HeapCell(self.heap.to_list(functor_list.into_iter())); + let listing_var = self[temp_v!(4)]; + + (self.unify_fn)(self, listing, listing_var); } &SystemClauseType::WriteTerm => { - let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], - indices, - "write_term", - 3, - )?; + let mut stream = + self.get_stream_or_alias(self[temp_v!(1)], indices, "write_term", 3)?; self.check_stream_properties( &mut stream, @@ -5321,14 +4746,13 @@ impl MachineState { 3, )?; - let opt_err = - if !stream.is_output_stream() { - Some("stream") // 8.14.2.3 g) - } else if stream.options.stream_type == StreamType::Binary { - Some("binary_stream") // 8.14.2.3 h) - } else { - None - }; + let opt_err = if !stream.is_output_stream() { + Some("stream") // 8.14.2.3 g) + } else if stream.options().stream_type == StreamType::Binary { + Some("binary_stream") // 8.14.2.3 h) + } else { + None + }; if let Some(err_string) = opt_err { return Err(self.stream_permission_error( @@ -5342,22 +4766,18 @@ impl MachineState { let addr = self[temp_v!(2)]; - let printer = - match self.write_term(&indices.op_dir)? { - None => { - self.fail = true; - return Ok(()); - } - Some(printer) => { - printer - } - }; + let printer = match self.write_term(&indices.op_dir)? { + None => { + self.fail = true; + return Ok(()); + } + Some(printer) => printer, + }; let output = printer.print(addr); match write!(&mut stream, "{}", output.result()) { - Ok(_) => { - } + Ok(_) => {} Err(_) => { let stub = MachineError::functor_stub(clause_name!("open"), 4); let err = MachineError::existence_error( @@ -5374,16 +4794,13 @@ impl MachineState { &SystemClauseType::WriteTermToChars => { let addr = self[temp_v!(2)]; - let printer = - match self.write_term(&indices.op_dir)? { - None => { - self.fail = true; - return Ok(()); - } - Some(printer) => { - printer - } - }; + let printer = match self.write_term(&indices.op_dir)? { + None => { + self.fail = true; + return Ok(()); + } + Some(printer) => printer, + }; let result = printer.print(addr).result(); let chars = self.heap.put_complete_string(&result); @@ -5397,21 +4814,19 @@ impl MachineState { } } &SystemClauseType::ScryerPrologVersion => { - use crate::git_version::git_version; + use git_version::git_version; let version = self[temp_v!(1)]; - let buffer = - git_version!(cargo_prefix = "cargo:", fallback = "unknown"); + let buffer = git_version!(cargo_prefix = "cargo:", fallback = "unknown"); let chars = buffer.chars().map(|c| Addr::Char(c)); let result = Addr::HeapCell(self.heap.to_list(chars)); - self.unify(version, result); + (self.unify_fn)(self, version, result); } &SystemClauseType::CryptoRandomByte => { let arg = self[temp_v!(1)]; let mut bytes: [u8; 1] = [0]; match rng().fill(&mut bytes) { - Ok(()) => { - } + Ok(()) => {} Err(_) => { // the error payload here is of type 'Unspecified', // which contains no information whatsoever. So, for now, @@ -5421,11 +4836,11 @@ impl MachineState { } } - let byte = self.heap.to_unifiable( - HeapCellValue::Integer(Rc::new(Integer::from(bytes[0]))) - ); + let byte = self + .heap + .to_unifiable(HeapCellValue::Integer(Rc::new(Integer::from(bytes[0])))); - self.unify(arg, byte); + (self.unify_fn)(self, arg, byte); } &SystemClauseType::CryptoDataHash => { let encoding = self.atom_argument_to_string(2); @@ -5433,43 +4848,122 @@ impl MachineState { let algorithm = self.atom_argument_to_string(4); - let ints_list = - match algorithm.as_str() { - "sha3_224" => { let mut context = Sha3_224::new(); - context.input(&bytes); - Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) } - "sha3_256" => { let mut context = Sha3_256::new(); - context.input(&bytes); - Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) } - "sha3_384" => { let mut context = Sha3_384::new(); - context.input(&bytes); - Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) } - "sha3_512" => { let mut context = Sha3_512::new(); - context.input(&bytes); - Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) } - "blake2s256" => { let mut context = Blake2s::new(); - context.input(&bytes); - Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) } - "blake2b512" => { let mut context = Blake2b::new(); - context.input(&bytes); - Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) } - "ripemd160" => { let mut context = Ripemd160::new(); - context.input(&bytes); - Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) } - _ => { let ints = digest::digest( - match algorithm.as_str() { - "sha256" => { &digest::SHA256 } - "sha384" => { &digest::SHA384 } - "sha512" => { &digest::SHA512 } - "sha512_256" => { &digest::SHA512_256 } - _ => { unreachable!() } - }, - &bytes); - Addr::HeapCell(self.heap.to_list(ints.as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) - } - }; + let ints_list = match algorithm.as_str() { + "sha3_224" => { + let mut context = Sha3_224::new(); + context.input(&bytes); + Addr::HeapCell( + self.heap.to_list( + context + .result() + .as_ref() + .iter() + .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), + ), + ) + } + "sha3_256" => { + let mut context = Sha3_256::new(); + context.input(&bytes); + Addr::HeapCell( + self.heap.to_list( + context + .result() + .as_ref() + .iter() + .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), + ), + ) + } + "sha3_384" => { + let mut context = Sha3_384::new(); + context.input(&bytes); + Addr::HeapCell( + self.heap.to_list( + context + .result() + .as_ref() + .iter() + .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), + ), + ) + } + "sha3_512" => { + let mut context = Sha3_512::new(); + context.input(&bytes); + Addr::HeapCell( + self.heap.to_list( + context + .result() + .as_ref() + .iter() + .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), + ), + ) + } + "blake2s256" => { + let mut context = Blake2s::new(); + context.input(&bytes); + Addr::HeapCell( + self.heap.to_list( + context + .result() + .as_ref() + .iter() + .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), + ), + ) + } + "blake2b512" => { + let mut context = Blake2b::new(); + context.input(&bytes); + Addr::HeapCell( + self.heap.to_list( + context + .result() + .as_ref() + .iter() + .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), + ), + ) + } + "ripemd160" => { + let mut context = Ripemd160::new(); + context.input(&bytes); + Addr::HeapCell( + self.heap.to_list( + context + .result() + .as_ref() + .iter() + .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), + ), + ) + } + _ => { + let ints = digest::digest( + match algorithm.as_str() { + "sha256" => &digest::SHA256, + "sha384" => &digest::SHA384, + "sha512" => &digest::SHA512, + "sha512_256" => &digest::SHA512_256, + _ => { + unreachable!() + } + }, + &bytes, + ); + Addr::HeapCell( + self.heap.to_list( + ints.as_ref() + .iter() + .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), + ), + ) + } + }; - self.unify(self[temp_v!(3)], ints_list); + (self.unify_fn)(self, self[temp_v!(3)], ints_list); } &SystemClauseType::CryptoDataHKDF => { let encoding = self.atom_argument_to_string(2); @@ -5483,40 +4977,53 @@ impl MachineState { let length = self.store(self.deref(self[temp_v!(6)])); - let length = - match Number::try_from((length, &self.heap)) { - Ok(Number::Fixnum(n)) => { - usize::try_from(n).unwrap() + let length = match Number::try_from((length, &self.heap)) { + Ok(Number::Fixnum(n)) => usize::try_from(n).unwrap(), + Ok(Number::Integer(n)) => match n.to_usize() { + Some(u) => u, + _ => { + self.fail = true; + return Ok(()); } - Ok(Number::Integer(n)) => { - match n.to_usize() { - Some(u) => { u } - _ => { self.fail = true; return Ok(()); } - } + }, + _ => { + unreachable!() + } + }; + + let ints_list = { + let digest_alg = match algorithm.as_str() { + "sha256" => hkdf::HKDF_SHA256, + "sha384" => hkdf::HKDF_SHA384, + "sha512" => hkdf::HKDF_SHA512, + _ => { + self.fail = true; + return Ok(()); } - _ => { unreachable!() } }; + let salt = hkdf::Salt::new(digest_alg, &salt); + let mut bytes: Vec = Vec::new(); + bytes.resize(length, 0); + match salt.extract(&data).expand(&[&info[..]], MyKey(length)) { + Ok(r) => { + r.fill(&mut bytes).unwrap(); + } + _ => { + self.fail = true; + return Ok(()); + } + } - let ints_list = - { let digest_alg = - match algorithm.as_str() { - "sha256" => { hkdf::HKDF_SHA256 } - "sha384" => { hkdf::HKDF_SHA384 } - "sha512" => { hkdf::HKDF_SHA512 } - _ => { self.fail = true; return Ok(()); } - }; - let salt = hkdf::Salt::new(digest_alg, &salt); - let mut bytes : Vec = Vec::new(); - bytes.resize(length, 0); - match salt.extract(&data).expand(&[&info[..]], MyKey(length)) { - Ok(r) => { r.fill(&mut bytes).unwrap(); } - _ => { self.fail = true; return Ok(()); } - } + Addr::HeapCell( + self.heap.to_list( + bytes + .iter() + .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), + ), + ) + }; - Addr::HeapCell(self.heap.to_list(bytes.iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) - }; - - self.unify(self[temp_v!(7)], ints_list); + (self.unify_fn)(self, self[temp_v!(7)], ints_list); } &SystemClauseType::CryptoPasswordHash => { let stub1 = MachineError::functor_stub(clause_name!("crypto_password_hash"), 3); @@ -5526,35 +5033,40 @@ impl MachineState { let iterations = self.store(self.deref(self[temp_v!(3)])); - let iterations = - match Number::try_from((iterations, &self.heap)) { - Ok(Number::Fixnum(n)) => { - u64::try_from(n).unwrap() + let iterations = match Number::try_from((iterations, &self.heap)) { + Ok(Number::Fixnum(n)) => u64::try_from(n).unwrap(), + Ok(Number::Integer(n)) => match n.to_u64() { + Some(i) => i, + None => { + self.fail = true; + return Ok(()); } - Ok(Number::Integer(n)) => { - match n.to_u64() { - Some(i) => { i } - None => { - self.fail = true; - return Ok(()); - } - } - } - _ => { - unreachable!() - } - }; + }, + _ => { + unreachable!() + } + }; - let ints_list = - { let mut bytes = [0u8; digest::SHA512_OUTPUT_LEN]; - pbkdf2::derive(pbkdf2::PBKDF2_HMAC_SHA512, - NonZeroU32::new(iterations as u32).unwrap(), &salt, - &data, &mut bytes); + let ints_list = { + let mut bytes = [0u8; digest::SHA512_OUTPUT_LEN]; + pbkdf2::derive( + pbkdf2::PBKDF2_HMAC_SHA512, + NonZeroU32::new(iterations as u32).unwrap(), + &salt, + &data, + &mut bytes, + ); - Addr::HeapCell(self.heap.to_list(bytes.iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) - }; + Addr::HeapCell( + self.heap.to_list( + bytes + .iter() + .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), + ), + ) + }; - self.unify(self[temp_v!(4)], ints_list); + (self.unify_fn)(self, self[temp_v!(4)], ints_list); } &SystemClauseType::CryptoDataEncrypt => { let encoding = self.atom_argument_to_string(3); @@ -5570,22 +5082,33 @@ impl MachineState { let key = aead::LessSafeKey::new(unbound_key); let mut in_out = data.clone(); - let tag = - match key.seal_in_place_separate_tag(nonce, aead::Aad::from(aad), &mut in_out) { - Ok(d) => { d } - _ => { self.fail = true; return Ok(()); } - }; + let tag = match key.seal_in_place_separate_tag( + nonce, + aead::Aad::from(aad), + &mut in_out, + ) { + Ok(d) => d, + _ => { + self.fail = true; + return Ok(()); + } + }; - let tag_list = - Addr::HeapCell(self.heap.to_list(tag.as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))); + let tag_list = Addr::HeapCell( + self.heap.to_list( + tag.as_ref() + .iter() + .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), + ), + ); let complete_string = { - let buffer = String::from_iter(in_out.iter().map(|b| *b as char)); - self.heap.put_complete_string(&buffer) - }; + let buffer = String::from_iter(in_out.iter().map(|b| *b as char)); + self.heap.put_complete_string(&buffer) + }; - self.unify(self[temp_v!(6)], tag_list); - self.unify(self[temp_v!(7)], complete_string); + (self.unify_fn)(self, self[temp_v!(6)], tag_list); + (self.unify_fn)(self, self[temp_v!(7)], complete_string); } &SystemClauseType::CryptoDataDecrypt => { let data = self.string_encoding_bytes(1, "octet"); @@ -5603,47 +5126,53 @@ impl MachineState { let mut in_out = data.clone(); let complete_string = { - let decrypted_data = - match key.open_in_place(nonce, aead::Aad::from(aad), &mut in_out) { - Ok(d) => { d } - _ => { self.fail = true; return Ok(()); } - }; + let decrypted_data = + match key.open_in_place(nonce, aead::Aad::from(aad), &mut in_out) { + Ok(d) => d, + _ => { + self.fail = true; + return Ok(()); + } + }; - let buffer = match encoding.as_str() { - "octet" => { String::from_iter(decrypted_data.iter().map(|b| *b as char)) } - "utf8" => { match String::from_utf8(decrypted_data.to_vec()) { - Ok(str) => { str } - _ => { self.fail = true; return Ok(()); } - } - } - _ => { unreachable!() } - }; + let buffer = match encoding.as_str() { + "octet" => String::from_iter(decrypted_data.iter().map(|b| *b as char)), + "utf8" => match String::from_utf8(decrypted_data.to_vec()) { + Ok(str) => str, + _ => { + self.fail = true; + return Ok(()); + } + }, + _ => { + unreachable!() + } + }; - self.heap.put_complete_string(&buffer) - }; + self.heap.put_complete_string(&buffer) + }; - self.unify(self[temp_v!(6)], complete_string); + (self.unify_fn)(self, self[temp_v!(6)], complete_string); } &SystemClauseType::CryptoCurveScalarMult => { let curve = self.atom_argument_to_string(1); let curve_id = match curve.as_str() { - "secp112r1" => { Nid::SECP112R1 } - "secp256k1" => { Nid::SECP256K1 } - _ => { unreachable!() } - }; + "secp112r1" => Nid::SECP112R1, + "secp256k1" => Nid::SECP256K1, + _ => { + unreachable!() + } + }; let scalar = self.store(self.deref(self[temp_v!(2)])); - let scalar = - match Number::try_from((scalar, &self.heap)) { - Ok(Number::Fixnum(n)) => { - Integer::from(n) - } - Ok(Number::Integer(n)) => { - Integer::from(&*n.clone()) - } - _ => { unreachable!() } - }; + let scalar = match Number::try_from((scalar, &self.heap)) { + Ok(Number::Fixnum(n)) => Integer::from(n), + Ok(Number::Integer(n)) => Integer::from(&*n.clone()), + _ => { + unreachable!() + } + }; let stub = MachineError::functor_stub(clause_name!("crypto_curve_scalar_mult"), 5); let qbytes = self.integers_to_bytevec(temp_v!(3), stub); @@ -5657,36 +5186,47 @@ impl MachineState { let mut rx = BigNum::new().unwrap(); let mut ry = BigNum::new().unwrap(); - result.affine_coordinates_gfp(&group, &mut rx, &mut ry, &mut bnctx).ok(); - let sx = self.heap.put_complete_string(&rx.to_dec_str().unwrap().to_string()); - let sy = self.heap.put_complete_string(&ry.to_dec_str().unwrap().to_string()); + result + .affine_coordinates_gfp(&group, &mut rx, &mut ry, &mut bnctx) + .ok(); + let sx = self + .heap + .put_complete_string(&rx.to_dec_str().unwrap().to_string()); + let sy = self + .heap + .put_complete_string(&ry.to_dec_str().unwrap().to_string()); - self.unify(self[temp_v!(4)], sx); - self.unify(self[temp_v!(5)], sy); + (self.unify_fn)(self, self[temp_v!(4)], sx); + (self.unify_fn)(self, self[temp_v!(5)], sy); } &SystemClauseType::Ed25519NewKeyPair => { let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(rng()).unwrap(); let complete_string = { - let buffer = String::from_iter(pkcs8_bytes.as_ref().iter().map(|b| *b as char)); - self.heap.put_complete_string(&buffer) - }; + let buffer = String::from_iter(pkcs8_bytes.as_ref().iter().map(|b| *b as char)); + self.heap.put_complete_string(&buffer) + }; - self.unify(self[temp_v!(1)], complete_string); + (self.unify_fn)(self, self[temp_v!(1)], complete_string); } &SystemClauseType::Ed25519KeyPairPublicKey => { let bytes = self.string_encoding_bytes(1, "octet"); let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&bytes) { - Ok(kp) => { kp } - _ => { self.fail = true; return Ok(()); } - }; + Ok(kp) => kp, + _ => { + self.fail = true; + return Ok(()); + } + }; let complete_string = { - let buffer = String::from_iter(key_pair.public_key().as_ref().iter().map(|b| *b as char)); - self.heap.put_complete_string(&buffer) - }; + let buffer = String::from_iter( + key_pair.public_key().as_ref().iter().map(|b| *b as char), + ); + self.heap.put_complete_string(&buffer) + }; - self.unify(self[temp_v!(2)], complete_string); + (self.unify_fn)(self, self[temp_v!(2)], complete_string); } &SystemClauseType::Ed25519Sign => { let key = self.string_encoding_bytes(1, "octet"); @@ -5694,16 +5234,24 @@ impl MachineState { let data = self.string_encoding_bytes(2, &encoding); let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&key) { - Ok(kp) => { kp } - _ => { self.fail = true; return Ok(()); } - }; + Ok(kp) => kp, + _ => { + self.fail = true; + return Ok(()); + } + }; let sig = key_pair.sign(&data); - let sig_list = - Addr::HeapCell(self.heap.to_list(sig.as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))); + let sig_list = Addr::HeapCell( + self.heap.to_list( + sig.as_ref() + .iter() + .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), + ), + ); - self.unify(self[temp_v!(4)], sig_list); + (self.unify_fn)(self, self[temp_v!(4)], sig_list); } &SystemClauseType::Ed25519Verify => { let key = self.string_encoding_bytes(1, "octet"); @@ -5714,8 +5262,11 @@ impl MachineState { let peer_public_key = signature::UnparsedPublicKey::new(&signature::ED25519, &key); match peer_public_key.verify(&data, &signature) { - Ok(_) => { } - _ => { self.fail = true; return Ok(()); } + Ok(_) => {} + _ => { + self.fail = true; + return Ok(()); + } } } &SystemClauseType::Curve25519ScalarMult => { @@ -5731,23 +5282,25 @@ impl MachineState { let string = String::from_iter(result[..].iter().map(|b| *b as char)); let cstr = self.heap.put_complete_string(&string); - self.unify(self[temp_v!(3)], cstr); + (self.unify_fn)(self, self[temp_v!(3)], cstr); } &SystemClauseType::LoadHTML => { let string = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); let doc = select::document::Document::from_read(string.as_bytes()).unwrap(); let result = self.html_node_to_term(indices, doc.nth(0).unwrap()); - self.unify(self[temp_v!(2)], result); + (self.unify_fn)(self, self[temp_v!(2)], result); } &SystemClauseType::LoadXML => { let string = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); match roxmltree::Document::parse(&string) { - Ok(doc) => { let result = self.xml_node_to_term(indices, doc.root_element()); - self.unify(self[temp_v!(2)], result); + Ok(doc) => { + let result = self.xml_node_to_term(indices, doc.root_element()); + (self.unify_fn)(self, self[temp_v!(2)], result); } - _ => { self.fail = true; - return Ok(()); + _ => { + self.fail = true; + return Ok(()); } } } @@ -5756,7 +5309,7 @@ impl MachineState { match env::var(key) { Ok(value) => { let cstr = self.heap.put_complete_string(&value); - self.unify(self[temp_v!(2)], cstr); + (self.unify_fn)(self, self[temp_v!(2)], cstr); } _ => { self.fail = true; @@ -5777,20 +5330,19 @@ impl MachineState { let padding = self.atom_argument_to_string(3); let charset = self.atom_argument_to_string(4); - let config = - if padding == "true" { - if charset == "standard" { - base64::STANDARD - } else { - base64::URL_SAFE - } + let config = if padding == "true" { + if charset == "standard" { + base64::STANDARD } else { - if charset == "standard" { - base64::STANDARD_NO_PAD - } else { - base64::URL_SAFE_NO_PAD - } - }; + base64::URL_SAFE + } + } else { + if charset == "standard" { + base64::STANDARD_NO_PAD + } else { + base64::URL_SAFE_NO_PAD + } + }; if self.store(self.deref(self[temp_v!(1)])).is_ref() { let b64 = self.heap_pstr_iter(self[temp_v!(2)]).to_string(); @@ -5800,7 +5352,7 @@ impl MachineState { Ok(bs) => { let string = String::from_iter(bs.iter().map(|b| *b as char)); let cstr = self.heap.put_complete_string(&string); - self.unify(self[temp_v!(1)], cstr); + (self.unify_fn)(self, self[temp_v!(1)], cstr); } _ => { self.fail = true; @@ -5811,7 +5363,6 @@ impl MachineState { let mut bytes = vec![]; for c in self.heap_pstr_iter(self[temp_v!(1)]).to_string().chars() { if c as u32 > 255 { - let stub = MachineError::functor_stub(clause_name!("chars_base64"), 3); let err = MachineError::type_error( @@ -5828,23 +5379,126 @@ impl MachineState { let b64 = base64::encode_config(bytes, config); let cstr = self.heap.put_complete_string(&b64); - self.unify(self[temp_v!(2)], cstr); + (self.unify_fn)(self, self[temp_v!(2)], cstr); } } + &SystemClauseType::LoadLibraryAsStream => { + let library_name = atom_from!(self, self.store(self.deref(self[temp_v!(1)]))); + + use crate::LIBRARIES; + + match LIBRARIES.borrow().get(library_name.as_str()) { + Some(library) => { + let var_ref = Ref::HeapCell( + self.heap + .push(HeapCellValue::Stream(Stream::from(*library))), + ); + + self.bind(var_ref, self[temp_v!(2)]); + + let mut path_buf = machine::current_dir(); + + path_buf.push("/lib"); + path_buf.push(library_name.as_str()); + + let library_path_str = path_buf.to_str().unwrap(); + let library_path = + clause_name!(library_path_str.to_string(), self.atom_tbl); + + let library_path_ref = + Ref::HeapCell(self.heap.push(HeapCellValue::Atom(library_path, None))); + + self.bind(library_path_ref, self[temp_v!(3)]); + } + None => { + return Err(self.error_form( + MachineError::existence_error( + self.heap.h(), + ExistenceError::ModuleSource(ModuleSource::Library(library_name)), + ), + MachineError::functor_stub(clause_name!("load"), 1), + )); + } + } + } + &SystemClauseType::DevourWhitespace => { + let stream = + self.get_stream_or_alias(self[temp_v!(1)], indices, "$devour_whitespace", 1)?; + + match self.devour_whitespace(stream, self.atom_tbl.clone()) { + Ok(false) => {} // not at EOF. + _ => { + self.fail = true; + return Ok(()); + } + } + } + &SystemClauseType::IsSTOEnabled => { + if self.unify_fn as usize == MachineState::unify_with_occurs_check as usize { + let value = self.heap.to_unifiable( + HeapCellValue::Atom(clause_name!("true"), None), + ); + + (self.unify_fn)(self, self[temp_v!(1)], value); + } else if self.unify_fn as usize == MachineState::unify_with_occurs_check_with_error as usize { + let value = self.heap.to_unifiable( + HeapCellValue::Atom(clause_name!("error"), None), + ); + + (self.unify_fn)(self, self[temp_v!(1)], value); + } else { + let value = self.heap.to_unifiable( + HeapCellValue::Atom(clause_name!("false"), None), + ); + + (self.unify_fn)(self, self[temp_v!(1)], value); + } + } + &SystemClauseType::SetSTOAsUnify => { + self.unify_fn = MachineState::unify_with_occurs_check; + self.bind_fn = MachineState::bind_with_occurs_check_wrapper; + } + &SystemClauseType::SetNSTOAsUnify => { + self.unify_fn = MachineState::unify; + self.bind_fn = MachineState::bind; + } + &SystemClauseType::SetSTOWithErrorAsUnify => { + self.unify_fn = MachineState::unify_with_occurs_check_with_error; + self.bind_fn = MachineState::bind_with_occurs_check_with_error_wrapper; + } + &SystemClauseType::HomeDirectory => { + let path = match dirs_next::home_dir() { + Some(path) => path, + None => { + self.fail = true; + return Ok(()); + } + }; + + if path.is_dir() { + if let Some(path) = path.to_str() { + let path_string = self.heap.put_complete_string(path); + + self.unify(self[temp_v!(1)], path_string); + return return_from_clause!(self.last_call, self); + } + } + + self.fail = true; + } }; return_from_clause!(self.last_call, self) } - pub(super) - fn systemtime_to_timestamp( - &mut self, - system_time: SystemTime - ) -> Addr { + pub(super) fn systemtime_to_timestamp(&mut self, system_time: SystemTime) -> Addr { let datetime: DateTime = system_time.into(); let mut fstr = "[".to_string(); - let specifiers = vec!["Y","m","d","H","M","S","y","b","B","a","A","w","u","U","W","j","D","x","v"]; + let specifiers = vec![ + "Y", "m", "d", "H", "M", "S", "y", "b", "B", "a", "A", "w", "u", "U", "W", "j", "D", + "x", "v", + ]; for spec in specifiers { fstr.push_str(&format!("'{}'=\"%{}\", ", spec, spec).to_string()); } @@ -5853,11 +5507,7 @@ impl MachineState { self.heap.put_complete_string(&s) } - pub(super) - fn atom_argument_to_string( - &mut self, - atom_arg: usize, - ) -> String { + pub(super) fn atom_argument_to_string(&mut self, atom_arg: usize) -> String { match self.store(self.deref(self[temp_v!(atom_arg)])) { Addr::Con(h) if self.heap.atom_at(h) => { if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { @@ -5872,29 +5522,25 @@ impl MachineState { } } - pub(super) - fn string_encoding_bytes( - &mut self, - data_arg: usize, - encoding: &str, - ) -> Vec { + pub(super) fn string_encoding_bytes(&mut self, data_arg: usize, encoding: &str) -> Vec { let data = self.heap_pstr_iter(self[temp_v!(data_arg)]).to_string(); match encoding { - "utf8" => { data.into_bytes() } + "utf8" => data.into_bytes(), "octet" => { let mut buf = vec![]; - for c in data.chars() { + for c in data.chars() { buf.push(c as u8); } buf } - _ => { unreachable!() } + _ => { + unreachable!() + } } } - pub(super) - fn xml_node_to_term( + pub(super) fn xml_node_to_term( &mut self, indices: &mut IndexStore, node: roxmltree::Node, @@ -5905,16 +5551,15 @@ impl MachineState { } else { let mut avec = Vec::new(); for attr in node.attributes() { - let chars = clause_name!(String::from(attr.name()), indices.atom_tbl); - let name = self.heap.to_unifiable( - HeapCellValue::Atom(chars, None) - ); + let chars = clause_name!(String::from(attr.name()), self.atom_tbl); + let name = self.heap.to_unifiable(HeapCellValue::Atom(chars, None)); let value = self.heap.put_complete_string(&attr.value()); avec.push(HeapCellValue::Addr(Addr::HeapCell(self.heap.h()))); - self.heap.push(HeapCellValue::NamedStr(2, clause_name!("="), None)); + self.heap + .push(HeapCellValue::NamedStr(2, clause_name!("="), None)); self.heap.push(HeapCellValue::Addr(name)); self.heap.push(HeapCellValue::Addr(value)); } @@ -5926,14 +5571,13 @@ impl MachineState { } let children = Addr::HeapCell(self.heap.to_list(cvec.into_iter())); - let chars = clause_name!(String::from(node.tag_name().name()), indices.atom_tbl); - let tag = self.heap.to_unifiable( - HeapCellValue::Atom(chars, None) - ); + let chars = clause_name!(String::from(node.tag_name().name()), self.atom_tbl); + let tag = self.heap.to_unifiable(HeapCellValue::Atom(chars, None)); let result = Addr::HeapCell(self.heap.h()); - self.heap.push(HeapCellValue::NamedStr(3, clause_name!("element"), None)); + self.heap + .push(HeapCellValue::NamedStr(3, clause_name!("element"), None)); self.heap.push(HeapCellValue::Addr(tag)); self.heap.push(HeapCellValue::Addr(attrs)); self.heap.push(HeapCellValue::Addr(children)); @@ -5942,29 +5586,28 @@ impl MachineState { } } - pub(super) - fn html_node_to_term( + pub(super) fn html_node_to_term( &mut self, indices: &mut IndexStore, node: select::node::Node, ) -> Addr { match node.name() { - None => { let string = String::from(node.text()); - self.heap.put_complete_string(&string) + None => { + let string = String::from(node.text()); + self.heap.put_complete_string(&string) } Some(name) => { let mut avec = Vec::new(); for attr in node.attrs() { - let chars = clause_name!(String::from(attr.0), indices.atom_tbl); - let name = self.heap.to_unifiable( - HeapCellValue::Atom(chars, None) - ); + let chars = clause_name!(String::from(attr.0), self.atom_tbl); + let name = self.heap.to_unifiable(HeapCellValue::Atom(chars, None)); let value = self.heap.put_complete_string(&String::from(attr.1)); avec.push(HeapCellValue::Addr(Addr::HeapCell(self.heap.h()))); - self.heap.push(HeapCellValue::NamedStr(2, clause_name!("="), None)); + self.heap + .push(HeapCellValue::NamedStr(2, clause_name!("="), None)); self.heap.push(HeapCellValue::Addr(name)); self.heap.push(HeapCellValue::Addr(value)); } @@ -5976,14 +5619,13 @@ impl MachineState { } let children = Addr::HeapCell(self.heap.to_list(cvec.into_iter())); - let chars = clause_name!(String::from(name), indices.atom_tbl); - let tag = self.heap.to_unifiable( - HeapCellValue::Atom(chars, None) - ); + let chars = clause_name!(String::from(name), self.atom_tbl); + let tag = self.heap.to_unifiable(HeapCellValue::Atom(chars, None)); let result = Addr::HeapCell(self.heap.h()); - self.heap.push(HeapCellValue::NamedStr(3, clause_name!("element"), None)); + self.heap + .push(HeapCellValue::NamedStr(3, clause_name!("element"), None)); self.heap.push(HeapCellValue::Addr(tag)); self.heap.push(HeapCellValue::Addr(attrs)); self.heap.push(HeapCellValue::Addr(children)); @@ -5994,7 +5636,6 @@ impl MachineState { } } - fn rng() -> &'static dyn SecureRandom { use std::ops::Deref; diff --git a/src/machine/term_expansion.rs b/src/machine/term_expansion.rs deleted file mode 100644 index 6ee8f8d3..00000000 --- a/src/machine/term_expansion.rs +++ /dev/null @@ -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(terms: I, mut term: Term, sym: ClauseName) -> Term -where - I: DoubleEndedIterator, -{ - 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, - tail: Box, -) -> Result>, 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, - 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), - goal_expansion_additions: (Predicate, VecDeque), -} - -impl ExpansionAdditionResult { - pub fn take_term_expansions(&mut self) -> (Predicate, VecDeque) { - 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) { - 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, - atom_tbl: TabledData, - 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) { - self.parser.set_atom_tbl(atom_tbl); - } - - #[inline] - pub fn eof(&mut self) -> Result { - 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 { - 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 { - 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 { - 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 { - 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, - ) -> Result, 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 { - 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()) - } - } -} diff --git a/src/machine/term_stream.rs b/src/machine/term_stream.rs new file mode 100644 index 00000000..e55a5499 --- /dev/null +++ b/src/machine/term_stream.rs @@ -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; + fn eof(&mut self) -> Result; + fn listing_src(&self) -> &ListingSource; + fn evacuate<'a>(loader: Loader<'a, Self>) -> Result; +} + +#[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, + 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 { + self.parser.reset(); + self.parser + .read_term(op_dir) + .map_err(CompilationError::from) + } + + #[inline] + fn eof(&mut self) -> Result { + 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) -> Result { + 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, + 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, + 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 { + Ok(self.term_queue.pop_front().unwrap()) + } + + #[inline] + fn eof(&mut self) -> Result { + return Ok(self.term_queue.is_empty()); + } + + #[inline] + fn listing_src(&self) -> &ListingSource { + &self.listing_src + } + + #[inline] + fn evacuate(loader: Loader) -> Result { + Ok(loader.to_load_state_payload()) + } +} diff --git a/src/machine/toplevel.rs b/src/machine/toplevel.rs deleted file mode 100644 index eaa17691..00000000 --- a/src/machine/toplevel.rs +++ /dev/null @@ -1,1352 +0,0 @@ -use crate::prolog_parser::ast::*; -use crate::prolog_parser::tabled_rc::*; - -use crate::forms::*; -use crate::iterators::*; -use crate::machine::machine_errors::*; -use crate::machine::machine_indices::*; -use crate::machine::term_expansion::*; -use crate::machine::*; - -use crate::indexmap::{IndexMap, IndexSet}; - -use std::borrow::BorrowMut; -use std::cell::Cell; -use std::collections::VecDeque; -use std::convert::TryFrom; -use std::fmt; -use std::mem; -use std::ops::DerefMut; -use std::rc::Rc; - -enum IndexSource<'a, T> { - TermStream, - Local(&'a mut T) -} - -impl<'a, T: fmt::Debug> fmt::Debug for IndexSource<'a, T> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match self { - IndexSource::TermStream => write!(fmt, "TermStream"), - IndexSource::Local(ref local) => write!(fmt, "Local({:?})", local), - } - } -} - -fn op_dir<'a, 'b: 'a>(from: &'b IndexSource<'a, IndexStore>) -> RefOrOwned<'a, OpDir> { - match from { - IndexSource::TermStream => RefOrOwned::Owned(OpDir::new()), - IndexSource::Local(ref indices) => RefOrOwned::Borrowed(&indices.op_dir) - } -} - -#[derive(Debug)] -struct CompositeIndices<'a, 'b, 'c> { - term_stream: &'b mut TermStream<'a>, - index_src: IndexSource<'c, IndexStore>, - static_code_dir: Option> -} - -impl<'a, 'b, 'c> CompositeIndices<'a, 'b, 'c> { - fn new( - term_stream: &'b mut TermStream<'a>, - index_src: IndexSource<'c, IndexStore>, - static_code_dir: Option>, - ) -> Self { - CompositeIndices { - term_stream, - index_src, - static_code_dir, - } - } - - fn atom_tbl(&self) -> TabledData { - match self.index_src { - IndexSource::TermStream => self.term_stream.wam.indices.atom_tbl.clone(), - IndexSource::Local(ref indices) => indices.atom_tbl.clone(), - } - } - - fn local_code_dir(&mut self) -> &mut CodeDir { - match self.index_src { - IndexSource::TermStream => &mut self.term_stream.wam.indices.code_dir, - IndexSource::Local(ref mut indices) => &mut indices.code_dir, - } - } - - fn static_code_dir(&self) -> Option<&CodeDir> { - match self.static_code_dir { - Some(IndexSource::TermStream) => Some(&self.term_stream.wam.indices.code_dir), - Some(IndexSource::Local(ref code_dir)) => Some(code_dir), - None => None - } - } - - fn get_code_index(&mut self, name: ClauseName, arity: usize) -> CodeIndex { - let idx_opt = self.local_code_dir().get(&(name.clone(), arity)); - let idx_opt = match idx_opt { - Some(idx) => Some(idx.clone()), - None => match self.static_code_dir() { - Some(ref code_dir) => code_dir.get(&(name.clone(), arity)).cloned(), - _ => None, - } - }; - - if let Some(idx) = idx_opt { - self.local_code_dir().insert((name.clone(), arity), idx.clone()); - idx - } else { - let idx = CodeIndex::default(); - self.local_code_dir().insert((name.clone(), arity), idx.clone()); - idx - } - } - - fn get_clause_type( - &mut self, - name: ClauseName, - arity: usize, - spec: Option, - ) -> ClauseType { - match ClauseType::from(name, arity, spec) { - ClauseType::Named(name, arity, _) => { - let idx = self.get_code_index(name.clone(), arity); - ClauseType::Named(name, arity, idx.clone()) - } - ClauseType::Op(name, spec, _) => { - let idx = self.get_code_index(name.clone(), arity); - ClauseType::Op(name, spec, idx.clone()) - } - ct => ct, - } - } - - fn add_in_situ_module_info(&mut self, module_name: ClauseName, term: &mut Term) - { - let atom_tbl = - match self.term_stream.wam.indices.in_situ_module_dir.get(&module_name) { - Some(ref module_stub) => module_stub.atom_tbl.clone(), - None => { - let atom_tbl = match self.term_stream.wam.indices.modules.get(&module_name) { - Some(ref module) => module.atom_tbl.clone(), - None => TabledData::new(module_name.to_rc()), - }; - - self.term_stream.wam.indices.in_situ_module_dir.insert( - module_name.clone(), - ModuleStub::new(atom_tbl.clone()), - ); - - atom_tbl - } - }; - - if let Some(name) = term.name() { - term.set_name(name.with_table(atom_tbl)); - } - } -} - -fn as_compile_time_hook( - name: &str, - arity: usize, - terms: &Vec>, -) -> Option { - match (name, arity) { - ("term_expansion", 2) => Some(CompileTimeHook::TermExpansion), - ("goal_expansion", 2) => Some(CompileTimeHook::GoalExpansion), - (":", 2) => { - if let &Term::Constant(_, Constant::Atom(ref name, _)) = &terms[0].as_ref() { - if name.as_str() == "user" { - if let &Term::Clause(_, ref name, ref terms, _) = &terms[1].as_ref() { - return match name.as_str() { - "term_expansion" if terms.len() == 2 => { - Some(CompileTimeHook::UserTermExpansion) - } - "goal_expansion" if terms.len() == 2 => { - Some(CompileTimeHook::UserGoalExpansion) - } - _ => None, - }; - } - } - } - - None - } - _ => None, - } -} - -#[inline] -fn is_compile_time_hook(name: &ClauseName, terms: &Vec>) -> Option { - if name.as_str() == ":-" { - if let Some(ref term) = terms.first() { - if let &Term::Clause(_, ref name, ref terms, _) = term.as_ref() { - return as_compile_time_hook(name.as_str(), terms.len(), terms); - } - } - } - - as_compile_time_hook(name.as_str(), terms.len(), terms) -} - -type CompileTimeHookCompileInfo = (CompileTimeHook, PredicateClause, VecDeque); - -pub fn to_op_decl(prec: usize, spec: &str, name: ClauseName) -> Result { - match spec { - "xfx" => Ok(OpDecl(prec, XFX, name)), - "xfy" => Ok(OpDecl(prec, XFY, name)), - "yfx" => Ok(OpDecl(prec, YFX, name)), - "fx" => Ok(OpDecl(prec, FX, name)), - "fy" => Ok(OpDecl(prec, FY, name)), - "xf" => Ok(OpDecl(prec, XF, name)), - "yf" => Ok(OpDecl(prec, YF, name)), - _ => Err(ParserError::InconsistentEntry), - } -} - -fn setup_op_decl( - mut terms: Vec>, - atom_tbl: TabledData, -) -> Result { - let name = match *terms.pop().unwrap() { - Term::Constant(_, Constant::Atom(name, _)) => name, - Term::Constant(_, Constant::Char(c)) => clause_name!(c.to_string(), atom_tbl.clone()), - _ => return Err(ParserError::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.clone()), - _ => return Err(ParserError::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(ParserError::InconsistentEntry), - }, - _ => return Err(ParserError::InconsistentEntry), - }; - - to_op_decl(prec, spec.as_str(), name) -} - -fn setup_predicate_indicator(term: &mut Term) -> Result -{ - 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 - .to_constant() - .and_then(|c| { - match c { - Constant::Integer(n) => n.to_usize(), - Constant::Fixnum(n) => usize::try_from(n).ok(), - _ => None - } - }) - .ok_or(ParserError::InvalidModuleExport)?; - - let name = name - .to_constant() - .and_then(|c| c.to_atom()) - .ok_or(ParserError::InvalidModuleExport)?; - - if slash.as_str() == "/" { - Ok((name, arity)) - } else { - Ok((name, arity + 2)) - } - } - _ => Err(ParserError::InvalidModuleExport), - } -} - -fn setup_scoped_predicate_indicator(term: &mut Term) -> Result -{ - 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(ParserError::InvalidModuleExport)?; - - let key = setup_predicate_indicator(&mut predicate_indicator)?; - - Ok((module_name, key)) - } - _ => Err(ParserError::InvalidModuleExport), - } -} - -fn setup_module_export( - mut term: Term, - atom_tbl: TabledData, -) -> Result { - 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(ParserError::InvalidModuleDecl) - } - } else { - Err(ParserError::InvalidModuleDecl) - } - }) -} - -fn setup_module_decl( - mut terms: Vec>, - atom_tbl: TabledData, -) -> Result { - let mut export_list = *terms.pop().unwrap(); - let name = terms - .pop() - .unwrap() - .to_constant() - .and_then(|c| c.to_atom()) - .ok_or(ParserError::InvalidModuleDecl)?; - - 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 export_list.to_constant() != Some(Constant::EmptyList) { - Err(ParserError::InvalidModuleDecl) - } else { - Ok(ModuleDecl { name, exports }) - } -} - -fn read_library_path( - term: Term, - atom_tbl: TabledData, -) -> Option { - match term { - Term::Constant(_, Constant::Atom(atom, _)) => { - Some(atom.defrock_brackets()) - } - _ => { - let mut atoms = vec![]; - - for term in unfold_by_str(term, "/") { - match term { - Term::Constant(_, Constant::Atom(atom, _)) => { - atoms.push(atom.as_str().to_owned()); - } - _ => return None, - } - } - - Some(clause_name!(atoms.join("/"), atom_tbl)) - } - } -} - -fn setup_use_module_decl(mut terms: Vec>, atom_tbl: TabledData) -> Result { - match *terms.pop().unwrap() { - Term::Clause(_, ref name, ref mut terms, None) - if name.as_str() == "library" && terms.len() == 1 => - { - read_library_path(*terms.pop().unwrap(), atom_tbl) - .map(|c| ModuleSource::Library(c)) - .ok_or(ParserError::InvalidUseModuleDecl) - } - Term::Constant(_, Constant::Atom(ref name, _)) => - Ok(ModuleSource::File(name.clone())), - _ => Err(ParserError::InvalidUseModuleDecl), - } -} - -fn setup_double_quotes(mut terms: Vec>) -> Result { - 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(ParserError::InvalidDoubleQuotesDecl), - } - } - _ => { - Err(ParserError::InvalidDoubleQuotesDecl) - } - } - }, - _ => { - Err(ParserError::InvalidDoubleQuotesDecl) - } - } -} - -type UseModuleExport = (ModuleSource, Vec); - -fn setup_qualified_import( - mut terms: Vec>, - atom_tbl: TabledData, -) -> Result { - 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 => - { - read_library_path(*terms.pop().unwrap(), atom_tbl.clone()) - .map(|c| ModuleSource::Library(c)) - .ok_or(ParserError::InvalidUseModuleDecl) - } - Term::Constant(_, Constant::Atom(ref name, _)) => Ok(ModuleSource::File(name.clone())), - _ => Err(ParserError::InvalidUseModuleDecl), - }?; - - let mut exports = vec![]; - - while let Term::Cons(_, t1, t2) = export_list { - exports.push(setup_module_export(*t1, atom_tbl.clone())?); - export_list = *t2; - } - - if export_list.to_constant() != Some(Constant::EmptyList) { - Err(ParserError::InvalidModuleDecl) - } else { - Ok((module_src, exports)) - } -} - -fn merge_clauses(tls: &mut VecDeque) -> Result -{ - let mut clauses: Vec = vec![]; - - while let Some(tl) = tls.pop_front() { - match tl { - TopLevel::Query(_) if clauses.is_empty() && tls.is_empty() => return Ok(tl), - TopLevel::Declaration(_) if clauses.is_empty() => return Ok(tl), - TopLevel::Query(_) => return Err(ParserError::InconsistentEntry), - TopLevel::Fact(..) => { - if let TopLevel::Fact(fact, line_num, col_num) = tl { - let clause = PredicateClause::Fact(fact, line_num, col_num); - clauses.push(clause); - } - } - TopLevel::Rule(..) => { - if let TopLevel::Rule(rule, line_num, col_num) = tl { - let clause = PredicateClause::Rule(rule, line_num, col_num); - clauses.push(clause); - } - } - TopLevel::Predicate(..) => { - if let TopLevel::Predicate(predicate) = tl { - clauses.extend(predicate.clauses().into_iter()) - } - } - _ => { - tls.push_front(tl); - break; - } - } - } - - if clauses.is_empty() { - Err(ParserError::InconsistentEntry) - } else { - Ok(TopLevel::Predicate(Predicate(clauses))) - } -} - -fn mark_cut_variables_as(terms: &mut Vec, 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) -> 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) { - 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!(","), - )); - } -} - -fn flatten_hook(mut term: Term) -> Term { - if let Term::Clause(_, ref mut name, ref mut terms, _) = &mut term { - match (name.as_str(), terms.len()) { - (":-", 2) => { - let inner_term = match terms.first_mut().map(|term| term.borrow_mut()) { - Some(&mut Term::Clause(_, ref name, ref mut inner_terms, _)) => { - if name.as_str() == ":" && inner_terms.len() == 2 { - Some(*inner_terms.pop().unwrap()) - } else { - None - } - } - _ => None, - }; - - if let Some(inner_term) = inner_term { - mem::swap(&mut terms[0], &mut Box::new(inner_term)); - } - } - (":", 2) => return *terms.pop().unwrap(), - _ => {} - } - } - - term -} - -fn draw_from_term_dir_impl( - term_dir: &TermDir, - term_dirs: &mut TermDirQuantum, - key: &PredicateKey, - preds: &mut Vec, - queue: &mut VecDeque -) { - if let Some(entry) = term_dirs.get_mut(key) { - if entry.is_fresh { - entry.is_fresh = false; - - (entry.new_terms.0).0.extend(preds.drain(0 ..)); - entry.new_terms.1.extend(queue.drain(0 ..)); - - *preds = (entry.old_terms.0).0 - .iter() - .cloned() - .chain((entry.new_terms.0).0.iter().cloned()) - .collect(); - - *queue = entry.old_terms.1 - .iter() - .cloned() - .chain(entry.new_terms.1.iter().cloned()) - .collect(); - } else { - *entry = TermDirQuantumEntry::new(); - } - } else if term_dir.contains_key(key) { - let entry = TermDirQuantumEntry::from(&Predicate::new(), &VecDeque::new()); - term_dirs.insert(key.clone(), entry); - } -} - -fn draw_from_term_dir( - indices: &CompositeIndices, - intra_module_term_dirs: &mut IndexMap, - top_level_term_dirs: &mut TermDirQuantum, - key: &PredicateKey, - preds: &mut Vec, - queue: &mut VecDeque, -) { - let module = key.0.owning_module(); - - // aaarghhh.. - match indices.term_stream.wam.indices.in_situ_module_dir.get(&module) { - // modify module_stub to do this right. - Some(ref module_stub) if key.0.has_table(&module_stub.atom_tbl) => { - if let Some(ref mut term_dirs) = intra_module_term_dirs.get_mut(&module) { - if let Some(ref module) = indices.term_stream.wam.indices.modules.get(&module) { - return draw_from_term_dir_impl( - &module.term_dir, - term_dirs, - key, - preds, - queue, - ); - } - } - } - _ => {} - } - - draw_from_term_dir_impl( - &indices.term_stream.wam.code_repo.term_dir, - top_level_term_dirs, - key, - preds, - queue, - ); -} - -fn setup_declaration<'a, 'b, 'c>( - indices: &mut CompositeIndices<'a, 'b, 'c>, - flags: MachineFlags, - mut terms: Vec>, - line_num: usize, - col_num: usize, -) -> Result { - let term = *terms.pop().unwrap(); - - 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)) - } - ("initialization", 1) => { - let mut rel_worker = RelationWorker::new(flags, line_num, col_num); - let (query_terms, _) = rel_worker.setup_query(indices, terms, false, false)?; - let queue = rel_worker.parse_queue(indices)?; - - Ok(Declaration::ModuleInitialization(query_terms, queue)) - } - ("module", 2) => - Ok(Declaration::Module(setup_module_decl(terms, indices.atom_tbl())?)), - ("op", 3) => - Ok(Declaration::Op(setup_op_decl(terms, indices.atom_tbl())?)), - ("non_counted_backtracking", 1) => { - let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?; - Ok(Declaration::NonCountedBacktracking(name, arity)) - } - ("set_prolog_flag", 2) => { - Ok(Declaration::SetPrologFlag(setup_double_quotes(terms)?)) - } - ("multifile", 1) => { - let mut term = *terms.pop().unwrap(); - - match setup_predicate_indicator(&mut term) { - Ok((name, arity)) => { - Ok(Declaration::MultiFile(MultiFileIndicator::LocalScoped(name, arity))) - } - _ => { - setup_scoped_predicate_indicator(&mut term) - .map(|key| { - Declaration::MultiFile(MultiFileIndicator::ModuleScoped(key)) - }) - } - } - } - ("use_module", 1) => { - Ok(Declaration::UseModule(setup_use_module_decl(terms, indices.atom_tbl())?)) - } - ("use_module", 2) => { - let (name, exports) = setup_qualified_import(terms, indices.atom_tbl())?; - Ok(Declaration::UseQualifiedModule(name, exports)) - } - _ => { - Err(ParserError::InconsistentEntry) - } - }, - _ => { - Err(ParserError::InconsistentEntry) - } - } -} - -#[derive(Debug)] -struct RelationWorker { - flags: MachineFlags, - dynamic_clauses: Vec<(Term, Term)>, // Head, Body. - queue: VecDeque>, - line_num: usize, - col_num: usize -} - -impl RelationWorker { - fn new(flags: MachineFlags, line_num: usize, col_num: usize) -> Self { - RelationWorker { - dynamic_clauses: vec![], - flags, - queue: VecDeque::new(), - line_num, - col_num - } - } - - fn setup_fact(&mut self, term: Term, assume_dyn: bool) -> Result { - match term { - Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => { - let tail = - Term::Constant(Cell::default(), Constant::Atom(clause_name!("true"), None)); - - if assume_dyn { - self.dynamic_clauses.push((term.clone(), tail)); - } - - Ok(term) - } - _ => Err(ParserError::InadmissibleFact), - } - } - - fn compute_head(&self, term: &Term) -> Vec { - 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, 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) { - // 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) { - 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) { - 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, 'b, 'c>( - &mut self, - indices: &mut CompositeIndices<'a, 'b, 'c>, - term: Term, - ) -> Result { - match term { - Term::Constant(_, Constant::Atom(name, fixity)) => { - if name.as_str() == "!" || name.as_str() == "blocked_!" { - Ok(QueryTerm::BlockedCut) - } else { - let ct = indices.get_clause_type(name, 0, fixity); - Ok(QueryTerm::Clause(Cell::default(), ct, vec![], false)) - } - } - 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(ParserError::InadmissibleQueryTerm) - } - } - _ => { - let ct = indices.get_clause_type(name, terms.len(), fixity); - Ok(QueryTerm::Clause(Cell::default(), ct, terms, false)) - } - } - Term::Var(..) => Ok(QueryTerm::Clause( - Cell::default(), - ClauseType::CallN, - vec![Box::new(term)], - false, - )), - _ => Err(ParserError::InadmissibleQueryTerm), - } - } - - fn pre_query_term<'a, 'b, 'c>( - &mut self, - indices: &mut CompositeIndices<'a, 'b, 'c>, - term: Term, - ) -> Result { - match term { - Term::Clause(r, name, mut subterms, fixity) => { - if subterms.len() == 1 && name.as_str() == "$call_with_default_policy" { - self.to_query_term(indices, *subterms.pop().unwrap()) - .map(|mut query_term| { - query_term.set_default_caller(); - query_term - }) - } else { - self.to_query_term(indices, Term::Clause(r, name, subterms, fixity)) - } - } - _ => self.to_query_term(indices, term), - } - } - - fn setup_query<'a, 'b, 'c>( - &mut self, - indices: &mut CompositeIndices<'a, 'b, 'c>, - terms: Vec>, - blocks_cuts: bool, - assume_dyn: bool, - ) -> Result<(Vec, Term), ParserError> { - let mut query_terms = vec![]; - let mut work_queue = VecDeque::from(terms); - let mut machine_st = MachineState::new(); - - let mut dynamic_clause_terms = vec![]; - - while let Some(term) = work_queue.pop_front() { - let term = *term; - let op_dir = op_dir(&indices.index_src); - - let mut expanded_terms = indices.term_stream.expand_goals( - &mut machine_st, - op_dir.as_ref(), - VecDeque::from(vec![term]) - )?; - - while let Some(term) = expanded_terms.pop() { - work_queue.push_front(Box::new(term)); - } - - if 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 !blocks_cuts { - mark_cut_variable(&mut term); - } - - if assume_dyn { - dynamic_clause_terms.push(term.clone()); - } - - query_terms.push(self.pre_query_term(indices, term)?); - } - } - - let dynamic_clause_body = - if let Some(term) = dynamic_clause_terms.pop() { - fold_by_str(dynamic_clause_terms.into_iter(), term, clause_name!(",")) - } else { - Term::Constant(Cell::default(), Constant::Atom(clause_name!("true"), None)) - }; - - Ok((query_terms, dynamic_clause_body)) - } - - fn setup_hook<'a, 'b, 'c>( - &mut self, - hook: CompileTimeHook, - indices: &mut CompositeIndices<'a, 'b, 'c>, - term: Term, - ) -> Result { - match flatten_hook(term) { - Term::Clause(r, name, terms, _) => { - if name == hook.name() && terms.len() == hook.arity() { - let term = self.setup_fact(Term::Clause(r, name, terms, None), false)?; - Ok((hook, PredicateClause::Fact(term, 0, 0), VecDeque::from(vec![]))) - } else if name.as_str() == ":-" && terms.len() == 2 { - let rule = self.setup_rule(indices, terms, true, false)?; - let results_queue = self.parse_queue(indices)?; - - Ok((hook, PredicateClause::Rule(rule, 0, 0), results_queue)) - } else { - Err(ParserError::InvalidHook) - } - } - _ => Err(ParserError::InvalidHook), - } - } - - fn setup_rule<'a, 'b, 'c>( - &mut self, - indices: &mut CompositeIndices<'a, 'b, 'c>, - mut terms: Vec>, - blocks_cuts: bool, - assume_dyn: bool, - ) -> Result { - let dynamic_term_head = *terms.first().cloned().unwrap(); - let post_head_terms: Vec<_> = terms.drain(1 ..).collect(); - - let (mut query_terms, dynamic_term_body) = - self.setup_query(indices, post_head_terms, blocks_cuts, assume_dyn)?; - - if assume_dyn { - self.dynamic_clauses.push((dynamic_term_head, dynamic_term_body)); - } - - 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(ParserError::InvalidRuleHead), - } - } - - fn try_term_to_query<'a, 'b, 'c>( - &mut self, - indices: &mut CompositeIndices<'a, 'b, 'c>, - terms: Vec>, - blocks_cuts: bool, - ) -> Result { - let (result, _) = self.setup_query( - indices, - terms, - blocks_cuts, - false, - )?; - - Ok(TopLevel::Query(result)) - } - - fn compact_module_scoped_head<'a, 'b, 'c>( - &self, - term: &mut Term, - indices: &mut CompositeIndices<'a, 'b, 'c>, - ) { - let inner_term = match term { - Term::Clause(_, ref name, ref mut inner_terms, _) - if name.as_str() == ":" && inner_terms.len() == 2 => { - let module_name = match inner_terms[0].as_ref() { - &Term::Constant(_, Constant::Atom(ref module, _)) => { - module.clone() - } - _ => { - return; - } - }; - - indices.add_in_situ_module_info(module_name, inner_terms[1].deref_mut()); - *inner_terms.pop().unwrap() - } - _ => { - return; - } - }; - - *term = inner_term; - } - - fn try_term_to_tl<'a, 'b, 'c>( - &mut self, - indices: &mut CompositeIndices<'a, 'b, 'c>, - term: Term, - blocks_cuts: bool, - ) -> Result { - match term { - Term::Clause(r, name, mut terms, fixity) => { - if let Some(hook) = is_compile_time_hook(&name, &terms) { - let term = Term::Clause(r, name, terms, fixity); - let (hook, clause, queue) = self.setup_hook(hook, indices, term)?; - - Ok(TopLevel::Declaration(Declaration::Hook( - hook, clause, queue, - ))) - } else if name.as_str() == "?-" { - self.try_term_to_query(indices, terms, blocks_cuts) - } else if name.as_str() == ":-" && terms.len() == 2 { - self.compact_module_scoped_head(&mut terms[0], indices); - - Ok(TopLevel::Rule(self.setup_rule( - indices, - terms, - blocks_cuts, - true, - )?, self.line_num, self.col_num)) - } else if name.as_str() == ":-" && terms.len() == 1 { - Ok(TopLevel::Declaration(setup_declaration(indices, self.flags, terms, - self.line_num, self.col_num)?)) - } else { - let mut term = Term::Clause(r, name, terms, fixity); - self.compact_module_scoped_head(&mut term, indices); - - Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num)) - } - } - term => { - Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num)) - } - } - } - - fn try_terms_to_tls<'a, 'b, 'c, I>( - &mut self, - indices: &mut CompositeIndices<'a, 'b, 'c>, - terms: I, - blocks_cuts: bool, - ) -> Result, ParserError> - where - I: IntoIterator - { - let mut results = VecDeque::new(); - - for term in terms.into_iter() { - results.push_back(self.try_term_to_tl(indices, term, blocks_cuts)?); - } - - Ok(results) - } - - fn parse_queue<'a, 'b, 'c>( - &mut self, - indices: &mut CompositeIndices<'a, 'b, 'c>, - ) -> Result, ParserError> { - let mut queue = VecDeque::new(); - - while let Some(terms) = self.queue.pop_front() { - let clauses = merge_clauses(&mut self.try_terms_to_tls(indices, terms, false)?)?; - queue.push_back(clauses); - } - - Ok(queue) - } - - fn absorb(&mut self, other: RelationWorker) { - self.queue.extend(other.queue.into_iter()); - self.dynamic_clauses.extend(other.dynamic_clauses.into_iter()); - } -} - -pub type DynamicClause = Vec<(Term, Term)>; - -pub type DynamicClauseMap = IndexMap<(ClauseName, usize), DynamicClause>; - -#[derive(Debug)] -pub struct TopLevelBatchWorker<'a> { - pub(crate) term_stream: TermStream<'a>, - rel_worker: RelationWorker, - pub(crate) results: Vec<(Predicate, VecDeque)>, - pub(crate) dynamic_clause_map: DynamicClauseMap, - pub(crate) in_module: bool, - pub(crate) term_dirs: TermDirQuantum, - pub(crate) intra_module_term_dirs: IndexMap, - pub(crate) non_counted_bt_preds: IndexSet, -} - -impl<'a> TopLevelBatchWorker<'a> { - pub fn new( - stream: &'a mut ParsingStream, - atom_tbl: TabledData, - flags: MachineFlags, - wam: &'a mut Machine, - ) -> Self { - let term_stream = TermStream::new(stream, atom_tbl, flags, wam); - - let line_num = term_stream.line_num(); - let col_num = term_stream.col_num(); - - TopLevelBatchWorker { - term_stream, - rel_worker: RelationWorker::new(flags, line_num, col_num), - results: vec![], - dynamic_clause_map: IndexMap::new(), - in_module: false, - term_dirs: TermDirQuantum::new(), - intra_module_term_dirs: IndexMap::new(), - non_counted_bt_preds: IndexSet::new(), - } - } - - fn try_term_to_tl( - &mut self, - indices: &mut IndexStore, - term: Term, - ) -> Result<(TopLevel, RelationWorker), SessionError> { - let line_num = self.term_stream.line_num(); - let col_num = self.term_stream.col_num(); - - let mut new_rel_worker = RelationWorker::new(self.rel_worker.flags, line_num, col_num); - let mut indices = CompositeIndices::new( - &mut self.term_stream, - IndexSource::Local(indices), - if self.in_module { None } else { Some(IndexSource::TermStream) } - ); - - Ok(( - new_rel_worker.try_term_to_tl(&mut indices, term, true)?, - new_rel_worker, - )) - } - - fn process_result( - &mut self, - indices: &mut IndexStore, - preds: &mut Vec, - ) -> Result<(), SessionError> { - let mut indices = CompositeIndices::new( - &mut self.term_stream, - IndexSource::Local(indices), - if self.in_module { None } else { Some(IndexSource::TermStream) }, - ); - - let key = (preds[0].name().unwrap(), preds[0].arity()); - - let mut preds = mem::replace(preds, vec![]); - let mut queue = self.rel_worker.parse_queue(&mut indices)?; - - draw_from_term_dir( - &indices, - &mut self.intra_module_term_dirs, - &mut self.term_dirs, - &key, - &mut preds, - &mut queue, - ); - - let result = (Predicate(preds), queue); - - indices.term_stream.wam.code_repo.add_in_situ_result( - &result, - &mut indices.term_stream.wam.indices.in_situ_code_dir, - &mut indices.term_stream.wam.indices.in_situ_module_dir, - &self.non_counted_bt_preds, - )?; - - Ok(self.results.push(result)) - } - - fn take_dynamic_clauses(&mut self) { - let (name, arity) = match self.rel_worker.dynamic_clauses.first() { - Some((head, _)) => (head.name().unwrap(), head.arity()), - None => return, - }; - - match self.dynamic_clause_map.get_mut(&(name.clone(), arity)) { - Some(ref mut entry) => { - entry.clear(); // don't treat dynamic predicates as if they're discontiguous. - entry.extend(self.rel_worker.dynamic_clauses.drain(0 ..)); - } - _ => { - self.rel_worker.dynamic_clauses.clear(); - } - } - } - - pub fn consume( - &mut self, - indices: &mut IndexStore, - ) -> Result, SessionError> { - let mut preds = vec![]; - - while !self.term_stream.eof()? { - let term = self.term_stream.read_term(&indices.op_dir)?; - - // if is_consistent is false, preds is non-empty. - let term = if !term.is_consistent(&preds) { - self.process_result(indices, &mut preds)?; - self.take_dynamic_clauses(); - - // expand the term after the addition of the previous - // predicate. - self.term_stream.expand_term(term, &indices.op_dir)? - } else { - term - }; - - let (mut tl, new_rel_worker) = self.try_term_to_tl(indices, term)?; - - if tl.is_end_of_file_atom() { - tl = TopLevel::Declaration(Declaration::EndOfFile); - } - - self.rel_worker.absorb(new_rel_worker); - - match tl { - TopLevel::Fact(fact, line_num, col_num) => - preds.push(PredicateClause::Fact(fact, line_num, col_num)), - TopLevel::Rule(rule, line_num, col_num) => - preds.push(PredicateClause::Rule(rule, line_num, col_num)), - TopLevel::Predicate(pred) => - preds.extend(pred.0), - TopLevel::Declaration(decl) => - return Ok(Some(decl)), - TopLevel::Query(_) => - return Err(SessionError::QueryCannotBeDefinedAsFact), - } - } - - if !preds.is_empty() { - self.process_result(indices, &mut preds)?; - self.take_dynamic_clauses(); - } - - Ok(None) - } -} diff --git a/src/macros.rs b/src/macros.rs index 7de7da2f..b8b6d802 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -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; + } + } + }}; +} diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 89168bf9..00000000 --- a/src/main.rs +++ /dev/null @@ -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(); -} diff --git a/src/read.rs b/src/read.rs index 5e972a08..366962cb 100644 --- a/src/read.rs +++ b/src/read.rs @@ -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; +pub(crate) type PrologStream = ParsingStream; 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 { + pub(crate) fn peek_byte(&mut self) -> std::io::Result { 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 { + pub(crate) fn peek_char(&mut self) -> std::io::Result { 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 { 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, + ) -> Result { + 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, @@ -193,11 +202,18 @@ impl MachineState { ) -> Result { 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, + } } } diff --git a/src/targets.rs b/src/targets.rs index 643ea1d5..78e988e5 100644 --- a/src/targets.rs +++ b/src/targets.rs @@ -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>; fn iter(_: &'a Term) -> Self::Iterator; diff --git a/src/tests/hello_world.pl b/src/tests/hello_world.pl new file mode 100644 index 00000000..e7fd4e20 --- /dev/null +++ b/src/tests/hello_world.pl @@ -0,0 +1,6 @@ +:- use_module(library(debug)). +:- use_module(library(format)). + +hello_world :- write('Hello World!'), nl. + +:- initialization(hello_world). \ No newline at end of file diff --git a/src/toplevel.pl b/src/toplevel.pl index bbada3a2..e0f1bcc1 100644 --- a/src/toplevel.pl +++ b/src/toplevel.pl @@ -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 - ). diff --git a/src/write.rs b/src/write.rs index cf40509d..4aa84e99 100644 --- a/src/write.rs +++ b/src/write.rs @@ -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), } } diff --git a/tests/scryer.rs b/tests/scryer.rs new file mode 100644 index 00000000..55d67a73 --- /dev/null +++ b/tests/scryer.rs @@ -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::::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"")); +}