Merge pull request #843 from mthom/rebis-dev

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

View File

@@ -17,11 +17,16 @@ jobs:
profile: minimal profile: minimal
toolchain: ${{ matrix.rust-version }} toolchain: ${{ matrix.rust-version }}
override: true override: true
- name: Build - name: Build lib
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: rustc 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 - name: Test
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:

38
Cargo.lock generated
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

@@ -2,15 +2,17 @@
name = "prolog_parser" name = "prolog_parser"
version = "0.8.68" version = "0.8.68"
authors = ["Mark Thom <markjordanthom@gmail.com>"] authors = ["Mark Thom <markjordanthom@gmail.com>"]
edition = "2018"
repository = "https://github.com/mthom/scryer-prolog" 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" license = "BSD-3-Clause"
[dependencies] [dependencies]
indexmap = "1.0.2"
lexical = "2.1.0" lexical = "2.1.0"
ordered-float = "0.5.0" ordered-float = "0.5.0"
rug = { optional = true, version = "1.4.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" unicode_reader = "1.0.0"
[lib] [lib]

View File

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

View File

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

View File

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

View File

@@ -1,106 +1,138 @@
#[macro_export] #[macro_export]
macro_rules! char_class { macro_rules! char_class {
($c: expr, [$head:expr]) => ($c == $head); ($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_export]
macro_rules! symbolic_control_char { 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_export]
macro_rules! space_char { macro_rules! space_char {
($c: expr) => ($c == ' ') ($c: expr) => {
$c == ' '
};
} }
#[macro_export] #[macro_export]
macro_rules! layout_char { 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_export]
macro_rules! symbolic_hexadecimal_char { macro_rules! symbolic_hexadecimal_char {
($c: expr) => ($c == 'x') ($c: expr) => {
$c == 'x'
};
} }
#[macro_export] #[macro_export]
macro_rules! octal_digit_char { macro_rules! octal_digit_char {
($c: expr) => ($c >= '0' && $c <= '7') ($c: expr) => {
('0'..='7').contains(&$c)
};
} }
#[macro_export] #[macro_export]
macro_rules! binary_digit_char { macro_rules! binary_digit_char {
($c: expr) => ($c >= '0' && $c <= '1') ($c: expr) => {
$c >= '0' && $c <= '1'
};
} }
#[macro_export] #[macro_export]
macro_rules! hexadecimal_digit_char { macro_rules! hexadecimal_digit_char {
($c: expr) => ($c >= '0' && $c <= '9' || ($c: expr) => {
$c >= 'A' && $c <= 'F' || ('0'..='9').contains(&$c) || ('A'..='F').contains(&$c) || ('a'..='f').contains(&$c)
$c >= 'a' && $c <= 'f') };
} }
#[macro_export] #[macro_export]
macro_rules! exponent_char { macro_rules! exponent_char {
($c: expr) => ($c == 'e' || $c == 'E') ($c: expr) => {
$c == 'e' || $c == 'E'
};
} }
#[macro_export] #[macro_export]
macro_rules! sign_char { macro_rules! sign_char {
($c: expr) => ($c == '-' || $c == '+') ($c: expr) => {
$c == '-' || $c == '+'
};
} }
#[macro_export] #[macro_export]
macro_rules! new_line_char { macro_rules! new_line_char {
($c: expr) => ($c == '\n') ($c: expr) => {
$c == '\n'
};
} }
#[macro_export] #[macro_export]
macro_rules! end_line_comment_char { macro_rules! end_line_comment_char {
($c: expr) => ($c == '%') ($c: expr) => {
$c == '%'
};
} }
#[macro_export] #[macro_export]
macro_rules! comment_1_char { macro_rules! comment_1_char {
($c: expr) => ($c == '/') ($c: expr) => {
$c == '/'
};
} }
#[macro_export] #[macro_export]
macro_rules! comment_2_char { macro_rules! comment_2_char {
($c: expr) => ($c == '*') ($c: expr) => {
$c == '*'
};
} }
#[macro_export] #[macro_export]
macro_rules! capital_letter_char { macro_rules! capital_letter_char {
($c: expr) => ($c >= 'A' && $c <= 'Z') ($c: expr) => {
('A'..='Z').contains(&$c)
};
} }
#[macro_export] #[macro_export]
macro_rules! small_letter_char { macro_rules! small_letter_char {
($c: expr) => ($c >= 'a' && $c <= 'z') ($c: expr) => {
('a'..='z').contains(&$c)
};
} }
#[macro_export] #[macro_export]
macro_rules! variable_indicator_char { macro_rules! variable_indicator_char {
($c: expr) => ($c == '_') ($c: expr) => {
$c == '_'
};
} }
#[macro_export] #[macro_export]
macro_rules! graphic_char { macro_rules! graphic_char {
($c: expr) => (char_class!($c, ['#', '$', '&', '*', '+', '-', '.', '/', ':', ($c: expr) => ($crate::char_class!($c, ['#', '$', '&', '*', '+', '-', '.', '/', ':',
'<', '=', '>', '?', '@', '^', '~'])) '<', '=', '>', '?', '@', '^', '~']))
} }
#[macro_export] #[macro_export]
macro_rules! graphic_token_char { 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_export]
macro_rules! alpha_char { macro_rules! alpha_char {
($c: expr) => ($c: expr) => {
(match $c { match $c {
'a'..='z' => true, 'a'..='z' => true,
'A'..='Z' => true, 'A'..='Z' => true,
'_' => true, '_' => true,
@@ -120,68 +152,95 @@ macro_rules! alpha_char {
'\u{0590}'..='\u{05FF}' => true, // Hebrew '\u{0590}'..='\u{05FF}' => true, // Hebrew
'\u{0600}'..='\u{06FF}' => true, // Arabic '\u{0600}'..='\u{06FF}' => true, // Arabic
'\u{0700}'..='\u{074F}' => true, // Syriac '\u{0700}'..='\u{074F}' => true, // Syriac
_ => false _ => false,
}) }
};
} }
#[macro_export] #[macro_export]
macro_rules! decimal_digit_char { macro_rules! decimal_digit_char {
($c: expr) => ($c >= '0' && $c <= '9') ($c: expr) => {
('0'..='9').contains(&$c)
};
} }
#[macro_export] #[macro_export]
macro_rules! decimal_point_char { macro_rules! decimal_point_char {
($c: expr) => ($c == '.') ($c: expr) => {
$c == '.'
};
} }
#[macro_export] #[macro_export]
macro_rules! alpha_numeric_char { 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_export]
macro_rules! cut_char { macro_rules! cut_char {
($c: expr) => ($c == '!') ($c: expr) => {
$c == '!'
};
} }
#[macro_export] #[macro_export]
macro_rules! semicolon_char { macro_rules! semicolon_char {
($c: expr) => ($c == ';') ($c: expr) => {
$c == ';'
};
} }
#[macro_export] #[macro_export]
macro_rules! backslash_char { macro_rules! backslash_char {
($c: expr) => ($c == '\\') ($c: expr) => {
$c == '\\'
};
} }
#[macro_export] #[macro_export]
macro_rules! single_quote_char { macro_rules! single_quote_char {
($c: expr) => ($c == '\'') ($c: expr) => {
$c == '\''
};
} }
#[macro_export] #[macro_export]
macro_rules! double_quote_char { macro_rules! double_quote_char {
($c: expr) => ($c == '"') ($c: expr) => {
$c == '"'
};
} }
#[macro_export] #[macro_export]
macro_rules! back_quote_char { macro_rules! back_quote_char {
($c: expr) => ($c == '`') ($c: expr) => {
$c == '`'
};
} }
#[macro_export] #[macro_export]
macro_rules! meta_char { macro_rules! meta_char {
($c: expr) => ( char_class!($c, ['\\', '\'', '"', '`']) ) ($c: expr) => {
$crate::char_class!($c, ['\\', '\'', '"', '`'])
};
} }
#[macro_export] #[macro_export]
macro_rules! solo_char { macro_rules! solo_char {
($c: expr) => ( char_class!($c, ['!', '(', ')', ',', ';', '[', ']', ($c: expr) => {
'{', '}', '|', '%']) ) $crate::char_class!($c, ['!', '(', ')', ',', ';', '[', ']', '{', '}', '|', '%'])
};
} }
#[macro_export] #[macro_export]
macro_rules! prolog_char { macro_rules! prolog_char {
($c: expr) => (graphic_char!($c) || alpha_numeric_char!($c) || solo_char!($c) || ($c: expr) => {
layout_char!($c) || meta_char!($c)) $crate::graphic_char!($c)
|| $crate::alpha_numeric_char!($c)
|| $crate::solo_char!($c)
|| $crate::layout_char!($c)
|| $crate::meta_char!($c)
};
} }

View File

@@ -1,10 +1,10 @@
use ast::*; use crate::ast::*;
use lexer::*; use crate::lexer::*;
use tabled_rc::*; use crate::tabled_rc::*;
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
use rug::ops::NegAssign; use crate::rug::ops::NegAssign;
use std::cell::Cell; use std::cell::Cell;
use std::io::Read; use std::io::Read;
@@ -23,18 +23,23 @@ enum TokenType {
Close, Close,
CloseList, // ']' CloseList, // ']'
CloseCurly, // '}' CloseCurly, // '}'
End End,
} }
impl TokenType { impl TokenType {
fn is_sep(self) -> bool { fn is_sep(self) -> bool {
match self { matches!(
TokenType::HeadTailSeparator | TokenType::OpenCT | TokenType::Open | self,
TokenType::Close | TokenType::OpenList | TokenType::CloseList | TokenType::HeadTailSeparator
TokenType::OpenCurly | TokenType::CloseCurly | TokenType::Comma | TokenType::OpenCT
=> true, | TokenType::Open
_ => false | TokenType::Close
} | TokenType::OpenList
| TokenType::CloseList
| TokenType::OpenCurly
| TokenType::CloseCurly
| TokenType::Comma
)
} }
} }
@@ -42,40 +47,47 @@ impl TokenType {
struct TokenDesc { struct TokenDesc {
tt: TokenType, tt: TokenType,
priority: usize, priority: usize,
spec: u32 spec: u32,
} }
pub pub fn get_clause_spec(
fn get_clause_spec(name: ClauseName, arity: usize, op_dir: CompositeOp) -> Option<SharedOpDesc> name: ClauseName,
{ arity: usize,
op_dir: &CompositeOpDir,
) -> Option<SharedOpDesc> {
match arity { match arity {
1 => { 1 => {
/* This is a clause with an operator principal functor. Prefix operators /* This is a clause with an operator principal functor. Prefix operators
are supposed over post. are supposed over post.
*/ */
if let Some(OpDirValue(cell, _)) = op_dir.get(name.clone(), Fixity::Pre) { if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::Pre) {
return Some(cell); return Some(cell.clone());
} }
if let Some(OpDirValue(cell, _)) = op_dir.get(name, Fixity::Post) { if let Some(OpDirValue(cell)) = op_dir.get(name, Fixity::Post) {
return Some(cell); return Some(cell.clone());
}
}
2 => {
if let Some(OpDirValue(cell)) = op_dir.get(name, Fixity::In) {
return Some(cell.clone());
}
} }
},
2 =>
if let Some(OpDirValue(cell, _)) = op_dir.get(name, Fixity::In) {
return Some(cell);
},
_ => {} _ => {}
}; };
None None
} }
pub fn get_desc(name: ClauseName, op_dir: CompositeOp) -> Option<OpDesc> pub fn get_op_desc(name: ClauseName, op_dir: &CompositeOpDir) -> Option<OpDesc> {
{ let mut op_desc = OpDesc {
let mut op_desc = OpDesc { pre: 0, inf: 0, post: 0, spec: 0 }; 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(); let (pri, spec) = cell.get();
if pri > 0 { if pri > 0 {
@@ -86,7 +98,7 @@ pub fn get_desc(name: ClauseName, op_dir: CompositeOp) -> Option<OpDesc>
} }
} }
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(); let (pri, spec) = cell.get();
if pri > 0 { if pri > 0 {
@@ -95,7 +107,7 @@ pub fn get_desc(name: ClauseName, op_dir: CompositeOp) -> Option<OpDesc>
} }
} }
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(); let (pri, spec) = cell.get();
if pri > 0 { if pri > 0 {
@@ -111,8 +123,7 @@ pub fn get_desc(name: ClauseName, op_dir: CompositeOp) -> Option<OpDesc>
} }
} }
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 d2.priority <= priority
&& is_term!(d3.spec) && is_term!(d3.spec)
&& is_term!(d1.spec) && is_term!(d1.spec)
@@ -120,8 +131,7 @@ fn affirm_xfx(priority: usize, d2: TokenDesc, d3: TokenDesc, d1: TokenDesc) -> b
&& d1.priority < d2.priority && 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 d2.priority <= priority
&& ((is_term!(d3.spec) && d3.priority < d2.priority) && ((is_term!(d3.spec) && d3.priority < d2.priority)
|| (is_lterm!(d3.spec) && d3.priority == d2.priority)) || (is_lterm!(d3.spec) && d3.priority == d2.priority))
@@ -129,9 +139,7 @@ fn affirm_yfx(priority: usize, d2: TokenDesc, d3: TokenDesc, d1: TokenDesc) -> b
&& d1.priority < d2.priority && 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 d2.priority < priority
&& is_term!(d3.spec) && is_term!(d3.spec)
&& d3.priority < d2.priority && d3.priority < d2.priority
@@ -139,49 +147,35 @@ fn affirm_xfy(priority: usize, d2: TokenDesc, d3: TokenDesc, d1: TokenDesc) -> b
&& d1.priority <= d2.priority && 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; let is_valid_lterm = is_lterm!(d2.spec) && d2.priority == d1.priority;
(is_term!(d2.spec) && d2.priority < d1.priority) || is_valid_lterm (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 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 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 d2.priority <= priority && is_term!(d1.spec) && d1.priority < d2.priority
} }
fn sep_to_atom(tt: TokenType) -> Option<ClauseName> fn sep_to_atom(tt: TokenType) -> Option<ClauseName> {
{
match tt { match tt {
TokenType::Open | TokenType::OpenCT => TokenType::Open | TokenType::OpenCT => Some(clause_name!("(")),
Some(clause_name!("(")), TokenType::Close => Some(clause_name!(")")),
TokenType::Close => TokenType::OpenList => Some(clause_name!("[")),
Some(clause_name!(")")), TokenType::CloseList => Some(clause_name!("]")),
TokenType::OpenList => TokenType::OpenCurly => Some(clause_name!("{")),
Some(clause_name!("[")), TokenType::CloseCurly => Some(clause_name!("}")),
TokenType::CloseList => TokenType::HeadTailSeparator => Some(clause_name!("|")),
Some(clause_name!("]")), TokenType::Comma => Some(clause_name!(",")),
TokenType::OpenCurly => TokenType::End => Some(clause_name!(".")),
Some(clause_name!("{")), _ => None,
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 pre: usize,
pub inf: usize, pub inf: usize,
pub post: usize, pub post: usize,
pub spec: Specifier pub spec: Specifier,
} }
#[derive(Debug)] #[derive(Debug)]
@@ -201,13 +195,12 @@ pub struct Parser<'a, R: Read> {
terms: Vec<Term>, terms: Vec<Term>,
} }
fn read_tokens<'a, R: Read>(lexer: &mut Lexer<'a, R>) -> Result<Vec<Token>, ParserError> fn read_tokens<R: Read>(lexer: &mut Lexer<R>) -> Result<Vec<Token>, ParserError> {
{
let mut tokens = vec![]; let mut tokens = vec![];
loop { loop {
let token = lexer.next_token()?; let token = lexer.next_token()?;
let at_end = Token::End == token; let at_end = token.is_end();
tokens.push(token); tokens.push(token);
@@ -227,10 +220,12 @@ impl<'a, R: Read> Parser<'a, R> {
atom_tbl: TabledData<Atom>, atom_tbl: TabledData<Atom>,
flags: MachineFlags, flags: MachineFlags,
) -> Self { ) -> Self {
Parser { lexer: Lexer::new(atom_tbl, flags, stream), Parser {
lexer: Lexer::new(atom_tbl, flags, stream),
tokens: vec![], tokens: vec![],
stack: Vec::new(), stack: Vec::new(),
terms: Vec::new() } terms: Vec::new(),
}
} }
#[inline] #[inline]
@@ -255,50 +250,46 @@ impl<'a, R: Read> Parser<'a, R> {
fn get_term_name(&mut self, td: TokenDesc) -> Option<(ClauseName, Option<SharedOpDesc>)> { fn get_term_name(&mut self, td: TokenDesc) -> Option<(ClauseName, Option<SharedOpDesc>)> {
match td.tt { match td.tt {
TokenType::HeadTailSeparator => { TokenType::HeadTailSeparator => Some((
Some((clause_name!("|"), Some(SharedOpDesc::new(td.priority, td.spec)))) clause_name!("|"),
} Some(SharedOpDesc::new(td.priority, td.spec)),
TokenType::Comma => { )),
Some((clause_name!(","), Some(SharedOpDesc::new(1000, XFY)))) TokenType::Comma => Some((clause_name!(","), Some(SharedOpDesc::new(1000, XFY)))),
} TokenType::Term => match self.terms.pop() {
TokenType::Term => { Some(Term::Constant(_, Constant::Atom(atom, spec))) => Some((atom, spec)),
match self.terms.pop() {
Some(Term::Constant(_, Constant::Atom(atom, spec))) =>
Some((atom, spec)),
Some(term) => { Some(term) => {
self.terms.push(term); self.terms.push(term);
None None
}
_ => 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(arg2) = self.terms.pop() {
if let Some((name, shared_op_desc)) = self.get_term_name(td) { if let Some((name, shared_op_desc)) = self.get_term_name(td) {
if let Some(arg1) = self.terms.pop() { if let Some(arg1) = self.terms.pop() {
let term = Term::Clause(Cell::default(), let term = Term::Clause(
Cell::default(),
name, name,
vec![Box::new(arg1), Box::new(arg2)], vec![Box::new(arg1), Box::new(arg2)],
shared_op_desc); shared_op_desc,
);
self.terms.push(term); self.terms.push(term);
self.stack.push(TokenDesc { tt: TokenType::Term, self.stack.push(TokenDesc {
tt: TokenType::Term,
priority: td.priority, priority: td.priority,
spec }); 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 arg1) = self.terms.pop() {
if let Some(mut name) = self.terms.pop() { if let Some(mut name) = self.terms.pop() {
if is_postfix!(assoc) { if is_postfix!(assoc) {
@@ -306,32 +297,41 @@ impl<'a, R: Read> Parser<'a, R> {
} }
if let Term::Constant(_, Constant::Atom(name, shared_op_desc)) = name { if let Term::Constant(_, Constant::Atom(name, shared_op_desc)) = name {
let term = Term::Clause(Cell::default(), name, vec![Box::new(arg1)], let term =
shared_op_desc); Term::Clause(Cell::default(), name, vec![Box::new(arg1)], shared_op_desc);
self.terms.push(term); self.terms.push(term);
self.stack.push(TokenDesc { tt: TokenType::Term, self.stack.push(TokenDesc {
tt: TokenType::Term,
priority: td.priority, priority: td.priority,
spec }); spec,
});
} }
} }
} }
} }
fn promote_atom_op(&mut self, atom: ClauseName, priority: usize, assoc: u32, fn promote_atom_op(
op_dir_val: Option<OpDirValue>) &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()); 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.terms
self.stack.push(TokenDesc { tt: TokenType::Term, priority, spec: assoc }); .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 { let tt = match token {
Token::Constant(Constant::String(s)) Token::Constant(Constant::String(s)) if self.lexer.flags.double_quotes.is_codes() => {
if self.lexer.flags.double_quotes.is_codes() => {
let mut list = Term::Constant(Cell::default(), Constant::EmptyList); let mut list = Term::Constant(Cell::default(), Constant::EmptyList);
for c in s.chars().rev() { for c in s.chars().rev() {
@@ -351,7 +351,7 @@ impl<'a, R: Read> Parser<'a, R> {
Token::Constant(c) => { Token::Constant(c) => {
self.terms.push(Term::Constant(Cell::default(), c)); self.terms.push(Term::Constant(Cell::default(), c));
TokenType::Term TokenType::Term
}, }
Token::Var(v) => { Token::Var(v) => {
if v.trim() == "_" { if v.trim() == "_" {
self.terms.push(Term::AnonVar); self.terms.push(Term::AnonVar);
@@ -360,7 +360,7 @@ impl<'a, R: Read> Parser<'a, R> {
} }
TokenType::Term TokenType::Term
}, }
Token::Comma => TokenType::Comma, Token::Comma => TokenType::Comma,
Token::Open => TokenType::Open, Token::Open => TokenType::Open,
Token::Close => TokenType::Close, 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(desc1) = self.stack.pop() {
if let Some(desc2) = self.stack.pop() { if let Some(desc2) = self.stack.pop() {
if let Some(desc3) = 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); self.push_binary_op(desc2, LTERM);
continue; 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); self.push_binary_op(desc2, LTERM);
continue; 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); self.push_binary_op(desc2, TERM);
continue; continue;
} else { } else {
@@ -425,12 +420,12 @@ impl<'a, R: Read> Parser<'a, R> {
} }
} }
fn compute_arity_in_brackets(&self) -> Option<usize> fn compute_arity_in_brackets(&self) -> Option<usize> {
{
let mut arity = 0; let mut arity = 0;
for (i, desc) in self.stack.iter().rev().enumerate() { 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 { if let TokenType::Comma = desc.tt {
return None; return None;
} else if is_term!(desc.spec) || is_op!(desc.spec) || is_negate!(desc.spec) { } 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 None
} }
fn reduce_term(&mut self, op_dir: CompositeOp) -> bool fn reduce_term(&mut self, op_dir: &CompositeOpDir) -> bool {
{
if self.stack.is_empty() { if self.stack.is_empty() {
return false; return false;
} }
@@ -464,7 +458,7 @@ impl<'a, R: Read> Parser<'a, R> {
let arity = match self.compute_arity_in_brackets() { let arity = match self.compute_arity_in_brackets() {
Some(arity) => arity, Some(arity) => arity,
None => return false None => return false,
}; };
if self.stack.len() > 2 * arity { if self.stack.len() > 2 * arity {
@@ -475,10 +469,6 @@ impl<'a, R: Read> Parser<'a, R> {
return false; return false;
} }
} }
if arity >= 2 && is_prefix!(self.stack[idx].spec) && self.stack[idx].priority > 0 {
return false;
}
} else { } else {
return false; return false;
} }
@@ -490,9 +480,7 @@ impl<'a, R: Read> Parser<'a, R> {
if self.atomize_term(&self.terms[idx - 1]).is_some() { if self.atomize_term(&self.terms[idx - 1]).is_some() {
self.stack.truncate(stack_len + 1); self.stack.truncate(stack_len + 1);
let mut subterms: Vec<_> = self.terms.drain(idx ..) let mut subterms: Vec<_> = self.terms.drain(idx..).map(Box::new).collect();
.map(|t| Box::new(t))
.collect();
if let Some(name) = self.terms.pop().and_then(|t| self.atomize_term(&t)) { if let Some(name) = self.terms.pop().and_then(|t| self.atomize_term(&t)) {
// reduce the '.' functor to a cons cell if it applies. // 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)); self.terms.push(Term::Cons(Cell::default(), head, tail));
} else { } else {
let spec = get_clause_spec(name.clone(), subterms.len(), op_dir); 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, if let Some(&mut TokenDesc {
ref mut tt }) = self.stack.last_mut() ref mut priority,
ref mut spec,
ref mut tt,
}) = self.stack.last_mut()
{ {
*tt = TokenType::Term; *tt = TokenType::Term;
*priority = 0; *priority = 0;
@@ -531,8 +523,7 @@ impl<'a, R: Read> Parser<'a, R> {
self.stack.clear() 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() { if let Some(term) = self.terms.pop() {
let op_desc = self.stack[index - 1]; let op_desc = self.stack[index - 1];
@@ -548,8 +539,7 @@ impl<'a, R: Read> Parser<'a, R> {
self.terms.extend(terms.into_iter()); self.terms.extend(terms.into_iter());
return arity; return arity;
} }
_ => { _ => {}
}
} }
} }
@@ -559,12 +549,12 @@ impl<'a, R: Read> Parser<'a, R> {
0 0
} }
fn compute_arity_in_list(&self) -> Option<usize> fn compute_arity_in_list(&self) -> Option<usize> {
{
let mut arity = 0; let mut arity = 0;
for (i, desc) in self.stack.iter().rev().enumerate() { 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 { if let TokenType::Comma = desc.tt {
return None; return None;
} else if is_term!(desc.spec) || is_op!(desc.spec) { } else if is_term!(desc.spec) || is_op!(desc.spec) {
@@ -590,8 +580,7 @@ impl<'a, R: Read> Parser<'a, R> {
None None
} }
fn reduce_list(&mut self) -> Result<bool, ParserError> fn reduce_list(&mut self) -> Result<bool, ParserError> {
{
if self.stack.is_empty() { if self.stack.is_empty() {
return Ok(false); return Ok(false);
} }
@@ -602,7 +591,8 @@ impl<'a, R: Read> Parser<'a, R> {
td.tt = TokenType::Term; td.tt = TokenType::Term;
td.priority = 0; td.priority = 0;
self.terms.push(Term::Constant(Cell::default(), Constant::EmptyList)); self.terms
.push(Term::Constant(Cell::default(), Constant::EmptyList));
return Ok(true); return Ok(true);
} }
} }
@@ -611,7 +601,7 @@ impl<'a, R: Read> Parser<'a, R> {
let mut arity = match self.compute_arity_in_list() { let mut arity = match self.compute_arity_in_list() {
Some(arity) => arity, Some(arity) => arity,
None => return Ok(false) None => return Ok(false),
}; };
// we know that self.stack.len() >= 2 by this point. // we know that self.stack.len() >= 2 by this point.
@@ -621,11 +611,14 @@ impl<'a, R: Read> Parser<'a, R> {
let end_term = if self.stack[idx].tt != TokenType::HeadTailSeparator { let end_term = if self.stack[idx].tt != TokenType::HeadTailSeparator {
Term::Constant(Cell::default(), Constant::EmptyList) Term::Constant(Cell::default(), Constant::EmptyList)
} else { } else {
let term = let term = match self.terms.pop() {
match self.terms.pop() {
Some(term) => term, 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,
))
}
}; };
if self.stack[idx].priority > 1000 { if self.stack[idx].priority > 1000 {
@@ -639,15 +632,17 @@ impl<'a, R: Read> Parser<'a, R> {
let idx = self.terms.len() - arity; let idx = self.terms.len() - arity;
let list = self.terms.drain(idx ..) let list = self.terms.drain(idx..).rev().fold(end_term, |acc, t| {
.rev() Term::Cons(Cell::default(), Box::new(t), Box::new(acc))
.fold(end_term, |acc, t| Term::Cons(Cell::default(), });
Box::new(t),
Box::new(acc)));
self.stack.truncate(list_len); 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); self.terms.push(list);
Ok(true) Ok(true)
@@ -664,8 +659,7 @@ impl<'a, R: Read> Parser<'a, R> {
td.priority = 0; td.priority = 0;
td.spec = TERM; td.spec = TERM;
let term = Term::Constant(Cell::default(), let term = Term::Constant(Cell::default(), atom!("{}", self.lexer.atom_tbl));
atom!("{}", self.lexer.atom_tbl));
self.terms.push(term); self.terms.push(term);
return Ok(true); return Ok(true);
} }
@@ -687,12 +681,20 @@ impl<'a, R: Read> Parser<'a, R> {
let term = match self.terms.pop() { let term = match self.terms.pop() {
Some(term) => term, 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!("{}"), self.terms.push(Term::Clause(
vec![Box::new(term)], None)); Cell::default(),
clause_name!("{}"),
vec![Box::new(term)],
None,
));
return Ok(true); return Ok(true);
} }
@@ -716,8 +718,7 @@ impl<'a, R: Read> Parser<'a, R> {
let idx = self.stack.len() - 2; let idx = self.stack.len() - 2;
match self.stack.remove(idx) { let td = self.stack.remove(idx);
td =>
match td.tt { match td.tt {
TokenType::Open | TokenType::OpenCT => { TokenType::Open | TokenType::OpenCT => {
if self.stack[idx].tt == TokenType::Comma { if self.stack[idx].tt == TokenType::Comma {
@@ -725,26 +726,32 @@ impl<'a, R: Read> Parser<'a, R> {
} }
if let Some(atom) = sep_to_atom(self.stack[idx].tt) { if let Some(atom) = sep_to_atom(self.stack[idx].tt) {
self.terms.push(Term::Constant(Cell::default(), Constant::Atom(atom, None))); self.terms
.push(Term::Constant(Cell::default(), Constant::Atom(atom, None)));
} }
self.stack[idx].spec = TERM; self.stack[idx].spec = TERM;
self.stack[idx].tt = TokenType::Term; self.stack[idx].tt = TokenType::Term;
self.stack[idx].priority = 0; self.stack[idx].priority = 0;
true true
},
_ => false
} }
_ => false,
} }
} }
fn shift_op(&mut self, name: ClauseName, op_dir: CompositeOp) -> Result<bool, ParserError> { fn shift_op(&mut self, name: ClauseName, op_dir: &CompositeOpDir) -> Result<bool, ParserError> {
if let Some(OpDesc { pre, inf, post, spec }) = get_desc(name.clone(), op_dir) { if let Some(OpDesc {
pre,
inf,
post,
spec,
}) = get_op_desc(name.clone(), op_dir)
{
if (pre > 0 && inf + post > 0) || is_negate!(spec) { if (pre > 0 && inf + post > 0) || is_negate!(spec) {
match self.tokens.last().ok_or(ParserError::UnexpectedEOF)? { match self.tokens.last().ok_or(ParserError::UnexpectedEOF)? {
// do this when layout hasn't been inserted, // do this when layout hasn't been inserted,
// ie. why we don't match on Token::Open. // ie. why we don't match on Token::Open.
&Token::OpenCT => { Token::OpenCT => {
// can't be prefix, so either inf == 0 // can't be prefix, so either inf == 0
// or post == 0. // or post == 0.
self.reduce_op(inf + post); 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 fixity = if inf > 0 { Fixity::In } else { Fixity::Post };
let op_dir_val = op_dir.get(name.clone(), fixity); let op_dir_val = op_dir.get(name.clone(), fixity);
self.promote_atom_op(name, inf + post, spec & (XFX | XFY | YFX | YF | XF), self.promote_atom_op(
op_dir_val); name,
}, inf + post,
spec & (XFX | XFY | YFX | YF | XF),
op_dir_val,
);
}
_ => { _ => {
self.reduce_op(inf + post); 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 fixity = if inf > 0 { Fixity::In } else { Fixity::Post };
let op_dir_val = op_dir.get(name.clone(), fixity); let op_dir_val = op_dir.get(name.clone(), fixity);
self.promote_atom_op(name, inf + post, self.promote_atom_op(
name,
inf + post,
spec & (XFX | XFY | YFX | XF | YF), spec & (XFX | XFY | YFX | XF | YF),
op_dir_val); op_dir_val,
);
} else { } else {
let op_dir_val = op_dir.get(name.clone(), Fixity::Pre); 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 { } else {
let op_dir_val = op_dir.get(name.clone(), Fixity::Pre); 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 { } else {
let op_dir_val = op_dir.get(name.clone(), let op_dir_val = op_dir.get(
name.clone(),
if pre + inf == 0 { if pre + inf == 0 {
Fixity::Post Fixity::Post
} else if post + pre == 0 { } else if post + pre == 0 {
Fixity::In Fixity::In
} else { } else {
Fixity::Pre Fixity::Pre
}); },
);
self.reduce_op(pre + inf + post); // only one non-zero priority among these. 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); self.promote_atom_op(name, pre + inf + post, spec, op_dir_val);
} }
Ok(true) Ok(true)
} else { // not an operator. } else {
// not an operator.
Ok(false) Ok(false)
} }
} }
fn atomize_term(&self, term: &Term) -> Option<ClauseName> { fn atomize_term(&self, term: &Term) -> Option<ClauseName> {
match term { match term {
&Term::Constant(_, ref c) => self.atomize_constant(c), Term::Constant(_, ref c) => self.atomize_constant(c),
_ => None _ => None,
} }
} }
fn atomize_constant(&self, c: &Constant) -> Option<ClauseName> { fn atomize_constant(&self, c: &Constant) -> Option<ClauseName> {
match c { match c {
&Constant::Atom(ref name, _) => Some(name.clone()), Constant::Atom(ref name, _) => Some(name.clone()),
&Constant::Char(c) => Constant::Char(c) => Some(clause_name!(c.to_string(), self.lexer.atom_tbl)),
Some(clause_name!(c.to_string(), self.lexer.atom_tbl)), Constant::EmptyList => Some(clause_name!(c.to_string(), self.lexer.atom_tbl)),
&Constant::EmptyList => _ => None,
Some(clause_name!(c.to_string(), self.lexer.atom_tbl)),
_ => None
} }
} }
fn negate_number<N, Negator, ToConstant>( fn negate_number<N, Negator, ToConstant>(&mut self, n: N, negator: Negator, constr: ToConstant)
&mut self, where
n: N, Negator: Fn(N) -> N,
negator: Negator, ToConstant: Fn(N) -> Constant,
constr: ToConstant
)
where Negator: Fn(N) -> N,
ToConstant: Fn(N) -> Constant
{ {
if let Some(desc) = self.stack.last().cloned() { if let Some(desc) = self.stack.last().cloned() {
if let Some(term) = self.terms.last().cloned() { if let Some(term) = self.terms.last().cloned() {
match term { match term {
Term::Constant(_, Constant::Atom(ref name, _)) Term::Constant(_, Constant::Atom(ref name, _))
if name.as_str() == "-" && (is_prefix!(desc.spec) || is_negate!(desc.spec)) => { if name.as_str() == "-"
&& (is_prefix!(desc.spec) || is_negate!(desc.spec)) =>
{
self.stack.pop(); self.stack.pop();
self.terms.pop(); self.terms.pop();
self.shift(Token::Constant(constr(negator(n))), 0, TERM); self.shift(Token::Constant(constr(negator(n))), 0, TERM);
return; return;
}, }
_ => {} _ => {}
} }
} }
@@ -843,44 +866,39 @@ impl<'a, R: Read> Parser<'a, R> {
self.shift(Token::Constant(constr(n)), 0, TERM); 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<T: NegAssign>(mut t: Rc<T>) -> Rc<T> { fn negate_rc<T: NegAssign>(mut t: Rc<T>) -> Rc<T> {
match Rc::get_mut(&mut t) { if let Some(t) = Rc::get_mut(&mut t) {
Some(t) => {
t.neg_assign(); t.neg_assign();
}
None => {
}
}; };
t t
} }
match token { match token {
Token::Constant(Constant::Fixnum(n)) => Token::Constant(Constant::Fixnum(n)) => self.negate_number(n, |n| -n, Constant::Fixnum),
self.negate_number(n, |n| -n, Constant::Fixnum), Token::Constant(Constant::Integer(n)) => {
Token::Constant(Constant::Integer(n)) => self.negate_number(n, negate_rc, Constant::Integer)
self.negate_number(n, negate_rc, Constant::Integer), }
Token::Constant(Constant::Rational(n)) => Token::Constant(Constant::Rational(n)) => {
self.negate_number(n, negate_rc, Constant::Rational), self.negate_number(n, negate_rc, Constant::Rational)
Token::Constant(Constant::Float(n)) => }
self.negate_number( Token::Constant(Constant::Float(n)) => {
n, self.negate_number(n, |n| OrderedFloat(-n.into_inner()), Constant::Float)
|n| OrderedFloat(-n.into_inner()), }
|n| Constant::Float(n) Token::Constant(c) => {
),
Token::Constant(c) =>
if let Some(name) = self.atomize_constant(&c) { if let Some(name) = self.atomize_constant(&c) {
if !self.shift_op(name, op_dir)? { if !self.shift_op(name, op_dir)? {
self.shift(Token::Constant(c), 0, TERM); self.shift(Token::Constant(c), 0, TERM);
} }
} else { } else {
self.shift(Token::Constant(c), 0, TERM); self.shift(Token::Constant(c), 0, TERM);
}, }
}
Token::Var(v) => self.shift(Token::Var(v), 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::OpenCT => self.shift(Token::OpenCT, 1300, DELIMITER),
Token::Close => Token::Close => {
if !self.reduce_term(op_dir) { if !self.reduce_term(op_dir) {
if !self.reduce_brackets() { if !self.reduce_brackets() {
return Err(ParserError::IncompleteReduction( return Err(ParserError::IncompleteReduction(
@@ -888,50 +906,55 @@ impl<'a, R: Read> Parser<'a, R> {
self.lexer.col_num, self.lexer.col_num,
)); ));
} }
}, }
}
Token::OpenList => self.shift(Token::OpenList, 1300, DELIMITER), Token::OpenList => self.shift(Token::OpenList, 1300, DELIMITER),
Token::CloseList => Token::CloseList => {
if !self.reduce_list()? { if !self.reduce_list()? {
return Err(ParserError::IncompleteReduction( return Err(ParserError::IncompleteReduction(
self.lexer.line_num, self.lexer.line_num,
self.lexer.col_num, self.lexer.col_num,
)); ));
}, }
}
Token::OpenCurly => self.shift(Token::OpenCurly, 1300, DELIMITER), Token::OpenCurly => self.shift(Token::OpenCurly, 1300, DELIMITER),
Token::CloseCurly => Token::CloseCurly => {
if !self.reduce_curly()? { if !self.reduce_curly()? {
return Err(ParserError::IncompleteReduction( return Err(ParserError::IncompleteReduction(
self.lexer.line_num, self.lexer.line_num,
self.lexer.col_num, self.lexer.col_num,
)); ));
}, }
}
Token::HeadTailSeparator => { Token::HeadTailSeparator => {
/* '|' as an operator must have priority > 1000 and can only be infix. /* '|' 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 * 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)) .map(|OpDesc { inf, spec, .. }| (inf, spec))
.unwrap_or((1000, DELIMITER)); .unwrap_or((1000, DELIMITER));
self.reduce_op(priority); self.reduce_op(priority);
self.shift(Token::HeadTailSeparator, priority, spec); self.shift(Token::HeadTailSeparator, priority, spec);
}, }
Token::Comma => { Token::Comma => {
self.reduce_op(1000); self.reduce_op(1000);
self.shift(Token::Comma, 1000, XFY); self.shift(Token::Comma, 1000, XFY);
}, }
Token::End => Token::End => match self.stack.last().map(|t| t.tt) {
match self.stack.last().map(|t| t.tt) {
Some(TokenType::Open) Some(TokenType::Open)
| Some(TokenType::OpenCT) | Some(TokenType::OpenCT)
| Some(TokenType::OpenList) | Some(TokenType::OpenList)
| Some(TokenType::OpenCurly) | Some(TokenType::OpenCurly)
| Some(TokenType::HeadTailSeparator) | Some(TokenType::HeadTailSeparator)
| Some(TokenType::Comma) | Some(TokenType::Comma) => {
=> return Err(ParserError::IncompleteReduction(self.lexer.line_num, return Err(ParserError::IncompleteReduction(
self.lexer.col_num)), self.lexer.line_num,
_ => {} self.lexer.col_num,
))
} }
_ => {}
},
} }
Ok(()) Ok(())
@@ -942,8 +965,18 @@ impl<'a, R: Read> Parser<'a, R> {
self.lexer.eof() self.lexer.eof()
} }
pub fn read_term(&mut self, op_dir: CompositeOp) -> Result<Term, ParserError> #[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<Term, ParserError> {
self.tokens = read_tokens(&mut self.lexer)?; self.tokens = read_tokens(&mut self.lexer)?;
while let Some(token) = self.tokens.pop() { while let Some(token) = self.tokens.pop() {
@@ -953,31 +986,27 @@ impl<'a, R: Read> Parser<'a, R> {
self.reduce_op(1400); self.reduce_op(1400);
if self.terms.len() > 1 || self.stack.len() > 1 { 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() { match self.terms.pop() {
Some(term) => if self.terms.is_empty() { Some(term) => {
if self.terms.is_empty() {
Ok(term) Ok(term)
} else { } else {
Err(ParserError::IncompleteReduction(self.lexer.line_num, self.lexer.col_num)) Err(ParserError::IncompleteReduction(
}, self.lexer.line_num,
_ => Err(ParserError::IncompleteReduction(self.lexer.line_num, self.lexer.col_num)) self.lexer.col_num,
))
} }
} }
_ => Err(ParserError::IncompleteReduction(
pub fn read(&mut self, op_dir: CompositeOp) -> Result<Vec<Term>, ParserError> self.lexer.line_num,
{ self.lexer.col_num,
let mut terms = Vec::new(); )),
loop {
terms.push(self.read_term(op_dir)?);
if self.lexer.eof()? {
break;
} }
} }
Ok(terms)
}
} }

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,18 @@
use crate::prolog_parser::ast::*; use prolog_parser::ast::*;
use prolog_parser::clause_name;
use crate::clause_types::*; use crate::clause_types::*;
use crate::forms::*; use crate::forms::*;
use crate::indexing::IndexingCodePtr;
use crate::machine::heap::*; use crate::machine::heap::*;
use crate::machine::machine_errors::MachineStub; use crate::machine::machine_errors::MachineStub;
use crate::machine::machine_indices::*; use crate::machine::machine_indices::*;
use crate::rug::Integer; use crate::rug::Integer;
use crate::indexmap::IndexMap; use indexmap::IndexMap;
use slice_deque::SliceDeque;
use std::collections::VecDeque;
use std::rc::Rc; use std::rc::Rc;
fn reg_type_into_functor(r: RegType) -> MachineStub { fn reg_type_into_functor(r: RegType) -> MachineStub {
@@ -32,9 +35,7 @@ impl Level {
impl ArithmeticTerm { impl ArithmeticTerm {
fn into_functor(&self) -> MachineStub { fn into_functor(&self) -> MachineStub {
match self { match self {
&ArithmeticTerm::Reg(r) => { &ArithmeticTerm::Reg(r) => reg_type_into_functor(r),
reg_type_into_functor(r)
}
&ArithmeticTerm::Interm(i) => { &ArithmeticTerm::Interm(i) => {
functor!("intermediate", [integer(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)] #[derive(Debug)]
pub enum ChoiceInstruction { pub(crate) enum ChoiceInstruction {
DynamicElse(usize, Death, NextOrFail),
DynamicInternalElse(usize, Death, NextOrFail),
DefaultRetryMeElse(usize), DefaultRetryMeElse(usize),
DefaultTrustMe, DefaultTrustMe(usize),
RetryMeElse(usize), RetryMeElse(usize),
TrustMe, TrustMe(usize),
TryMeElse(usize), TryMeElse(usize),
} }
impl ChoiceInstruction { impl ChoiceInstruction {
pub fn to_functor(&self) -> MachineStub { pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
match self { 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) => { &ChoiceInstruction::TryMeElse(offset) => {
functor!("try_me_else", [integer(offset)]) functor!("try_me_else", [integer(offset)])
} }
&ChoiceInstruction::RetryMeElse(offset) => { &ChoiceInstruction::RetryMeElse(offset) => {
functor!("retry_me_else", [integer(offset)]) functor!("retry_me_else", [integer(offset)])
} }
&ChoiceInstruction::TrustMe => { &ChoiceInstruction::TrustMe(offset) => {
functor!("trust_me") functor!("trust_me", [integer(offset)])
} }
&ChoiceInstruction::DefaultRetryMeElse(offset) => { &ChoiceInstruction::DefaultRetryMeElse(offset) => {
functor!("default_retry_me_else", [integer(offset)]) functor!("default_retry_me_else", [integer(offset)])
} }
&ChoiceInstruction::DefaultTrustMe => { &ChoiceInstruction::DefaultTrustMe(offset) => {
functor!("default_trust_me") functor!("default_trust_me", [integer(offset)])
} }
} }
} }
} }
#[derive(Debug)] #[derive(Debug)]
pub enum CutInstruction { pub(crate) enum CutInstruction {
Cut(RegType), Cut(RegType),
GetLevel(RegType), GetLevel(RegType),
GetLevelAndUnify(RegType), GetLevelAndUnify(RegType),
@@ -85,7 +179,7 @@ pub enum CutInstruction {
} }
impl CutInstruction { impl CutInstruction {
pub fn to_functor(&self, h: usize) -> MachineStub { pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
match self { match self {
&CutInstruction::Cut(r) => { &CutInstruction::Cut(r) => {
let rt_stub = reg_type_into_functor(r); let rt_stub = reg_type_into_functor(r);
@@ -106,21 +200,15 @@ impl CutInstruction {
} }
} }
#[derive(Debug)] #[derive(Clone, Copy, Debug)]
pub enum IndexedChoiceInstruction { pub(crate) enum IndexedChoiceInstruction {
Retry(usize), Retry(usize),
Trust(usize), Trust(usize),
Try(usize), Try(usize),
} }
impl From<IndexedChoiceInstruction> for Line {
fn from(i: IndexedChoiceInstruction) -> Self {
Line::IndexedChoice(i)
}
}
impl IndexedChoiceInstruction { impl IndexedChoiceInstruction {
pub fn offset(&self) -> usize { pub(crate) fn offset(&self) -> usize {
match self { match self {
&IndexedChoiceInstruction::Retry(offset) => offset, &IndexedChoiceInstruction::Retry(offset) => offset,
&IndexedChoiceInstruction::Trust(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 { match self {
&IndexedChoiceInstruction::Try(offset) => { &IndexedChoiceInstruction::Try(offset) => {
functor!("try", [integer(offset)]) functor!("try", [integer(offset)])
@@ -145,43 +233,110 @@ impl IndexedChoiceInstruction {
/// A `Line` is an instruction (cf. page 98 of wambook). /// A `Line` is an instruction (cf. page 98 of wambook).
#[derive(Debug)] #[derive(Debug)]
pub enum Line { pub(crate) enum IndexingLine {
Indexing(IndexingInstruction),
IndexedChoice(SliceDeque<IndexedChoiceInstruction>),
DynamicIndexedChoice(SliceDeque<usize>),
}
impl From<IndexingInstruction> for IndexingLine {
#[inline]
fn from(instr: IndexingInstruction) -> Self {
IndexingLine::Indexing(instr)
}
}
impl From<SliceDeque<IndexedChoiceInstruction>> for IndexingLine {
#[inline]
fn from(instrs: SliceDeque<IndexedChoiceInstruction>) -> Self {
IndexingLine::IndexedChoice(instrs)
}
}
#[derive(Debug)]
pub(crate) enum Line {
Arithmetic(ArithmeticInstruction), Arithmetic(ArithmeticInstruction),
Choice(ChoiceInstruction), Choice(ChoiceInstruction),
Control(ControlInstruction), Control(ControlInstruction),
Cut(CutInstruction), Cut(CutInstruction),
Fact(FactInstruction), Fact(FactInstruction),
Indexing(IndexingInstruction), IndexingCode(Vec<IndexingLine>),
IndexedChoice(IndexedChoiceInstruction), IndexedChoice(IndexedChoiceInstruction),
DynamicIndexedChoice(usize),
Query(QueryInstruction), Query(QueryInstruction),
} }
impl Line { impl Line {
pub fn is_head_instr(&self) -> bool { #[inline]
pub(crate) fn is_head_instr(&self) -> bool {
match self { match self {
&Line::Cut(_) => true,
&Line::Fact(_) => true, &Line::Fact(_) => true,
&Line::Query(_) => true, &Line::Query(_) => true,
_ => false, _ => false,
} }
} }
pub fn to_functor(&self, h: usize) -> MachineStub { pub(crate) fn enqueue_functors(&self, mut h: usize, functors: &mut Vec<MachineStub>) {
match self { match self {
&Line::Arithmetic(ref arith_instr) => arith_instr.to_functor(h), &Line::Arithmetic(ref arith_instr) => functors.push(arith_instr.to_functor(h)),
&Line::Choice(ref choice_instr) => choice_instr.to_functor(), &Line::Choice(ref choice_instr) => functors.push(choice_instr.to_functor(h)),
&Line::Control(ref control_instr) => control_instr.to_functor(), &Line::Control(ref control_instr) => functors.push(control_instr.to_functor()),
&Line::Cut(ref cut_instr) => cut_instr.to_functor(h), &Line::Cut(ref cut_instr) => functors.push(cut_instr.to_functor(h)),
&Line::Fact(ref fact_instr) => fact_instr.to_functor(h), &Line::Fact(ref fact_instr) => functors.push(fact_instr.to_functor(h)),
&Line::Indexing(ref indexing_instr) => indexing_instr.to_functor(), &Line::IndexingCode(ref indexing_instrs) => {
&Line::IndexedChoice(ref indexed_choice_instr) => indexed_choice_instr.to_functor(), for indexing_instr in indexing_instrs {
&Line::Query(ref query_instr) => query_instr.to_functor(h), match indexing_instr {
IndexingLine::Indexing(indexing_instr) => {
let section = indexing_instr.to_functor(h);
h += section.len();
functors.push(section);
}
IndexingLine::IndexedChoice(indexed_choice_instrs) => {
for indexed_choice_instr in indexed_choice_instrs {
let section = indexed_choice_instr.to_functor();
h += section.len();
functors.push(section);
}
}
IndexingLine::DynamicIndexedChoice(indexed_choice_instrs) => {
for indexed_choice_instr in indexed_choice_instrs {
let section = functor!("dynamic", [integer(*indexed_choice_instr)]);
h += section.len();
functors.push(section);
}
}
}
}
}
&Line::IndexedChoice(ref indexed_choice_instr) => {
functors.push(indexed_choice_instr.to_functor())
}
&Line::DynamicIndexedChoice(ref indexed_choice_instr) => {
functors.push(functor!("dynamic", [integer(*indexed_choice_instr)]));
}
&Line::Query(ref query_instr) => functors.push(query_instr.to_functor(h)),
} }
} }
} }
#[inline]
pub(crate) fn to_indexing_line_mut(line: &mut Line) -> Option<&mut Vec<IndexingLine>> {
match line {
Line::IndexingCode(ref mut indexing_code) => Some(indexing_code),
_ => None,
}
}
#[inline]
pub(crate) fn to_indexing_line(line: &Line) -> Option<&Vec<IndexingLine>> {
match line {
Line::IndexingCode(ref indexing_code) => Some(indexing_code),
_ => None,
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ArithmeticInstruction { pub(crate) enum ArithmeticInstruction {
Add(ArithmeticTerm, ArithmeticTerm, usize), Add(ArithmeticTerm, ArithmeticTerm, usize),
Sub(ArithmeticTerm, ArithmeticTerm, usize), Sub(ArithmeticTerm, ArithmeticTerm, usize),
Mul(ArithmeticTerm, ArithmeticTerm, usize), Mul(ArithmeticTerm, ArithmeticTerm, usize),
@@ -231,11 +386,7 @@ fn arith_instr_unary_functor(
) -> MachineStub { ) -> MachineStub {
let at_stub = at.into_functor(); let at_stub = at.into_functor();
functor!( functor!(name, [aux(h, 0), integer(t)], [at_stub])
name,
[aux(h, 0), integer(t)],
[at_stub]
)
} }
fn arith_instr_bin_functor( fn arith_instr_bin_functor(
@@ -256,7 +407,7 @@ fn arith_instr_bin_functor(
} }
impl ArithmeticInstruction { impl ArithmeticInstruction {
pub fn to_functor(&self, h: usize) -> MachineStub { pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
match self { match self {
&ArithmeticInstruction::Add(ref at_1, ref at_2, t) => { &ArithmeticInstruction::Add(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "add", at_1, 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) => { &ArithmeticInstruction::Gcd(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "gcd", at_1, at_2, t) arith_instr_bin_functor(h, "gcd", at_1, at_2, t)
} }
&ArithmeticInstruction::Sign(ref at, t) => { &ArithmeticInstruction::Sign(ref at, t) => arith_instr_unary_functor(h, "sign", 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::Cos(ref at, t) => { &ArithmeticInstruction::Tan(ref at, t) => arith_instr_unary_functor(h, "tan", at, t),
arith_instr_unary_functor(h, "cos", 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::Sin(ref at, t) => { &ArithmeticInstruction::ACos(ref at, t) => arith_instr_unary_functor(h, "acos", at, t),
arith_instr_unary_functor(h, "sin", 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::Tan(ref at, t) => { &ArithmeticInstruction::Sqrt(ref at, t) => arith_instr_unary_functor(h, "sqrt", at, t),
arith_instr_unary_functor(h, "tan", at, t) &ArithmeticInstruction::Abs(ref at, t) => arith_instr_unary_functor(h, "abs", 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) => { &ArithmeticInstruction::Float(ref at, t) => {
arith_instr_unary_functor(h, "float", at, t) arith_instr_unary_functor(h, "float", at, t)
} }
@@ -366,12 +495,8 @@ impl ArithmeticInstruction {
&ArithmeticInstruction::Floor(ref at, t) => { &ArithmeticInstruction::Floor(ref at, t) => {
arith_instr_unary_functor(h, "floor", at, t) arith_instr_unary_functor(h, "floor", at, t)
} }
&ArithmeticInstruction::Neg(ref at, t) => { &ArithmeticInstruction::Neg(ref at, t) => arith_instr_unary_functor(h, "-", at, t),
arith_instr_unary_functor(h, "-", at, t) &ArithmeticInstruction::Plus(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) => { &ArithmeticInstruction::BitwiseComplement(ref at, t) => {
arith_instr_unary_functor(h, "\\", at, t) arith_instr_unary_functor(h, "\\", at, t)
} }
@@ -380,28 +505,28 @@ impl ArithmeticInstruction {
} }
#[derive(Debug)] #[derive(Debug)]
pub enum ControlInstruction { pub(crate) enum ControlInstruction {
Allocate(usize), // num_frames. Allocate(usize), // num_frames.
// name, arity, perm_vars after threshold, last call, use default call policy. // name, arity, perm_vars after threshold, last call, use default call policy.
CallClause(ClauseType, usize, usize, bool, bool), CallClause(ClauseType, usize, usize, bool, bool),
Deallocate, Deallocate,
JmpBy(usize, usize, usize, bool), // arity, global_offset, perm_vars after threshold, last call. 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, Proceed,
} }
impl ControlInstruction { impl ControlInstruction {
pub fn perm_vars(&self) -> Option<usize> { pub(crate) fn perm_vars(&self) -> Option<usize> {
match self { match self {
ControlInstruction::CallClause(_, _, num_cells, ..) => ControlInstruction::CallClause(_, _, num_cells, ..) => Some(*num_cells),
Some(*num_cells), ControlInstruction::JmpBy(_, _, num_cells, ..) => Some(*num_cells),
ControlInstruction::JmpBy(_, _, num_cells, ..) => _ => None,
Some(*num_cells),
_ =>
None
} }
} }
pub fn to_functor(&self) -> MachineStub { pub(crate) fn to_functor(&self) -> MachineStub {
match self { match self {
&ControlInstruction::Allocate(num_frames) => { &ControlInstruction::Allocate(num_frames) => {
functor!("allocate", [integer(num_frames)]) functor!("allocate", [integer(num_frames)])
@@ -418,6 +543,9 @@ impl ControlInstruction {
&ControlInstruction::JmpBy(_, offset, ..) => { &ControlInstruction::JmpBy(_, offset, ..) => {
functor!("jmp_by", [integer(offset)]) functor!("jmp_by", [integer(offset)])
} }
&ControlInstruction::RevJmpBy(offset) => {
functor!("rev_jmp_by", [integer(offset)])
}
&ControlInstruction::Proceed => { &ControlInstruction::Proceed => {
functor!("proceed") functor!("proceed")
} }
@@ -427,42 +555,101 @@ impl ControlInstruction {
/// `IndexingInstruction` cf. page 110 of wambook. /// `IndexingInstruction` cf. page 110 of wambook.
#[derive(Debug)] #[derive(Debug)]
pub enum IndexingInstruction { pub(crate) enum IndexingInstruction {
// The first index is the optimal argument being indexed. // The first index is the optimal argument being indexed.
SwitchOnTerm(usize, usize, usize, usize, usize), SwitchOnTerm(
SwitchOnConstant(usize, usize, IndexMap<Constant, usize>), usize,
SwitchOnStructure(usize, usize, IndexMap<(ClauseName, usize), usize>), IndexingCodePtr,
} IndexingCodePtr,
IndexingCodePtr,
impl From<IndexingInstruction> for Line { IndexingCodePtr,
fn from(i: IndexingInstruction) -> Self { ),
Line::Indexing(i) SwitchOnConstant(IndexMap<Constant, IndexingCodePtr>),
} SwitchOnStructure(IndexMap<(ClauseName, usize), IndexingCodePtr>),
} }
impl IndexingInstruction { impl IndexingInstruction {
pub fn to_functor(&self) -> MachineStub { pub(crate) fn to_functor(&self, mut h: usize) -> MachineStub {
match self { match self {
&IndexingInstruction::SwitchOnTerm(arg, vars, constants, lists, structures) => { &IndexingInstruction::SwitchOnTerm(arg, vars, constants, lists, structures) => {
functor!( functor!(
"switch_on_term", "switch_on_term",
[integer(arg), [
integer(vars), integer(arg),
integer(constants), indexing_code_ptr(h, vars),
integer(lists), indexing_code_ptr(h, constants),
integer(structures)] 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!( functor!(
"switch_on_constant", "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!( functor!(
"switch_on_structure", "switch_on_structure",
[integer(arg), integer(structures)] [aux(orig_h, 0)],
[key_value_list_stub]
) )
} }
} }
@@ -470,7 +657,7 @@ impl IndexingInstruction {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum FactInstruction { pub(crate) enum FactInstruction {
GetConstant(Level, Constant, RegType), GetConstant(Level, Constant, RegType),
GetList(Level, RegType), GetList(Level, RegType),
GetPartialString(Level, String, RegType, bool), GetPartialString(Level, String, RegType, bool),
@@ -485,7 +672,7 @@ pub enum FactInstruction {
} }
impl FactInstruction { impl FactInstruction {
pub fn to_functor(&self, h: usize) -> MachineStub { pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
match self { match self {
&FactInstruction::GetConstant(lvl, ref c, r) => { &FactInstruction::GetConstant(lvl, ref c, r) => {
let lvl_stub = lvl.into_functor(); let lvl_stub = lvl.into_functor();
@@ -501,11 +688,7 @@ impl FactInstruction {
let lvl_stub = lvl.into_functor(); let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r); let rt_stub = reg_type_into_functor(r);
functor!( functor!("get_list", [aux(h, 0), aux(h, 1)], [lvl_stub, rt_stub])
"get_list",
[aux(h, 0), aux(h, 1)],
[lvl_stub, rt_stub]
)
} }
&FactInstruction::GetPartialString(lvl, ref s, r, has_tail) => { &FactInstruction::GetPartialString(lvl, ref s, r, has_tail) => {
let lvl_stub = lvl.into_functor(); let lvl_stub = lvl.into_functor();
@@ -529,20 +712,12 @@ impl FactInstruction {
&FactInstruction::GetValue(r, arg) => { &FactInstruction::GetValue(r, arg) => {
let rt_stub = reg_type_into_functor(r); let rt_stub = reg_type_into_functor(r);
functor!( functor!("get_value", [aux(h, 0), integer(arg)], [rt_stub])
"get_value",
[aux(h, 0), integer(arg)],
[rt_stub]
)
} }
&FactInstruction::GetVariable(r, arg) => { &FactInstruction::GetVariable(r, arg) => {
let rt_stub = reg_type_into_functor(r); let rt_stub = reg_type_into_functor(r);
functor!( functor!("get_variable", [aux(h, 0), integer(arg)], [rt_stub])
"get_variable",
[aux(h, 0), integer(arg)],
[rt_stub]
)
} }
&FactInstruction::UnifyConstant(ref c) => { &FactInstruction::UnifyConstant(ref c) => {
functor!("unify_constant", [constant(h, c)], []) functor!("unify_constant", [constant(h, c)], [])
@@ -550,29 +725,17 @@ impl FactInstruction {
&FactInstruction::UnifyLocalValue(r) => { &FactInstruction::UnifyLocalValue(r) => {
let rt_stub = reg_type_into_functor(r); let rt_stub = reg_type_into_functor(r);
functor!( functor!("unify_local_value", [aux(h, 0)], [rt_stub])
"unify_local_value",
[aux(h, 0)],
[rt_stub]
)
} }
&FactInstruction::UnifyVariable(r) => { &FactInstruction::UnifyVariable(r) => {
let rt_stub = reg_type_into_functor(r); let rt_stub = reg_type_into_functor(r);
functor!( functor!("unify_variable", [aux(h, 0)], [rt_stub])
"unify_variable",
[aux(h, 0)],
[rt_stub]
)
} }
&FactInstruction::UnifyValue(r) => { &FactInstruction::UnifyValue(r) => {
let rt_stub = reg_type_into_functor(r); let rt_stub = reg_type_into_functor(r);
functor!( functor!("unify_value", [aux(h, 0)], [rt_stub])
"unify_value",
[aux(h, 0)],
[rt_stub]
)
} }
&FactInstruction::UnifyVoid(vars) => { &FactInstruction::UnifyVoid(vars) => {
functor!("unify_void", [integer(vars)]) functor!("unify_void", [integer(vars)])
@@ -582,7 +745,7 @@ impl FactInstruction {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum QueryInstruction { pub(crate) enum QueryInstruction {
GetVariable(RegType, usize), GetVariable(RegType, usize),
PutConstant(Level, Constant, RegType), PutConstant(Level, Constant, RegType),
PutList(Level, RegType), PutList(Level, RegType),
@@ -599,12 +762,11 @@ pub enum QueryInstruction {
} }
impl QueryInstruction { impl QueryInstruction {
pub fn to_functor(&self, h: usize) -> MachineStub { pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
match self { match self {
&QueryInstruction::PutUnsafeValue(norm, arg) => functor!( &QueryInstruction::PutUnsafeValue(norm, arg) => {
"put_unsafe_value", functor!("put_unsafe_value", [integer(norm), integer(arg)])
[integer(norm), integer(arg)] }
),
&QueryInstruction::PutConstant(lvl, ref c, r) => { &QueryInstruction::PutConstant(lvl, ref c, r) => {
let lvl_stub = lvl.into_functor(); let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r); let rt_stub = reg_type_into_functor(r);
@@ -619,11 +781,7 @@ impl QueryInstruction {
let lvl_stub = lvl.into_functor(); let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r); let rt_stub = reg_type_into_functor(r);
functor!( functor!("put_list", [aux(h, 0), aux(h, 1)], [lvl_stub, rt_stub])
"put_list",
[aux(h, 0), aux(h, 1)],
[lvl_stub, rt_stub]
)
} }
&QueryInstruction::PutPartialString(lvl, ref s, r, has_tail) => { &QueryInstruction::PutPartialString(lvl, ref s, r, has_tail) => {
let lvl_stub = lvl.into_functor(); let lvl_stub = lvl.into_functor();
@@ -647,29 +805,17 @@ impl QueryInstruction {
&QueryInstruction::PutValue(r, arg) => { &QueryInstruction::PutValue(r, arg) => {
let rt_stub = reg_type_into_functor(r); let rt_stub = reg_type_into_functor(r);
functor!( functor!("put_value", [aux(h, 0), integer(arg)], [rt_stub])
"put_value",
[aux(h, 0), integer(arg)],
[rt_stub]
)
} }
&QueryInstruction::GetVariable(r, arg) => { &QueryInstruction::GetVariable(r, arg) => {
let rt_stub = reg_type_into_functor(r); let rt_stub = reg_type_into_functor(r);
functor!( functor!("get_variable", [aux(h, 0), integer(arg)], [rt_stub])
"get_variable",
[aux(h, 0), integer(arg)],
[rt_stub]
)
} }
&QueryInstruction::PutVariable(r, arg) => { &QueryInstruction::PutVariable(r, arg) => {
let rt_stub = reg_type_into_functor(r); let rt_stub = reg_type_into_functor(r);
functor!( functor!("put_variable", [aux(h, 0), integer(arg)], [rt_stub])
"put_variable",
[aux(h, 0), integer(arg)],
[rt_stub]
)
} }
&QueryInstruction::SetConstant(ref c) => { &QueryInstruction::SetConstant(ref c) => {
functor!("set_constant", [constant(h, c)], []) functor!("set_constant", [constant(h, c)], [])
@@ -677,29 +823,17 @@ impl QueryInstruction {
&QueryInstruction::SetLocalValue(r) => { &QueryInstruction::SetLocalValue(r) => {
let rt_stub = reg_type_into_functor(r); let rt_stub = reg_type_into_functor(r);
functor!( functor!("set_local_value", [aux(h, 0)], [rt_stub])
"set_local_value",
[aux(h, 0)],
[rt_stub]
)
} }
&QueryInstruction::SetVariable(r) => { &QueryInstruction::SetVariable(r) => {
let rt_stub = reg_type_into_functor(r); let rt_stub = reg_type_into_functor(r);
functor!( functor!("set_variable", [aux(h, 0)], [rt_stub])
"set_variable",
[aux(h, 0)],
[rt_stub]
)
} }
&QueryInstruction::SetValue(r) => { &QueryInstruction::SetValue(r) => {
let rt_stub = reg_type_into_functor(r); let rt_stub = reg_type_into_functor(r);
functor!( functor!("set_value", [aux(h, 0)], [rt_stub])
"set_value",
[aux(h, 0)],
[rt_stub]
)
} }
&QueryInstruction::SetVoid(vars) => { &QueryInstruction::SetVoid(vars) => {
functor!("set_void", [integer(vars)]) functor!("set_void", [integer(vars)])
@@ -708,10 +842,6 @@ impl QueryInstruction {
} }
} }
pub type CompiledFact = Vec<FactInstruction>; pub(crate) type CompiledFact = Vec<FactInstruction>;
pub type ThirdLevelIndex = Vec<IndexedChoiceInstruction>; pub(crate) type Code = Vec<Line>;
pub type Code = Vec<Line>;
pub type CodeDeque = VecDeque<Line>;

View File

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

25
src/lib.rs Normal file
View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -50,7 +50,7 @@ dif(X, Y) :-
gather_dif_goals([]) --> []. gather_dif_goals([]) --> [].
gather_dif_goals([(X \== Y) | Goals]) --> gather_dif_goals([(X \== Y) | Goals]) -->
( { X \= Y } -> [] ( { X \= Y } -> []
; [dif(X, Y)] ; [dif:dif(X, Y)]
), ),
gather_dif_goals(Goals). gather_dif_goals(Goals).

View File

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

View File

@@ -1,5 +1,5 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Written March 2020 by Markus Triska (triska@metalevel.at) Written 2020, 2021 by Markus Triska (triska@metalevel.at)
Part of Scryer Prolog. Part of Scryer Prolog.
This library provides the nonterminal format_//2 to describe 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. 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. From and To denote the positions of surrounding tab stops.
Elements is a list of elements that occur in a cell, 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(Fs, Args, Tab, [glue(Char,_)|Es], VNs).
cells([~,t|Fs], Args, Tab, Es, VNs) --> !, cells([~,t|Fs], Args, Tab, Es, VNs) --> !,
cells(Fs, Args, Tab, [glue(' ',_)|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) --> cells([~|Fs0], Args0, Tab, Es, VNs) -->
{ numeric_argument(Fs0, Num, ['|'|Fs], Args0, Args) }, { numeric_argument(Fs0, Num, ['|'|Fs], Args0, Args) },
!, !,
@@ -381,15 +386,15 @@ format(Stream, Fs, Args) :-
flush_output(Stream). flush_output(Stream).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
?- phrase(cells("hello", [], 0, []), Cs). ?- phrase(format:cells("hello", [], 0, [], []), Cs).
?- phrase(cells("hello~10|", [], 0, []), Cs). ?- phrase(format:cells("hello~10|", [], 0, [], []), Cs).
?- phrase(cells("~ta~t~10|", [], 0, []), Cs). ?- phrase(format:cells("~ta~t~10|", [], 0, [], []), Cs).
?- phrase(format_("~`at~50|", []), Ls). ?- phrase(format_("~`at~50|", []), Ls).
?- phrase(cells("~`at~50|", [], 0, []), Cs), ?- phrase(format:cells("~`at~50|", [], 0, [], []), Cs),
phrase(format_cells(Cs), Ls). phrase(format:format_cells(Cs), Ls).
?- phrase(format:cells("~ta~t~tb~tc~21|", [], 0, [], []), Cs). ?- 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 ...")])] 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). ?- phrase(format:cells("~ta~t~4|", [], 0, [], []), Cs).

View File

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

View File

@@ -10,7 +10,7 @@
Usage Usage
========== ==========
The main predicate of the library is http_listen/2, which needs a port number 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 as one HTTP method (in lowercase) and followed by a Route Match and a predicate
which will handle the call. which will handle the call.
@@ -58,6 +58,8 @@
url_decode//1 url_decode//1
]). ]).
:- meta_predicate http_listen(?, 2).
:- use_module(library(sockets)). :- use_module(library(sockets)).
:- use_module(library(dcgs)). :- use_module(library(dcgs)).
:- use_module(library(format)). :- use_module(library(format)).
@@ -68,8 +70,17 @@
:- use_module(library(time)). :- use_module(library(time)).
:- use_module(library(crypto)). :- 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 % Server initialization
http_listen(Port, Handlers) :- http_listen_(Port, Handlers) :-
must_be(integer, Port), must_be(integer, Port),
must_be(list, Handlers), must_be(list, Handlers),
once(socket_server_open(Port, Socket)), once(socket_server_open(Port, Socket)),
@@ -99,7 +110,7 @@ accept_loop(Socket, Handlers) :-
HttpResponse = http_response(_, _, _), HttpResponse = http_response(_, _, _),
(call(Handler, HttpRequest, HttpResponse) -> (call(Handler, HttpRequest, HttpResponse) ->
send_response(Stream, 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", []) ; format(Stream, "HTTP/1.0 404 Not Found\r\n\r\n", [])

View File

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

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

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

View File

@@ -8,8 +8,22 @@
:- use_module(library(error)). :- 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) :- length(Xs, N) :-
var(N), !, var(N),
!,
'$skip_max_list'(M, -1, Xs, Xs0), '$skip_max_list'(M, -1, Xs, Xs0),
( Xs0 == [] -> N = M ( Xs0 == [] -> N = M
; var(Xs0) -> length_addendum(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], [Y1|Ys], YsPreludeRev, Xss) :-
reverse(Xs, Ys, [Y1|YsPreludeRev], Xss). reverse(Xs, Ys, [Y1|YsPreludeRev], Xss).
maplist(_, []). maplist(_, []).
maplist(Cont1, [E1|E1s]) :- maplist(Cont1, [E1|E1s]) :-
call(Cont1, E1), call(Cont1, E1),
@@ -87,21 +100,25 @@ maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s]) :-
call(Cont, E1, E2, E3, E4), call(Cont, E1, E2, E3, E4),
maplist(Cont, E1s, E2s, E3s, E4s). maplist(Cont, E1s, E2s, E3s, E4s).
maplist(_, [], [], [], [], []). maplist(_, [], [], [], [], []).
maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s]) :- maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s]) :-
call(Cont, E1, E2, E3, E4, E5), call(Cont, E1, E2, E3, E4, E5),
maplist(Cont, E1s, E2s, E3s, E4s, E5s). maplist(Cont, E1s, E2s, E3s, E4s, E5s).
maplist(_, [], [], [], [], [], []). maplist(_, [], [], [], [], [], []).
maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s]) :- maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s]) :-
call(Cont, E1, E2, E3, E4, E5, E6), call(Cont, E1, E2, E3, E4, E5, E6),
maplist(Cont, E1s, E2s, E3s, E4s, E5s, E6s). maplist(Cont, E1s, E2s, E3s, E4s, E5s, E6s).
maplist(_, [], [], [], [], [], [], []). maplist(_, [], [], [], [], [], [], []).
maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7s]) :- 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), call(Cont, E1, E2, E3, E4, E5, E6, E7),
maplist(Cont, E1s, E2s, E3s, E4s, E5s, E6s, E7s). maplist(Cont, E1s, E2s, E3s, E4s, E5s, E6s, E7s).
maplist(_, [], [], [], [], [], [], [], []). maplist(_, [], [], [], [], [], [], [], []).
maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7s], [E8|E8s]) :- 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), 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) :- sum_list(Ls, S) :-
foldl(sum_, Ls, 0, S). foldl(lists:sum_, Ls, 0, S).
sum_(L, S0, S) :- S is S0 + L. 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(Goal_4, Xs, Ys, A0, A) :-
foldl_(Xs, Ys, Goal_4, A0, A). foldl_(Xs, Ys, Goal_4, A0, A).
foldl_([], [], _, A, A). foldl_([], [], _, A, A).
foldl_([X|Xs], [Y|Ys], G_4, A0, A) :- foldl_([X|Xs], [Y|Ys], G_4, A0, A) :-
call(G_4, X, Y, A0, A1), call(G_4, X, Y, A0, A1),
@@ -142,17 +160,17 @@ transpose(Ls, Ts) :-
lists_transpose([], []). lists_transpose([], []).
lists_transpose([L|Ls], Ts) :- lists_transpose([L|Ls], Ts) :-
maplist(same_length(L), Ls), maplist(lists:same_length(L), Ls),
foldl(transpose_, L, Ts, [L|Ls], _). foldl(lists:transpose_, L, Ts, [L|Ls], _).
transpose_(_, Fs, Lists0, Lists) :- 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_first_rest([L|Ls], L, Ls).
list_to_set(Ls0, Ls) :- list_to_set(Ls0, Ls) :-
maplist(with_var, Ls0, LVs0), maplist(lists:with_var, Ls0, LVs0),
keysort(LVs0, LVs), keysort(LVs0, LVs),
same_elements(LVs), same_elements(LVs),
pick_firsts(LVs0, Ls). pick_firsts(LVs0, Ls).
@@ -170,7 +188,7 @@ with_var(E, E-_).
same_elements([]). same_elements([]).
same_elements([EV|EVs]) :- same_elements([EV|EVs]) :-
foldl(unify_same, EVs, EV, _). foldl(lists:unify_same, EVs, EV, _).
unify_same(E-V, Prev-Var, E-V) :- unify_same(E-V, Prev-Var, E-V) :-
( Prev == E -> ( Prev == E ->
@@ -203,13 +221,13 @@ nth0_search(N0, N, [_|Es], E) :-
list_max([N|Ns], Max) :- list_max([N|Ns], Max) :-
foldl(list_max_, Ns, N, Max). foldl(lists:list_max_, Ns, N, Max).
list_max_(N, Max0, Max) :- list_max_(N, Max0, Max) :-
Max is max(N, Max0). Max is max(N, Max0).
list_min([N|Ns], Min) :- list_min([N|Ns], Min) :-
foldl(list_min_, Ns, N, Min). foldl(lists:list_min_, Ns, N, Min).
list_min_(N, Min0, Min) :- list_min_(N, Min0, Min) :-
Min is min(N, Min0). Min is min(N, Min0).

View File

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

View File

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

View File

@@ -7,6 +7,9 @@
:- use_module(library(iso_ext), [setup_call_cleanup/3, partial_string/3]). :- use_module(library(iso_ext), [setup_call_cleanup/3, partial_string/3]).
:- use_module(library(lists), [member/2]). :- 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) :-
phrase_from_file(NT, File, []). phrase_from_file(NT, File, []).

View File

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

View File

@@ -15,7 +15,7 @@ parse_socket_options_(Option, OptionPair) :-
parse_socket_options(Options, OptionValues, Stub) :- parse_socket_options(Options, OptionValues, Stub) :-
DefaultOptions = [alias-[], eof_action-eof_code, reposition-false, tls-false, type-text], 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) :- socket_client_open(Addr, Stream, Options) :-
( var(Addr) -> ( var(Addr) ->

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

1404
src/loader.pl Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

1201
src/machine/load_state.rs Normal file

File diff suppressed because it is too large Load Diff

2261
src/machine/loader.rs Normal file

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

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

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

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

View File

@@ -1,11 +1,11 @@
:- module('$project_atts', [copy_term/3]). :- module('$project_atts', [copy_term/3]).
'$attribute_goals_driver'(QueryVars, AttrVars) :- driver(QueryVars, AttrVars) :-
gather_modules(AttrVars, Modules0, _), gather_attr_modules(AttrVars, Modules0),
sort(Modules0, Modules), sort(Modules0, Modules),
call_project_attributes(Modules, QueryVars, AttrVars), call_project_attributes(Modules, QueryVars, AttrVars),
call_attribute_goals(Modules, call_query_var_goals, QueryVars), call_attribute_goals(Modules, '$project_atts':call_query_var_goals, QueryVars),
call_attribute_goals(Modules, call_attr_var_goals, AttrVars). call_attribute_goals(Modules, '$project_atts':call_attr_var_goals, AttrVars).
enqueue_goals(Goals0) :- enqueue_goals(Goals0) :-
nonvar(Goals0), nonvar(Goals0),
@@ -51,11 +51,11 @@ call_attribute_goals([Module | Modules], GoalCaller, AttrVars) :-
call_query_var_goals([], _, []). call_query_var_goals([], _, []).
call_query_var_goals([AttrVar|AttrVars], Module, Goals) :- call_query_var_goals([AttrVar|AttrVars], Module, Goals) :-
( catch(( Module:attribute_goals(AttrVar, Goals, RGoals0) ( catch(( Module:attribute_goals(AttrVar, Goals, RGoals0),
, atts:'$default_attr_list'(Module, AttrVar, RGoals0, RGoals) atts:'$default_attr_list'(Module, AttrVar, RGoals0, RGoals)
), ),
E, E,
( '$print_attribute_goals_exception'(Module, E), ( '$project_atts':'$print_attribute_goals_exception'(Module, E),
atts:'$default_attr_list'(Module, AttrVar, Goals, RGoals) atts:'$default_attr_list'(Module, AttrVar, Goals, RGoals)
)) ))
-> true -> true
@@ -67,24 +67,13 @@ call_attr_var_goals([], _, []).
call_attr_var_goals([AttrVar|AttrVars], Module, Goals) :- call_attr_var_goals([AttrVar|AttrVars], Module, Goals) :-
( catch(Module:attribute_goals(AttrVar, Goals, RGoals), ( catch(Module:attribute_goals(AttrVar, Goals, RGoals),
E, E,
'$print_attribute_goals_exception'(Module, E) '$project_atts':'$print_attribute_goals_exception'(Module, E)
) )
-> true -> true
; true ; true
), ),
call_attr_var_goals(AttrVars, Module, RGoals). 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([], _, Gs, Gs).
module_prefixed_goals([G|Gs], Module, [MG|MGs], TailGs) :- 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), module_prefixed_goals(Goals0, Module, Goals, Gs),
call_attribute_goals_with_module_prefix(Modules, GoalCaller, AttrVars, 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) :- copy_term(Source, Dest, Goals) :-
'$term_attributed_variables'(Source, Vars), '$term_attributed_variables'(Source, AttrVars),
gather_modules(Vars, Modules0, _), gather_attr_modules(AttrVars, Modules0),
sort(Modules0, Modules), 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), sort(Goals0, Goals1),
!, !,
'$copy_term_without_attr_vars'([Source | Goals1], [Dest | Goals]). '$copy_term_without_attr_vars'([Source | Goals1], [Dest | Goals]).

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

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

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

File diff suppressed because it is too large Load Diff

View File

@@ -68,10 +68,18 @@ macro_rules! functor {
}); });
($name:expr, [$($dt:ident($($value:expr),*)),+]) => ({ ($name:expr, [$($dt:ident($($value:expr),*)),+]) => ({
{ {
let arity = count_tt!($($dt) +); use crate::machine::heap::*;
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), vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None),
$(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ] $(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ];
result.extend(addendum.into_iter());
result
} }
}); });
($name:expr, $fixity:expr) => ( ($name:expr, $fixity:expr) => (
@@ -115,6 +123,22 @@ macro_rules! functor_term {
(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))) HeapCellValue::Integer(Rc::new(Integer::from($e)))
); );
(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) => ( (clause_name($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
HeapCellValue::Atom($e, None) HeapCellValue::Atom($e, None)
); );
@@ -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 { macro_rules! return_from_clause {
($lco:expr, $machine_st:expr) => {{ ($lco:expr, $machine_st:expr) => {{
if let CodePtr::VerifyAttrInterrupt(_) = $machine_st.p { 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 { macro_rules! index_store {
($atom_tbl:expr, $code_dir:expr, $op_dir:expr, $modules:expr) => { ($code_dir:expr, $op_dir:expr, $modules:expr) => {
IndexStore { IndexStore {
atom_tbl: $atom_tbl,
code_dir: $code_dir, code_dir: $code_dir,
module_dir: ModuleDir::new(), extensible_predicates: ExtensiblePredicates::new(),
dynamic_code_dir: DynamicCodeDir::new(), local_extensible_predicates: LocalExtensiblePredicates::new(),
global_variables: GlobalVarDir::new(), global_variables: GlobalVarDir::new(),
in_situ_code_dir: InSituCodeDir::new(), meta_predicates: MetaPredicateDir::new(),
in_situ_module_dir: ModuleStubDir::new(),
op_dir: $op_dir,
modules: $modules, modules: $modules,
stream_aliases: StreamAliasDir::new(), op_dir: $op_dir,
streams: StreamDir::new(), 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 { macro_rules! put_constant {
($lvl:expr, $cons:expr, $r:expr) => { ($lvl:expr, $cons:expr, $r:expr) => {
QueryInstruction::PutConstant($lvl, $cons, $r) QueryInstruction::PutConstant($lvl, $cons, $r)
@@ -387,6 +386,7 @@ macro_rules! get_level_and_unify {
}; };
} }
/*
macro_rules! unwind_protect { macro_rules! unwind_protect {
($e: expr, $protected: expr) => { ($e: expr, $protected: expr) => {
match $e { match $e {
@@ -398,7 +398,8 @@ macro_rules! unwind_protect {
} }
}; };
} }
*/
/*
macro_rules! discard_result { macro_rules! discard_result {
($f: expr) => { ($f: expr) => {
match $f { match $f {
@@ -406,7 +407,7 @@ macro_rules! discard_result {
} }
}; };
} }
*/
macro_rules! ar_reg { macro_rules! ar_reg {
($r: expr) => { ($r: expr) => {
ArithmeticTerm::Reg($r) ArithmeticTerm::Reg($r)
@@ -414,7 +415,7 @@ macro_rules! ar_reg {
} }
macro_rules! atom_from { macro_rules! atom_from {
($self:expr, $indices:expr, $e:expr) => { ($self:expr, $e:expr) => {
match $e { match $e {
Addr::Con(h) if $self.heap.atom_at(h) => { Addr::Con(h) if $self.heap.atom_at(h) => {
match &$self.heap[h] { match &$self.heap[h] {
@@ -427,7 +428,7 @@ macro_rules! atom_from {
} }
} }
Addr::Char(c) => { Addr::Char(c) => {
clause_name!(c.to_string(), $indices.atom_tbl.clone()) clause_name!(c.to_string(), $self.atom_tbl)
} }
_ => { _ => {
unreachable!() unreachable!()
@@ -435,3 +436,15 @@ macro_rules! atom_from {
} }
} }
} }
macro_rules! try_or_fail {
($s:expr, $e:expr) => {{
match $e {
Ok(val) => val,
Err(msg) => {
$s.throw_exception(msg);
return;
}
}
}};
}

View File

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

View File

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

View File

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

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

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

View File

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

View File

@@ -1,6 +1,8 @@
use crate::clause_types::*; use crate::clause_types::*;
use crate::forms::*; use crate::forms::*;
use crate::indexing::IndexingCodePtr;
use crate::instructions::*; use crate::instructions::*;
use crate::machine::loader::CompilationTarget;
use crate::machine::machine_errors::*; use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*; use crate::machine::machine_indices::*;
@@ -10,14 +12,8 @@ impl fmt::Display for LocalCodePtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
LocalCodePtr::DirEntry(p) => write!(f, "LocalCodePtr::DirEntry({})", p), LocalCodePtr::DirEntry(p) => write!(f, "LocalCodePtr::DirEntry({})", p),
LocalCodePtr::InSituDirEntry(p) => write!(f, "LocalCodePtr::InSituDirEntry({})", p), LocalCodePtr::Halt => write!(f, "LocalCodePtr::Halt"),
LocalCodePtr::TopLevel(cn, p) => write!(f, "LocalCodePtr::TopLevel({}, {})", cn, p), LocalCodePtr::IndexingBuf(p, o, i) => write!(f, "LocalCodePtr::IndexingBuf({}, {}, {})", p, o, i),
LocalCodePtr::UserGoalExpansion(p) => {
write!(f, "LocalCodePtr::UserGoalExpansion({})", p)
}
LocalCodePtr::UserTermExpansion(p) => {
write!(f, "LocalCodePtr::UserTermExpansion({})", p)
}
} }
} }
} }
@@ -25,16 +21,72 @@ impl fmt::Display for LocalCodePtr {
impl fmt::Display for REPLCodePtr { impl fmt::Display for REPLCodePtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
REPLCodePtr::CompileBatch => REPLCodePtr::AddDiscontiguousPredicate =>
write!(f, "REPLCodePtr::CompileBatch"), 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 => REPLCodePtr::UseModule =>
write!(f, "REPLCodePtr::UseModule"), write!(f, "REPLCodePtr::UseModule"),
REPLCodePtr::UseQualifiedModule => REPLCodePtr::MetaPredicateProperty =>
write!(f, "REPLCodePtr::UseQualifiedModule"), write!(f, "REPLCodePtr::MetaPredicateProperty"),
REPLCodePtr::UseModuleFromFile => REPLCodePtr::BuiltInProperty =>
write!(f, "REPLCodePtr::UseModuleFromFile"), write!(f, "REPLCodePtr::BuiltInProperty"),
REPLCodePtr::UseQualifiedModuleFromFile => REPLCodePtr::DynamicProperty =>
write!(f, "REPLCodePtr::UseQualifiedModuleFromFile") 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 { match self {
&IndexPtr::DynamicUndefined => write!(f, "undefined"), &IndexPtr::DynamicUndefined => write!(f, "undefined"),
&IndexPtr::Undefined => write!(f, "undefined"), &IndexPtr::Undefined => write!(f, "undefined"),
&IndexPtr::Index(i) => write!(f, "{}", i), &IndexPtr::DynamicIndex(i) | &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"), }
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) => { &FactInstruction::GetStructure(ref ct, ref arity, ref r) => {
write!(f, "get_structure {}/{}, {}", ct.name(), arity, 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) => { &FactInstruction::GetVariable(ref x, ref a) => {
write!(f, "fact:get_variable {}, A{}", x, a) write!(f, "fact:get_variable {}, A{}", x, a)
} }
&FactInstruction::UnifyConstant(ref constant) => { &FactInstruction::UnifyConstant(ref constant) => {
write!(f, "unify_constant {}", constant) write!(f, "unify_constant {}", constant)
} }
&FactInstruction::UnifyVariable(ref r) => write!(f, "unify_variable {}", r), &FactInstruction::UnifyVariable(ref r) => {
&FactInstruction::UnifyLocalValue(ref r) => write!(f, "unify_local_value {}", r), write!(f, "unify_variable {}", r)
&FactInstruction::UnifyValue(ref r) => write!(f, "unify_value {}", r), }
&FactInstruction::UnifyVoid(n) => write!(f, "unify_void {}", n), &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 { impl fmt::Display for ClauseType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
&ClauseType::System(SystemClauseType::SetCutPoint(r)) => write!(f, "$set_cp({})", r), &ClauseType::System(SystemClauseType::SetCutPoint(r)) => {
&ClauseType::Named(ref name, _, ref idx) | &ClauseType::Op(ref name, _, ref idx) => { write!(f, "$set_cp({})", r)
let idx = idx.0.borrow(); }
write!(f, "{}:{}/{}", idx.1, name, idx.0) &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::Atom(ref atom, _) => write!(f, "{}", atom.as_str()),
&HeapCellValue::DBRef(ref db_ref) => write!(f, "{}", db_ref), &HeapCellValue::DBRef(ref db_ref) => write!(f, "{}", db_ref),
&HeapCellValue::Integer(ref n) => write!(f, "{}", n), &HeapCellValue::Integer(ref n) => write!(f, "{}", n),
&HeapCellValue::LoadStatePayload(_) => write!(f, "LoadStatePayload"),
&HeapCellValue::Rational(ref n) => write!(f, "{}", n), &HeapCellValue::Rational(ref n) => write!(f, "{}", n),
&HeapCellValue::NamedStr(arity, ref name, Some(ref cell)) => write!( &HeapCellValue::NamedStr(arity, ref name, Some(ref cell)) => write!(
f, f,
@@ -209,6 +282,7 @@ impl fmt::Display for Addr {
&Addr::CutPoint(cp) => write!(f, "Addr::CutPoint({})", cp), &Addr::CutPoint(cp) => write!(f, "Addr::CutPoint({})", cp),
&Addr::Con(ref c) => write!(f, "Addr::Con({})", c), &Addr::Con(ref c) => write!(f, "Addr::Con({})", c),
&Addr::Lis(l) => write!(f, "Addr::Lis({})", l), &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::AttrVar(h) => write!(f, "Addr::AttrVar({})", h),
&Addr::HeapCell(h) => write!(f, "Addr::HeapCell({})", h), &Addr::HeapCell(h) => write!(f, "Addr::HeapCell({})", h),
&Addr::StackCell(fr, sc) => write!(f, "Addr::StackCell({}, {})", fr, sc), &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) => { &ControlInstruction::JmpBy(arity, offset, pvs, true) => {
write!(f, "jmp_by_execute {}/{}, {}", offset, arity, pvs) write!(f, "jmp_by_execute {}/{}, {}", offset, arity, pvs)
} }
&ControlInstruction::RevJmpBy(offset) => {
write!(f, "rev_jmp_by {}", offset)
}
&ControlInstruction::Proceed => write!(f, "proceed"), &ControlInstruction::Proceed => write!(f, "proceed"),
} }
} }
@@ -262,13 +339,60 @@ impl fmt::Display for IndexedChoiceInstruction {
impl fmt::Display for ChoiceInstruction { impl fmt::Display for ChoiceInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { 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) => { &ChoiceInstruction::DefaultRetryMeElse(offset) => {
write!(f, "retry_me_else_by_default {}", offset) write!(f, "retry_me_else_by_default {}", offset)
} }
&ChoiceInstruction::RetryMeElse(offset) => write!(f, "retry_me_else {}", offset), &ChoiceInstruction::RetryMeElse(offset) =>
&ChoiceInstruction::DefaultTrustMe => write!(f, "trust_me_by_default"), write!(f, "retry_me_else {}", offset),
&ChoiceInstruction::TrustMe => write!(f, "trust_me"), &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) => { &IndexingInstruction::SwitchOnTerm(a, v, c, l, s) => {
write!(f, "switch_on_term {}, {}, {}, {}, {}", a, v, c, l, s) write!(f, "switch_on_term {}, {}, {}, {}, {}", a, v, c, l, s)
} }
&IndexingInstruction::SwitchOnConstant(_, num_cs, _) => { &IndexingInstruction::SwitchOnConstant(ref constants) => {
write!(f, "switch_on_constant {}", num_cs) write!(f, "switch_on_constant {}", constants.len())
} }
&IndexingInstruction::SwitchOnStructure(_, num_ss, _) => { &IndexingInstruction::SwitchOnStructure(ref structures) => {
write!(f, "switch_on_structure {}", num_ss) write!(f, "switch_on_structure {}", structures.len())
} }
} }
} }
@@ -295,15 +419,15 @@ impl fmt::Display for SessionError {
&SessionError::ExistenceError(ref err) => { &SessionError::ExistenceError(ref err) => {
write!(f, "{}", err) write!(f, "{}", err)
} }
&SessionError::CannotOverwriteBuiltIn(ref msg) => { // &SessionError::CannotOverwriteBuiltIn(ref msg) => {
write!(f, "cannot overwrite {}", msg) // write!(f, "cannot overwrite {}", msg)
} // }
&SessionError::CannotOverwriteImport(ref msg) => { // &SessionError::CannotOverwriteImport(ref msg) => {
write!(f, "cannot overwrite import {}", msg) // write!(f, "cannot overwrite import {}", msg)
} // }
&SessionError::InvalidFileName(ref filename) => { // &SessionError::InvalidFileName(ref filename) => {
write!(f, "filename {} is invalid", filename) // write!(f, "filename {} is invalid", filename)
} // }
&SessionError::ModuleDoesNotContainExport(ref module, ref key) => { &SessionError::ModuleDoesNotContainExport(ref module, ref key) => {
write!( write!(
f, f,
@@ -319,12 +443,20 @@ impl fmt::Display for SessionError {
&SessionError::NamelessEntry => { &SessionError::NamelessEntry => {
write!(f, "the predicate head is not an atom or clause.") write!(f, "the predicate head is not an atom or clause.")
} }
&SessionError::ParserError(ref e) => { &SessionError::CompilationError(ref e) => {
write!(f, "syntax_error({})", e.as_str()) write!(f, "syntax_error({:?})", e)
} }
&SessionError::QueryCannotBeDefinedAsFact => { &SessionError::QueryCannotBeDefinedAsFact => {
write!(f, "queries cannot be defined as facts.") 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 { impl fmt::Display for Line {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
@@ -372,8 +528,15 @@ impl fmt::Display for Line {
&Line::Control(ref control_instr) => write!(f, "{}", control_instr), &Line::Control(ref control_instr) => write!(f, "{}", control_instr),
&Line::Cut(ref cut_instr) => write!(f, "{}", cut_instr), &Line::Cut(ref cut_instr) => write!(f, "{}", cut_instr),
&Line::Fact(ref fact_instr) => write!(f, "{}", fact_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::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), &Line::Query(ref query_instr) => write!(f, "{}", query_instr),
} }
} }

65
tests/scryer.rs Normal file
View File

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