Merge remote-tracking branch 'upstream/rebis-dev' into add-ugraphs-library

This commit is contained in:
Adrián Arroyo Calle
2022-01-07 19:14:34 +01:00
93 changed files with 37379 additions and 23840 deletions

2
.gitignore vendored
View File

@@ -1,3 +1,5 @@
src/static_atoms.rs
target/ target/

800
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "scryer-prolog" name = "scryer-prolog"
version = "0.8.128" version = "0.9.0"
authors = ["Mark Thom <markjordanthom@gmail.com>"] authors = ["Mark Thom <markjordanthom@gmail.com>"]
edition = "2021" edition = "2021"
description = "A modern Prolog implementation written mostly in Rust." description = "A modern Prolog implementation written mostly in Rust."
@@ -12,34 +12,45 @@ categories = ["command-line-utilities"]
build = "build.rs" build = "build.rs"
[workspace] [workspace]
members = ["crates/prolog_parser", "crates/num-rug-adapter"] members = ["crates/num-rug-adapter",
"crates/static-string-indexing",
"crates/instructions-template",
"crates/to-syn-value",
"crates/to-syn-value_derive"]
[features]
num = ["num-rug-adapter"]
# no default features to make num tests work
# workaround for --no-default-features and --features not working intuitively for workspaces with a root package
# see rust-lang/cargo#7160
default = ["rug"]
[build-dependencies] [build-dependencies]
indexmap = "1.0.2" indexmap = "1.0.2"
static-string-indexing = { path = "./crates/static-string-indexing" }
[features] instructions-template = { path = "./crates/instructions-template" }
default = ["rug", "prolog_parser/rug"] proc-macro2 = "*"
num = ["num-rug-adapter", "prolog_parser/num"]
[dependencies] [dependencies]
cpu-time = "1.0.0" cpu-time = "1.0.0"
crossterm = "0.16.0" crossterm = "0.16.0"
dirs-next = "2.0.0" dirs-next = "2.0.0"
divrem = "0.1.0" divrem = "0.1.0"
downcast = "0.10.0" fxhash = "0.2.1"
git-version = "0.3.4" git-version = "0.3.4"
hostname = "0.3.1" hostname = "0.3.1"
indexmap = "1.0.2" indexmap = "1.0.2"
lazy_static = "1.4.0" lazy_static = "1.4.0"
lexical = "5.2.2"
libc = "0.2.62" libc = "0.2.62"
modular-bitfield = { git = "https://github.com/mthom/modular-bitfield" } # modular-bitfield = "0.11.2"
nix = "0.15.0" nix = "0.15.0"
num-rug-adapter = { optional = true, path = "./crates/num-rug-adapter" } num-rug-adapter = { optional = true, path = "./crates/num-rug-adapter" }
ordered-float = "0.5.0" ordered-float = "2.1.1"
prolog_parser = { path = "./crates/prolog_parser", default-features = false } phf = { version = "0.9", features = ["macros"] }
ref_thread_local = "0.0.0" ref_thread_local = "0.0.0"
rug = { version = "1.4.0", optional = true } rug = { version = "1.12.0", optional = true }
rustyline = "7.0.0" rustyline = "9.0.0"
unicode_reader = "1.0.0"
ring = "0.16.13" ring = "0.16.13"
ripemd160 = "0.8.0" ripemd160 = "0.8.0"
sha3 = "0.8.2" sha3 = "0.8.2"
@@ -50,9 +61,15 @@ chrono = "0.4.11"
select = "0.4.3" select = "0.4.3"
roxmltree = "0.11.0" roxmltree = "0.11.0"
base64 = "0.12.3" base64 = "0.12.3"
smallvec = "*"
sodiumoxide = "0.2.6" sodiumoxide = "0.2.6"
static_assertions = "1.1.0"
slice-deque = "0.3.0" slice-deque = "0.3.0"
[dev-dependencies] [dev-dependencies]
assert_cmd = "1.0.3" assert_cmd = "1.0.3"
predicates-core = "1.0.2" predicates-core = "1.0.2"
serial_test = "0.5.1"
[profile.release]
debug = true

View File

@@ -7,6 +7,27 @@ programming, which is itself written in a high-level language.
![Scryer Logo: Cryer](logo/scryer.png) ![Scryer Logo: Cryer](logo/scryer.png)
# Rebis Development Branch
![Art Card](logo/art_card.jpg)
This is the Rebis Development Branch (rebis-dev). This iteration of
Rebis contains sweeping changes to the instruction dispatch loop
alongside a compacted heap representation. These changes are to
enhance the performance and robustness of Scryer Prolog and to prepare
for the introduction of a mark-compacting garbage collector.
Several performance enhancing changes are due before rebis-dev will be
considered ready for merging into master, among them:
* Replacing choice points pivoting on inlined deterministic predicates
(`atom`, `var`, etc) with if/else ladders
* Inlining all built-ins and system call instructions
* Greatly reducing the number of instructions used to compile disjunctives
* Storing short atoms to heap cells without writing them to the atom table
The rebis-dev branch should be built with **Rust 1.57 and up**.
## Phase 1 ## Phase 1
Produce an implementation of the Warren Abstract Machine in Rust, done Produce an implementation of the Warren Abstract Machine in Rust, done

View File

@@ -1,8 +1,12 @@
use static_string_indexing::index_static_strings;
use instructions_template::generate_instructions_rs;
use std::env; use std::env;
use std::fs; use std::fs;
use std::fs::File; use std::fs::File;
use std::io::Write; use std::io::Write;
use std::path::Path; use std::path::Path;
use std::process::Command;
fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) { fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) {
let entries = match current_dir.read_dir() { let entries = match current_dir.read_dir() {
@@ -48,6 +52,35 @@ fn main() {
let mut m = IndexMap::new();\n", let mut m = IndexMap::new();\n",
) )
.unwrap(); .unwrap();
find_prolog_files(&mut libraries, "", &lib_path); find_prolog_files(&mut libraries, "", &lib_path);
libraries.write_all(b"\n m\n };\n}\n").unwrap(); libraries.write_all(b"\n m\n };\n}\n").unwrap();
let instructions_path = Path::new("src/instructions.rs");
let mut instructions_file = File::create(&instructions_path).unwrap();
let quoted_output = generate_instructions_rs();
instructions_file
.write_all(quoted_output.to_string().as_bytes())
.unwrap();
Command::new("rustfmt")
.arg(instructions_path.as_os_str())
.spawn().unwrap()
.wait().unwrap();
let static_atoms_path = Path::new("src/static_atoms.rs");
let mut static_atoms_file = File::create(&static_atoms_path).unwrap();
let quoted_output = index_static_strings();
static_atoms_file
.write_all(quoted_output.to_string().as_bytes())
.unwrap();
Command::new("rustfmt")
.arg(static_atoms_path.as_os_str())
.spawn().unwrap()
.wait().unwrap();
} }

129
crates/instructions-template/Cargo.lock generated Normal file
View File

@@ -0,0 +1,129 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "heck"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "indexmap"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "instructions-template"
version = "0.1.0"
dependencies = [
"indexmap",
"proc-macro2",
"quote",
"strum",
"strum_macros",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "392a54546fda6b7cc663379d0e6ce8b324cf88aecc5a499838e1be9781bdce2e"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustversion"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
[[package]]
name = "strum"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cae14b91c7d11c9a851d3fbc80a963198998c2a64eec840477fa92d8ce9b70bb"
[[package]]
name = "strum_macros"
version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn",
]
[[package]]
name = "syn"
version = "1.0.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecb2e6da8ee5eb9a61068762a32fa9619cc591ceb055b3687f4cd4051ec2e06b"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "to-syn-value"
version = "0.1.0"
dependencies = [
"syn",
"to-syn-value_derive",
]
[[package]]
name = "to-syn-value_derive"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-segmentation"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"

View File

@@ -0,0 +1,14 @@
[package]
name = "instructions-template"
version = "0.1.0"
edition = "2021"
[dependencies]
indexmap = "*"
proc-macro2 = "*"
quote = "*"
strum = "0.23"
strum_macros = "0.23"
syn = { version = "*", features = ['full', 'visit', 'extra-traits'] }
to-syn-value = { path = "../to-syn-value" }
to-syn-value_derive = { path = "../to-syn-value_derive" }

File diff suppressed because it is too large Load Diff

View File

@@ -1,265 +0,0 @@
# 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

@@ -1,26 +0,0 @@
[package]
name = "prolog_parser"
version = "0.8.68"
authors = ["Mark Thom <markjordanthom@gmail.com>"]
edition = "2021"
repository = "https://github.com/mthom/scryer-prolog"
description = " An operator precedence parser for the Rebis development version of Scryer Prolog, an up and coming ISO Prolog implementation."
license = "BSD-3-Clause"
[dependencies]
indexmap = "1.0.2"
lexical = "5.2.1"
ordered-float = "0.5.0"
rug = { optional = true, version = "1.4.0" }
num-rug-adapter = { optional = true, path = "../num-rug-adapter" }
unicode_reader = "1.0.0"
[lib]
path = "src/lib.rs"
[features]
num = ["num-rug-adapter"]
# no default features to make num tests work
# workaround for --no-default-features and --features not working intuitively for workspaces with a root package
# see rust-lang/cargo#7160
# default = ["rug"]

View File

@@ -1,782 +0,0 @@
use crate::rug::{Integer, Rational};
use crate::tabled_rc::*;
use ordered_float::*;
use crate::put_back_n::*;
use std::cell::Cell;
use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::io::{Bytes, Error as IOError, Read};
use std::ops::Deref;
use std::rc::Rc;
use std::vec::Vec;
use indexmap::IndexMap;
use unicode_reader::CodePoints;
pub type Atom = String;
pub type Var = String;
pub type Specifier = u32;
pub const MAX_ARITY: usize = 1023;
pub const XFX: u32 = 0x0001;
pub const XFY: u32 = 0x0002;
pub const YFX: u32 = 0x0004;
pub const XF: u32 = 0x0010;
pub const YF: u32 = 0x0020;
pub const FX: u32 = 0x0040;
pub const FY: u32 = 0x0080;
pub const DELIMITER: u32 = 0x0100;
pub const TERM: u32 = 0x1000;
pub const LTERM: u32 = 0x3000;
pub const NEGATIVE_SIGN: u32 = 0x0200;
#[macro_export]
macro_rules! clause_name {
($name: expr, $tbl: expr) => {
$crate::ast::ClauseName::User($crate::tabled_rc::TabledRc::new($name, $tbl.clone()))
};
($name: expr) => {
$crate::ast::ClauseName::BuiltIn($name)
};
}
#[macro_export]
macro_rules! atom {
($e:expr, $tbl:expr) => {
$crate::ast::Constant::Atom(
$crate::ast::ClauseName::User($crate::tabled_rc!($e, $tbl)),
None,
)
};
($e:expr) => {
$crate::ast::Constant::Atom($crate::clause_name!($e), None)
};
}
#[macro_export]
macro_rules! rc_atom {
($e:expr) => {
Rc::new(String::from($e))
};
}
macro_rules! is_term {
($x:expr) => {
($x & $crate::ast::TERM) != 0
};
}
macro_rules! is_lterm {
($x:expr) => {
($x & $crate::ast::LTERM) != 0
};
}
macro_rules! is_op {
($x:expr) => {
$x & ($crate::ast::XF
| $crate::ast::YF
| $crate::ast::FX
| $crate::ast::FY
| $crate::ast::XFX
| $crate::ast::XFY
| $crate::ast::YFX)
!= 0
};
}
macro_rules! is_negate {
($x:expr) => {
($x & $crate::ast::NEGATIVE_SIGN) != 0
};
}
#[macro_export]
macro_rules! is_prefix {
($x:expr) => {
$x & ($crate::ast::FX | $crate::ast::FY) != 0
};
}
#[macro_export]
macro_rules! is_postfix {
($x:expr) => {
$x & ($crate::ast::XF | $crate::ast::YF) != 0
};
}
#[macro_export]
macro_rules! is_infix {
($x:expr) => {
($x & ($crate::ast::XFX | $crate::ast::XFY | $crate::ast::YFX)) != 0
};
}
#[macro_export]
macro_rules! is_xfx {
($x:expr) => {
($x & $crate::ast::XFX) != 0
};
}
#[macro_export]
macro_rules! is_xfy {
($x:expr) => {
($x & $crate::ast::XFY) != 0
};
}
#[macro_export]
macro_rules! is_yfx {
($x:expr) => {
($x & $crate::ast::YFX) != 0
};
}
#[macro_export]
macro_rules! is_yf {
($x:expr) => {
($x & $crate::ast::YF) != 0
};
}
#[macro_export]
macro_rules! is_xf {
($x:expr) => {
($x & $crate::ast::XF) != 0
};
}
#[macro_export]
macro_rules! is_fx {
($x:expr) => {
($x & $crate::ast::FX) != 0
};
}
#[macro_export]
macro_rules! is_fy {
($x:expr) => {
($x & $crate::ast::FY) != 0
};
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum RegType {
Perm(usize),
Temp(usize),
}
impl Default for RegType {
fn default() -> Self {
RegType::Temp(0)
}
}
impl RegType {
pub fn reg_num(self) -> usize {
match self {
RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num,
}
}
pub fn is_perm(self) -> bool {
matches!(self, RegType::Perm(_))
}
}
impl fmt::Display for RegType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
RegType::Perm(val) => write!(f, "Y{}", val),
RegType::Temp(val) => write!(f, "X{}", val),
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum VarReg {
ArgAndNorm(RegType, usize),
Norm(RegType),
}
impl VarReg {
pub fn norm(self) -> RegType {
match self {
VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg,
}
}
}
impl fmt::Display for VarReg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg),
VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg),
VarReg::ArgAndNorm(RegType::Perm(reg), arg) => write!(f, "Y{} A{}", reg, arg),
VarReg::ArgAndNorm(RegType::Temp(reg), arg) => write!(f, "X{} A{}", reg, arg),
}
}
}
impl Default for VarReg {
fn default() -> Self {
VarReg::Norm(RegType::default())
}
}
#[macro_export]
macro_rules! temp_v {
($x:expr) => {
$crate::ast::RegType::Temp($x)
};
}
#[macro_export]
macro_rules! perm_v {
($x:expr) => {
$crate::ast::RegType::Perm($x)
};
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum GenContext {
Head,
Mid(usize),
Last(usize), // Mid & Last: chunk_num
}
impl GenContext {
pub fn chunk_num(self) -> usize {
match self {
GenContext::Head => 0,
GenContext::Mid(cn) | GenContext::Last(cn) => cn,
}
}
}
pub type OpDirKey = (ClauseName, Fixity);
#[derive(Debug, Clone)]
pub struct OpDirValue(pub SharedOpDesc);
impl OpDirValue {
pub fn new(spec: Specifier, priority: usize) -> Self {
OpDirValue(SharedOpDesc::new(priority, spec))
}
#[inline]
pub fn shared_op_desc(&self) -> SharedOpDesc {
self.0.clone()
}
}
// name and fixity -> operator type and precedence.
pub type OpDir = IndexMap<OpDirKey, OpDirValue>;
#[derive(Debug, Clone, Copy)]
pub struct MachineFlags {
pub double_quotes: DoubleQuotes,
}
impl Default for MachineFlags {
fn default() -> Self {
MachineFlags {
double_quotes: DoubleQuotes::default(),
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum DoubleQuotes {
Atom,
Chars,
Codes,
}
impl DoubleQuotes {
pub fn is_chars(self) -> bool {
matches!(self, DoubleQuotes::Chars)
}
pub fn is_atom(self) -> bool {
matches!(self, DoubleQuotes::Atom)
}
pub fn is_codes(self) -> bool {
matches!(self, DoubleQuotes::Codes)
}
}
impl Default for DoubleQuotes {
fn default() -> Self {
DoubleQuotes::Chars
}
}
pub fn default_op_dir() -> OpDir {
let mut op_dir = OpDir::new();
op_dir.insert((clause_name!(":-"), Fixity::In), OpDirValue::new(XFX, 1200));
op_dir.insert((clause_name!(":-"), Fixity::Pre), OpDirValue::new(FX, 1200));
op_dir.insert((clause_name!("?-"), Fixity::Pre), OpDirValue::new(FX, 1200));
op_dir.insert((clause_name!(","), Fixity::In), OpDirValue::new(XFY, 1000));
op_dir
}
#[derive(Debug, Clone)]
pub enum ArithmeticError {
NonEvaluableFunctor(Constant, usize),
UninstantiatedVar,
}
#[derive(Debug)]
pub enum ParserError {
BackQuotedString(usize, usize),
UnexpectedChar(char, usize, usize),
UnexpectedEOF,
IO(IOError),
IncompleteReduction(usize, usize),
InvalidSingleQuotedCharacter(char),
MissingQuote(usize, usize),
NonPrologChar(usize, usize),
ParseBigInt(usize, usize),
Utf8Error(usize, usize),
}
impl ParserError {
pub fn line_and_col_num(&self) -> Option<(usize, usize)> {
match self {
&ParserError::BackQuotedString(line_num, col_num)
| &ParserError::UnexpectedChar(_, line_num, col_num)
| &ParserError::IncompleteReduction(line_num, col_num)
| &ParserError::MissingQuote(line_num, col_num)
| &ParserError::NonPrologChar(line_num, col_num)
| &ParserError::ParseBigInt(line_num, col_num)
| &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)),
_ => None,
}
}
pub fn as_str(&self) -> &'static str {
match self {
ParserError::BackQuotedString(..) => "back_quoted_string",
ParserError::UnexpectedChar(..) => "unexpected_char",
ParserError::UnexpectedEOF => "unexpected_end_of_file",
ParserError::IncompleteReduction(..) => "incomplete_reduction",
ParserError::InvalidSingleQuotedCharacter(..) => "invalid_single_quoted_character",
ParserError::IO(_) => "input_output_error",
ParserError::MissingQuote(..) => "missing_quote",
ParserError::NonPrologChar(..) => "non_prolog_character",
ParserError::ParseBigInt(..) => "cannot_parse_big_int",
ParserError::Utf8Error(..) => "utf8_conversion_error",
}
}
}
impl From<IOError> for ParserError {
fn from(err: IOError) -> ParserError {
ParserError::IO(err)
}
}
impl From<&IOError> for ParserError {
fn from(error: &IOError) -> ParserError {
if error.get_ref().filter(|e| e.is::<BadUtf8Error>()).is_some() {
ParserError::Utf8Error(0, 0)
} else {
ParserError::IO(error.kind().into())
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct CompositeOpDir<'a, 'b> {
pub primary_op_dir: Option<&'b OpDir>,
pub secondary_op_dir: &'a OpDir,
}
impl<'a, 'b> CompositeOpDir<'a, 'b> {
#[inline]
pub fn new(secondary_op_dir: &'a OpDir, primary_op_dir: Option<&'b OpDir>) -> Self {
CompositeOpDir {
primary_op_dir,
secondary_op_dir,
}
}
#[inline]
pub(crate) fn get(&self, name: ClauseName, fixity: Fixity) -> Option<&OpDirValue> {
let entry = if let Some(ref primary_op_dir) = &self.primary_op_dir {
primary_op_dir.get(&(name.clone(), fixity))
} else {
None
};
entry.or_else(move || self.secondary_op_dir.get(&(name, fixity)))
}
}
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub enum Fixity {
In,
Post,
Pre,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct SharedOpDesc(Rc<Cell<(usize, Specifier)>>);
impl SharedOpDesc {
#[inline]
pub fn new(priority: usize, spec: Specifier) -> Self {
SharedOpDesc(Rc::new(Cell::new((priority, spec))))
}
#[inline]
pub fn ptr_eq(lop_desc: &SharedOpDesc, rop_desc: &SharedOpDesc) -> bool {
Rc::ptr_eq(&lop_desc.0, &rop_desc.0)
}
#[inline]
pub fn arity(&self) -> usize {
if self.get().1 & (XFX | XFY | YFX) == 0 {
1
} else {
2
}
}
#[inline]
pub fn get(&self) -> (usize, Specifier) {
self.0.get()
}
#[inline]
pub fn set(&self, prec: usize, spec: Specifier) {
self.0.set((prec, spec));
}
#[inline]
pub fn prec(&self) -> usize {
self.0.get().0
}
#[inline]
pub fn assoc(&self) -> Specifier {
self.0.get().1
}
}
impl Deref for SharedOpDesc {
type Target = Cell<(usize, Specifier)>;
#[inline]
fn deref(&self) -> &Self::Target {
self.0.deref()
}
}
// this ensures that SharedOpDesc (which is not consistently placed in
// every atom!) doesn't affect the value of an atom hash. If
// SharedOpDesc values are to be indexed, a BTreeMap or BTreeSet
// should be used, obviously.
impl Hash for SharedOpDesc {
fn hash<H: Hasher>(&self, state: &mut H) {
0.hash(state)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Constant {
Atom(ClauseName, Option<SharedOpDesc>),
Char(char),
EmptyList,
Fixnum(isize),
Integer(Rc<Integer>),
Rational(Rc<Rational>),
Float(OrderedFloat<f64>),
String(Rc<String>),
Usize(usize),
}
impl fmt::Display for Constant {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Constant::Atom(ref atom, _) => {
if atom.as_str().chars().any(|c| "`.$'\" ".contains(c)) {
write!(f, "'{}'", atom.as_str())
} else {
write!(f, "{}", atom.as_str())
}
}
Constant::Char(c) => write!(f, "'{}'", *c as u32),
Constant::EmptyList => write!(f, "[]"),
Constant::Fixnum(n) => write!(f, "{}", n),
Constant::Integer(ref n) => write!(f, "{}", n),
Constant::Rational(ref n) => write!(f, "{}", n),
Constant::Float(ref n) => write!(f, "{}", n),
Constant::String(ref s) => write!(f, "\"{}\"", &s),
Constant::Usize(integer) => write!(f, "u{}", integer),
}
}
}
impl Constant {
pub fn to_atom(&self) -> Option<ClauseName> {
match self {
Constant::Atom(a, _) => Some(a.defrock_brackets()),
_ => None,
}
}
}
#[derive(Debug, Clone)]
pub enum ClauseName {
BuiltIn(&'static str),
User(TabledRc<Atom>),
}
impl fmt::Display for ClauseName {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl Hash for ClauseName {
fn hash<H: Hasher>(&self, state: &mut H) {
(*self.as_str()).hash(state)
}
}
impl PartialEq for ClauseName {
fn eq(&self, other: &ClauseName) -> bool {
*self.as_str() == *other.as_str()
}
}
impl Eq for ClauseName {}
impl Ord for ClauseName {
fn cmp(&self, other: &ClauseName) -> Ordering {
(*self.as_str()).cmp(other.as_str())
}
}
impl PartialOrd for ClauseName {
fn partial_cmp(&self, other: &ClauseName) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<'a> From<&'a TabledRc<Atom>> for ClauseName {
fn from(name: &'a TabledRc<Atom>) -> ClauseName {
ClauseName::User(name.clone())
}
}
impl ClauseName {
#[inline]
pub fn owning_module(&self) -> Self {
match self {
ClauseName::User(ref name) => {
let module = name.owning_module();
ClauseName::User(TabledRc {
atom: module.clone(),
table: TabledData::new(module),
})
}
_ => clause_name!("user"),
}
}
#[inline]
pub fn to_rc(&self) -> Rc<String> {
match self {
ClauseName::BuiltIn(s) => Rc::new(s.to_string()),
ClauseName::User(ref rc) => rc.inner(),
}
}
#[inline]
pub fn with_table(self, atom_tbl: TabledData<Atom>) -> Self {
match self {
ClauseName::BuiltIn(_) => self,
ClauseName::User(mut name) => {
name.table = atom_tbl;
ClauseName::User(name)
}
}
}
#[inline]
pub fn has_table(&self, atom_tbl: &TabledData<Atom>) -> bool {
match self {
ClauseName::BuiltIn(_) => false,
ClauseName::User(ref name) => &name.table == atom_tbl,
}
}
#[inline]
pub fn has_table_of(&self, other: &ClauseName) -> bool {
match self {
ClauseName::BuiltIn(_) => {
matches!(other, ClauseName::BuiltIn(_))
}
ClauseName::User(ref name) => other.has_table(&name.table),
}
}
#[inline]
pub fn as_str(&self) -> &str {
match self {
ClauseName::BuiltIn(s) => s,
ClauseName::User(ref name) => name.as_ref(),
}
}
#[inline]
pub fn is_char(&self) -> bool {
!self.as_str().is_empty() && self.as_str().chars().nth(1).is_none()
}
pub fn defrock_brackets(&self) -> Self {
fn defrock_brackets(s: &str) -> &str {
if s.starts_with('(') && s.ends_with(')') {
&s[1..s.len() - 1]
} else {
s
}
}
match self {
ClauseName::BuiltIn(s) => ClauseName::BuiltIn(defrock_brackets(s)),
ClauseName::User(s) => {
ClauseName::User(tabled_rc!(defrock_brackets(s.as_str()).to_owned(), s.table))
}
}
}
}
impl AsRef<str> for ClauseName {
#[inline]
fn as_ref(&self) -> &str {
self.as_str()
}
}
#[derive(Debug, Clone)]
pub enum Term {
AnonVar,
Clause(
Cell<RegType>,
ClauseName,
Vec<Box<Term>>,
Option<SharedOpDesc>,
),
Cons(Cell<RegType>, Box<Term>, Box<Term>),
Constant(Cell<RegType>, Constant),
Var(Cell<VarReg>, Rc<Var>),
}
impl Term {
pub fn shared_op_desc(&self) -> Option<SharedOpDesc> {
match self {
Term::Clause(_, _, _, ref spec) => spec.clone(),
Term::Constant(_, Constant::Atom(_, ref spec)) => spec.clone(),
_ => None,
}
}
pub fn into_constant(self) -> Option<Constant> {
match self {
Term::Constant(_, c) => Some(c),
_ => None,
}
}
pub fn first_arg(&self) -> Option<&Term> {
match self {
Term::Clause(_, _, ref terms, _) => terms.first().map(|bt| bt.as_ref()),
_ => None,
}
}
pub fn set_name(&mut self, new_name: ClauseName) {
match self {
Term::Constant(_, Constant::Atom(ref mut atom, _))
| Term::Clause(_, ref mut atom, ..) => {
*atom = new_name;
}
_ => {}
}
}
pub fn name(&self) -> Option<ClauseName> {
match self {
&Term::Constant(_, Constant::Atom(ref atom, _)) | &Term::Clause(_, ref atom, ..) => {
Some(atom.clone())
}
_ => None,
}
}
pub fn arity(&self) -> usize {
match self {
Term::Clause(_, _, ref child_terms, ..) => child_terms.len(),
_ => 0,
}
}
}
fn unfold_by_str_once(term: &mut Term, s: &str) -> Option<(Term, Term)> {
if let Term::Clause(_, ref name, ref mut subterms, _) = term {
if name.as_str() == s && subterms.len() == 2 {
let snd = *subterms.pop().unwrap();
let fst = *subterms.pop().unwrap();
return Some((fst, snd));
}
}
None
}
pub fn unfold_by_str(mut term: Term, s: &str) -> Vec<Term> {
let mut terms = vec![];
while let Some((fst, snd)) = unfold_by_str_once(&mut term, s) {
terms.push(fst);
term = snd;
}
terms.push(term);
terms
}
pub type ParsingStream<R> = PutBackN<CodePoints<Bytes<R>>>;
use unicode_reader::BadUtf8Error;
#[inline]
pub fn parsing_stream<R: Read>(src: R) -> Result<ParsingStream<R>, ParserError> {
let mut stream = put_back_n(CodePoints::from(src.bytes()));
match stream.peek() {
None => Ok(stream), // empty stream is handled gracefully by Lexer::eof
Some(Err(error)) => Err(ParserError::from(error)),
Some(Ok(c)) => {
if *c == '\u{feff}' {
// skip UTF-8 BOM
stream.next();
}
Ok(stream)
}
}
}

View File

@@ -1,71 +0,0 @@
use std::iter::Peekable;
#[derive(Debug, Clone)]
pub struct PutBackN<I: Iterator> {
top: Vec<I::Item>,
iter: Peekable<I>,
}
pub fn put_back_n<I>(iterable: I) -> PutBackN<I::IntoIter>
where I: IntoIterator
{
PutBackN {
top: Vec::new(),
iter: iterable.into_iter().peekable(),
}
}
impl<I: Iterator> PutBackN<I> {
#[inline]
pub(crate)
fn put_back(&mut self, item: I::Item) {
self.top.push(item);
}
#[inline]
pub fn take_buf(&mut self) -> Vec<I::Item> {
std::mem::replace(&mut self.top, vec![])
}
#[inline]
pub(crate)
fn peek(&mut self) -> Option<&I::Item> {
if self.top.is_empty() {
/* This is a kludge for Ctrl-D not being
* handled properly if self.iter().peek() isn't called
* first. */
match self.iter.peek() {
Some(_) => {
self.iter.next().and_then(move |item| {
self.top.push(item);
self.top.last()
})
}
None => {
None
}
}
} else {
self.top.last()
}
}
#[inline]
pub(crate)
fn put_back_all<DEI: DoubleEndedIterator<Item = I::Item>>(&mut self, iter: DEI) {
self.top.extend(iter.rev());
}
}
impl<I: Iterator> Iterator for PutBackN<I> {
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
if self.top.is_empty() {
self.iter.next()
} else {
self.top.pop()
}
}
}

View File

@@ -1,154 +0,0 @@
use std::cell::{RefCell, RefMut};
use std::cmp::Ordering;
use std::collections::HashSet;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::rc::Rc;
pub struct TabledData<T> {
table: Rc<RefCell<HashSet<Rc<T>>>>,
pub(crate) module_name: Rc<String>,
}
impl<T: Hash + Eq + fmt::Debug> fmt::Debug for TabledData<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("TabledData")
.field("table", &self.table)
.field("module_name", &self.table)
.finish()
}
}
impl<T> Clone for TabledData<T> {
fn clone(&self) -> Self {
TabledData {
table: self.table.clone(),
module_name: self.module_name.clone(),
}
}
}
impl<T: PartialEq> PartialEq for TabledData<T> {
fn eq(&self, other: &TabledData<T>) -> bool {
Rc::ptr_eq(&self.table, &other.table) && self.module_name == other.module_name
}
}
impl<T: Hash + Eq> TabledData<T> {
#[inline]
pub fn new(module_name: Rc<String>) -> Self {
TabledData {
table: Rc::new(RefCell::new(HashSet::new())),
module_name,
}
}
#[inline]
pub fn borrow_mut(&self) -> RefMut<HashSet<Rc<T>>> {
self.table.borrow_mut()
}
}
pub struct TabledRc<T: Hash + Eq> {
pub(crate) atom: Rc<T>,
pub table: TabledData<T>,
}
impl<T: Hash + Eq + fmt::Debug> fmt::Debug for TabledRc<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("TabledRc")
.field("atom", &self.atom)
.field("table", &self.table)
.finish()
}
}
// this Clone instance is manually defined to prevent the compiler
// from complaining when deriving Clone for StringList.
impl<T: Hash + Eq> Clone for TabledRc<T> {
fn clone(&self) -> Self {
TabledRc {
atom: self.atom.clone(),
table: self.table.clone(),
}
}
}
impl<T: Ord + Hash + Eq> PartialOrd for TabledRc<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.atom.cmp(&other.atom))
}
}
impl<T: Ord + Hash + Eq> Ord for TabledRc<T> {
fn cmp(&self, other: &Self) -> Ordering {
self.atom.cmp(&other.atom)
}
}
impl<T: Hash + Eq> PartialEq for TabledRc<T> {
fn eq(&self, other: &TabledRc<T>) -> bool {
self.atom == other.atom
}
}
impl<T: Hash + Eq> Eq for TabledRc<T> {}
impl<T: Hash + Eq> Hash for TabledRc<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.atom.hash(state)
}
}
impl<T: Hash + Eq + ToString> TabledRc<T> {
pub fn new(atom: T, table: TabledData<T>) -> Self {
let atom = match table.borrow_mut().take(&atom) {
Some(atom) => atom,
None => Rc::new(atom),
};
table.borrow_mut().insert(atom.clone());
TabledRc { atom, table }
}
#[inline]
pub fn inner(&self) -> Rc<T> {
self.atom.clone()
}
#[inline]
pub(crate) fn owning_module(&self) -> Rc<String> {
self.table.module_name.clone()
}
}
impl<T: Hash + Eq> Drop for TabledRc<T> {
fn drop(&mut self) {
if Rc::strong_count(&self.atom) == 2 {
self.table.borrow_mut().remove(&self.atom);
}
}
}
impl<T: Hash + Eq> Deref for TabledRc<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&*self.atom
}
}
impl<T: Hash + Eq + fmt::Display> fmt::Display for TabledRc<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", &*self.atom)
}
}
#[macro_export]
macro_rules! tabled_rc {
($e:expr, $tbl:expr) => {
$crate::tabled_rc::TabledRc::new(String::from($e), $tbl.clone())
};
}

View File

@@ -0,0 +1,11 @@
[package]
name = "static-string-indexing"
version = "0.1.0"
edition = "2021"
[dependencies]
proc-macro2 = "*"
syn = { version = "*", features = ['full', 'visit', 'extra-traits'] }
indexmap = "*"
walkdir = "2"
quote = "*"

View File

@@ -0,0 +1,161 @@
use proc_macro2::TokenStream;
use syn::*;
use syn::parse::*;
use syn::visit::*;
use indexmap::IndexSet;
struct StaticStrVisitor {
static_strs: IndexSet<String>,
}
impl StaticStrVisitor {
fn new() -> Self {
Self { static_strs: IndexSet::new() }
}
}
struct MacroFnArgs {
args: Vec<Expr>,
}
struct ReadHeapCellExprAndArms {
expr: Expr,
arms: Vec<Arm>,
}
impl Parse for ReadHeapCellExprAndArms {
fn parse(input: ParseStream) -> Result<Self> {
let mut arms = vec![];
let expr = input.parse()?;
input.parse::<Token![,]>()?;
arms.push(input.parse()?);
while !input.is_empty() {
if let Ok(_) = input.parse::<Token![,]>() {}
arms.push(input.parse()?);
}
Ok(ReadHeapCellExprAndArms { expr, arms })
}
}
impl Parse for MacroFnArgs {
fn parse(input: ParseStream) -> Result<Self> {
let mut args = vec![];
if !input.is_empty() {
args.push(input.parse()?);
}
while !input.is_empty() {
if let Ok(_) = input.parse::<Token![,]>() {}
args.push(input.parse()?);
}
Ok(MacroFnArgs { args })
}
}
impl<'ast> Visit<'ast> for StaticStrVisitor {
fn visit_macro(&mut self, m: &'ast Macro) {
let Macro { path, .. } = m;
if path.is_ident("atom") {
if let Some(Lit::Str(string)) = m.parse_body::<Lit>().ok() {
self.static_strs.insert(string.value());
}
} else if path.is_ident("read_heap_cell") {
if let Some(m) = m.parse_body::<ReadHeapCellExprAndArms>().ok() {
self.visit_expr(&m.expr);
for e in m.arms {
self.visit_arm(&e);
}
}
} else {
if let Some(m) = m.parse_body::<MacroFnArgs>().ok() {
for e in m.args {
self.visit_expr(&e);
}
}
}
}
}
pub fn index_static_strings() -> TokenStream {
use quote::*;
use std::ffi::OsStr;
use std::fs::File;
use std::io::Read;
use walkdir::WalkDir;
fn filter_rust_files(e: &walkdir::DirEntry) -> bool {
if e.path().is_dir() {
return true;
}
e.path().extension().and_then(OsStr::to_str) == Some("rs")
}
let mut visitor = StaticStrVisitor::new();
for entry in WalkDir::new("src/").into_iter().filter_entry(filter_rust_files) {
let entry = entry.unwrap();
if entry.path().is_dir() {
continue;
}
let mut file = match File::open(entry.path()) {
Ok(file) => file,
Err(_) => continue,
};
let mut src = String::new();
match file.read_to_string(&mut src) {
Ok(_) => {}
Err(e) => {
panic!("error reading file: {:?}", e);
}
}
let syntax = match syn::parse_file(&src) {
Ok(s) => s,
Err(e) => {
panic!("parse error: {} in file {:?}", e, entry.path());
}
};
visitor.visit_file(&syntax);
}
let indices = (0 .. visitor.static_strs.len()).map(|i| i << 3);
let indices_iter = indices.clone();
let static_strs_len = visitor.static_strs.len();
let static_strs: &Vec<_> = &visitor.static_strs.into_iter().collect();
quote! {
use phf;
static STRINGS: [&'static str; #static_strs_len] = [
#(
#static_strs,
)*
];
#[macro_export]
macro_rules! atom {
#((#static_strs) => { Atom { index: #indices_iter } };)*
}
static STATIC_ATOMS_MAP: phf::Map<&'static str, Atom> = phf::phf_map! {
#(#static_strs => { Atom { index: #indices } },)*
};
}
}

View File

@@ -0,0 +1,10 @@
[package]
name = "to-syn-value"
version = "0.1.0"
authors = ["Mark Thom <markjordanthom@gmail.com>"]
edition = "2021"
publish = false
[dependencies]
syn = { version = "*", features = ['full', 'visit', 'extra-traits'] }
to-syn-value_derive = { path = "../to-syn-value_derive" }

View File

@@ -0,0 +1,3 @@
pub trait ToDeriveInput {
fn to_derive_input() -> syn::DeriveInput;
}

View File

@@ -0,0 +1,14 @@
[package]
name = "to-syn-value_derive"
version = "0.1.0"
authors = ["Mark Thom <markjordanthom@gmail.com>"]
edition = "2021"
publish = false
[lib]
proc-macro = true
[dependencies]
proc-macro2 = "*"
syn = { version = "*", features = ['full', 'visit', 'extra-traits'] }
quote = "*"

View File

@@ -0,0 +1,20 @@
use syn::*;
use quote::*;
#[proc_macro_derive(ToDeriveInput)]
pub fn derive_to_derive_input(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let derive_input = parse_macro_input!(input as DeriveInput);
let ty_name = derive_input.ident.clone();
quote! {
use to_syn_value::*;
impl ToDeriveInput for #ty_name {
fn to_derive_input() -> syn::DeriveInput {
syn::parse_quote! {
#derive_input
}
}
}
}.into()
}

BIN
logo/art_card.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

View File

@@ -1,10 +1,10 @@
use prolog_parser::ast::*; use crate::parser::ast::*;
use prolog_parser::temp_v; use crate::temp_v;
use crate::fixtures::*; use crate::fixtures::*;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*;
use crate::machine::machine_indices::*; use crate::machine::machine_indices::*;
use crate::targets::*;
use std::cell::Cell; use std::cell::Cell;
use std::rc::Rc; use std::rc::Rc;
@@ -12,42 +12,42 @@ use std::rc::Rc;
pub(crate) 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 Code)
where where
Target: CompilationTarget<'a>; Target: crate::targets::CompilationTarget<'a>;
fn mark_non_var<Target>( fn mark_non_var<Target>(
&mut self, &mut self,
_: Level, _: Level,
_: GenContext, _: GenContext,
_: &'a Cell<RegType>, _: &'a Cell<RegType>,
_: &mut Vec<Target>, _: &mut Code,
) where ) where
Target: CompilationTarget<'a>; Target: crate::targets::CompilationTarget<'a>;
fn mark_reserved_var<Target>( fn mark_reserved_var<Target>(
&mut self, &mut self,
_: Rc<Var>, _: Rc<String>,
_: Level, _: Level,
_: &'a Cell<VarReg>, _: &'a Cell<VarReg>,
_: GenContext, _: GenContext,
_: &mut Vec<Target>, _: &mut Code,
_: RegType, _: RegType,
_: bool, _: bool,
) where ) where
Target: CompilationTarget<'a>; Target: crate::targets::CompilationTarget<'a>;
fn mark_var<Target>( fn mark_var<Target>(
&mut self, &mut self,
_: Rc<Var>, _: Rc<String>,
_: Level, _: Level,
_: &'a Cell<VarReg>, _: &'a Cell<VarReg>,
_: GenContext, _: GenContext,
_: &mut Vec<Target>, _: &mut Code,
) where ) where
Target: CompilationTarget<'a>; Target: crate::targets::CompilationTarget<'a>;
fn reset(&mut self); fn reset(&mut self);
fn reset_contents(&mut self) {} fn reset_contents(&mut self) {}
fn reset_arg(&mut self, _: usize); fn reset_arg(&mut self, _: usize);
fn reset_at_head(&mut self, _: &Vec<Box<Term>>); fn reset_at_head(&mut self, args: &Vec<Term>);
fn advance_arg(&mut self); fn advance_arg(&mut self);
@@ -83,17 +83,17 @@ pub(crate) trait Allocator<'a> {
perm_vs perm_vs
} }
fn get(&self, var: Rc<Var>) -> RegType { fn get(&self, var: Rc<String>) -> RegType {
self.bindings() self.bindings()
.get(&var) .get(&var)
.map_or(temp_v!(0), |v| v.as_reg_type()) .map_or(temp_v!(0), |v| v.as_reg_type())
} }
fn is_unbound(&self, var: Rc<Var>) -> bool { fn is_unbound(&self, var: Rc<String>) -> bool {
self.get(var).reg_num() == 0 self.get(var).reg_num() == 0
} }
fn record_register(&mut self, var: Rc<Var>, r: RegType) { fn record_register(&mut self, var: Rc<String>, r: RegType) {
match self.bindings_mut().get_mut(&var).unwrap() { match self.bindings_mut().get_mut(&var).unwrap() {
&mut VarData::Temp(_, ref mut s, _) => *s = r.reg_num(), &mut VarData::Temp(_, ref mut s, _) => *s = r.reg_num(),
&mut VarData::Perm(ref mut s) => *s = r.reg_num(), &mut VarData::Perm(ref mut s) => *s = r.reg_num(),

793
src/arena.rs Normal file
View File

@@ -0,0 +1,793 @@
use crate::machine::loader::LiveLoadState;
use crate::machine::machine_indices::*;
use crate::machine::streams::*;
use crate::read::*;
use modular_bitfield::prelude::*;
use ordered_float::OrderedFloat;
use rug::{Integer, Rational};
use std::alloc;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::mem;
use std::net::TcpListener;
use std::ops::{Deref, DerefMut};
use std::ptr;
#[macro_export]
macro_rules! arena_alloc {
($e:expr, $arena:expr) => {{
let result = $e;
#[allow(unused_unsafe)]
unsafe { $arena.alloc(result) }
}};
}
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq)]
#[bits = 7]
pub enum ArenaHeaderTag {
F64 = 0b01,
Integer = 0b10,
Rational = 0b11,
OssifiedOpDir = 0b0000100,
LiveLoadState = 0b0001000,
InactiveLoadState = 0b1011000,
InputFileStream = 0b10000,
OutputFileStream = 0b10100,
NamedTcpStream = 0b011100,
NamedTlsStream = 0b100000,
ReadlineStream = 0b110000,
StaticStringStream = 0b110100,
ByteStream = 0b111000,
StandardOutputStream = 0b1100,
StandardErrorStream = 0b11000,
NullStream = 0b111100,
TcpListener = 0b1000000,
Dropped = 0b1000100,
}
#[bitfield]
#[derive(Copy, Clone, Debug)]
pub struct ArenaHeader {
size: B56,
m: bool,
tag: ArenaHeaderTag,
}
const_assert!(mem::size_of::<ArenaHeader>() == 8);
impl ArenaHeader {
#[inline]
pub fn build_with(size: u64, tag: ArenaHeaderTag) -> Self {
ArenaHeader::new()
.with_size(size)
.with_tag(tag)
.with_m(false)
}
#[inline]
pub fn get_tag(self) -> ArenaHeaderTag {
self.tag()
}
}
#[derive(Debug, PartialEq, PartialOrd, Eq, Ord)]
pub struct TypedArenaPtr<T: ?Sized>(ptr::NonNull<T>);
impl<T: ?Sized + Hash> Hash for TypedArenaPtr<T> {
#[inline(always)]
fn hash<H: Hasher>(&self, hasher: &mut H) {
(&*self as &T).hash(hasher)
}
}
impl<T: ?Sized> Clone for TypedArenaPtr<T> {
fn clone(&self) -> Self {
TypedArenaPtr(self.0)
}
}
impl<T: ?Sized> Copy for TypedArenaPtr<T> {}
impl<T: ?Sized> Deref for TypedArenaPtr<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { self.0.as_ref() }
}
}
impl<T: ?Sized> DerefMut for TypedArenaPtr<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.0.as_mut() }
}
}
impl<T: fmt::Display> fmt::Display for TypedArenaPtr<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", **self)
}
}
impl<T: ?Sized> TypedArenaPtr<T> {
#[inline]
pub const fn new(data: *mut T) -> Self {
unsafe { TypedArenaPtr(ptr::NonNull::new_unchecked(data)) }
}
#[inline]
pub fn as_ptr(&self) -> *mut T {
self.0.as_ptr()
}
#[inline]
pub fn header_ptr(&self) -> *const ArenaHeader {
let mut ptr = self.as_ptr() as *const u8 as usize;
ptr -= mem::size_of::<*const ArenaHeader>();
ptr as *const ArenaHeader
}
#[inline]
fn header_ptr_mut(&mut self) -> *mut ArenaHeader {
let mut ptr = self.as_ptr() as *const u8 as usize;
ptr -= mem::size_of::<*const ArenaHeader>();
ptr as *mut ArenaHeader
}
#[inline]
pub fn get_mark_bit(&self) -> bool {
unsafe { (*self.header_ptr()).m() }
}
#[inline]
pub fn set_tag(&mut self, tag: ArenaHeaderTag) {
unsafe { (*self.header_ptr_mut()).set_tag(tag); }
}
#[inline]
pub fn get_tag(&self) -> ArenaHeaderTag {
unsafe { (*self.header_ptr()).get_tag() }
}
#[inline]
pub fn mark(&mut self) {
unsafe {
(*self.header_ptr_mut()).set_m(true);
}
}
#[inline]
pub fn unmark(&mut self) {
unsafe {
(*self.header_ptr_mut()).set_m(false);
}
}
}
pub trait ArenaAllocated {
type PtrToAllocated;
fn tag() -> ArenaHeaderTag;
fn size(&self) -> usize;
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated
where
Self: Sized;
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct F64Ptr(pub TypedArenaPtr<OrderedFloat<f64>>);
impl fmt::Display for F64Ptr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", *self)
}
}
impl Deref for F64Ptr {
type Target = TypedArenaPtr<OrderedFloat<f64>>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for F64Ptr {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl ArenaAllocated for OrderedFloat<f64> {
type PtrToAllocated = F64Ptr;
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::F64
}
#[inline]
fn size(&self) -> usize {
mem::size_of::<Self>()
}
#[inline]
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
unsafe {
ptr::write(dst, self);
F64Ptr(TypedArenaPtr::new(dst as *mut Self))
}
}
}
impl ArenaAllocated for Integer {
type PtrToAllocated = TypedArenaPtr<Integer>;
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::Integer
}
#[inline]
fn size(&self) -> usize {
mem::size_of::<Self>()
}
#[inline]
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
unsafe {
ptr::write(dst, self);
TypedArenaPtr::new(dst as *mut Self)
}
}
}
impl ArenaAllocated for Rational {
type PtrToAllocated = TypedArenaPtr<Rational>;
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::Rational
}
#[inline]
fn size(&self) -> usize {
mem::size_of::<Self>()
}
#[inline]
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
unsafe {
ptr::write(dst, self);
TypedArenaPtr::new(dst as *mut Self)
}
}
}
impl ArenaAllocated for OssifiedOpDir {
type PtrToAllocated = TypedArenaPtr<OssifiedOpDir>;
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::OssifiedOpDir
}
#[inline]
fn size(&self) -> usize {
mem::size_of::<Self>()
}
#[inline]
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
unsafe {
ptr::write(dst, self);
TypedArenaPtr::new(dst as *mut Self)
}
}
}
impl ArenaAllocated for LiveLoadState {
type PtrToAllocated = TypedArenaPtr<LiveLoadState>;
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::LiveLoadState
}
#[inline]
fn size(&self) -> usize {
mem::size_of::<Self>()
}
#[inline]
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
unsafe {
ptr::write(dst, self);
TypedArenaPtr::new(dst as *mut Self)
}
}
}
impl ArenaAllocated for TcpListener {
type PtrToAllocated = TypedArenaPtr<TcpListener>;
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::TcpListener
}
#[inline]
fn size(&self) -> usize {
mem::size_of::<Self>()
}
#[inline]
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
unsafe {
ptr::write(dst, self);
TypedArenaPtr::new(dst as *mut Self)
}
}
}
#[derive(Clone, Copy, Debug)]
struct AllocSlab {
next: *mut AllocSlab,
header: ArenaHeader,
}
#[derive(Debug)]
pub struct Arena(*mut AllocSlab);
unsafe impl Send for Arena {}
unsafe impl Sync for Arena {}
impl Arena {
#[inline]
pub fn new() -> Self {
Arena(ptr::null_mut())
}
pub unsafe fn alloc<T: ArenaAllocated>(&mut self, value: T) -> T::PtrToAllocated {
let size = value.size() + mem::size_of::<AllocSlab>();
let align = mem::align_of::<AllocSlab>();
let layout = alloc::Layout::from_size_align_unchecked(size, align);
let slab = alloc::alloc(layout) as *mut AllocSlab;
(*slab).next = self.0;
(*slab).header = ArenaHeader::build_with(value.size() as u64, T::tag());
let offset = (*slab).payload_offset();
let result = value.copy_to_arena(offset as *mut T);
self.0 = slab;
result
}
}
unsafe fn drop_slab_in_place(value: &mut AllocSlab) {
use crate::parser::char_reader::CharReader;
match value.header.tag() {
ArenaHeaderTag::Integer => {
ptr::drop_in_place(value.payload_offset::<Integer>());
}
ArenaHeaderTag::Rational => {
ptr::drop_in_place(value.payload_offset::<Rational>());
}
ArenaHeaderTag::InputFileStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<InputFileStream>>>());
}
ArenaHeaderTag::OutputFileStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<OutputFileStream>>());
}
ArenaHeaderTag::NamedTcpStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<NamedTcpStream>>>());
}
ArenaHeaderTag::NamedTlsStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<NamedTlsStream>>>());
}
ArenaHeaderTag::ReadlineStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<ReadlineStream>>());
}
ArenaHeaderTag::StaticStringStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<StaticStringStream>>());
}
ArenaHeaderTag::ByteStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<ByteStream>>>());
}
ArenaHeaderTag::OssifiedOpDir => {
ptr::drop_in_place(value.payload_offset::<OssifiedOpDir>());
}
ArenaHeaderTag::LiveLoadState | ArenaHeaderTag::InactiveLoadState => {
ptr::drop_in_place(value.payload_offset::<LiveLoadState>());
}
ArenaHeaderTag::Dropped => {
}
ArenaHeaderTag::TcpListener => {
ptr::drop_in_place(value.payload_offset::<TcpListener>());
}
ArenaHeaderTag::StandardOutputStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<StandardOutputStream>>());
}
ArenaHeaderTag::StandardErrorStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<StandardErrorStream>>());
}
ArenaHeaderTag::F64 | ArenaHeaderTag::NullStream => {
}
}
}
impl Drop for Arena {
fn drop(&mut self) {
let mut ptr = self.0;
while !ptr.is_null() {
unsafe {
let ptr_r = &*ptr;
let layout = alloc::Layout::from_size_align_unchecked(
ptr_r.slab_size(),
mem::align_of::<AllocSlab>(),
);
drop_slab_in_place(&mut *ptr);
let next_ptr = ptr_r.next;
alloc::dealloc(ptr as *mut u8, layout);
ptr = next_ptr;
}
}
self.0 = ptr::null_mut();
}
}
const_assert!(mem::size_of::<AllocSlab>() == 16);
impl AllocSlab {
#[inline]
fn slab_size(&self) -> usize {
self.header.size() as usize + mem::size_of::<AllocSlab>()
}
fn payload_offset<T>(&self) -> *mut T {
let mut ptr = (self as *const AllocSlab) as usize;
ptr += mem::size_of::<AllocSlab>();
ptr as *mut T
}
}
const_assert!(mem::size_of::<OrderedFloat<f64>>() == 8);
#[cfg(test)]
mod tests {
use crate::machine::mock_wam::*;
use crate::machine::partial_string::*;
use ordered_float::OrderedFloat;
use rug::{Integer, Rational};
#[test]
fn float_ptr_cast() {
let mut wam = MockWAM::new();
let f = OrderedFloat(0f64);
let mut fp = arena_alloc!(f, &mut wam.machine_st.arena);
let cell = HeapCellValue::from(fp);
assert_eq!(cell.get_tag(), HeapCellValueTag::F64);
assert_eq!(fp.get_mark_bit(), false);
assert_eq!(**fp, f);
fp.mark();
assert_eq!(fp.get_mark_bit(), true);
read_heap_cell!(cell,
(HeapCellValueTag::F64, ptr) => {
assert_eq!(**ptr, f)
}
_ => { unreachable!() }
);
}
#[test]
fn heap_cell_value_const_cast() {
let mut wam = MockWAM::new();
let const_value = HeapCellValue::from(ConsPtr::build_with(
0x0000_5555_ff00_0431 as *const _,
ConsPtrMaskTag::Cons,
));
match const_value.to_untyped_arena_ptr() {
Some(arena_ptr) => {
assert_eq!(arena_ptr.into_bytes(), const_value.into_bytes());
}
None => {
assert!(false);
}
}
let stream = Stream::from_static_string("test", &mut wam.machine_st.arena);
let stream_cell =
HeapCellValue::from(ConsPtr::build_with(stream.as_ptr(), ConsPtrMaskTag::Cons));
match stream_cell.to_untyped_arena_ptr() {
Some(arena_ptr) => {
assert_eq!(arena_ptr.into_bytes(), stream_cell.into_bytes());
}
None => {
assert!(false);
}
}
}
#[test]
fn heap_put_literal_tests() {
let mut wam = MockWAM::new();
// integer
let big_int = 2 * Integer::from(1u64 << 63);
let big_int_ptr: TypedArenaPtr<Integer> = arena_alloc!(big_int, &mut wam.machine_st.arena);
assert!(!big_int_ptr.as_ptr().is_null());
let cell = HeapCellValue::from(Literal::Integer(big_int_ptr));
assert_eq!(cell.get_tag(), HeapCellValueTag::Cons);
let untyped_arena_ptr = match cell.to_untyped_arena_ptr() {
Some(ptr) => ptr,
None => {
assert!(false);
unreachable!()
}
};
match_untyped_arena_ptr!(untyped_arena_ptr,
(ArenaHeaderTag::Integer, n) => {
assert_eq!(&*n, &(2 * Integer::from(1u64 << 63)))
}
_ => unreachable!()
);
read_heap_cell!(cell,
(HeapCellValueTag::Cons, cons_ptr) => {
match_untyped_arena_ptr!(cons_ptr,
(ArenaHeaderTag::Integer, n) => {
assert_eq!(&*n, &(2 * Integer::from(1u64 << 63)))
}
_ => { unreachable!() }
)
}
_ => { unreachable!() }
);
// rational
let big_rat = 2 * Rational::from(1u64 << 63);
let big_rat_ptr: TypedArenaPtr<Rational> = arena_alloc!(big_rat, &mut wam.machine_st.arena);
assert!(!big_rat_ptr.as_ptr().is_null());
let rat_cell = typed_arena_ptr_as_cell!(big_rat_ptr);
assert_eq!(cell.get_tag(), HeapCellValueTag::Cons);
match rat_cell.to_untyped_arena_ptr() {
Some(untyped_arena_ptr) => {
assert_eq!(
Some(big_rat_ptr.header_ptr()),
Some(untyped_arena_ptr.into()),
);
}
None => {
assert!(false); // we fail.
}
}
// assert_eq!(wam.machine_st.heap[1usize].get_tag(), HeapCellValueTag::Cons);
read_heap_cell!(rat_cell,
(HeapCellValueTag::Cons, cons_ptr) => {
match_untyped_arena_ptr!(cons_ptr,
(ArenaHeaderTag::Rational, n) => {
assert_eq!(&*n, &(2 * Rational::from(1u64 << 63)));
}
_ => unreachable!()
)
}
_ => { unreachable!() }
);
// atom
let f_atom = atom!("f");
let g_atom = atom!("g");
assert_eq!(f_atom.as_str(), "f");
assert_eq!(g_atom.as_str(), "g");
let f_atom_cell = atom_as_cell!(f_atom);
let g_atom_cell = atom_as_cell!(g_atom);
assert_eq!(f_atom_cell.get_tag(), HeapCellValueTag::Atom);
match f_atom_cell.to_atom() {
Some(atom) => {
assert_eq!(f_atom, atom);
assert_eq!(atom.as_str(), "f");
}
None => {
assert!(false);
}
}
read_heap_cell!(f_atom_cell,
(HeapCellValueTag::Atom, (atom, arity)) => {
assert_eq!(f_atom, atom);
assert_eq!(arity, 0);
assert_eq!(atom.as_str(), "f");
}
_ => { unreachable!() }
);
read_heap_cell!(g_atom_cell,
(HeapCellValueTag::Atom, (atom, arity)) => {
assert_eq!(g_atom, atom);
assert_eq!(arity, 0);
assert_eq!(atom.as_str(), "g");
}
_ => { unreachable!() }
);
// complete string
let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "ronan", &mut wam.machine_st.atom_tbl);
let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
assert_eq!(pstr_cell.get_tag(), HeapCellValueTag::PStr);
match pstr_cell.to_pstr() {
Some(pstr) => {
assert_eq!(pstr.as_str_from(0), "ronan");
}
None => {
assert!(false);
}
}
read_heap_cell!(pstr_cell,
(HeapCellValueTag::PStr, pstr_atom) => {
let pstr = PartialString::from(pstr_atom);
assert_eq!(pstr.as_str_from(0), "ronan");
}
_ => { unreachable!() }
);
// fixnum
let fixnum_cell = fixnum_as_cell!(Fixnum::build_with(3));
assert_eq!(fixnum_cell.get_tag(), HeapCellValueTag::Fixnum);
match fixnum_cell.to_fixnum() {
Some(n) => assert_eq!(n.get_num(), 3),
None => assert!(false),
}
read_heap_cell!(fixnum_cell,
(HeapCellValueTag::Fixnum, n) => {
assert_eq!(n.get_num(), 3);
}
_ => { unreachable!() }
);
let fixnum_b_cell = fixnum_as_cell!(Fixnum::build_with(1 << 55));
assert_eq!(fixnum_b_cell.get_tag(), HeapCellValueTag::Fixnum);
match fixnum_b_cell.to_fixnum() {
Some(n) => assert_eq!(n.get_num(), 1 << 55),
None => assert!(false),
}
match Fixnum::build_with_checked(1 << 57) {
Ok(_) => assert!(false),
_ => assert!(true),
}
match Fixnum::build_with_checked(i64::MAX) {
Ok(_) => assert!(false),
_ => assert!(true),
}
match Fixnum::build_with_checked(i64::MIN) {
Ok(_) => assert!(false),
_ => assert!(true),
}
match Fixnum::build_with_checked(-1) {
Ok(n) => assert_eq!(n.get_num(), -1),
_ => assert!(false),
}
match Fixnum::build_with_checked((1 << 56) - 1) {
Ok(n) => assert_eq!(n.get_num(), (1 << 56) - 1),
_ => assert!(false),
}
match Fixnum::build_with_checked(-(1 << 56)) {
Ok(n) => assert_eq!(n.get_num(), -(1 << 56)),
_ => assert!(false),
}
match Fixnum::build_with_checked(-(1 << 56) - 1) {
Ok(_n) => assert!(false),
_ => assert!(true),
}
match Fixnum::build_with_checked(-1) {
Ok(n) => assert_eq!(-n, Fixnum::build_with(1)),
_ => assert!(false),
}
// float
let float = OrderedFloat(3.1415926f64);
let float_ptr = arena_alloc!(float, &mut wam.machine_st.arena);
assert!(!float_ptr.as_ptr().is_null());
let float_cell = typed_arena_ptr_as_cell!(float_ptr);
assert_eq!(cell.get_tag(), HeapCellValueTag::Cons);
match float_cell.to_untyped_arena_ptr() {
Some(untyped_arena_ptr) => {
assert_eq!(Some(float_ptr.header_ptr()), Some(untyped_arena_ptr.into()),);
}
None => {
assert!(false); // we fail.
}
}
// char
let c = 'c';
let char_cell = char_as_cell!(c);
read_heap_cell!(char_cell,
(HeapCellValueTag::Char, c) => {
assert_eq!(c, 'c');
}
_ => { unreachable!() }
);
let c = 'Ћ';
let cyrillic_char_cell = char_as_cell!(c);
read_heap_cell!(cyrillic_char_cell,
(HeapCellValueTag::Char, c) => {
assert_eq!(c, 'Ћ');
}
_ => { unreachable!() }
);
// empty list
let cell = empty_list_as_cell!();
read_heap_cell!(cell,
(HeapCellValueTag::Atom, (el, _arity)) => {
assert_eq!(el.flat_index() as usize, empty_list_as_cell!().get_value());
assert_eq!(el.as_str(), "[]");
}
_ => { unreachable!() }
);
}
}

View File

@@ -1,18 +1,18 @@
use prolog_parser::ast::*; use crate::arena::*;
use prolog_parser::{atom, clause_name}; use crate::atom_table::*;
use crate::clause_types::*;
use crate::fixtures::*; use crate::fixtures::*;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*; use crate::instructions::*;
use crate::iterators::*; use crate::iterators::*;
use crate::types::*;
use crate::parser::ast::*;
use crate::parser::rug::ops::PowAssign;
use crate::parser::rug::{Assign, Integer, Rational};
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::rug::ops::PowAssign;
use crate::rug::{Assign, Integer, Rational};
use ordered_float::*; use ordered_float::*;
use std::cell::Cell; use std::cell::Cell;
@@ -20,10 +20,33 @@ use std::cmp::{max, min, Ordering};
use std::convert::TryFrom; use std::convert::TryFrom;
use std::f64; use std::f64;
use std::num::FpCategory; use std::num::FpCategory;
use std::ops::{Add, Div, Mul, Neg, Sub}; use std::ops::Div;
use std::rc::Rc; use std::rc::Rc;
use std::vec::Vec; use std::vec::Vec;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ArithmeticTerm {
Reg(RegType),
Interm(usize),
Number(Number),
}
impl ArithmeticTerm {
pub(crate) fn interm_or(&self, interm: usize) -> usize {
if let &ArithmeticTerm::Interm(interm) = self {
interm
} else {
interm
}
}
}
impl Default for ArithmeticTerm {
fn default() -> Self {
ArithmeticTerm::Number(Number::default())
}
}
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct ArithInstructionIterator<'a> { pub(crate) struct ArithInstructionIterator<'a> {
state_stack: Vec<TermIterState<'a>>, state_stack: Vec<TermIterState<'a>>,
@@ -37,31 +60,30 @@ impl<'a> ArithInstructionIterator<'a> {
.push(TermIterState::subterm_to_state(lvl, term)); .push(TermIterState::subterm_to_state(lvl, term));
} }
fn new(term: &'a Term) -> Result<Self, ArithmeticError> { fn from(term: &'a Term) -> Result<Self, ArithmeticError> {
let state = match term { let state = match term {
&Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar), Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar),
&Term::Clause(ref cell, ref name, ref terms, ref fixity) => { Term::Clause(cell, name, terms) => match ClauseType::from(*name, terms.len()) {
match ClauseType::from(name.clone(), terms.len(), fixity.clone()) { ct @ ClauseType::Named(..) => {
ct @ ClauseType::Named(..) | ct @ ClauseType::Op(..) => {
Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms)) Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
} }
ClauseType::Inlined(InlinedClauseType::IsFloat(_)) => { ClauseType::Inlined(InlinedClauseType::IsFloat(_)) => {
let ct = ClauseType::Named(clause_name!("float"), 1, CodeIndex::default()); let ct = ClauseType::Named(1, atom!("float"), CodeIndex::default());
Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms)) Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
} }
_ => Err(ArithmeticError::NonEvaluableFunctor( _ => Err(ArithmeticError::NonEvaluableFunctor(
Constant::Atom(name.clone(), fixity.clone()), Literal::Atom(*name),
terms.len(), terms.len(),
)), )),
}? }?,
Term::Literal(cell, cons) => TermIterState::Literal(Level::Shallow, cell, cons),
Term::Cons(..) | Term::PartialString(..) => {
return Err(ArithmeticError::NonEvaluableFunctor(
Literal::Atom(atom!(".")),
2,
))
} }
&Term::Constant(ref cell, ref cons) => { Term::Var(cell, var) => TermIterState::Var(Level::Shallow, cell, var.clone()),
TermIterState::Constant(Level::Shallow, cell, cons)
}
&Term::Cons(_, _, _) => {
return Err(ArithmeticError::NonEvaluableFunctor(atom!("'.'"), 2))
}
&Term::Var(ref cell, ref var) => TermIterState::Var(Level::Shallow, cell, var.clone()),
}; };
Ok(ArithInstructionIterator { Ok(ArithInstructionIterator {
@@ -72,9 +94,9 @@ impl<'a> ArithInstructionIterator<'a> {
#[derive(Debug)] #[derive(Debug)]
pub(crate) enum ArithTermRef<'a> { pub(crate) enum ArithTermRef<'a> {
Constant(&'a Constant), Literal(&'a Literal),
Op(ClauseName, usize), // name, arity. Op(Atom, usize), // name, arity.
Var(&'a Cell<VarReg>, Rc<Var>), Var(&'a Cell<VarReg>, Rc<String>),
} }
impl<'a> Iterator for ArithInstructionIterator<'a> { impl<'a> Iterator for ArithInstructionIterator<'a> {
@@ -97,14 +119,20 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
ct, ct,
subterms, subterms,
)); ));
self.push_subterm(lvl, subterms[child_num].as_ref());
self.push_subterm(lvl, &subterms[child_num]);
} }
} }
TermIterState::Constant(_, _, c) => return Some(Ok(ArithTermRef::Constant(c))), TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(c))),
TermIterState::Var(_, cell, var) => { TermIterState::Var(_, cell, var) => {
return Some(Ok(ArithTermRef::Var(cell, var.clone()))) return Some(Ok(ArithTermRef::Var(cell, var.clone())));
}
_ => {
return Some(Err(ArithmeticError::NonEvaluableFunctor(
Literal::Atom(atom!(".")),
2,
)));
} }
_ => return Some(Err(ArithmeticError::NonEvaluableFunctor(atom!("'.'"), 2))),
}; };
} }
@@ -129,10 +157,31 @@ impl<'a> ArithmeticTermIter<'a> for &'a Term {
type Iter = ArithInstructionIterator<'a>; type Iter = ArithInstructionIterator<'a>;
fn iter(self) -> Result<Self::Iter, ArithmeticError> { fn iter(self) -> Result<Self::Iter, ArithmeticError> {
ArithInstructionIterator::new(self) ArithInstructionIterator::from(self)
} }
} }
fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: &Literal) -> Result<(), ArithmeticError> {
match c {
Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(*n))),
Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(*n))),
Literal::Float(n) => interm.push(ArithmeticTerm::Number(Number::Float(***n))),
Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(*n))),
Literal::Atom(name) if name == &atom!("e") => interm.push(ArithmeticTerm::Number(
Number::Float(OrderedFloat(f64::consts::E)),
)),
Literal::Atom(name) if name == &atom!("pi") => interm.push(ArithmeticTerm::Number(
Number::Float(OrderedFloat(f64::consts::PI)),
)),
Literal::Atom(name) if name == &atom!("epsilon") => interm.push(ArithmeticTerm::Number(
Number::Float(OrderedFloat(f64::EPSILON)),
)),
_ => return Err(ArithmeticError::NonEvaluableFunctor(*c, 0)),
}
Ok(())
}
impl<'a> ArithmeticEvaluator<'a> { impl<'a> ArithmeticEvaluator<'a> {
pub(crate) fn new(bindings: &'a AllocVarDict, target_int: usize) -> Self { pub(crate) fn new(bindings: &'a AllocVarDict, target_int: usize) -> Self {
ArithmeticEvaluator { ArithmeticEvaluator {
@@ -143,68 +192,64 @@ impl<'a> ArithmeticEvaluator<'a> {
} }
fn get_unary_instr( fn get_unary_instr(
name: ClauseName, &self,
name: Atom,
a1: ArithmeticTerm, a1: ArithmeticTerm,
t: usize, t: usize,
) -> Result<ArithmeticInstruction, ArithmeticError> { ) -> Result<Instruction, ArithmeticError> {
match name.as_str() { match name {
"abs" => Ok(ArithmeticInstruction::Abs(a1, t)), atom!("abs") => Ok(Instruction::Abs(a1, t)),
"-" => Ok(ArithmeticInstruction::Neg(a1, t)), atom!("-") => Ok(Instruction::Neg(a1, t)),
"+" => Ok(ArithmeticInstruction::Plus(a1, t)), atom!("+") => Ok(Instruction::Plus(a1, t)),
"cos" => Ok(ArithmeticInstruction::Cos(a1, t)), atom!("cos") => Ok(Instruction::Cos(a1, t)),
"sin" => Ok(ArithmeticInstruction::Sin(a1, t)), atom!("sin") => Ok(Instruction::Sin(a1, t)),
"tan" => Ok(ArithmeticInstruction::Tan(a1, t)), atom!("tan") => Ok(Instruction::Tan(a1, t)),
"log" => Ok(ArithmeticInstruction::Log(a1, t)), atom!("log") => Ok(Instruction::Log(a1, t)),
"exp" => Ok(ArithmeticInstruction::Exp(a1, t)), atom!("exp") => Ok(Instruction::Exp(a1, t)),
"sqrt" => Ok(ArithmeticInstruction::Sqrt(a1, t)), atom!("sqrt") => Ok(Instruction::Sqrt(a1, t)),
"acos" => Ok(ArithmeticInstruction::ACos(a1, t)), atom!("acos") => Ok(Instruction::ACos(a1, t)),
"asin" => Ok(ArithmeticInstruction::ASin(a1, t)), atom!("asin") => Ok(Instruction::ASin(a1, t)),
"atan" => Ok(ArithmeticInstruction::ATan(a1, t)), atom!("atan") => Ok(Instruction::ATan(a1, t)),
"float" => Ok(ArithmeticInstruction::Float(a1, t)), atom!("float") => Ok(Instruction::Float(a1, t)),
"truncate" => Ok(ArithmeticInstruction::Truncate(a1, t)), atom!("truncate") => Ok(Instruction::Truncate(a1, t)),
"round" => Ok(ArithmeticInstruction::Round(a1, t)), atom!("round") => Ok(Instruction::Round(a1, t)),
"ceiling" => Ok(ArithmeticInstruction::Ceiling(a1, t)), atom!("ceiling") => Ok(Instruction::Ceiling(a1, t)),
"floor" => Ok(ArithmeticInstruction::Floor(a1, t)), atom!("floor") => Ok(Instruction::Floor(a1, t)),
"sign" => Ok(ArithmeticInstruction::Sign(a1, t)), atom!("sign") => Ok(Instruction::Sign(a1, t)),
"\\" => Ok(ArithmeticInstruction::BitwiseComplement(a1, t)), atom!("\\") => Ok(Instruction::BitwiseComplement(a1, t)),
_ => Err(ArithmeticError::NonEvaluableFunctor( _ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 1)),
Constant::Atom(name, None),
1,
)),
} }
} }
fn get_binary_instr( fn get_binary_instr(
name: ClauseName, &self,
name: Atom,
a1: ArithmeticTerm, a1: ArithmeticTerm,
a2: ArithmeticTerm, a2: ArithmeticTerm,
t: usize, t: usize,
) -> Result<ArithmeticInstruction, ArithmeticError> { ) -> Result<Instruction, ArithmeticError> {
match name.as_str() { match name {
"+" => Ok(ArithmeticInstruction::Add(a1, a2, t)), atom!("+") => Ok(Instruction::Add(a1, a2, t)),
"-" => Ok(ArithmeticInstruction::Sub(a1, a2, t)), atom!("-") => Ok(Instruction::Sub(a1, a2, t)),
"/" => Ok(ArithmeticInstruction::Div(a1, a2, t)), atom!("/") => Ok(Instruction::Div(a1, a2, t)),
"//" => Ok(ArithmeticInstruction::IDiv(a1, a2, t)), atom!("//") => Ok(Instruction::IDiv(a1, a2, t)),
"max" => Ok(ArithmeticInstruction::Max(a1, a2, t)), atom!("max") => Ok(Instruction::Max(a1, a2, t)),
"min" => Ok(ArithmeticInstruction::Min(a1, a2, t)), atom!("min") => Ok(Instruction::Min(a1, a2, t)),
"div" => Ok(ArithmeticInstruction::IntFloorDiv(a1, a2, t)), atom!("div") => Ok(Instruction::IntFloorDiv(a1, a2, t)),
"rdiv" => Ok(ArithmeticInstruction::RDiv(a1, a2, t)), atom!("rdiv") => Ok(Instruction::RDiv(a1, a2, t)),
"*" => Ok(ArithmeticInstruction::Mul(a1, a2, t)), atom!("*") => Ok(Instruction::Mul(a1, a2, t)),
"**" => Ok(ArithmeticInstruction::Pow(a1, a2, t)), atom!("**") => Ok(Instruction::Pow(a1, a2, t)),
"^" => Ok(ArithmeticInstruction::IntPow(a1, a2, t)), atom!("^") => Ok(Instruction::IntPow(a1, a2, t)),
">>" => Ok(ArithmeticInstruction::Shr(a1, a2, t)), atom!(">>") => Ok(Instruction::Shr(a1, a2, t)),
"<<" => Ok(ArithmeticInstruction::Shl(a1, a2, t)), atom!("<<") => Ok(Instruction::Shl(a1, a2, t)),
"/\\" => Ok(ArithmeticInstruction::And(a1, a2, t)), atom!("/\\") => Ok(Instruction::And(a1, a2, t)),
"\\/" => Ok(ArithmeticInstruction::Or(a1, a2, t)), atom!("\\/") => Ok(Instruction::Or(a1, a2, t)),
"xor" => Ok(ArithmeticInstruction::Xor(a1, a2, t)), atom!("xor") => Ok(Instruction::Xor(a1, a2, t)),
"mod" => Ok(ArithmeticInstruction::Mod(a1, a2, t)), atom!("mod") => Ok(Instruction::Mod(a1, a2, t)),
"rem" => Ok(ArithmeticInstruction::Rem(a1, a2, t)), atom!("rem") => Ok(Instruction::Rem(a1, a2, t)),
"gcd" => Ok(ArithmeticInstruction::Gcd(a1, a2, t)), atom!("gcd") => Ok(Instruction::Gcd(a1, a2, t)),
"atan2" => Ok(ArithmeticInstruction::ATan2(a1, a2, t)), atom!("atan2") => Ok(Instruction::ATan2(a1, a2, t)),
_ => Err(ArithmeticError::NonEvaluableFunctor( _ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 2)),
Constant::Atom(name, None),
2,
)),
} }
} }
@@ -219,9 +264,9 @@ impl<'a> ArithmeticEvaluator<'a> {
fn instr_from_clause( fn instr_from_clause(
&mut self, &mut self,
name: ClauseName, name: Atom,
arity: usize, arity: usize,
) -> Result<ArithmeticInstruction, ArithmeticError> { ) -> Result<Instruction, ArithmeticError> {
match arity { match arity {
1 => { 1 => {
let a1 = self.interm.pop().unwrap(); let a1 = self.interm.pop().unwrap();
@@ -233,7 +278,7 @@ impl<'a> ArithmeticEvaluator<'a> {
a1.interm_or(0) a1.interm_or(0)
}; };
Self::get_unary_instr(name, a1, ninterm) self.get_unary_instr(name, a1, ninterm)
} }
2 => { 2 => {
let a2 = self.interm.pop().unwrap(); let a2 = self.interm.pop().unwrap();
@@ -257,60 +302,22 @@ impl<'a> ArithmeticEvaluator<'a> {
min_interm min_interm
}; };
Self::get_binary_instr(name, a1, a2, ninterm) self.get_binary_instr(name, a1, a2, ninterm)
} }
_ => Err(ArithmeticError::NonEvaluableFunctor( _ => Err(ArithmeticError::NonEvaluableFunctor(
Constant::Atom(name, None), Literal::Atom(name),
arity, arity,
)), )),
} }
} }
fn push_constant(&mut self, c: &Constant) -> Result<(), ArithmeticError> { pub(crate) fn eval(&mut self, src: &'a Term) -> Result<ArithCont, ArithmeticError> {
match c {
&Constant::Fixnum(n) => self.interm.push(ArithmeticTerm::Number(Number::Fixnum(n))),
&Constant::Integer(ref n) => self
.interm
.push(ArithmeticTerm::Number(Number::Integer(n.clone()))),
&Constant::Float(ref n) => self
.interm
.push(ArithmeticTerm::Number(Number::Float(n.clone()))),
&Constant::Rational(ref n) => self
.interm
.push(ArithmeticTerm::Number(Number::Rational(n.clone()))),
&Constant::Atom(ref name, _) if name.as_str() == "e" => {
self.interm
.push(ArithmeticTerm::Number(Number::Float(OrderedFloat(
f64::consts::E,
))))
}
&Constant::Atom(ref name, _) if name.as_str() == "pi" => {
self.interm
.push(ArithmeticTerm::Number(Number::Float(OrderedFloat(
f64::consts::PI,
))))
}
&Constant::Atom(ref name, _) if name.as_str() == "epsilon" => {
self.interm
.push(ArithmeticTerm::Number(Number::Float(OrderedFloat(
f64::EPSILON,
))))
}
_ => return Err(ArithmeticError::NonEvaluableFunctor(c.clone(), 0)),
}
Ok(())
}
pub(crate) fn eval<Iter>(&mut self, src: Iter) -> Result<ArithCont, ArithmeticError>
where
Iter: ArithmeticTermIter<'a>,
{
let mut code = vec![]; let mut code = vec![];
let mut iter = src.iter()?;
for term_ref in src.iter()? { while let Some(term_ref) = iter.next() {
match term_ref? { match term_ref? {
ArithTermRef::Constant(c) => self.push_constant(c)?, ArithTermRef::Literal(c) => push_literal(&mut self.interm, c)?,
ArithTermRef::Var(cell, name) => { ArithTermRef::Var(cell, name) => {
let r = if cell.get().norm().reg_num() == 0 { let r = if cell.get().norm().reg_num() == 0 {
match self.bindings.get(&name) { match self.bindings.get(&name) {
@@ -325,7 +332,7 @@ impl<'a> ArithmeticEvaluator<'a> {
self.interm.push(ArithmeticTerm::Reg(r)); self.interm.push(ArithmeticTerm::Reg(r));
} }
ArithTermRef::Op(name, arity) => { ArithTermRef::Op(name, arity) => {
code.push(Line::Arithmetic(self.instr_from_clause(name, arity)?)); code.push(self.instr_from_clause(name, arity)?);
} }
} }
} }
@@ -335,27 +342,31 @@ impl<'a> ArithmeticEvaluator<'a> {
} }
// integer division rounding function -- 9.1.3.1. // integer division rounding function -- 9.1.3.1.
pub(crate) fn rnd_i<'a>(n: &'a Number) -> RefOrOwned<'a, Number> { pub(crate) fn rnd_i<'a>(n: &'a Number, arena: &mut Arena) -> Number {
match n { match n {
&Number::Integer(_) => RefOrOwned::Borrowed(n), &Number::Integer(_) | &Number::Fixnum(_) => *n,
&Number::Float(OrderedFloat(f)) => RefOrOwned::Owned(Number::from( &Number::Float(OrderedFloat(f)) => fixnum!(Number, f.round() as i64, arena),
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());
(&mut fract, &mut floor).assign(r_ref); (&mut fract, &mut floor).assign(r_ref);
RefOrOwned::Owned(Number::from(floor)) Number::Integer(arena_alloc!(floor, arena))
} }
} }
} }
impl From<Fixnum> for Integer {
#[inline]
fn from(n: Fixnum) -> Integer {
Integer::from(n.get_num())
}
}
// floating point rounding function -- 9.1.4.1. // floating point rounding function -- 9.1.4.1.
pub(crate) 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.get_num() as f64,
&Number::Integer(ref n) => n.to_f64(), &Number::Integer(ref n) => n.to_f64(),
&Number::Float(OrderedFloat(f)) => f, &Number::Float(OrderedFloat(f)) => f,
&Number::Rational(ref r) => r.to_f64(), &Number::Rational(ref r) => r.to_f64(),
@@ -392,27 +403,27 @@ where
} }
#[inline] #[inline]
fn float_fn_to_f(n: isize) -> Result<f64, EvalError> { pub(crate) fn float_fn_to_f(n: i64) -> Result<f64, EvalError> {
classify_float(n as f64, rnd_f) classify_float(n as f64, rnd_f)
} }
#[inline] #[inline]
fn float_i_to_f(n: &Integer) -> Result<f64, EvalError> { pub(crate) fn float_i_to_f(n: &Integer) -> Result<f64, EvalError> {
classify_float(n.to_f64(), rnd_f) classify_float(n.to_f64(), rnd_f)
} }
#[inline] #[inline]
fn float_r_to_f(r: &Rational) -> Result<f64, EvalError> { pub(crate) fn float_r_to_f(r: &Rational) -> Result<f64, EvalError> {
classify_float(r.to_f64(), rnd_f) classify_float(r.to_f64(), rnd_f)
} }
#[inline] #[inline]
fn add_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> { pub(crate) fn add_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
Ok(OrderedFloat(classify_float(f1 + f2, rnd_f)?)) Ok(OrderedFloat(classify_float(f1 + f2, rnd_f)?))
} }
#[inline] #[inline]
fn mul_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> { pub(crate) fn mul_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
Ok(OrderedFloat(classify_float(f1 * f2, rnd_f)?)) Ok(OrderedFloat(classify_float(f1 * f2, rnd_f)?))
} }
@@ -425,161 +436,36 @@ fn div_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
} }
} }
impl Add<Number> for Number {
type Output = Result<Number, EvalError>;
fn add(self, rhs: Number) -> Self::Output {
match (self, rhs) {
(Number::Fixnum(n1), Number::Fixnum(n2)) => {
Ok(if let Some(result) = n1.checked_add(n2) {
Number::Fixnum(result)
} else {
Number::from(Integer::from(n1) + Integer::from(n2))
})
}
(Number::Fixnum(n1), Number::Integer(n2))
| (Number::Integer(n2), Number::Fixnum(n1)) => {
Ok(Number::from(Integer::from(n1) + &*n2))
}
(Number::Fixnum(n1), Number::Rational(n2))
| (Number::Rational(n2), Number::Fixnum(n1)) => {
Ok(Number::from(Rational::from(n1) + &*n2))
}
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2)))
| (Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => {
Ok(Number::Float(add_f(float_fn_to_f(n1)?, n2)?))
}
(Number::Integer(n1), Number::Integer(n2)) => {
Ok(Number::from(Integer::from(&*n1) + &*n2)) // add_i
}
(Number::Integer(n1), Number::Float(OrderedFloat(n2)))
| (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
Ok(Number::Float(add_f(float_i_to_f(&n1)?, n2)?))
}
(Number::Integer(n1), Number::Rational(n2))
| (Number::Rational(n2), Number::Integer(n1)) => {
Ok(Number::from(Rational::from(&*n1) + &*n2))
}
(Number::Rational(n1), Number::Float(OrderedFloat(n2)))
| (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
Ok(Number::Float(add_f(float_r_to_f(&n1)?, n2)?))
}
(Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => {
Ok(Number::Float(add_f(f1, f2)?))
}
(Number::Rational(r1), Number::Rational(r2)) => {
Ok(Number::from(Rational::from(&*r1) + &*r2))
}
}
}
}
impl Neg for Number {
type Output = Number;
fn neg(self) -> Self::Output {
match self {
Number::Fixnum(n) => {
if let Some(n) = n.checked_neg() {
Number::Fixnum(n)
} else {
Number::from(-Integer::from(n))
}
}
Number::Integer(n) => Number::Integer(Rc::new(-Integer::from(&*n))),
Number::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)),
Number::Rational(r) => Number::Rational(Rc::new(-Rational::from(&*r))),
}
}
}
impl Sub<Number> for Number {
type Output = Result<Number, EvalError>;
fn sub(self, rhs: Number) -> Self::Output {
self.add(-rhs)
}
}
impl Mul<Number> for Number {
type Output = Result<Number, EvalError>;
fn mul(self, rhs: Number) -> Self::Output {
match (self, rhs) {
(Number::Fixnum(n1), Number::Fixnum(n2)) => {
Ok(if let Some(result) = n1.checked_mul(n2) {
Number::Fixnum(result)
} else {
Number::from(Integer::from(n1) * Integer::from(n2))
})
}
(Number::Fixnum(n1), Number::Integer(n2))
| (Number::Integer(n2), Number::Fixnum(n1)) => {
Ok(Number::from(Integer::from(n1) * &*n2))
}
(Number::Fixnum(n1), Number::Rational(n2))
| (Number::Rational(n2), Number::Fixnum(n1)) => {
Ok(Number::from(Rational::from(n1) * &*n2))
}
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2)))
| (Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => {
Ok(Number::Float(mul_f(float_fn_to_f(n1)?, n2)?))
}
(Number::Integer(n1), Number::Integer(n2)) => {
Ok(Number::Integer(Rc::new(Integer::from(&*n1) * &*n2))) // mul_i
}
(Number::Integer(n1), Number::Float(OrderedFloat(n2)))
| (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
Ok(Number::Float(mul_f(float_i_to_f(&n1)?, n2)?))
}
(Number::Integer(n1), Number::Rational(n2))
| (Number::Rational(n2), Number::Integer(n1)) => {
Ok(Number::Rational(Rc::new(Rational::from(&*n1) * &*n2)))
}
(Number::Rational(n1), Number::Float(OrderedFloat(n2)))
| (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
Ok(Number::Float(mul_f(float_r_to_f(&n1)?, n2)?))
}
(Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => {
Ok(Number::Float(mul_f(f1, f2)?))
}
(Number::Rational(r1), Number::Rational(r2)) => {
Ok(Number::Rational(Rc::new(Rational::from(&*r1) * &*r2)))
}
}
}
}
impl Div<Number> for Number { impl Div<Number> for Number {
type Output = Result<Number, EvalError>; type Output = Result<Number, EvalError>;
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)) => Ok(Number::Float(div_f( (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f(
float_fn_to_f(n1)?, float_fn_to_f(n1.get_num())?,
float_fn_to_f(n2)?, float_fn_to_f(n2.get_num())?,
)?)), )?)),
(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.get_num())?,
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.get_num())?,
)?)), )?)),
(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.get_num())?,
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.get_num())?,
)?)), )?)),
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) => { (Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) => {
Ok(Number::Float(div_f(float_fn_to_f(n1)?, n2)?)) Ok(Number::Float(div_f(float_fn_to_f(n1.get_num())?, n2)?))
} }
(Number::Float(OrderedFloat(n1)), Number::Fixnum(n2)) => { (Number::Float(OrderedFloat(n1)), Number::Fixnum(n2)) => {
Ok(Number::Float(div_f(n1, float_fn_to_f(n2)?)?)) Ok(Number::Float(div_f(n1, float_fn_to_f(n2.get_num())?)?))
} }
(Number::Integer(n1), Number::Integer(n2)) => Ok(Number::Float(div_f( (Number::Integer(n1), Number::Integer(n2)) => Ok(Number::Float(div_f(
float_i_to_f(&n1)?, float_i_to_f(&n1)?,
@@ -620,14 +506,14 @@ impl PartialEq for Number {
fn eq(&self, rhs: &Self) -> bool { fn eq(&self, rhs: &Self) -> bool {
match (self, rhs) { match (self, rhs) {
(&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.eq(&n2), (&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.eq(&n2),
(&Number::Fixnum(n1), &Number::Integer(ref n2)) => n1.eq(&**n2), (&Number::Fixnum(n1), &Number::Integer(ref n2)) => n1.get_num().eq(&**n2),
(&Number::Integer(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2), (&Number::Integer(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2.get_num()),
(&Number::Fixnum(n1), &Number::Rational(ref n2)) => n1.eq(&**n2), (&Number::Fixnum(n1), &Number::Rational(ref n2)) => n1.get_num().eq(&**n2),
(&Number::Rational(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2), (&Number::Rational(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2.get_num()),
(&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1 as f64).eq(&n2), (&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1.get_num() as f64).eq(&n2),
(&Number::Float(n1), &Number::Fixnum(n2)) => n1.eq(&OrderedFloat(n2 as f64)), (&Number::Float(n1), &Number::Fixnum(n2)) => n1.eq(&OrderedFloat(n2.get_num() as f64)),
(&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.eq(n2), (&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.eq(n2),
(&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).eq(&n2), (&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).eq(n2),
(&Number::Float(n1), &Number::Integer(ref n2)) => n1.eq(&OrderedFloat(n2.to_f64())), (&Number::Float(n1), &Number::Integer(ref n2)) => n1.eq(&OrderedFloat(n2.to_f64())),
(&Number::Integer(ref n1), &Number::Rational(ref n2)) => { (&Number::Integer(ref n1), &Number::Rational(ref n2)) => {
#[cfg(feature = "num")] #[cfg(feature = "num")]
@@ -659,6 +545,46 @@ impl PartialEq for Number {
impl Eq for Number {} impl Eq for Number {}
impl PartialOrd<usize> for Number {
#[inline]
fn partial_cmp(&self, rhs: &usize) -> Option<Ordering> {
match self {
Number::Fixnum(n) => {
let n = n.get_num();
if n < 0i64 {
Some(Ordering::Less)
} else {
(n as usize).partial_cmp(rhs)
}
}
Number::Integer(n) => (&**n).partial_cmp(rhs),
Number::Rational(r) => (&**r).partial_cmp(rhs),
Number::Float(f) => f.partial_cmp(&OrderedFloat(*rhs as f64)),
}
}
}
impl PartialEq<usize> for Number {
#[inline]
fn eq(&self, rhs: &usize) -> bool {
match self {
Number::Fixnum(n) => {
let n = n.get_num();
if n < 0i64 {
false
} else {
(n as usize).eq(rhs)
}
}
Number::Integer(n) => (&**n).eq(rhs),
Number::Rational(r) => (&**r).eq(rhs),
Number::Float(f) => f.eq(&OrderedFloat(*rhs as f64)),
}
}
}
impl PartialOrd for Number { impl PartialOrd for Number {
fn partial_cmp(&self, rhs: &Number) -> Option<Ordering> { fn partial_cmp(&self, rhs: &Number) -> Option<Ordering> {
Some(self.cmp(rhs)) Some(self.cmp(rhs))
@@ -668,15 +594,17 @@ impl PartialOrd for Number {
impl Ord for Number { impl Ord for Number {
fn cmp(&self, rhs: &Number) -> Ordering { fn cmp(&self, rhs: &Number) -> Ordering {
match (self, rhs) { match (self, rhs) {
(&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.cmp(&n2), (&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.get_num().cmp(&n2.get_num()),
(&Number::Fixnum(n1), Number::Integer(n2)) => Integer::from(n1).cmp(&*n2), (&Number::Fixnum(n1), Number::Integer(n2)) => Integer::from(n1.get_num()).cmp(&*n2),
(Number::Integer(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Integer::from(n2)), (Number::Integer(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Integer::from(n2.get_num())),
(&Number::Fixnum(n1), Number::Rational(n2)) => Rational::from(n1).cmp(&*n2), (&Number::Fixnum(n1), Number::Rational(n2)) => Rational::from(n1.get_num()).cmp(&*n2),
(Number::Rational(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Rational::from(n2)), (Number::Rational(n1), &Number::Fixnum(n2)) => {
(&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1 as f64).cmp(&n2), (&**n1).cmp(&Rational::from(n2.get_num()))
(&Number::Float(n1), &Number::Fixnum(n2)) => n1.cmp(&OrderedFloat(n2 as f64)), }
(&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1.get_num() as f64).cmp(&n2),
(&Number::Float(n1), &Number::Fixnum(n2)) => n1.cmp(&OrderedFloat(n2.get_num() as f64)),
(&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.cmp(n2), (&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.cmp(n2),
(&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(&n2), (&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(n2),
(&Number::Float(n1), &Number::Integer(ref n2)) => n1.cmp(&OrderedFloat(n2.to_f64())), (&Number::Float(n1), &Number::Integer(ref n2)) => n1.cmp(&OrderedFloat(n2.to_f64())),
(&Number::Integer(ref n1), &Number::Rational(ref n2)) => { (&Number::Integer(ref n1), &Number::Rational(ref n2)) => {
#[cfg(feature = "num")] #[cfg(feature = "num")]
@@ -706,54 +634,38 @@ impl Ord for Number {
} }
} }
impl<'a> TryFrom<(Addr, &'a Heap)> for Number { impl TryFrom<HeapCellValue> for Number {
type Error = (); type Error = ();
fn try_from((addr, heap): (Addr, &'a Heap)) -> Result<Number, Self::Error> {
match addr {
Addr::Fixnum(n) => Ok(Number::from(n)),
Addr::Float(n) => Ok(Number::Float(n)),
Addr::Usize(n) => {
if let Ok(n) = isize::try_from(n) {
Ok(Number::from(n))
} else {
Ok(Number::from(Integer::from(n)))
}
}
Addr::Con(h) => Number::try_from(&heap[h]),
_ => Err(()),
}
}
}
impl<'a> TryFrom<&'a HeapCellValue> for Number {
type Error = ();
fn try_from(value: &'a HeapCellValue) -> Result<Number, Self::Error> {
match value {
HeapCellValue::Addr(addr) => match addr {
&Addr::Fixnum(n) => Ok(Number::from(n)),
&Addr::Float(n) => Ok(Number::Float(n)),
&Addr::Usize(n) => {
if let Ok(n) = isize::try_from(n) {
Ok(Number::from(n))
} else {
Ok(Number::from(Integer::from(n)))
}
}
_ => Err(()),
},
HeapCellValue::Integer(n) => Ok(Number::Integer(n.clone())),
HeapCellValue::Rational(n) => Ok(Number::Rational(n.clone())),
_ => Err(()),
}
}
}
impl<'a> From<&'a Integer> for Number {
#[inline] #[inline]
fn from(src: &'a Integer) -> Self { fn try_from(value: HeapCellValue) -> Result<Number, Self::Error> {
Number::Integer(Rc::new(Integer::from(src))) read_heap_cell!(value,
(HeapCellValueTag::Cons, c) => {
match_untyped_arena_ptr!(c,
(ArenaHeaderTag::F64, n) => {
Ok(Number::Float(*n))
}
(ArenaHeaderTag::Integer, n) => {
Ok(Number::Integer(n))
}
(ArenaHeaderTag::Rational, n) => {
Ok(Number::Rational(n))
}
_ => {
Err(())
}
)
}
(HeapCellValueTag::F64, n) => {
Ok(Number::Float(**n))
}
(HeapCellValueTag::Fixnum, n) => {
Ok(Number::Fixnum(n))
}
_ => {
Err(())
}
)
} }
} }

366
src/atom_table.rs Normal file
View File

@@ -0,0 +1,366 @@
use crate::parser::ast::MAX_ARITY;
use crate::raw_block::*;
use crate::types::*;
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ptr;
use std::slice;
use std::str;
use indexmap::IndexSet;
use modular_bitfield::prelude::*;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Atom {
pub index: usize,
}
const_assert!(mem::size_of::<Atom>() == 8);
include!("./static_atoms.rs");
impl<'a> From<&'a Atom> for Atom {
#[inline]
fn from(atom: &'a Atom) -> Self {
*atom
}
}
impl From<bool> for Atom {
#[inline]
fn from(value: bool) -> Self {
if value { atom!("true") } else { atom!("false") }
}
}
#[cfg(test)]
use std::cell::RefCell;
const ATOM_TABLE_INIT_SIZE: usize = 1 << 16;
const ATOM_TABLE_ALIGN: usize = 8;
#[cfg(test)]
thread_local! {
static ATOM_TABLE_BUF_BASE: RefCell<*const u8> = RefCell::new(ptr::null_mut());
}
#[cfg(not(test))]
static mut ATOM_TABLE_BUF_BASE: *const u8 = ptr::null_mut();
#[cfg(test)]
fn set_atom_tbl_buf_base(ptr: *const u8) {
ATOM_TABLE_BUF_BASE.with(|atom_table_buf_base| {
*atom_table_buf_base.borrow_mut() = ptr;
});
}
#[cfg(test)]
pub(crate) fn get_atom_tbl_buf_base() -> *const u8 {
ATOM_TABLE_BUF_BASE.with(|atom_table_buf_base| *atom_table_buf_base.borrow())
}
#[cfg(not(test))]
fn set_atom_tbl_buf_base(ptr: *const u8) {
unsafe {
ATOM_TABLE_BUF_BASE = ptr;
}
}
#[cfg(not(test))]
pub(crate) fn get_atom_tbl_buf_base() -> *const u8 {
unsafe { ATOM_TABLE_BUF_BASE }
}
impl RawBlockTraits for AtomTable {
#[inline]
fn init_size() -> usize {
ATOM_TABLE_INIT_SIZE
}
#[inline]
fn align() -> usize {
ATOM_TABLE_ALIGN
}
}
#[bitfield]
#[derive(Copy, Clone, Debug)]
struct AtomHeader {
#[allow(unused)] m: bool,
len: B50,
#[allow(unused)] padding: B13,
}
impl AtomHeader {
fn build_with(len: u64) -> Self {
AtomHeader::new().with_len(len).with_m(false)
}
}
impl Borrow<str> for Atom {
#[inline]
fn borrow(&self) -> &str {
self.as_str()
}
}
impl Hash for Atom {
#[inline]
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.as_str().hash(hasher)
// hasher.write_usize(self.index)
}
}
#[macro_export]
macro_rules! is_char {
($s:expr) => {
!$s.is_empty() && $s.chars().nth(1).is_none()
};
}
impl Atom {
#[inline]
pub fn buf(self) -> *const u8 {
let ptr = self.as_ptr();
if ptr.is_null() {
return ptr::null();
}
(ptr as usize + mem::size_of::<AtomHeader>()) as *const u8
}
#[inline(always)]
pub fn is_static(self) -> bool {
self.index < STRINGS.len() << 3
}
#[inline(always)]
pub fn as_ptr(self) -> *const u8 {
if self.is_static() {
ptr::null()
} else {
(get_atom_tbl_buf_base() as usize + self.index - (STRINGS.len() << 3)) as *const u8
}
}
#[inline(always)]
pub fn from(index: usize) -> Self {
Self { index }
}
#[inline(always)]
pub fn len(self) -> usize {
if self.is_static() {
STRINGS[self.index >> 3].len()
} else {
unsafe { ptr::read(self.as_ptr() as *const AtomHeader).len() as _ }
}
}
#[inline(always)]
pub fn flat_index(self) -> u64 {
(self.index >> 3) as u64
}
pub fn as_char(self) -> Option<char> {
let s = self.as_str();
let mut it = s.chars();
let c1 = it.next();
let c2 = it.next();
if c2.is_none() { c1 } else { None }
}
#[inline]
pub fn chars(&self) -> str::Chars {
self.as_str().chars()
}
#[inline]
pub fn as_str(&self) -> &str {
unsafe {
let ptr = self.as_ptr();
if ptr.is_null() {
return STRINGS[self.index >> 3];
}
let header = ptr::read::<AtomHeader>(ptr as *const _);
let len = header.len() as usize;
let buf = (ptr as usize + mem::size_of::<AtomHeader>()) as *mut u8;
str::from_utf8_unchecked(slice::from_raw_parts(buf, len))
}
}
pub fn defrock_brackets(&self, atom_tbl: &mut AtomTable) -> Self {
let s = self.as_str();
let s = if s.starts_with('(') && s.ends_with(')') {
&s['('.len_utf8()..s.len() - ')'.len_utf8()]
} else {
return *self;
};
atom_tbl.build_with(s)
}
}
unsafe fn write_to_ptr(string: &str, ptr: *mut u8) {
ptr::write(ptr as *mut _, AtomHeader::build_with(string.len() as u64));
let str_ptr = (ptr as usize + mem::size_of::<AtomHeader>()) as *mut u8;
ptr::copy_nonoverlapping(string.as_ptr(), str_ptr as *mut u8, string.len());
}
impl PartialOrd for Atom {
#[inline]
fn partial_cmp(&self, other: &Atom) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Atom {
#[inline]
fn cmp(&self, other: &Atom) -> Ordering {
self.as_str().cmp(other.as_str())
}
}
#[derive(Debug)]
pub struct AtomTable {
block: RawBlock<AtomTable>,
pub table: IndexSet<Atom>,
}
impl Drop for AtomTable {
fn drop(&mut self) {
self.block.deallocate();
}
}
impl AtomTable {
#[inline]
pub fn new() -> Self {
let table = Self {
block: RawBlock::new(),
table: IndexSet::new(),
};
set_atom_tbl_buf_base(table.block.base);
table
}
#[inline]
pub fn buf(&self) -> *const u8 {
self.block.base as *const u8
}
#[inline]
pub fn top(&self) -> *const u8 {
self.block.top
}
#[inline(always)]
fn lookup_str(&self, string: &str) -> Option<Atom> {
STATIC_ATOMS_MAP.get(string).or_else(|| self.table.get(string)).cloned()
}
pub fn build_with(&mut self, string: &str) -> Atom {
if let Some(atom) = self.lookup_str(string) {
return atom;
}
unsafe {
let size = mem::size_of::<AtomHeader>() + string.len();
let align_offset = 8 * mem::align_of::<AtomHeader>();
let size = (size & !(align_offset - 1)) + align_offset;
let len_ptr = {
let mut ptr;
loop {
ptr = self.block.alloc(size);
if ptr.is_null() {
self.block.grow();
set_atom_tbl_buf_base(self.block.base);
} else {
break;
}
}
ptr
};
let ptr_base = self.block.base as usize;
write_to_ptr(string, len_ptr);
let atom = Atom {
index: (STRINGS.len() << 3) + len_ptr as usize - ptr_base,
};
self.table.insert(atom);
atom
}
}
}
#[bitfield]
#[repr(u64)]
#[derive(Copy, Clone, Debug)]
pub struct AtomCell {
name: B46,
arity: B10,
#[allow(unused)] f: bool,
#[allow(unused)] m: bool,
#[allow(unused)] tag: B6,
}
impl AtomCell {
#[inline]
pub fn build_with(name: u64, arity: u16, tag: HeapCellValueTag) -> Self {
if arity > 0 {
debug_assert!(arity as usize <= MAX_ARITY);
AtomCell::new()
.with_name(name)
.with_arity(arity)
.with_f(false)
.with_tag(tag as u8)
} else {
AtomCell::new()
.with_name(name)
.with_f(false)
.with_tag(tag as u8)
}
}
#[inline]
pub fn get_index(self) -> usize {
self.name() as usize
}
#[inline]
pub fn get_name(self) -> Atom {
Atom::from(self.get_index() << 3)
}
#[inline]
pub fn get_arity(self) -> usize {
self.arity() as usize
}
#[inline]
pub fn get_name_and_arity(self) -> (Atom, usize) {
(Atom::from(self.get_index() << 3), self.get_arity())
}
}

View File

@@ -1,16 +1,12 @@
fn main() { fn main() {
use nix::sys::signal; use nix::sys::signal;
use scryer_prolog::read::readline;
use scryer_prolog::*; use scryer_prolog::*;
let handler = signal::SigHandler::Handler(handle_sigint); let handler = signal::SigHandler::Handler(handle_sigint);
unsafe { signal::signal(signal::Signal::SIGINT, handler) }.unwrap(); unsafe { signal::signal(signal::Signal::SIGINT, handler) }.unwrap();
let mut wam = machine::Machine::new( let mut wam = machine::Machine::new();
readline::input_stream(),
machine::Stream::stdout(),
machine::Stream::stderr(),
);
wam.run_top_level(); wam.run_top_level();
} }

View File

@@ -1,994 +0,0 @@
use prolog_parser::ast::*;
use prolog_parser::{clause_name, temp_v};
use crate::forms::Number;
use crate::machine::machine_indices::*;
use crate::rug::rand::RandState;
use ref_thread_local::{ref_thread_local, RefThreadLocal};
use std::collections::BTreeMap;
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub(crate) enum CompareNumberQT {
GreaterThan,
LessThan,
GreaterThanOrEqual,
LessThanOrEqual,
NotEqual,
Equal,
}
impl CompareNumberQT {
fn name(self) -> &'static str {
match self {
CompareNumberQT::GreaterThan => ">",
CompareNumberQT::LessThan => "<",
CompareNumberQT::GreaterThanOrEqual => ">=",
CompareNumberQT::LessThanOrEqual => "=<",
CompareNumberQT::NotEqual => "=\\=",
CompareNumberQT::Equal => "=:=",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum CompareTermQT {
LessThan,
LessThanOrEqual,
GreaterThanOrEqual,
GreaterThan,
}
impl CompareTermQT {
fn name<'a>(self) -> &'a str {
match self {
CompareTermQT::GreaterThan => "@>",
CompareTermQT::LessThan => "@<",
CompareTermQT::GreaterThanOrEqual => "@>=",
CompareTermQT::LessThanOrEqual => "@=<",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum ArithmeticTerm {
Reg(RegType),
Interm(usize),
Number(Number),
}
impl ArithmeticTerm {
pub(crate) fn interm_or(&self, interm: usize) -> usize {
if let &ArithmeticTerm::Interm(interm) = self {
interm
} else {
interm
}
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub(crate) enum InlinedClauseType {
CompareNumber(CompareNumberQT, ArithmeticTerm, ArithmeticTerm),
IsAtom(RegType),
IsAtomic(RegType),
IsCompound(RegType),
IsInteger(RegType),
IsNumber(RegType),
IsRational(RegType),
IsFloat(RegType),
IsNonVar(RegType),
IsVar(RegType),
}
ref_thread_local! {
pub(crate)static managed RANDOM_STATE: RandState<'static> = RandState::new();
}
ref_thread_local! {
pub(crate)static managed CLAUSE_TYPE_FORMS: BTreeMap<(&'static str, usize), ClauseType> = {
let mut m = BTreeMap::new();
let r1 = temp_v!(1);
let r2 = temp_v!(2);
m.insert((">", 2),
ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::GreaterThan, ar_reg!(r1), ar_reg!(r2))));
m.insert(("<", 2),
ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::LessThan, ar_reg!(r1), ar_reg!(r2))));
m.insert((">=", 2), ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::GreaterThanOrEqual, ar_reg!(r1), ar_reg!(r2))));
m.insert(("=<", 2), ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::LessThanOrEqual, ar_reg!(r1), ar_reg!(r2))));
m.insert(("=:=", 2), ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::Equal, ar_reg!(r1), ar_reg!(r2))));
m.insert(("=\\=", 2), ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::NotEqual, ar_reg!(r1), ar_reg!(r2))));
m.insert(("atom", 1), ClauseType::Inlined(InlinedClauseType::IsAtom(r1)));
m.insert(("atomic", 1), ClauseType::Inlined(InlinedClauseType::IsAtomic(r1)));
m.insert(("compound", 1), ClauseType::Inlined(InlinedClauseType::IsCompound(r1)));
m.insert(("integer", 1), ClauseType::Inlined(InlinedClauseType::IsInteger(r1)));
m.insert(("number", 1), ClauseType::Inlined(InlinedClauseType::IsNumber(r1)));
m.insert(("rational", 1), ClauseType::Inlined(InlinedClauseType::IsRational(r1)));
m.insert(("float", 1), ClauseType::Inlined(InlinedClauseType::IsFloat(r1)));
m.insert(("nonvar", 1), ClauseType::Inlined(InlinedClauseType::IsNonVar(r1)));
m.insert(("var", 1), ClauseType::Inlined(InlinedClauseType::IsVar(r1)));
m.insert(("acyclic_term", 1), ClauseType::BuiltIn(BuiltInClauseType::AcyclicTerm));
m.insert(("arg", 3), ClauseType::BuiltIn(BuiltInClauseType::Arg));
m.insert(("compare", 3), ClauseType::BuiltIn(BuiltInClauseType::Compare));
m.insert(("@>", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::GreaterThan)));
m.insert(("@<", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::LessThan)));
m.insert(("@>=", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::GreaterThanOrEqual)));
m.insert(("@=<", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::LessThanOrEqual)));
m.insert(("copy_term", 2), ClauseType::BuiltIn(BuiltInClauseType::CopyTerm));
m.insert(("==", 2), ClauseType::BuiltIn(BuiltInClauseType::Eq));
m.insert(("functor", 3), ClauseType::BuiltIn(BuiltInClauseType::Functor));
m.insert(("ground", 1), ClauseType::BuiltIn(BuiltInClauseType::Ground));
m.insert(("is", 2), ClauseType::BuiltIn(BuiltInClauseType::Is(r1, ar_reg!(r2))));
m.insert(("keysort", 2), ClauseType::BuiltIn(BuiltInClauseType::KeySort));
m.insert(("\\==", 2), ClauseType::BuiltIn(BuiltInClauseType::NotEq));
m.insert(("read", 2), ClauseType::BuiltIn(BuiltInClauseType::Read));
m.insert(("sort", 2), ClauseType::BuiltIn(BuiltInClauseType::Sort));
m
};
}
impl InlinedClauseType {
pub(crate) fn name(&self) -> &'static str {
match self {
&InlinedClauseType::CompareNumber(qt, ..) => qt.name(),
&InlinedClauseType::IsAtom(..) => "atom",
&InlinedClauseType::IsAtomic(..) => "atomic",
&InlinedClauseType::IsCompound(..) => "compound",
&InlinedClauseType::IsNumber(..) => "number",
&InlinedClauseType::IsInteger(..) => "integer",
&InlinedClauseType::IsRational(..) => "rational",
&InlinedClauseType::IsFloat(..) => "float",
&InlinedClauseType::IsNonVar(..) => "nonvar",
&InlinedClauseType::IsVar(..) => "var",
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub(crate) enum SystemClauseType {
AtomChars,
AtomCodes,
AtomLength,
BindFromRegister,
CallContinuation,
CharCode,
CharType,
CharsToNumber,
CodesToNumber,
CopyTermWithoutAttrVars,
CheckCutPoint,
Close,
CopyToLiftedHeap,
CreatePartialString,
CurrentHostname,
CurrentInput,
CurrentOutput,
DirectoryFiles,
FileSize,
FileExists,
DirectoryExists,
DirectorySeparator,
MakeDirectory,
MakeDirectoryPath,
DeleteFile,
RenameFile,
DeleteDirectory,
WorkingDirectory,
PathCanonical,
FileTime,
DeleteAttribute,
DeleteHeadAttribute,
DynamicModuleResolution(usize),
EnqueueAttributedVar,
FetchGlobalVar,
FirstStream,
FlushOutput,
GetByte,
GetChar,
GetNChars,
GetCode,
GetSingleChar,
ResetAttrVarState,
TruncateIfNoLiftedHeapGrowthDiff,
TruncateIfNoLiftedHeapGrowth,
GetAttributedVariableList,
GetAttrVarQueueDelimiter,
GetAttrVarQueueBeyond,
GetBValue,
GetContinuationChunk,
GetNextDBRef,
GetNextOpDBRef,
IsPartialString,
LookupDBRef,
LookupOpDBRef,
Halt,
GetLiftedHeapFromOffset,
GetLiftedHeapFromOffsetDiff,
GetSCCCleaner,
HeadIsDynamic,
InstallSCCCleaner,
InstallInferenceCounter,
LiftedHeapLength,
LoadLibraryAsStream,
ModuleExists,
NextEP,
NoSuchPredicate,
NumberToChars,
NumberToCodes,
OpDeclaration,
Open,
SetStreamOptions,
NextStream,
PartialStringTail,
PeekByte,
PeekChar,
PeekCode,
PointsToContinuationResetMarker,
PutByte,
PutChar,
PutChars,
PutCode,
REPL(REPLCodePtr),
ReadQueryTerm,
ReadTerm,
RedoAttrVarBinding,
RemoveCallPolicyCheck,
RemoveInferenceCounter,
ResetContinuationMarker,
RestoreCutPolicy,
SetCutPoint(RegType),
SetInput,
SetOutput,
StoreBacktrackableGlobalVar,
StoreGlobalVar,
StreamProperty,
SetStreamPosition,
InferenceLevel,
CleanUpBlock,
EraseBall,
Fail,
GetBall,
GetCurrentBlock,
GetCutPoint,
GetDoubleQuotes,
InstallNewBlock,
Maybe,
CpuNow,
CurrentTime,
QuotedToken,
ReadTermFromChars,
ResetBlock,
ReturnFromVerifyAttr,
SetBall,
SetCutPointByDefault(RegType),
SetDoubleQuotes,
SetSeed,
SkipMaxList,
Sleep,
SocketClientOpen,
SocketServerOpen,
SocketServerAccept,
SocketServerClose,
TLSAcceptClient,
TLSClientConnect,
Succeed,
TermAttributedVariables,
TermVariables,
TruncateLiftedHeapTo,
UnifyWithOccursCheck,
UnwindEnvironments,
UnwindStack,
Variant,
WAMInstructions,
WriteTerm,
WriteTermToChars,
ScryerPrologVersion,
CryptoRandomByte,
CryptoDataHash,
CryptoDataHKDF,
CryptoPasswordHash,
CryptoDataEncrypt,
CryptoDataDecrypt,
CryptoCurveScalarMult,
Ed25519Sign,
Ed25519Verify,
Ed25519NewKeyPair,
Ed25519KeyPairPublicKey,
Curve25519ScalarMult,
FirstNonOctet,
LoadHTML,
LoadXML,
GetEnv,
SetEnv,
UnsetEnv,
Shell,
PID,
CharsBase64,
DevourWhitespace,
IsSTOEnabled,
SetSTOAsUnify,
SetNSTOAsUnify,
SetSTOWithErrorAsUnify,
HomeDirectory,
DebugHook,
PopCount
}
impl SystemClauseType {
pub(crate) fn name(&self) -> ClauseName {
match self {
&SystemClauseType::AtomChars => clause_name!("$atom_chars"),
&SystemClauseType::AtomCodes => clause_name!("$atom_codes"),
&SystemClauseType::AtomLength => clause_name!("$atom_length"),
&SystemClauseType::BindFromRegister => clause_name!("$bind_from_register"),
&SystemClauseType::CallContinuation => clause_name!("$call_continuation"),
&SystemClauseType::CharCode => clause_name!("$char_code"),
&SystemClauseType::CharType => clause_name!("$char_type"),
&SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"),
&SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
&SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"),
&SystemClauseType::CopyTermWithoutAttrVars => {
clause_name!("$copy_term_without_attr_vars")
}
&SystemClauseType::CreatePartialString => clause_name!("$create_partial_string"),
&SystemClauseType::CurrentInput => clause_name!("$current_input"),
&SystemClauseType::CurrentHostname => clause_name!("$current_hostname"),
&SystemClauseType::CurrentOutput => clause_name!("$current_output"),
&SystemClauseType::DirectoryFiles => clause_name!("$directory_files"),
&SystemClauseType::FileSize => clause_name!("$file_size"),
&SystemClauseType::FileExists => clause_name!("$file_exists"),
&SystemClauseType::DirectoryExists => clause_name!("$directory_exists"),
&SystemClauseType::DirectorySeparator => clause_name!("$directory_separator"),
&SystemClauseType::MakeDirectory => clause_name!("$make_directory"),
&SystemClauseType::MakeDirectoryPath => clause_name!("$make_directory_path"),
&SystemClauseType::DeleteFile => clause_name!("$delete_file"),
&SystemClauseType::RenameFile => clause_name!("$rename_file"),
&SystemClauseType::DeleteDirectory => clause_name!("$delete_directory"),
&SystemClauseType::WorkingDirectory => clause_name!("$working_directory"),
&SystemClauseType::PathCanonical => clause_name!("$path_canonical"),
&SystemClauseType::FileTime => clause_name!("$file_time"),
&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::AddInSituFilenameModule) => {
clause_name!("$add_in_situ_filename_module")
}
&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::PushLoadContext) => {
clause_name!("$push_load_context")
}
&SystemClauseType::REPL(REPLCodePtr::PopLoadContext) => {
clause_name!("$pop_load_context")
}
&SystemClauseType::REPL(REPLCodePtr::PopLoadStatePayload) => {
clause_name!("$pop_load_state_payload")
}
&SystemClauseType::REPL(REPLCodePtr::LoadContextSource) => {
clause_name!("$prolog_lc_source")
}
&SystemClauseType::REPL(REPLCodePtr::LoadContextFile) => {
clause_name!("$prolog_lc_file")
}
&SystemClauseType::REPL(REPLCodePtr::LoadContextDirectory) => {
clause_name!("$prolog_lc_dir")
}
&SystemClauseType::REPL(REPLCodePtr::LoadContextModule) => {
clause_name!("$prolog_lc_module")
}
&SystemClauseType::REPL(REPLCodePtr::LoadContextStream) => {
clause_name!("$prolog_lc_stream")
}
&SystemClauseType::REPL(REPLCodePtr::MetaPredicateProperty) => {
clause_name!("$cpp_meta_predicate_property")
}
&SystemClauseType::REPL(REPLCodePtr::BuiltInProperty) => {
clause_name!("$cpp_built_in_property")
}
&SystemClauseType::REPL(REPLCodePtr::DynamicProperty) => {
clause_name!("$cpp_dynamic_property")
}
&SystemClauseType::REPL(REPLCodePtr::MultifileProperty) => {
clause_name!("$cpp_multifile_property")
}
&SystemClauseType::REPL(REPLCodePtr::DiscontiguousProperty) => {
clause_name!("$cpp_discontiguous_property")
}
&SystemClauseType::REPL(REPLCodePtr::AbolishClause) => clause_name!("$abolish_clause"),
&SystemClauseType::REPL(REPLCodePtr::IsConsistentWithTermQueue) => {
clause_name!("$is_consistent_with_term_queue")
}
&SystemClauseType::REPL(REPLCodePtr::FlushTermQueue) => {
clause_name!("$flush_term_queue")
}
&SystemClauseType::REPL(REPLCodePtr::RemoveModuleExports) => {
clause_name!("$remove_module_exports")
}
&SystemClauseType::REPL(REPLCodePtr::AddNonCountedBacktracking) => {
clause_name!("$add_non_counted_backtracking")
}
&SystemClauseType::Close => clause_name!("$close"),
&SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"),
&SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"),
&SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"),
&SystemClauseType::DynamicModuleResolution(_) => clause_name!("$module_call"),
&SystemClauseType::EnqueueAttributedVar => clause_name!("$enqueue_attr_var"),
&SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"),
&SystemClauseType::FirstStream => clause_name!("$first_stream"),
&SystemClauseType::FlushOutput => clause_name!("$flush_output"),
&SystemClauseType::GetByte => clause_name!("$get_byte"),
&SystemClauseType::GetChar => clause_name!("$get_char"),
&SystemClauseType::GetNChars => clause_name!("$get_n_chars"),
&SystemClauseType::GetCode => clause_name!("$get_code"),
&SystemClauseType::GetSingleChar => clause_name!("$get_single_char"),
&SystemClauseType::ResetAttrVarState => clause_name!("$reset_attr_var_state"),
&SystemClauseType::TruncateIfNoLiftedHeapGrowth => {
clause_name!("$truncate_if_no_lh_growth")
}
&SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => {
clause_name!("$truncate_if_no_lh_growth_diff")
}
&SystemClauseType::GetAttributedVariableList => clause_name!("$get_attr_list"),
&SystemClauseType::GetAttrVarQueueDelimiter => {
clause_name!("$get_attr_var_queue_delim")
}
&SystemClauseType::GetAttrVarQueueBeyond => clause_name!("$get_attr_var_queue_beyond"),
&SystemClauseType::GetContinuationChunk => clause_name!("$get_cont_chunk"),
&SystemClauseType::GetLiftedHeapFromOffset => clause_name!("$get_lh_from_offset"),
&SystemClauseType::GetLiftedHeapFromOffsetDiff => {
clause_name!("$get_lh_from_offset_diff")
}
&SystemClauseType::GetBValue => clause_name!("$get_b_value"),
// &SystemClauseType::GetClause => clause_name!("$get_clause"),
&SystemClauseType::GetNextDBRef => clause_name!("$get_next_db_ref"),
&SystemClauseType::GetNextOpDBRef => clause_name!("$get_next_op_db_ref"),
&SystemClauseType::LookupDBRef => clause_name!("$lookup_db_ref"),
&SystemClauseType::LookupOpDBRef => clause_name!("$lookup_op_db_ref"),
&SystemClauseType::GetDoubleQuotes => clause_name!("$get_double_quotes"),
// &SystemClauseType::GetModuleClause => clause_name!("$get_module_clause"),
&SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"),
&SystemClauseType::Halt => clause_name!("$halt"),
&SystemClauseType::HeadIsDynamic => clause_name!("$head_is_dynamic"),
&SystemClauseType::Open => clause_name!("$open"),
&SystemClauseType::SetStreamOptions => clause_name!("$set_stream_options"),
&SystemClauseType::OpDeclaration => clause_name!("$op"),
&SystemClauseType::InstallSCCCleaner => clause_name!("$install_scc_cleaner"),
&SystemClauseType::InstallInferenceCounter => {
clause_name!("$install_inference_counter")
}
&SystemClauseType::IsPartialString => clause_name!("$is_partial_string"),
&SystemClauseType::PartialStringTail => clause_name!("$partial_string_tail"),
&SystemClauseType::PeekByte => clause_name!("$peek_byte"),
&SystemClauseType::PeekChar => clause_name!("$peek_char"),
&SystemClauseType::PeekCode => clause_name!("$peek_code"),
&SystemClauseType::LiftedHeapLength => clause_name!("$lh_length"),
&SystemClauseType::Maybe => clause_name!("maybe"),
&SystemClauseType::CpuNow => clause_name!("$cpu_now"),
&SystemClauseType::CurrentTime => clause_name!("$current_time"),
// &SystemClauseType::ModuleAssertDynamicPredicateToFront => {
// clause_name!("$module_asserta")
// }
// &SystemClauseType::ModuleAssertDynamicPredicateToBack => {
// clause_name!("$module_assertz")
// }
// &SystemClauseType::ModuleHeadIsDynamic => clause_name!("$module_head_is_dynamic"),
&SystemClauseType::ModuleExists => clause_name!("$module_exists"),
&SystemClauseType::NextStream => clause_name!("$next_stream"),
&SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"),
&SystemClauseType::NumberToChars => clause_name!("$number_to_chars"),
&SystemClauseType::NumberToCodes => clause_name!("$number_to_codes"),
&SystemClauseType::PointsToContinuationResetMarker => {
clause_name!("$points_to_cont_reset_marker")
}
&SystemClauseType::PutByte => {
clause_name!("$put_byte")
}
&SystemClauseType::PutChar => {
clause_name!("$put_char")
}
&SystemClauseType::PutChars => {
clause_name!("$put_chars")
}
&SystemClauseType::PutCode => {
clause_name!("$put_code")
}
&SystemClauseType::QuotedToken => {
clause_name!("$quoted_token")
}
&SystemClauseType::RedoAttrVarBinding => clause_name!("$redo_attr_var_binding"),
&SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"),
&SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"),
&SystemClauseType::RestoreCutPolicy => clause_name!("$restore_cut_policy"),
&SystemClauseType::SetCutPoint(_) => clause_name!("$set_cp"),
&SystemClauseType::SetInput => clause_name!("$set_input"),
&SystemClauseType::SetOutput => clause_name!("$set_output"),
&SystemClauseType::SetSeed => clause_name!("$set_seed"),
&SystemClauseType::StreamProperty => clause_name!("$stream_property"),
&SystemClauseType::SetStreamPosition => clause_name!("$set_stream_position"),
&SystemClauseType::StoreBacktrackableGlobalVar => {
clause_name!("$store_back_trackable_global_var")
}
&SystemClauseType::StoreGlobalVar => clause_name!("$store_global_var"),
&SystemClauseType::InferenceLevel => clause_name!("$inference_level"),
&SystemClauseType::CleanUpBlock => clause_name!("$clean_up_block"),
&SystemClauseType::EraseBall => clause_name!("$erase_ball"),
&SystemClauseType::Fail => clause_name!("$fail"),
&SystemClauseType::GetBall => clause_name!("$get_ball"),
&SystemClauseType::GetCutPoint => clause_name!("$get_cp"),
&SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"),
&SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"),
&SystemClauseType::NextEP => clause_name!("$nextEP"),
&SystemClauseType::ReadQueryTerm => clause_name!("$read_query_term"),
&SystemClauseType::ReadTerm => clause_name!("$read_term"),
&SystemClauseType::ReadTermFromChars => clause_name!("$read_term_from_chars"),
&SystemClauseType::ResetBlock => clause_name!("$reset_block"),
&SystemClauseType::ResetContinuationMarker => clause_name!("$reset_cont_marker"),
&SystemClauseType::ReturnFromVerifyAttr => clause_name!("$return_from_verify_attr"),
&SystemClauseType::SetBall => clause_name!("$set_ball"),
&SystemClauseType::SetCutPointByDefault(_) => clause_name!("$set_cp_by_default"),
&SystemClauseType::SetDoubleQuotes => clause_name!("$set_double_quotes"),
&SystemClauseType::SkipMaxList => clause_name!("$skip_max_list"),
&SystemClauseType::Sleep => clause_name!("$sleep"),
&SystemClauseType::SocketClientOpen => clause_name!("$socket_client_open"),
&SystemClauseType::SocketServerOpen => clause_name!("$socket_server_open"),
&SystemClauseType::SocketServerAccept => clause_name!("$socket_server_accept"),
&SystemClauseType::SocketServerClose => clause_name!("$socket_server_close"),
&SystemClauseType::TLSAcceptClient => clause_name!("$tls_accept_client"),
&SystemClauseType::TLSClientConnect => clause_name!("$tls_client_connect"),
&SystemClauseType::Succeed => clause_name!("$succeed"),
&SystemClauseType::TermAttributedVariables => {
clause_name!("$term_attributed_variables")
}
&SystemClauseType::TermVariables => clause_name!("$term_variables"),
&SystemClauseType::TruncateLiftedHeapTo => clause_name!("$truncate_lh_to"),
&SystemClauseType::UnifyWithOccursCheck => clause_name!("$unify_with_occurs_check"),
&SystemClauseType::UnwindEnvironments => clause_name!("$unwind_environments"),
&SystemClauseType::UnwindStack => clause_name!("$unwind_stack"),
&SystemClauseType::Variant => clause_name!("$variant"),
&SystemClauseType::WAMInstructions => clause_name!("$wam_instructions"),
&SystemClauseType::WriteTerm => clause_name!("$write_term"),
&SystemClauseType::WriteTermToChars => clause_name!("$write_term_to_chars"),
&SystemClauseType::ScryerPrologVersion => clause_name!("$scryer_prolog_version"),
&SystemClauseType::CryptoRandomByte => clause_name!("$crypto_random_byte"),
&SystemClauseType::CryptoDataHash => clause_name!("$crypto_data_hash"),
&SystemClauseType::CryptoDataHKDF => clause_name!("$crypto_data_hkdf"),
&SystemClauseType::CryptoPasswordHash => clause_name!("$crypto_password_hash"),
&SystemClauseType::CryptoDataEncrypt => clause_name!("$crypto_data_encrypt"),
&SystemClauseType::CryptoDataDecrypt => clause_name!("$crypto_data_decrypt"),
&SystemClauseType::CryptoCurveScalarMult => clause_name!("$crypto_curve_scalar_mult"),
&SystemClauseType::Ed25519Sign => clause_name!("$ed25519_sign"),
&SystemClauseType::Ed25519Verify => clause_name!("$ed25519_verify"),
&SystemClauseType::Ed25519NewKeyPair => clause_name!("$ed25519_new_keypair"),
&SystemClauseType::Ed25519KeyPairPublicKey => {
clause_name!("$ed25519_keypair_public_key")
}
&SystemClauseType::Curve25519ScalarMult => clause_name!("$curve25519_scalar_mult"),
&SystemClauseType::FirstNonOctet => clause_name!("$first_non_octet"),
&SystemClauseType::LoadHTML => clause_name!("$load_html"),
&SystemClauseType::LoadXML => clause_name!("$load_xml"),
&SystemClauseType::GetEnv => clause_name!("$getenv"),
&SystemClauseType::SetEnv => clause_name!("$setenv"),
&SystemClauseType::UnsetEnv => clause_name!("$unsetenv"),
&SystemClauseType::Shell => clause_name!("$shell"),
&SystemClauseType::PID => clause_name!("$pid"),
&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")
}
&SystemClauseType::DebugHook => clause_name!("$debug_hook"),
&SystemClauseType::PopCount => clause_name!("$popcount"),
}
}
pub(crate) fn from(name: &str, arity: usize) -> Option<SystemClauseType> {
match (name, arity) {
("$abolish_clause", 3) => Some(SystemClauseType::REPL(REPLCodePtr::AbolishClause)),
("$add_dynamic_predicate", 4) => {
Some(SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate))
}
("$add_multifile_predicate", 4) => {
Some(SystemClauseType::REPL(REPLCodePtr::AddMultifilePredicate))
}
("$add_discontiguous_predicate", 4) => Some(SystemClauseType::REPL(
REPLCodePtr::AddDiscontiguousPredicate,
)),
("$add_goal_expansion_clause", 3) => {
Some(SystemClauseType::REPL(REPLCodePtr::AddGoalExpansionClause))
}
("$add_term_expansion_clause", 2) => {
Some(SystemClauseType::REPL(REPLCodePtr::AddTermExpansionClause))
}
("$atom_chars", 2) => Some(SystemClauseType::AtomChars),
("$atom_codes", 2) => Some(SystemClauseType::AtomCodes),
("$atom_length", 2) => Some(SystemClauseType::AtomLength),
("$bind_from_register", 2) => Some(SystemClauseType::BindFromRegister),
("$call_continuation", 1) => Some(SystemClauseType::CallContinuation),
("$char_code", 2) => Some(SystemClauseType::CharCode),
("$char_type", 2) => Some(SystemClauseType::CharType),
("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber),
("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber),
("$copy_term_without_attr_vars", 2) => Some(SystemClauseType::CopyTermWithoutAttrVars),
("$create_partial_string", 3) => Some(SystemClauseType::CreatePartialString),
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
("$close", 2) => Some(SystemClauseType::Close),
("$current_hostname", 1) => Some(SystemClauseType::CurrentHostname),
("$current_input", 1) => Some(SystemClauseType::CurrentInput),
("$current_output", 1) => Some(SystemClauseType::CurrentOutput),
("$first_stream", 1) => Some(SystemClauseType::FirstStream),
("$next_stream", 2) => Some(SystemClauseType::NextStream),
("$flush_output", 1) => Some(SystemClauseType::FlushOutput),
("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute),
("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute),
("$get_next_db_ref", 2) => Some(SystemClauseType::GetNextDBRef),
("$get_next_op_db_ref", 2) => Some(SystemClauseType::GetNextOpDBRef),
("$lookup_db_ref", 3) => Some(SystemClauseType::LookupDBRef),
("$lookup_op_db_ref", 4) => Some(SystemClauseType::LookupOpDBRef),
("$module_call", _) => Some(SystemClauseType::DynamicModuleResolution(arity - 2)),
("$enqueue_attr_var", 1) => Some(SystemClauseType::EnqueueAttributedVar),
("$partial_string_tail", 2) => Some(SystemClauseType::PartialStringTail),
("$peek_byte", 2) => Some(SystemClauseType::PeekByte),
("$peek_char", 2) => Some(SystemClauseType::PeekChar),
("$peek_code", 2) => Some(SystemClauseType::PeekCode),
("$is_partial_string", 1) => Some(SystemClauseType::IsPartialString),
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
("$get_byte", 2) => Some(SystemClauseType::GetByte),
("$get_char", 2) => Some(SystemClauseType::GetChar),
("$get_n_chars", 3) => Some(SystemClauseType::GetNChars),
("$get_code", 2) => Some(SystemClauseType::GetCode),
("$get_single_char", 1) => Some(SystemClauseType::GetSingleChar),
("$points_to_cont_reset_marker", 1) => {
Some(SystemClauseType::PointsToContinuationResetMarker)
}
("$put_byte", 2) => Some(SystemClauseType::PutByte),
("$put_char", 2) => Some(SystemClauseType::PutChar),
("$put_chars", 2) => Some(SystemClauseType::PutChars),
("$put_code", 2) => Some(SystemClauseType::PutCode),
("$reset_attr_var_state", 0) => Some(SystemClauseType::ResetAttrVarState),
("$truncate_if_no_lh_growth", 1) => {
Some(SystemClauseType::TruncateIfNoLiftedHeapGrowth)
}
("$truncate_if_no_lh_growth_diff", 2) => {
Some(SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff)
}
("$get_attr_list", 2) => Some(SystemClauseType::GetAttributedVariableList),
("$get_b_value", 1) => Some(SystemClauseType::GetBValue),
("$get_lh_from_offset", 2) => Some(SystemClauseType::GetLiftedHeapFromOffset),
("$get_lh_from_offset_diff", 3) => Some(SystemClauseType::GetLiftedHeapFromOffsetDiff),
("$get_double_quotes", 1) => Some(SystemClauseType::GetDoubleQuotes),
("$get_scc_cleaner", 1) => Some(SystemClauseType::GetSCCCleaner),
("$halt", 1) => Some(SystemClauseType::Halt),
("$head_is_dynamic", 2) => Some(SystemClauseType::HeadIsDynamic),
("$install_scc_cleaner", 2) => Some(SystemClauseType::InstallSCCCleaner),
("$install_inference_counter", 3) => Some(SystemClauseType::InstallInferenceCounter),
("$lh_length", 1) => Some(SystemClauseType::LiftedHeapLength),
("$maybe", 0) => Some(SystemClauseType::Maybe),
("$cpu_now", 1) => Some(SystemClauseType::CpuNow),
("$current_time", 1) => Some(SystemClauseType::CurrentTime),
("$module_exists", 1) => Some(SystemClauseType::ModuleExists),
("$no_such_predicate", 2) => Some(SystemClauseType::NoSuchPredicate),
("$number_to_chars", 2) => Some(SystemClauseType::NumberToChars),
("$number_to_codes", 2) => Some(SystemClauseType::NumberToCodes),
("$op", 3) => Some(SystemClauseType::OpDeclaration),
("$open", 7) => Some(SystemClauseType::Open),
("$set_stream_options", 5) => Some(SystemClauseType::SetStreamOptions),
("$redo_attr_var_binding", 2) => Some(SystemClauseType::RedoAttrVarBinding),
("$remove_call_policy_check", 1) => Some(SystemClauseType::RemoveCallPolicyCheck),
("$remove_inference_counter", 2) => Some(SystemClauseType::RemoveInferenceCounter),
("$restore_cut_policy", 0) => Some(SystemClauseType::RestoreCutPolicy),
("$set_cp", 1) => Some(SystemClauseType::SetCutPoint(temp_v!(1))),
("$set_input", 1) => Some(SystemClauseType::SetInput),
("$set_output", 1) => Some(SystemClauseType::SetOutput),
("$stream_property", 3) => Some(SystemClauseType::StreamProperty),
("$set_stream_position", 2) => Some(SystemClauseType::SetStreamPosition),
("$inference_level", 2) => Some(SystemClauseType::InferenceLevel),
("$clean_up_block", 1) => Some(SystemClauseType::CleanUpBlock),
("$erase_ball", 0) => Some(SystemClauseType::EraseBall),
("$fail", 0) => Some(SystemClauseType::Fail),
("$get_attr_var_queue_beyond", 2) => Some(SystemClauseType::GetAttrVarQueueBeyond),
("$get_attr_var_queue_delim", 1) => Some(SystemClauseType::GetAttrVarQueueDelimiter),
("$get_ball", 1) => Some(SystemClauseType::GetBall),
("$get_cont_chunk", 3) => Some(SystemClauseType::GetContinuationChunk),
("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock),
("$get_cp", 1) => Some(SystemClauseType::GetCutPoint),
("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock),
("$quoted_token", 1) => Some(SystemClauseType::QuotedToken),
("$nextEP", 3) => Some(SystemClauseType::NextEP),
("$read_query_term", 5) => Some(SystemClauseType::ReadQueryTerm),
("$read_term", 5) => Some(SystemClauseType::ReadTerm),
("$read_term_from_chars", 2) => Some(SystemClauseType::ReadTermFromChars),
("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
("$reset_cont_marker", 0) => Some(SystemClauseType::ResetContinuationMarker),
("$return_from_verify_attr", 0) => Some(SystemClauseType::ReturnFromVerifyAttr),
("$set_ball", 1) => Some(SystemClauseType::SetBall),
("$set_cp_by_default", 1) => Some(SystemClauseType::SetCutPointByDefault(temp_v!(1))),
("$set_double_quotes", 1) => Some(SystemClauseType::SetDoubleQuotes),
("$set_seed", 1) => Some(SystemClauseType::SetSeed),
("$skip_max_list", 4) => Some(SystemClauseType::SkipMaxList),
("$sleep", 1) => Some(SystemClauseType::Sleep),
("$socket_client_open", 7) => Some(SystemClauseType::SocketClientOpen),
("$socket_server_open", 3) => Some(SystemClauseType::SocketServerOpen),
("$socket_server_accept", 7) => Some(SystemClauseType::SocketServerAccept),
("$socket_server_close", 1) => Some(SystemClauseType::SocketServerClose),
("$tls_accept_client", 4) => Some(SystemClauseType::TLSAcceptClient),
("$tls_client_connect", 3) => Some(SystemClauseType::TLSClientConnect),
("$store_global_var", 2) => Some(SystemClauseType::StoreGlobalVar),
("$store_backtrackable_global_var", 2) => {
Some(SystemClauseType::StoreBacktrackableGlobalVar)
}
("$term_attributed_variables", 2) => Some(SystemClauseType::TermAttributedVariables),
("$term_variables", 2) => Some(SystemClauseType::TermVariables),
("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo),
("$unwind_environments", 0) => Some(SystemClauseType::UnwindEnvironments),
("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack),
("$unify_with_occurs_check", 2) => Some(SystemClauseType::UnifyWithOccursCheck),
("$directory_files", 2) => Some(SystemClauseType::DirectoryFiles),
("$file_size", 2) => Some(SystemClauseType::FileSize),
("$file_exists", 1) => Some(SystemClauseType::FileExists),
("$directory_exists", 1) => Some(SystemClauseType::DirectoryExists),
("$directory_separator", 1) => Some(SystemClauseType::DirectorySeparator),
("$make_directory", 1) => Some(SystemClauseType::MakeDirectory),
("$make_directory_path", 1) => Some(SystemClauseType::MakeDirectoryPath),
("$delete_file", 1) => Some(SystemClauseType::DeleteFile),
("$rename_file", 2) => Some(SystemClauseType::RenameFile),
("$delete_directory", 1) => Some(SystemClauseType::DeleteDirectory),
("$working_directory", 2) => Some(SystemClauseType::WorkingDirectory),
("$path_canonical", 2) => Some(SystemClauseType::PathCanonical),
("$file_time", 3) => Some(SystemClauseType::FileTime),
("$clause_to_evacuable", 2) => {
Some(SystemClauseType::REPL(REPLCodePtr::ClauseToEvacuable))
}
("$scoped_clause_to_evacuable", 3) => {
Some(SystemClauseType::REPL(REPLCodePtr::ScopedClauseToEvacuable))
}
("$conclude_load", 1) => Some(SystemClauseType::REPL(REPLCodePtr::ConcludeLoad)),
("$use_module", 3) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)),
("$declare_module", 3) => Some(SystemClauseType::REPL(REPLCodePtr::DeclareModule)),
("$load_compiled_library", 3) => {
Some(SystemClauseType::REPL(REPLCodePtr::LoadCompiledLibrary))
}
("$push_load_state_payload", 1) => {
Some(SystemClauseType::REPL(REPLCodePtr::PushLoadStatePayload))
}
("$add_in_situ_filename_module", 1) => {
Some(SystemClauseType::REPL(REPLCodePtr::AddInSituFilenameModule))
}
("$asserta", 5) => Some(SystemClauseType::REPL(REPLCodePtr::Asserta)),
("$assertz", 5) => Some(SystemClauseType::REPL(REPLCodePtr::Assertz)),
("$retract_clause", 4) => Some(SystemClauseType::REPL(REPLCodePtr::Retract)),
("$is_consistent_with_term_queue", 4) => Some(SystemClauseType::REPL(
REPLCodePtr::IsConsistentWithTermQueue,
)),
("$flush_term_queue", 1) => Some(SystemClauseType::REPL(REPLCodePtr::FlushTermQueue)),
("$remove_module_exports", 2) => {
Some(SystemClauseType::REPL(REPLCodePtr::RemoveModuleExports))
}
("$add_non_counted_backtracking", 3) => Some(SystemClauseType::REPL(
REPLCodePtr::AddNonCountedBacktracking,
)),
("$variant", 2) => Some(SystemClauseType::Variant),
("$wam_instructions", 4) => Some(SystemClauseType::WAMInstructions),
("$write_term", 7) => Some(SystemClauseType::WriteTerm),
("$write_term_to_chars", 7) => Some(SystemClauseType::WriteTermToChars),
("$scryer_prolog_version", 1) => Some(SystemClauseType::ScryerPrologVersion),
("$crypto_random_byte", 1) => Some(SystemClauseType::CryptoRandomByte),
("$crypto_data_hash", 4) => Some(SystemClauseType::CryptoDataHash),
("$crypto_data_hkdf", 7) => Some(SystemClauseType::CryptoDataHKDF),
("$crypto_password_hash", 4) => Some(SystemClauseType::CryptoPasswordHash),
("$crypto_data_encrypt", 7) => Some(SystemClauseType::CryptoDataEncrypt),
("$crypto_data_decrypt", 6) => Some(SystemClauseType::CryptoDataDecrypt),
("$crypto_curve_scalar_mult", 5) => Some(SystemClauseType::CryptoCurveScalarMult),
("$ed25519_sign", 4) => Some(SystemClauseType::Ed25519Sign),
("$ed25519_verify", 4) => Some(SystemClauseType::Ed25519Verify),
("$ed25519_new_keypair", 1) => Some(SystemClauseType::Ed25519NewKeyPair),
("$ed25519_keypair_public_key", 2) => Some(SystemClauseType::Ed25519KeyPairPublicKey),
("$curve25519_scalar_mult", 3) => Some(SystemClauseType::Curve25519ScalarMult),
("$first_non_octet", 2) => Some(SystemClauseType::FirstNonOctet),
("$load_html", 3) => Some(SystemClauseType::LoadHTML),
("$load_xml", 3) => Some(SystemClauseType::LoadXML),
("$getenv", 2) => Some(SystemClauseType::GetEnv),
("$setenv", 2) => Some(SystemClauseType::SetEnv),
("$unsetenv", 1) => Some(SystemClauseType::UnsetEnv),
("$shell", 2) => Some(SystemClauseType::Shell),
("$pid", 1) => Some(SystemClauseType::PID),
("$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),
("$debug_hook", 0) => Some(SystemClauseType::DebugHook),
("$popcount", 2) => Some(SystemClauseType::PopCount),
_ => None,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub(crate) enum BuiltInClauseType {
AcyclicTerm,
Arg,
Compare,
CompareTerm(CompareTermQT),
CopyTerm,
Eq,
Functor,
Ground,
Is(RegType, ArithmeticTerm),
KeySort,
NotEq,
Read,
Sort,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum ClauseType {
BuiltIn(BuiltInClauseType),
CallN,
Inlined(InlinedClauseType),
Named(ClauseName, usize, CodeIndex), // name, arity, index.
Op(ClauseName, SharedOpDesc, CodeIndex),
System(SystemClauseType),
}
impl BuiltInClauseType {
pub(crate) fn name(&self) -> ClauseName {
match self {
&BuiltInClauseType::AcyclicTerm => clause_name!("acyclic_term"),
&BuiltInClauseType::Arg => clause_name!("arg"),
&BuiltInClauseType::Compare => clause_name!("compare"),
&BuiltInClauseType::CompareTerm(qt) => clause_name!(qt.name()),
&BuiltInClauseType::CopyTerm => clause_name!("copy_term"),
&BuiltInClauseType::Eq => clause_name!("=="),
&BuiltInClauseType::Functor => clause_name!("functor"),
&BuiltInClauseType::Ground => clause_name!("ground"),
&BuiltInClauseType::Is(..) => clause_name!("is"),
&BuiltInClauseType::KeySort => clause_name!("keysort"),
&BuiltInClauseType::NotEq => clause_name!("\\=="),
&BuiltInClauseType::Read => clause_name!("read"),
&BuiltInClauseType::Sort => clause_name!("sort"),
}
}
pub(crate) fn arity(&self) -> usize {
match self {
&BuiltInClauseType::AcyclicTerm => 1,
&BuiltInClauseType::Arg => 3,
&BuiltInClauseType::Compare => 2,
&BuiltInClauseType::CompareTerm(_) => 2,
&BuiltInClauseType::CopyTerm => 2,
&BuiltInClauseType::Eq => 2,
&BuiltInClauseType::Functor => 3,
&BuiltInClauseType::Ground => 1,
&BuiltInClauseType::Is(..) => 2,
&BuiltInClauseType::KeySort => 2,
&BuiltInClauseType::NotEq => 2,
&BuiltInClauseType::Read => 2,
&BuiltInClauseType::Sort => 2,
}
}
}
impl ClauseType {
pub(crate) fn spec(&self) -> Option<SharedOpDesc> {
match self {
&ClauseType::Op(_, ref spec, _) => Some(spec.clone()),
&ClauseType::Inlined(InlinedClauseType::CompareNumber(..))
| &ClauseType::BuiltIn(BuiltInClauseType::Is(..))
| &ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(_))
| &ClauseType::BuiltIn(BuiltInClauseType::NotEq)
| &ClauseType::BuiltIn(BuiltInClauseType::Eq) => Some(SharedOpDesc::new(700, XFX)),
_ => None,
}
}
pub(crate) fn name(&self) -> ClauseName {
match self {
&ClauseType::BuiltIn(ref built_in) => built_in.name(),
&ClauseType::CallN => clause_name!("$call"),
&ClauseType::Inlined(ref inlined) => clause_name!(inlined.name()),
&ClauseType::Op(ref name, ..) => name.clone(),
&ClauseType::Named(ref name, ..) => name.clone(),
&ClauseType::System(ref system) => system.name(),
}
}
pub(crate) fn from(name: ClauseName, arity: usize, spec: Option<SharedOpDesc>) -> Self {
CLAUSE_TYPE_FORMS
.borrow()
.get(&(name.as_str(), arity))
.cloned()
.unwrap_or_else(|| {
SystemClauseType::from(name.as_str(), arity)
.map(ClauseType::System)
.unwrap_or_else(|| {
if let Some(spec) = spec {
ClauseType::Op(name, spec, CodeIndex::default())
} else if name.as_str() == "$call" {
ClauseType::CallN
} else {
ClauseType::Named(name, arity, CodeIndex::default())
}
})
})
}
}
impl From<InlinedClauseType> for ClauseType {
fn from(inlined_ct: InlinedClauseType) -> Self {
ClauseType::Inlined(inlined_ct)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,16 @@
use indexmap::IndexMap; use indexmap::IndexMap;
use prolog_parser::ast::*;
use prolog_parser::temp_v;
use crate::allocator::*; use crate::allocator::*;
use crate::fixtures::*; use crate::fixtures::*;
use crate::forms::*; use crate::forms::Level;
use crate::instructions::*;
use crate::machine::machine_indices::*; use crate::machine::machine_indices::*;
use crate::targets::*; use crate::parser::ast::*;
use crate::targets::CompilationTarget;
use crate::temp_v;
use fxhash::FxBuildHasher;
use std::cell::Cell; use std::cell::Cell;
use std::collections::BTreeSet; use std::collections::BTreeSet;
@@ -15,23 +18,23 @@ use std::rc::Rc;
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct DebrayAllocator { pub(crate) struct DebrayAllocator {
bindings: IndexMap<Rc<Var>, VarData>, bindings: IndexMap<Rc<String>, VarData, FxBuildHasher>,
arg_c: usize, arg_c: usize,
temp_lb: usize, temp_lb: usize,
arity: usize, // 0 if not at head. arity: usize, // 0 if not at head.
contents: IndexMap<usize, Rc<Var>>, contents: IndexMap<usize, Rc<String>, FxBuildHasher>,
in_use: BTreeSet<usize>, in_use: BTreeSet<usize>,
} }
impl DebrayAllocator { impl DebrayAllocator {
fn is_curr_arg_distinct_from(&self, var: &Var) -> bool { fn is_curr_arg_distinct_from(&self, var: &String) -> bool {
match self.contents.get(&self.arg_c) { match self.contents.get(&self.arg_c) {
Some(t_var) if **t_var != *var => true, Some(t_var) if **t_var != *var => true,
_ => false, _ => false,
} }
} }
fn occurs_shallowly_in_head(&self, var: &Var, r: usize) -> bool { fn occurs_shallowly_in_head(&self, var: &String, r: usize) -> bool {
match self.bindings.get(var).unwrap() { match self.bindings.get(var).unwrap() {
&VarData::Temp(_, _, ref tvd) => tvd.use_set.contains(&(GenContext::Head, r)), &VarData::Temp(_, _, ref tvd) => tvd.use_set.contains(&(GenContext::Head, r)),
_ => false, _ => false,
@@ -44,7 +47,7 @@ impl DebrayAllocator {
in_use_range || self.in_use.contains(&r) in_use_range || self.in_use.contains(&r)
} }
fn alloc_with_cr(&self, var: &Var) -> usize { fn alloc_with_cr(&self, var: &String) -> usize {
match self.bindings.get(var) { match self.bindings.get(var) {
Some(&VarData::Temp(_, _, ref tvd)) => { Some(&VarData::Temp(_, _, ref tvd)) => {
for &(_, reg) in tvd.use_set.iter() { for &(_, reg) in tvd.use_set.iter() {
@@ -70,7 +73,7 @@ impl DebrayAllocator {
} }
} }
fn alloc_with_ca(&self, var: &Var) -> usize { fn alloc_with_ca(&self, var: &String) -> usize {
match self.bindings.get(var) { match self.bindings.get(var) {
Some(&VarData::Temp(_, _, ref tvd)) => { Some(&VarData::Temp(_, _, ref tvd)) => {
for &(_, reg) in tvd.use_set.iter() { for &(_, reg) in tvd.use_set.iter() {
@@ -98,7 +101,7 @@ impl DebrayAllocator {
} }
} }
fn alloc_in_last_goal_hint(&self, chunk_num: usize) -> Option<(Rc<Var>, usize)> { fn alloc_in_last_goal_hint(&self, chunk_num: usize) -> Option<(Rc<String>, usize)> {
// we want to allocate a register to the k^{th} parameter, par_k. // we want to allocate a register to the k^{th} parameter, par_k.
// par_k may not be a temporary variable. // par_k may not be a temporary variable.
let k = self.arg_c; let k = self.arg_c;
@@ -123,7 +126,7 @@ impl DebrayAllocator {
} }
} }
fn evacuate_arg<'a, Target>(&mut self, chunk_num: usize, target: &mut Vec<Target>) fn evacuate_arg<'a, Target>(&mut self, chunk_num: usize, target: &mut Vec<Instruction>)
where where
Target: CompilationTarget<'a>, Target: CompilationTarget<'a>,
{ {
@@ -149,10 +152,10 @@ impl DebrayAllocator {
fn alloc_reg_to_var<'a, Target>( fn alloc_reg_to_var<'a, Target>(
&mut self, &mut self,
var: &Var, var: &String,
lvl: Level, lvl: Level,
term_loc: GenContext, term_loc: GenContext,
target: &mut Vec<Target>, target: &mut Vec<Instruction>,
) -> usize ) -> usize
where where
Target: CompilationTarget<'a>, Target: CompilationTarget<'a>,
@@ -160,7 +163,7 @@ impl DebrayAllocator {
match term_loc { match term_loc {
GenContext::Head => { GenContext::Head => {
if let Level::Shallow = lvl { if let Level::Shallow = lvl {
self.evacuate_arg(0, target); self.evacuate_arg::<Target>(0, target);
self.alloc_with_cr(var) self.alloc_with_cr(var)
} else { } else {
self.alloc_with_ca(var) self.alloc_with_ca(var)
@@ -169,7 +172,7 @@ impl DebrayAllocator {
GenContext::Mid(_) => self.alloc_with_ca(var), GenContext::Mid(_) => self.alloc_with_ca(var),
GenContext::Last(chunk_num) => { GenContext::Last(chunk_num) => {
if let Level::Shallow = lvl { if let Level::Shallow = lvl {
self.evacuate_arg(chunk_num, target); self.evacuate_arg::<Target>(chunk_num, target);
self.alloc_with_cr(var) self.alloc_with_cr(var)
} else { } else {
self.alloc_with_ca(var) self.alloc_with_ca(var)
@@ -193,7 +196,7 @@ impl DebrayAllocator {
final_index final_index
} }
fn in_place(&self, var: &Var, term_loc: GenContext, r: RegType, k: usize) -> bool { fn in_place(&self, var: &String, term_loc: GenContext, r: RegType, k: usize) -> bool {
match term_loc { match term_loc {
GenContext::Head if !r.is_perm() => r.reg_num() == k, GenContext::Head if !r.is_perm() => r.reg_num() == k,
_ => match self.bindings().get(var).unwrap() { _ => match self.bindings().get(var).unwrap() {
@@ -210,13 +213,18 @@ impl<'a> Allocator<'a> for DebrayAllocator {
arity: 0, arity: 0,
arg_c: 1, arg_c: 1,
temp_lb: 1, temp_lb: 1,
bindings: IndexMap::new(), bindings: IndexMap::with_hasher(FxBuildHasher::default()),
contents: IndexMap::new(), contents: IndexMap::with_hasher(FxBuildHasher::default()),
in_use: BTreeSet::new(), in_use: BTreeSet::new(),
} }
} }
fn mark_anon_var<Target>(&mut self, lvl: Level, term_loc: GenContext, target: &mut Vec<Target>) fn mark_anon_var<Target>(
&mut self,
lvl: Level,
term_loc: GenContext,
target: &mut Vec<Instruction>,
)
where where
Target: CompilationTarget<'a>, Target: CompilationTarget<'a>,
{ {
@@ -228,7 +236,7 @@ impl<'a> Allocator<'a> for DebrayAllocator {
let k = self.arg_c; let k = self.arg_c;
if let GenContext::Last(chunk_num) = term_loc { if let GenContext::Last(chunk_num) = term_loc {
self.evacuate_arg(chunk_num, target); self.evacuate_arg::<Target>(chunk_num, target);
} }
self.arg_c += 1; self.arg_c += 1;
@@ -243,7 +251,7 @@ impl<'a> Allocator<'a> for DebrayAllocator {
lvl: Level, lvl: Level,
term_loc: GenContext, term_loc: GenContext,
cell: &Cell<RegType>, cell: &Cell<RegType>,
target: &mut Vec<Target>, target: &mut Vec<Instruction>,
) where ) where
Target: CompilationTarget<'a>, Target: CompilationTarget<'a>,
{ {
@@ -254,7 +262,7 @@ impl<'a> Allocator<'a> for DebrayAllocator {
let k = self.arg_c; let k = self.arg_c;
if let GenContext::Last(chunk_num) = term_loc { if let GenContext::Last(chunk_num) = term_loc {
self.evacuate_arg(chunk_num, target); self.evacuate_arg::<Target>(chunk_num, target);
} }
self.arg_c += 1; self.arg_c += 1;
@@ -270,20 +278,18 @@ impl<'a> Allocator<'a> for DebrayAllocator {
cell.set(r); cell.set(r);
} }
fn mark_var<Target>( fn mark_var<Target: CompilationTarget<'a>>(
&mut self, &mut self,
var: Rc<Var>, var: Rc<String>,
lvl: Level, lvl: Level,
cell: &'a Cell<VarReg>, cell: &'a Cell<VarReg>,
term_loc: GenContext, term_loc: GenContext,
target: &mut Vec<Target>, target: &mut Vec<Instruction>,
) where ) {
Target: CompilationTarget<'a>,
{
let (r, is_new_var) = match self.get(var.clone()) { let (r, is_new_var) = match self.get(var.clone()) {
RegType::Temp(0) => { RegType::Temp(0) => {
// here, r is temporary *and* unassigned. // here, r is temporary *and* unassigned.
let o = self.alloc_reg_to_var(&var, lvl, term_loc, target); let o = self.alloc_reg_to_var::<Target>(&var, lvl, term_loc, target);
cell.set(VarReg::Norm(RegType::Temp(o))); cell.set(VarReg::Norm(RegType::Temp(o)));
(RegType::Temp(o), true) (RegType::Temp(o), true)
@@ -297,27 +303,25 @@ impl<'a> Allocator<'a> for DebrayAllocator {
r => (r, false), r => (r, false),
}; };
self.mark_reserved_var(var, lvl, cell, term_loc, target, r, is_new_var); self.mark_reserved_var::<Target>(var, lvl, cell, term_loc, target, r, is_new_var);
} }
fn mark_reserved_var<Target>( fn mark_reserved_var<Target: CompilationTarget<'a>>(
&mut self, &mut self,
var: Rc<Var>, var: Rc<String>,
lvl: Level, lvl: Level,
cell: &'a Cell<VarReg>, cell: &'a Cell<VarReg>,
term_loc: GenContext, term_loc: GenContext,
target: &mut Vec<Target>, target: &mut Vec<Instruction>,
r: RegType, r: RegType,
is_new_var: bool, is_new_var: bool,
) where ) {
Target: CompilationTarget<'a>,
{
match lvl { match lvl {
Level::Root | Level::Shallow => { Level::Root | Level::Shallow => {
let k = self.arg_c; let k = self.arg_c;
if self.is_curr_arg_distinct_from(&var) { if self.is_curr_arg_distinct_from(&var) {
self.evacuate_arg(term_loc.chunk_num(), target); self.evacuate_arg::<Target>(term_loc.chunk_num(), target);
} }
self.arg_c += 1; self.arg_c += 1;
@@ -382,12 +386,12 @@ impl<'a> Allocator<'a> for DebrayAllocator {
self.bindings self.bindings
} }
fn reset_at_head(&mut self, args: &Vec<Box<Term>>) { fn reset_at_head(&mut self, args: &Vec<Term>) {
self.reset_arg(args.len()); self.reset_arg(args.len());
self.arity = args.len(); self.arity = args.len();
for (idx, arg) in args.iter().enumerate() { for (idx, arg) in args.iter().enumerate() {
if let &Term::Var(_, ref var) = arg.as_ref() { if let &Term::Var(_, ref var) = arg {
let r = self.get(var.clone()); let r = self.get(var.clone());
if !r.is_perm() && r.reg_num() == 0 { if !r.is_perm() && r.reg_num() == 0 {

View File

@@ -20,12 +20,6 @@
:- use_module(library(reif)). :- use_module(library(reif)).
permutation([], []).
permutation([X|Xs], Ys) :-
permutation(Xs, Yss),
select(X, Ys, Yss).
valid_time([H1,H2,M1,M2], T) :- valid_time([H1,H2,M1,M2], T) :-
memberd_t(H1, [0,1,2], TH1), memberd_t(H1, [0,1,2], TH1),
memberd_t(H2, [0,1,2,3,4,5,6,7,8,9], TH2), memberd_t(H2, [0,1,2,3,4,5,6,7,8,9], TH2),

View File

@@ -1,4 +1,4 @@
use prolog_parser::ast::*; use crate::parser::ast::*;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*; use crate::instructions::*;
@@ -84,8 +84,8 @@ type VariableFixture<'a> = (VarStatus, Vec<&'a Cell<VarReg>>);
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct VariableFixtures<'a> { pub(crate) struct VariableFixtures<'a> {
perm_vars: IndexMap<Rc<Var>, VariableFixture<'a>>, perm_vars: IndexMap<Rc<String>, VariableFixture<'a>>,
last_chunk_temp_vars: IndexSet<Rc<Var>>, last_chunk_temp_vars: IndexSet<Rc<String>>,
} }
impl<'a> VariableFixtures<'a> { impl<'a> VariableFixtures<'a> {
@@ -96,11 +96,11 @@ impl<'a> VariableFixtures<'a> {
} }
} }
pub(crate) fn insert(&mut self, var: Rc<Var>, vs: VariableFixture<'a>) { pub(crate) fn insert(&mut self, var: Rc<String>, vs: VariableFixture<'a>) {
self.perm_vars.insert(var, vs); self.perm_vars.insert(var, vs);
} }
pub(crate) fn insert_last_chunk_temp_var(&mut self, var: Rc<Var>) { pub(crate) fn insert_last_chunk_temp_var(&mut self, var: Rc<String>) {
self.last_chunk_temp_vars.insert(var); self.last_chunk_temp_vars.insert(var);
} }
@@ -115,7 +115,7 @@ impl<'a> VariableFixtures<'a> {
// Compute the conflict set of u. // Compute the conflict set of u.
// 1. // 1.
let mut use_sets: IndexMap<Rc<Var>, OccurrenceSet> = IndexMap::new(); let mut use_sets: IndexMap<Rc<String>, OccurrenceSet> = IndexMap::new();
for (var, &mut (ref mut var_status, _)) in self.iter_mut() { for (var, &mut (ref mut var_status, _)) in self.iter_mut() {
if let &mut VarStatus::Temp(_, ref mut var_data) = var_status { if let &mut VarStatus::Temp(_, ref mut var_data) = var_status {
@@ -153,11 +153,11 @@ impl<'a> VariableFixtures<'a> {
} }
} }
fn get_mut(&mut self, u: Rc<Var>) -> Option<&mut VariableFixture<'a>> { fn get_mut(&mut self, u: Rc<String>) -> Option<&mut VariableFixture<'a>> {
self.perm_vars.get_mut(&u) self.perm_vars.get_mut(&u)
} }
fn iter_mut(&mut self) -> indexmap::map::IterMut<Rc<Var>, VariableFixture<'a>> { fn iter_mut(&mut self) -> indexmap::map::IterMut<Rc<String>, VariableFixture<'a>> {
self.perm_vars.iter_mut() self.perm_vars.iter_mut()
} }
@@ -218,11 +218,11 @@ impl<'a> VariableFixtures<'a> {
} }
} }
pub(crate) fn into_iter(self) -> indexmap::map::IntoIter<Rc<Var>, VariableFixture<'a>> { pub(crate) fn into_iter(self) -> indexmap::map::IntoIter<Rc<String>, VariableFixture<'a>> {
self.perm_vars.into_iter() self.perm_vars.into_iter()
} }
fn values(&self) -> indexmap::map::Values<Rc<Var>, VariableFixture<'a>> { fn values(&self) -> indexmap::map::Values<Rc<String>, VariableFixture<'a>> {
self.perm_vars.values() self.perm_vars.values()
} }
@@ -272,10 +272,10 @@ impl UnsafeVarMarker {
} }
} }
pub(crate) fn mark_safe_vars(&mut self, query_instr: &QueryInstruction) -> bool { pub(crate) fn mark_safe_vars(&mut self, query_instr: &Instruction) -> bool {
match query_instr { match query_instr {
&QueryInstruction::PutVariable(r @ RegType::Temp(_), _) &Instruction::PutVariable(r @ RegType::Temp(_), _) |
| &QueryInstruction::SetVariable(r) => { &Instruction::SetVariable(r) => {
self.safe_vars.insert(r); self.safe_vars.insert(r);
true true
} }
@@ -283,10 +283,10 @@ impl UnsafeVarMarker {
} }
} }
pub(crate) fn mark_phase(&mut self, query_instr: &QueryInstruction, phase: usize) { pub(crate) fn mark_phase(&mut self, query_instr: &Instruction, phase: usize) {
match query_instr { match query_instr {
&QueryInstruction::PutValue(r @ RegType::Perm(_), _) &Instruction::PutValue(r @ RegType::Perm(_), _) |
| &QueryInstruction::SetValue(r) => { &Instruction::SetValue(r) => {
let p = self.unsafe_vars.entry(r).or_insert(0); let p = self.unsafe_vars.entry(r).or_insert(0);
*p = phase; *p = phase;
} }
@@ -294,21 +294,21 @@ impl UnsafeVarMarker {
} }
} }
pub(crate) fn mark_unsafe_vars(&mut self, query_instr: &mut QueryInstruction, phase: usize) { pub(crate) fn mark_unsafe_vars(&mut self, query_instr: &mut Instruction, phase: usize) {
match query_instr { match query_instr {
&mut QueryInstruction::PutValue(RegType::Perm(i), arg) => { &mut Instruction::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)) {
if p == phase { if p == phase {
*query_instr = QueryInstruction::PutUnsafeValue(i, arg); *query_instr = Instruction::PutUnsafeValue(i, arg);
self.safe_vars.insert(RegType::Perm(i)); self.safe_vars.insert(RegType::Perm(i));
} else { } else {
self.unsafe_vars.insert(RegType::Perm(i), p); self.unsafe_vars.insert(RegType::Perm(i), p);
} }
} }
} }
&mut QueryInstruction::SetValue(r) => { &mut Instruction::SetValue(r) => {
if !self.safe_vars.contains(&r) { if !self.safe_vars.contains(&r) {
*query_instr = QueryInstruction::SetLocalValue(r); *query_instr = Instruction::SetLocalValue(r);
self.safe_vars.insert(r); self.safe_vars.insert(r);
self.unsafe_vars.remove(&r); self.unsafe_vars.remove(&r);

View File

@@ -1,33 +1,41 @@
use prolog_parser::ast::*; use crate::arena::*;
use prolog_parser::parser::OpDesc; use crate::atom_table::*;
use prolog_parser::{clause_name, is_infix, is_postfix}; use crate::instructions::*;
use crate::machine::heap::*;
use crate::clause_types::*;
use crate::machine::loader::PredicateQueue; 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::rug::{Integer, Rational}; use crate::parser::ast::*;
use ordered_float::OrderedFloat; use crate::parser::parser::CompositeOpDesc;
use crate::parser::rug::{Integer, Rational};
use crate::types::*;
use fxhash::FxBuildHasher;
use indexmap::{IndexMap, IndexSet}; use indexmap::{IndexMap, IndexSet};
use ordered_float::OrderedFloat;
use slice_deque::*; use slice_deque::*;
use std::cell::Cell; use std::cell::Cell;
use std::convert::TryFrom;
use std::fmt;
use std::ops::AddAssign; use std::ops::AddAssign;
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
pub(crate) type PredicateKey = (ClauseName, usize); // name, arity. use crate::{is_infix, is_postfix};
pub(crate) type Predicate = Vec<PredicateClause>; pub type PredicateKey = (Atom, usize); // name, arity.
pub 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(crate) type JumpStub = Vec<Term>; pub type JumpStub = Vec<Term>;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) enum TopLevel { pub enum TopLevel {
Fact(Term), // Term, line_num, col_num Fact(Term), // Term, line_num, col_num
Predicate(Predicate), Predicate(Predicate),
Query(Vec<QueryTerm>), Query(Vec<QueryTerm>),
@@ -35,7 +43,7 @@ pub(crate) enum TopLevel {
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) enum AppendOrPrepend { pub enum AppendOrPrepend {
Append, Append,
Prepend, Prepend,
} }
@@ -51,7 +59,7 @@ impl AppendOrPrepend {
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) enum Level { pub enum Level {
Deep, Deep,
Root, Root,
Shallow, Shallow,
@@ -67,12 +75,12 @@ impl Level {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) enum QueryTerm { pub 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<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.
UnblockedCut(Cell<VarReg>), UnblockedCut(Cell<VarReg>),
GetLevelAndUnify(Cell<VarReg>, Rc<Var>), GetLevelAndUnify(Cell<VarReg>, Rc<String>),
Jump(JumpStub), Jump(JumpStub),
} }
@@ -95,25 +103,25 @@ impl QueryTerm {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct Rule { pub struct Rule {
pub(crate) head: (ClauseName, Vec<Box<Term>>, QueryTerm), pub(crate) head: (Atom, Vec<Term>, QueryTerm),
pub(crate) clauses: Vec<QueryTerm>, pub(crate) clauses: Vec<QueryTerm>,
} }
#[derive(Clone, Debug, Hash)] #[derive(Clone, Debug, Hash)]
pub(crate) enum ListingSource { pub enum ListingSource {
DynamicallyGenerated, DynamicallyGenerated,
File(ClauseName, PathBuf), // filename, path File(Atom, PathBuf), // filename, path
User, User,
} }
impl ListingSource { impl ListingSource {
pub(crate) fn from_file_and_path(filename: ClauseName, path_buf: PathBuf) -> Self { pub(crate) fn from_file_and_path(filename: Atom, path_buf: PathBuf) -> Self {
ListingSource::File(filename, path_buf) ListingSource::File(filename, path_buf)
} }
} }
pub(crate) trait ClauseInfo { pub trait ClauseInfo {
fn is_consistent(&self, clauses: &PredicateQueue) -> bool { fn is_consistent(&self, clauses: &PredicateQueue) -> bool {
match clauses.first() { match clauses.first() {
Some(cl) => { Some(cl) => {
@@ -123,14 +131,14 @@ pub(crate) trait ClauseInfo {
} }
} }
fn name(&self) -> Option<ClauseName>; fn name(&self) -> Option<Atom>;
fn arity(&self) -> usize; fn arity(&self) -> usize;
} }
impl ClauseInfo for PredicateKey { impl ClauseInfo for PredicateKey {
#[inline] #[inline]
fn name(&self) -> Option<ClauseName> { fn name(&self) -> Option<Atom> {
Some(self.0.clone()) Some(self.0)
} }
#[inline] #[inline]
@@ -140,28 +148,32 @@ impl ClauseInfo for PredicateKey {
} }
impl ClauseInfo for Term { impl ClauseInfo for Term {
fn name(&self) -> Option<ClauseName> { fn name(&self) -> Option<Atom> {
//, atom_tbl: &AtomTable) -> Option<StringBuffer> {
match self { match self {
Term::Clause(_, ref name, ref terms, _) => { Term::Clause(_, name, terms) => {
// let str_buf = StringBuffer::from(*name, atom_tbl);
match name.as_str() { match name.as_str() {
// str_buf.as_str() {
":-" => { ":-" => {
match terms.len() { match terms.len() {
1 => None, // a declaration. 1 => None, // a declaration.
2 => terms[0].name(), 2 => terms[0].name(), //.map(|name| StringBuffer::from(name, atom_tbl)),
_ => Some(clause_name!(":-")), _ => Some(*name),
} }
} }
_ => Some(name.clone()), _ => Some(*name), //str_buf),
} }
} }
Term::Constant(_, Constant::Atom(ref name, _)) => Some(name.clone()), Term::Literal(_, Literal::Atom(name)) => Some(*name), //Some(StringBuffer::from(*name, atom_tbl)),
_ => None, _ => None,
} }
} }
fn arity(&self) -> usize { fn arity(&self) -> usize {
match self { match self {
Term::Clause(_, ref name, ref terms, _) => match name.as_str() { Term::Clause(_, name, terms) => match name.as_str() {
":-" => match terms.len() { ":-" => match terms.len() {
1 => 0, 1 => 0,
2 => terms[0].arity(), 2 => terms[0].arity(),
@@ -175,8 +187,8 @@ impl ClauseInfo for Term {
} }
impl ClauseInfo for Rule { impl ClauseInfo for Rule {
fn name(&self) -> Option<ClauseName> { fn name(&self) -> Option<Atom> {
Some(self.head.0.clone()) Some(self.head.0)
} }
fn arity(&self) -> usize { fn arity(&self) -> usize {
@@ -185,7 +197,7 @@ impl ClauseInfo for Rule {
} }
impl ClauseInfo for PredicateClause { impl ClauseInfo for PredicateClause {
fn name(&self) -> Option<ClauseName> { fn name(&self) -> Option<Atom> {
match self { match self {
&PredicateClause::Fact(ref term, ..) => term.name(), &PredicateClause::Fact(ref term, ..) => term.name(),
&PredicateClause::Rule(ref rule, ..) => rule.name(), &PredicateClause::Rule(ref rule, ..) => rule.name(),
@@ -200,23 +212,21 @@ impl ClauseInfo for PredicateClause {
} }
} }
// pub(crate) type CompiledResult = (Predicate, VecDeque<TopLevel>);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) enum PredicateClause { pub enum PredicateClause {
Fact(Term), Fact(Term),
Rule(Rule), Rule(Rule),
} }
impl PredicateClause { impl PredicateClause {
// TODO: add this to `Term` in `prolog_parser` like `first_arg`. // TODO: add this to `Term` in `crate::parser` like `first_arg`.
pub(crate) fn args(&self) -> Option<&[Box<Term>]> { pub(crate) fn args(&self) -> Option<&[Term]> {
match *self { match self {
PredicateClause::Fact(ref term, ..) => match term { PredicateClause::Fact(term, ..) => match term {
Term::Clause(_, _, args, _) => Some(&args), Term::Clause(_, _, args) => Some(&args),
_ => None, _ => None,
}, },
PredicateClause::Rule(ref rule, ..) => { PredicateClause::Rule(rule, ..) => {
if rule.head.1.is_empty() { if rule.head.1.is_empty() {
None None
} else { } else {
@@ -228,36 +238,26 @@ impl PredicateClause {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) enum ModuleSource { pub enum ModuleSource {
Library(ClauseName), Library(Atom),
File(ClauseName), File(Atom),
} }
impl ModuleSource { impl ModuleSource {
pub(crate) fn as_functor_stub(&self) -> MachineStub { pub(crate) fn as_functor_stub(&self) -> MachineStub {
match self { match self {
ModuleSource::Library(ref name) => { ModuleSource::Library(name) => {
functor!("library", [clause_name(name.clone())]) functor!(atom!("library"), [atom(name)])
} }
ModuleSource::File(ref name) => { ModuleSource::File(name) => {
functor!(clause_name(name.clone())) functor!(name)
} }
} }
} }
} }
// pub(crate) type ScopedPredicateKey = (ClauseName, PredicateKey); // module name, predicate indicator.
/*
#[derive(Debug, Clone)]
pub(crate) enum MultiFileIndicator {
LocalScoped(ClauseName, usize), // name, arity
ModuleScoped(ScopedPredicateKey),
}
*/
#[derive(Clone, Copy, Hash, Debug)] #[derive(Clone, Copy, Hash, Debug)]
pub(crate) enum MetaSpec { pub enum MetaSpec {
Minus, Minus,
Plus, Plus,
Either, Either,
@@ -265,41 +265,25 @@ pub(crate) enum MetaSpec {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) enum Declaration { pub enum Declaration {
Dynamic(ClauseName, usize), Dynamic(Atom, usize),
MetaPredicate(ClauseName, ClauseName, Vec<MetaSpec>), // module name, name, meta-specs MetaPredicate(Atom, Atom, Vec<MetaSpec>), // module name, name, meta-specs
Module(ModuleDecl), Module(ModuleDecl),
NonCountedBacktracking(ClauseName, usize), // name, arity NonCountedBacktracking(Atom, usize), // name, arity
Op(OpDecl), Op(OpDecl),
UseModule(ModuleSource), UseModule(ModuleSource),
UseQualifiedModule(ModuleSource, IndexSet<ModuleExport>), UseQualifiedModule(ModuleSource, IndexSet<ModuleExport>),
} }
#[derive(Debug, Clone, Eq, Hash, PartialEq, Ord, PartialOrd)] #[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, Ord, PartialOrd)]
pub(crate) struct OpDecl { pub struct OpDecl {
pub(crate) prec: usize, pub(crate) op_desc: OpDesc,
pub(crate) spec: Specifier, pub(crate) name: Atom,
pub(crate) name: ClauseName,
} }
impl OpDecl { #[inline(always)]
#[inline] pub(crate) fn fixity(spec: u32) -> Fixity {
pub(crate) fn new(prec: usize, spec: Specifier, name: ClauseName) -> Self { match spec {
Self { prec, spec, name }
}
#[inline]
pub(crate) fn remove(&mut self, op_dir: &mut OpDir) {
let prec = self.prec;
self.prec = 0;
self.insert_into_op_dir(op_dir);
self.prec = prec;
}
#[inline]
pub(crate) fn fixity(&self) -> Fixity {
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,
@@ -307,29 +291,45 @@ impl OpDecl {
} }
} }
pub(crate) fn insert_into_op_dir(&self, op_dir: &mut OpDir) -> Option<(usize, Specifier)> {
let key = (self.name.clone(), self.fixity());
match op_dir.get(&key) { impl OpDecl {
#[inline]
pub(crate) fn new(op_desc: OpDesc, name: Atom) -> Self {
Self { op_desc, name }
}
#[inline]
pub(crate) fn remove(&mut self, op_dir: &mut OpDir) {
let prec = self.op_desc.get_prec();
self.op_desc.set(0, self.op_desc.get_spec());
self.insert_into_op_dir(op_dir);
self.op_desc.set(prec, self.op_desc.get_spec());
}
pub(crate) fn insert_into_op_dir(&self, op_dir: &mut OpDir) -> Option<OpDesc> {
let key = (self.name, fixity(self.op_desc.get_spec() as u32));
match op_dir.get_mut(&key) {
Some(cell) => { Some(cell) => {
return Some(cell.shared_op_desc().replace((self.prec, self.spec))); let (old_prec, old_spec) = cell.get();
cell.set(self.op_desc.get_prec(), self.op_desc.get_spec());
return Some(OpDesc::build_with(old_prec, old_spec));
} }
None => {} None => {}
} }
op_dir op_dir.insert(key, self.op_desc)
.insert(key, OpDirValue::new(self.spec, self.prec))
.map(|op_dir_value| op_dir_value.shared_op_desc().get())
} }
pub(crate) fn submit( pub(crate) fn submit(
&self, &self,
existing_desc: Option<OpDesc>, existing_desc: Option<CompositeOpDesc>,
op_dir: &mut OpDir, op_dir: &mut OpDir,
) -> Result<(), SessionError> { ) -> Result<(), SessionError> {
let (spec, name) = (self.spec, self.name.clone()); let (spec, name) = (self.op_desc.get_spec(), self.name.clone());
if is_infix!(spec) { if is_infix!(spec as u32) {
if let Some(desc) = existing_desc { if let Some(desc) = existing_desc {
if desc.post > 0 { if desc.post > 0 {
return Err(SessionError::OpIsInfixAndPostFix(name)); return Err(SessionError::OpIsInfixAndPostFix(name));
@@ -337,7 +337,7 @@ impl OpDecl {
} }
} }
if is_postfix!(spec) { if is_postfix!(spec as u32) {
if let Some(desc) = existing_desc { if let Some(desc) = existing_desc {
if desc.inf > 0 { if desc.inf > 0 {
return Err(SessionError::OpIsInfixAndPostFix(name)); return Err(SessionError::OpIsInfixAndPostFix(name));
@@ -350,22 +350,50 @@ impl OpDecl {
} }
} }
#[derive(Debug)]
pub enum AtomOrString {
Atom(Atom),
String(String),
}
impl AtomOrString {
#[inline]
pub fn as_str(&self) -> &str {
match self {
AtomOrString::Atom(atom) => atom.as_str(),
AtomOrString::String(string) => string.as_str(),
}
}
#[inline]
pub fn to_string(self) -> String {
match self {
AtomOrString::Atom(atom) => {
atom.as_str().to_owned()
}
AtomOrString::String(string) => {
string
}
}
}
}
pub(crate) fn fetch_atom_op_spec( pub(crate) fn fetch_atom_op_spec(
name: ClauseName, name: Atom,
spec: Option<SharedOpDesc>, spec: Option<OpDesc>,
op_dir: &OpDir, op_dir: &OpDir,
) -> Option<SharedOpDesc> { ) -> Option<OpDesc> {
fetch_op_spec_from_existing(name.clone(), 1, spec.clone(), op_dir) fetch_op_spec_from_existing(name, 1, spec, op_dir)
.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(crate) fn fetch_op_spec_from_existing( pub(crate) fn fetch_op_spec_from_existing(
name: ClauseName, name: Atom,
arity: usize, arity: usize,
spec: Option<SharedOpDesc>, op_desc: Option<OpDesc>,
op_dir: &OpDir, op_dir: &OpDir,
) -> Option<SharedOpDesc> { ) -> Option<OpDesc> {
if let Some(ref op_desc) = &spec { if let Some(ref op_desc) = &op_desc {
if op_desc.arity() != arity { if op_desc.arity() != arity {
/* it's possible to extend operator functors with /* it's possible to extend operator functors with
* additional terms. When that happens, * additional terms. When that happens,
@@ -374,36 +402,28 @@ pub(crate) fn fetch_op_spec_from_existing(
} }
} }
spec.or_else(|| fetch_op_spec(name, arity, op_dir)) op_desc.or_else(|| fetch_op_spec(name, arity, op_dir))
} }
pub(crate) fn fetch_op_spec( pub(crate) fn fetch_op_spec(name: Atom, arity: usize, op_dir: &OpDir) -> Option<OpDesc> {
name: ClauseName,
arity: usize,
op_dir: &OpDir,
) -> Option<SharedOpDesc> {
match arity { match arity {
2 => op_dir 2 => op_dir.get(&(name, Fixity::In)).and_then(|op_desc| {
.get(&(name, Fixity::In)) if op_desc.get_prec() > 0 {
.and_then(|OpDirValue(spec)| { Some(*op_desc)
if spec.prec() > 0 {
Some(spec.clone())
} else { } else {
None None
} }
}), }),
1 => { 1 => {
if let Some(OpDirValue(spec)) = op_dir.get(&(name.clone(), Fixity::Pre)) { if let Some(op_desc) = op_dir.get(&(name.clone(), Fixity::Pre)) {
if spec.prec() > 0 { if op_desc.get_prec() > 0 {
return Some(spec.clone()); return Some(*op_desc);
} }
} }
op_dir op_dir.get(&(name, Fixity::Post)).and_then(|op_desc| {
.get(&(name.clone(), Fixity::Post)) if op_desc.get_prec() > 0 {
.and_then(|OpDirValue(spec)| { Some(*op_desc)
if spec.prec() > 0 {
Some(spec.clone())
} else { } else {
None None
} }
@@ -413,22 +433,22 @@ pub(crate) fn fetch_op_spec(
} }
} }
pub(crate) type ModuleDir = IndexMap<ClauseName, Module>; pub(crate) type ModuleDir = IndexMap<Atom, Module, FxBuildHasher>;
#[derive(Debug, Clone, Eq, Hash, PartialEq)] #[derive(Debug, Clone, Eq, Hash, PartialEq)]
pub(crate) enum ModuleExport { pub enum ModuleExport {
OpDecl(OpDecl), OpDecl(OpDecl),
PredicateKey(PredicateKey), PredicateKey(PredicateKey),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct ModuleDecl { pub struct ModuleDecl {
pub(crate) name: ClauseName, pub(crate) name: Atom,
pub(crate) exports: Vec<ModuleExport>, pub(crate) exports: Vec<ModuleExport>,
} }
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct Module { pub struct Module {
pub(crate) module_decl: ModuleDecl, pub(crate) module_decl: ModuleDecl,
pub(crate) code_dir: CodeDir, pub(crate) code_dir: CodeDir,
pub(crate) op_dir: OpDir, pub(crate) op_dir: OpDir,
@@ -440,14 +460,19 @@ pub(crate) struct Module {
// Module's and related types are defined in forms. // Module's and related types are defined in forms.
impl Module { impl Module {
pub(crate) fn new(module_decl: ModuleDecl, listing_src: ListingSource) -> Self { pub(crate) fn new(
module_decl: ModuleDecl,
listing_src: ListingSource,
) -> Self {
Module { Module {
module_decl, module_decl,
code_dir: CodeDir::new(), code_dir: CodeDir::with_hasher(FxBuildHasher::default()),
op_dir: default_op_dir(), op_dir: default_op_dir(),
meta_predicates: MetaPredicateDir::new(), meta_predicates: MetaPredicateDir::with_hasher(FxBuildHasher::default()),
extensible_predicates: ExtensiblePredicates::new(), extensible_predicates: ExtensiblePredicates::with_hasher(FxBuildHasher::default()),
local_extensible_predicates: LocalExtensiblePredicates::new(), local_extensible_predicates: LocalExtensiblePredicates::with_hasher(
FxBuildHasher::default(),
),
listing_src, listing_src,
} }
} }
@@ -455,71 +480,137 @@ impl Module {
pub(crate) fn new_in_situ(module_decl: ModuleDecl) -> Self { pub(crate) fn new_in_situ(module_decl: ModuleDecl) -> Self {
Module { Module {
module_decl, module_decl,
code_dir: CodeDir::new(), code_dir: CodeDir::with_hasher(FxBuildHasher::default()),
op_dir: OpDir::new(), op_dir: OpDir::with_hasher(FxBuildHasher::default()),
meta_predicates: MetaPredicateDir::new(), meta_predicates: MetaPredicateDir::with_hasher(FxBuildHasher::default()),
extensible_predicates: ExtensiblePredicates::new(), extensible_predicates: ExtensiblePredicates::with_hasher(FxBuildHasher::default()),
local_extensible_predicates: LocalExtensiblePredicates::new(), local_extensible_predicates: LocalExtensiblePredicates::with_hasher(
FxBuildHasher::default()
),
listing_src: ListingSource::DynamicallyGenerated, listing_src: ListingSource::DynamicallyGenerated,
} }
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Copy, Clone)]
pub(crate) enum Number { pub enum Number {
Float(OrderedFloat<f64>), Float(OrderedFloat<f64>),
Integer(Rc<Integer>), Integer(TypedArenaPtr<Integer>),
Rational(Rc<Rational>), Rational(TypedArenaPtr<Rational>),
Fixnum(isize), Fixnum(Fixnum),
}
impl From<Integer> for Number {
#[inline]
fn from(n: Integer) -> Self {
Number::Integer(Rc::new(n))
}
}
impl From<Rational> for Number {
#[inline]
fn from(n: Rational) -> Self {
Number::Rational(Rc::new(n))
}
}
impl From<isize> for Number {
#[inline]
fn from(n: isize) -> Self {
Number::Fixnum(n)
}
} }
impl Default for Number { impl Default for Number {
fn default() -> Self { fn default() -> Self {
Number::Float(OrderedFloat(0f64)) Number::Fixnum(Fixnum::build_with(0))
} }
} }
impl Into<Constant> for Number { impl fmt::Display for Number {
#[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn into(self) -> Constant {
match self { match self {
Number::Fixnum(n) => Constant::Fixnum(n), Number::Float(fl) => write!(f, "{}", fl),
Number::Integer(n) => Constant::Integer(n), Number::Integer(n) => write!(f, "{}", n),
Number::Float(f) => Constant::Float(f), Number::Rational(r) => write!(f, "{}", r),
Number::Rational(r) => Constant::Rational(r), Number::Fixnum(n) => write!(f, "{}", n.get_num()),
} }
} }
} }
impl Into<HeapCellValue> for Number { pub trait ArenaFrom<T> {
fn arena_from(value: T, arena: &mut Arena) -> Self;
}
impl ArenaFrom<Integer> for Number {
#[inline] #[inline]
fn into(self) -> HeapCellValue { fn arena_from(value: Integer, arena: &mut Arena) -> Number {
match self { Number::Integer(arena_alloc!(value, arena))
Number::Fixnum(n) => HeapCellValue::Addr(Addr::Fixnum(n)), }
Number::Integer(n) => HeapCellValue::Integer(n), }
Number::Float(f) => HeapCellValue::Addr(Addr::Float(f)),
Number::Rational(r) => HeapCellValue::Rational(r), impl ArenaFrom<Rational> for Number {
#[inline]
fn arena_from(value: Rational, arena: &mut Arena) -> Number {
Number::Rational(arena_alloc!(value, arena))
}
}
impl ArenaFrom<usize> for Number {
#[inline]
fn arena_from(value: usize, arena: &mut Arena) -> Number {
match i64::try_from(value) {
Ok(value) => Fixnum::build_with_checked(value)
.map(Number::Fixnum)
.unwrap_or_else(|_| Number::Integer(arena_alloc!(Integer::from(value), arena))),
Err(_) => Number::Integer(arena_alloc!(Integer::from(value), arena)),
}
}
}
impl ArenaFrom<u64> for Number {
#[inline]
fn arena_from(value: u64, arena: &mut Arena) -> Number {
match i64::try_from(value) {
Ok(value) => Fixnum::build_with_checked(value)
.map(Number::Fixnum)
.unwrap_or_else(|_| Number::Integer(arena_alloc!(Integer::from(value), arena))),
Err(_) => Number::Integer(arena_alloc!(Integer::from(value), arena)),
}
}
}
impl ArenaFrom<i64> for Number {
#[inline]
fn arena_from(value: i64, arena: &mut Arena) -> Number {
Fixnum::build_with_checked(value)
.map(Number::Fixnum)
.unwrap_or_else(|_| Number::Integer(arena_alloc!(Integer::from(value), arena)))
}
}
impl ArenaFrom<isize> for Number {
#[inline]
fn arena_from(value: isize, arena: &mut Arena) -> Number {
Fixnum::build_with_checked(value as i64)
.map(Number::Fixnum)
.unwrap_or_else(|_| Number::Integer(arena_alloc!(Integer::from(value), arena)))
}
}
impl ArenaFrom<u32> for Number {
#[inline]
fn arena_from(value: u32, _arena: &mut Arena) -> Number {
Number::Fixnum(Fixnum::build_with(value as i64))
}
}
impl ArenaFrom<i32> for Number {
#[inline]
fn arena_from(value: i32, _arena: &mut Arena) -> Number {
Number::Fixnum(Fixnum::build_with(value as i64))
}
}
impl ArenaFrom<Number> for Literal {
#[inline]
fn arena_from(value: Number, arena: &mut Arena) -> Literal {
match value {
Number::Fixnum(n) => Literal::Fixnum(n),
Number::Integer(n) => Literal::Integer(n),
Number::Float(f) => Literal::Float(arena_alloc!(f, arena)),
Number::Rational(r) => Literal::Rational(r),
}
}
}
impl ArenaFrom<Number> for HeapCellValue {
#[inline]
fn arena_from(value: Number, arena: &mut Arena) -> HeapCellValue {
match value {
Number::Fixnum(n) => fixnum_as_cell!(n),
Number::Integer(n) => typed_arena_ptr_as_cell!(n),
Number::Float(n) => typed_arena_ptr_as_cell!(arena_alloc!(n, arena)),
Number::Rational(n) => typed_arena_ptr_as_cell!(n),
} }
} }
} }
@@ -528,9 +619,9 @@ impl Number {
#[inline] #[inline]
pub(crate) 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.get_num() > 0,
&Number::Integer(ref n) => &**n > &0, &Number::Integer(ref n) => &**n > &0,
&Number::Float(OrderedFloat(f)) => f.is_sign_positive(), &Number::Float(f) => f.is_sign_positive(),
&Number::Rational(ref r) => &**r > &0, &Number::Rational(ref r) => &**r > &0,
} }
} }
@@ -538,7 +629,7 @@ impl Number {
#[inline] #[inline]
pub(crate) 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.get_num() < 0,
&Number::Integer(ref n) => &**n < &0, &Number::Integer(ref n) => &**n < &0,
&Number::Float(OrderedFloat(f)) => f.is_sign_negative(), &Number::Float(OrderedFloat(f)) => f.is_sign_negative(),
&Number::Rational(ref r) => &**r < &0, &Number::Rational(ref r) => &**r < &0,
@@ -548,36 +639,20 @@ impl Number {
#[inline] #[inline]
pub(crate) 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.get_num() == 0,
&Number::Integer(ref n) => &**n == &0, &Number::Integer(ref n) => &**n == &0,
&Number::Float(f) => f == OrderedFloat(0f64), &Number::Float(f) => f == OrderedFloat(0f64),
&Number::Rational(ref r) => &**r == &0, &Number::Rational(ref r) => &**r == &0,
} }
} }
#[inline]
pub(crate) fn abs(self) -> Self {
match self {
Number::Fixnum(n) => {
if let Some(n) = n.checked_abs() {
Number::from(n)
} else {
Number::from(Integer::from(n).abs())
}
}
Number::Integer(n) => Number::from(Integer::from(n.abs_ref())),
Number::Float(f) => Number::Float(OrderedFloat(f.abs())),
Number::Rational(r) => Number::from(Rational::from(r.abs_ref())),
}
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) enum OptArgIndexKey { pub(crate) enum OptArgIndexKey {
Constant(usize, usize, Constant, Vec<Constant>), // index, IndexingCode location, opt arg, alternatives Literal(usize, usize, Literal, Vec<Literal>), // index, IndexingCode location, opt arg, alternatives
List(usize, usize), // index, IndexingCode location List(usize, usize), // index, IndexingCode location
None, None,
Structure(usize, usize, ClauseName, usize), // index, IndexingCode location, name, arity Structure(usize, usize, Atom, usize), // index, IndexingCode location, name, arity
} }
impl OptArgIndexKey { impl OptArgIndexKey {
@@ -589,7 +664,7 @@ impl OptArgIndexKey {
#[inline] #[inline]
pub(crate) fn arg_num(&self) -> usize { pub(crate) fn arg_num(&self) -> usize {
match &self { match &self {
OptArgIndexKey::Constant(arg_num, ..) OptArgIndexKey::Literal(arg_num, ..)
| OptArgIndexKey::Structure(arg_num, ..) | OptArgIndexKey::Structure(arg_num, ..)
| OptArgIndexKey::List(arg_num, _) => { | OptArgIndexKey::List(arg_num, _) => {
// these are always at least 1. // these are always at least 1.
@@ -607,7 +682,7 @@ impl OptArgIndexKey {
#[inline] #[inline]
pub(crate) fn switch_on_term_loc(&self) -> Option<usize> { pub(crate) fn switch_on_term_loc(&self) -> Option<usize> {
match &self { match &self {
OptArgIndexKey::Constant(_, loc, ..) OptArgIndexKey::Literal(_, loc, ..)
| OptArgIndexKey::Structure(_, loc, ..) | OptArgIndexKey::Structure(_, loc, ..)
| OptArgIndexKey::List(_, loc) => Some(*loc), | OptArgIndexKey::List(_, loc) => Some(*loc),
OptArgIndexKey::None => None, OptArgIndexKey::None => None,
@@ -617,7 +692,7 @@ impl OptArgIndexKey {
#[inline] #[inline]
pub(crate) fn set_switch_on_term_loc(&mut self, value: usize) { pub(crate) fn set_switch_on_term_loc(&mut self, value: usize) {
match self { match self {
OptArgIndexKey::Constant(_, ref mut loc, ..) OptArgIndexKey::Literal(_, ref mut loc, ..)
| OptArgIndexKey::Structure(_, ref mut loc, ..) | OptArgIndexKey::Structure(_, ref mut loc, ..)
| OptArgIndexKey::List(_, ref mut loc) => { | OptArgIndexKey::List(_, ref mut loc) => {
*loc = value; *loc = value;
@@ -631,7 +706,7 @@ impl AddAssign<usize> for OptArgIndexKey {
#[inline] #[inline]
fn add_assign(&mut self, n: usize) { fn add_assign(&mut self, n: usize) {
match self { match self {
OptArgIndexKey::Constant(_, ref mut o, ..) OptArgIndexKey::Literal(_, ref mut o, ..)
| OptArgIndexKey::List(_, ref mut o) | OptArgIndexKey::List(_, ref mut o)
| OptArgIndexKey::Structure(_, ref mut o, ..) => { | OptArgIndexKey::Structure(_, ref mut o, ..) => {
*o += n; *o += n;
@@ -700,6 +775,7 @@ pub(crate) struct LocalPredicateSkeleton {
pub(crate) is_multifile: bool, pub(crate) is_multifile: bool,
pub(crate) clause_clause_locs: SliceDeque<usize>, pub(crate) clause_clause_locs: SliceDeque<usize>,
pub(crate) clause_assert_margin: usize, pub(crate) clause_assert_margin: usize,
pub(crate) retracted_dynamic_clauses: Option<Vec<ClauseIndexInfo>>, // always None if non-dynamic.
} }
impl LocalPredicateSkeleton { impl LocalPredicateSkeleton {
@@ -711,6 +787,7 @@ impl LocalPredicateSkeleton {
is_multifile: false, is_multifile: false,
clause_clause_locs: sdeq![], clause_clause_locs: sdeq![],
clause_assert_margin: 0, clause_assert_margin: 0,
retracted_dynamic_clauses: Some(vec![]),
} }
} }
@@ -730,6 +807,20 @@ impl LocalPredicateSkeleton {
self.clause_clause_locs.clear(); self.clause_clause_locs.clear();
self.clause_assert_margin = 0; self.clause_assert_margin = 0;
} }
#[inline]
pub(crate) fn add_retracted_dynamic_clause_info(&mut self, clause_info: ClauseIndexInfo) {
debug_assert_eq!(self.is_dynamic, true);
if self.retracted_dynamic_clauses.is_none() {
self.retracted_dynamic_clauses = Some(vec![]);
}
self.retracted_dynamic_clauses
.as_mut()
.unwrap()
.push(clause_info);
}
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@@ -758,13 +849,6 @@ impl PredicateSkeleton {
} }
} }
#[inline]
pub(crate) fn reset(&mut self) {
self.core.clause_clause_locs.clear();
self.core.clause_assert_margin = 0;
self.clauses.clear();
}
pub(crate) fn target_pos_of_clause_clause_loc( pub(crate) fn target_pos_of_clause_clause_loc(
&self, &self,
clause_clause_loc: usize, clause_clause_loc: usize,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,33 +1,20 @@
use prolog_parser::ast::*; use crate::atom_table::*;
use prolog_parser::clause_name; use crate::parser::ast::*;
use prolog_parser::tabled_rc::*;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*; use crate::instructions::*;
use crate::rug::Integer;
use indexmap::IndexMap; use indexmap::IndexMap;
use slice_deque::{sdeq, SliceDeque}; use slice_deque::{sdeq, SliceDeque};
use std::convert::TryFrom;
use std::hash::Hash; use std::hash::Hash;
use std::iter::once; use std::iter::once;
use std::mem; use std::mem;
use std::rc::Rc;
#[derive(Debug, Clone, Copy)]
pub(crate) enum IndexingCodePtr {
External(usize), // the index points past the indexing instruction prelude.
DynamicExternal(usize), // an External index of a dynamic predicate, potentially invalidated by retraction.
Fail,
Internal(usize), // the index points into the indexing instruction prelude.
}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
enum OptArgIndexKeyType { enum OptArgIndexKeyType {
Structure, Structure,
Constant, Literal,
// List, // List,
} }
@@ -35,7 +22,7 @@ impl OptArgIndexKey {
#[inline] #[inline]
fn has_key_type(&self, key_type: OptArgIndexKeyType) -> bool { fn has_key_type(&self, key_type: OptArgIndexKeyType) -> bool {
match (self, key_type) { match (self, key_type) {
(OptArgIndexKey::Constant(..), OptArgIndexKeyType::Constant) (OptArgIndexKey::Literal(..), OptArgIndexKeyType::Literal)
| (OptArgIndexKey::Structure(..), OptArgIndexKeyType::Structure) | (OptArgIndexKey::Structure(..), OptArgIndexKeyType::Structure)
// | (OptArgIndexKey::List(..), OptArgIndexKeyType::List) // | (OptArgIndexKey::List(..), OptArgIndexKeyType::List)
=> true, => true,
@@ -45,11 +32,12 @@ impl OptArgIndexKey {
} }
#[inline] #[inline]
fn search_skeleton_for_first_key_type( fn search_skeleton_for_first_key_type<'a>(
skeleton: &[ClauseIndexInfo], skeleton: &'a [ClauseIndexInfo],
retracted_dynamic_clauses: &'a Option<Vec<ClauseIndexInfo>>,
key_type: OptArgIndexKeyType, key_type: OptArgIndexKeyType,
append_or_prepend: AppendOrPrepend, append_or_prepend: AppendOrPrepend,
) -> Option<&OptArgIndexKey> { ) -> Option<&'a OptArgIndexKey> {
if append_or_prepend.is_append() { if append_or_prepend.is_append() {
for clause_index_info in skeleton.iter().rev() { for clause_index_info in skeleton.iter().rev() {
if clause_index_info.opt_arg_index_key.has_key_type(key_type) { if clause_index_info.opt_arg_index_key.has_key_type(key_type) {
@@ -64,11 +52,20 @@ fn search_skeleton_for_first_key_type(
} }
} }
if let Some(retracted_clauses) = retracted_dynamic_clauses {
for clause_index_info in retracted_clauses.iter().rev() {
if clause_index_info.opt_arg_index_key.has_key_type(key_type) {
return Some(&clause_index_info.opt_arg_index_key);
}
}
}
None None
} }
struct IndexingCodeMergingPtr<'a> { struct IndexingCodeMergingPtr<'a> {
skeleton: &'a mut [ClauseIndexInfo], skeleton: &'a mut [ClauseIndexInfo],
retracted_dynamic_clauses: &'a Option<Vec<ClauseIndexInfo>>,
indexing_code: &'a mut Vec<IndexingLine>, indexing_code: &'a mut Vec<IndexingLine>,
offset: usize, offset: usize,
append_or_prepend: AppendOrPrepend, append_or_prepend: AppendOrPrepend,
@@ -79,22 +76,22 @@ impl<'a> IndexingCodeMergingPtr<'a> {
#[inline] #[inline]
fn new( fn new(
skeleton: &'a mut [ClauseIndexInfo], skeleton: &'a mut [ClauseIndexInfo],
retracted_dynamic_clauses: &'a Option<Vec<ClauseIndexInfo>>,
indexing_code: &'a mut Vec<IndexingLine>, indexing_code: &'a mut Vec<IndexingLine>,
append_or_prepend: AppendOrPrepend, append_or_prepend: AppendOrPrepend,
) -> Self { ) -> Self {
let is_dynamic = match &indexing_code[0] { let is_dynamic = match &indexing_code[0] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => { IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => match v {
match v {
IndexingCodePtr::External(_) => false, IndexingCodePtr::External(_) => false,
IndexingCodePtr::DynamicExternal(_) => true, IndexingCodePtr::DynamicExternal(_) => true,
_ => unreachable!() _ => unreachable!(),
} },
} _ => unreachable!(),
_ => unreachable!()
}; };
Self { Self {
skeleton, skeleton,
retracted_dynamic_clauses,
indexing_code, indexing_code,
offset: 0, offset: 0,
append_or_prepend, append_or_prepend,
@@ -105,15 +102,16 @@ impl<'a> IndexingCodeMergingPtr<'a> {
fn internalize_constant(&mut self, constant_ptr: IndexingCodePtr) { fn internalize_constant(&mut self, constant_ptr: IndexingCodePtr) {
let constant_key = search_skeleton_for_first_key_type( let constant_key = search_skeleton_for_first_key_type(
self.skeleton, self.skeleton,
OptArgIndexKeyType::Constant, self.retracted_dynamic_clauses,
OptArgIndexKeyType::Literal,
self.append_or_prepend, self.append_or_prepend,
); );
let mut constants = IndexMap::new(); let mut constants = IndexMap::new();
match constant_key { match constant_key {
Some(OptArgIndexKey::Constant(_, _, ref constant, _)) => { Some(OptArgIndexKey::Literal(_, _, constant, _)) => {
constants.insert(constant.clone(), constant_ptr); constants.insert(*constant, constant_ptr);
} }
_ => { _ => {
if let IndexingCodePtr::DynamicExternal(_) = constant_ptr { if let IndexingCodePtr::DynamicExternal(_) = constant_ptr {
@@ -145,7 +143,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
fn add_static_indexed_choice_for_constant( fn add_static_indexed_choice_for_constant(
&mut self, &mut self,
external: usize, external: usize,
constant: Constant, constant: Literal,
index: usize, index: usize,
) { ) {
let third_level_index = if self.append_or_prepend.is_append() { let third_level_index = if self.append_or_prepend.is_append() {
@@ -179,7 +177,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
fn add_dynamic_indexed_choice_for_constant( fn add_dynamic_indexed_choice_for_constant(
&mut self, &mut self,
external: usize, external: usize,
constant: Constant, constant: Literal,
index: usize, index: usize,
) { ) {
let third_level_index = if self.append_or_prepend.is_append() { let third_level_index = if self.append_or_prepend.is_append() {
@@ -232,8 +230,8 @@ impl<'a> IndexingCodeMergingPtr<'a> {
fn index_overlapping_constant( fn index_overlapping_constant(
&mut self, &mut self,
orig_constant: &Constant, orig_constant: Literal,
overlapping_constant: Constant, overlapping_constant: Literal,
index: usize, index: usize,
) { ) {
loop { loop {
@@ -252,7 +250,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
} }
IndexingCodePtr::DynamicExternal(_) | IndexingCodePtr::External(_) => { IndexingCodePtr::DynamicExternal(_) | IndexingCodePtr::External(_) => {
let mut constants = IndexMap::new(); let mut constants = IndexMap::new();
constants.insert(orig_constant.clone(), *c); constants.insert(orig_constant, *c);
*c = IndexingCodePtr::Internal(indexing_code_len); *c = IndexingCodePtr::Internal(indexing_code_len);
@@ -282,10 +280,18 @@ impl<'a> IndexingCodeMergingPtr<'a> {
); );
} }
Some(IndexingCodePtr::DynamicExternal(o)) => { Some(IndexingCodePtr::DynamicExternal(o)) => {
self.add_dynamic_indexed_choice_for_constant(o, overlapping_constant, index); self.add_dynamic_indexed_choice_for_constant(
o,
overlapping_constant,
index,
);
} }
Some(IndexingCodePtr::External(o)) => { Some(IndexingCodePtr::External(o)) => {
self.add_static_indexed_choice_for_constant(o, overlapping_constant, index); self.add_static_indexed_choice_for_constant(
o,
overlapping_constant,
index,
);
} }
Some(IndexingCodePtr::Internal(o)) => { Some(IndexingCodePtr::Internal(o)) => {
self.offset += o; self.offset += o;
@@ -307,7 +313,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
} }
} }
fn index_constant(&mut self, constant: Constant, index: usize) { fn index_constant(&mut self, constant: Literal, index: usize) {
loop { loop {
let indexing_code_len = self.indexing_code.len(); let indexing_code_len = self.indexing_code.len();
@@ -338,10 +344,16 @@ impl<'a> IndexingCodeMergingPtr<'a> {
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(constants)) => { IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(constants)) => {
match constants.get(&constant).cloned() { match constants.get(&constant).cloned() {
None | Some(IndexingCodePtr::Fail) if self.is_dynamic => { None | Some(IndexingCodePtr::Fail) if self.is_dynamic => {
constants.insert(constant, IndexingCodePtr::DynamicExternal(index)); constants.insert(
constant,
IndexingCodePtr::DynamicExternal(index),
);
} }
None | Some(IndexingCodePtr::Fail) => { None | Some(IndexingCodePtr::Fail) => {
constants.insert(constant, IndexingCodePtr::External(index)); constants.insert(
constant,
IndexingCodePtr::External(index),
);
} }
Some(IndexingCodePtr::DynamicExternal(o)) => { Some(IndexingCodePtr::DynamicExternal(o)) => {
self.add_dynamic_indexed_choice_for_constant(o, constant, index); self.add_dynamic_indexed_choice_for_constant(o, constant, index);
@@ -372,6 +384,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
fn internalize_structure(&mut self, structure_ptr: IndexingCodePtr) { fn internalize_structure(&mut self, structure_ptr: IndexingCodePtr) {
let structure_key = search_skeleton_for_first_key_type( let structure_key = search_skeleton_for_first_key_type(
self.skeleton, self.skeleton,
self.retracted_dynamic_clauses,
OptArgIndexKeyType::Structure, OptArgIndexKeyType::Structure,
self.append_or_prepend, self.append_or_prepend,
); );
@@ -379,8 +392,8 @@ impl<'a> IndexingCodeMergingPtr<'a> {
let mut structures = IndexMap::new(); let mut structures = IndexMap::new();
match structure_key { match structure_key {
Some(OptArgIndexKey::Structure(_, _, ref name, ref arity)) => { Some(OptArgIndexKey::Structure(_, _, name, arity)) => {
structures.insert((name.clone(), *arity), structure_ptr); structures.insert((*name, *arity), structure_ptr);
} }
_ => { _ => {
if let IndexingCodePtr::DynamicExternal(_) = structure_ptr { if let IndexingCodePtr::DynamicExternal(_) = structure_ptr {
@@ -428,8 +441,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
}; };
let indexing_code_len = self.indexing_code.len(); let indexing_code_len = self.indexing_code.len();
self.indexing_code self.indexing_code.push(IndexingLine::IndexedChoice(third_level_index));
.push(IndexingLine::IndexedChoice(third_level_index));
match &mut self.indexing_code[self.offset] { match &mut self.indexing_code[self.offset] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref mut structures)) => { IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref mut structures)) => {
@@ -599,6 +611,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
pub(crate) fn merge_clause_index( pub(crate) fn merge_clause_index(
target_indexing_code: &mut Vec<IndexingLine>, target_indexing_code: &mut Vec<IndexingLine>,
skeleton: &mut [ClauseIndexInfo], // the clause to be merged is the last element in the skeleton. skeleton: &mut [ClauseIndexInfo], // the clause to be merged is the last element in the skeleton.
retracted_clauses: &Option<Vec<ClauseIndexInfo>>,
new_clause_loc: usize, // the absolute location of the new clause in the code vector. new_clause_loc: usize, // the absolute location of the new clause in the code vector.
append_or_prepend: AppendOrPrepend, append_or_prepend: AppendOrPrepend,
) { ) {
@@ -609,27 +622,28 @@ pub(crate) fn merge_clause_index(
let mut merging_ptr = IndexingCodeMergingPtr::new( let mut merging_ptr = IndexingCodeMergingPtr::new(
skeleton, skeleton,
retracted_clauses,
target_indexing_code, target_indexing_code,
append_or_prepend, append_or_prepend,
); );
match &opt_arg_index_key { match &opt_arg_index_key {
OptArgIndexKey::Constant(_, index_loc, ref constant, ref overlapping_constants) => { OptArgIndexKey::Literal(_, index_loc, constant, ref overlapping_constants) => {
let offset = new_clause_loc - index_loc + 1; let offset = new_clause_loc - index_loc + 1;
merging_ptr.index_constant(constant.clone(), offset); merging_ptr.index_constant(*constant, offset);
for overlapping_constant in overlapping_constants { for overlapping_constant in overlapping_constants {
merging_ptr.offset = 0; merging_ptr.offset = 0;
merging_ptr.index_overlapping_constant( merging_ptr.index_overlapping_constant(
constant, *constant,
overlapping_constant.clone(), *overlapping_constant,
offset, offset,
); );
} }
} }
OptArgIndexKey::Structure(_, index_loc, ref name, ref arity) => { OptArgIndexKey::Structure(_, index_loc, name, arity) => {
merging_ptr.index_structure((name.clone(), *arity), new_clause_loc - index_loc + 1); merging_ptr.index_structure((*name, *arity), new_clause_loc - index_loc + 1);
} }
OptArgIndexKey::List(_, index_loc) => { OptArgIndexKey::List(_, index_loc) => {
merging_ptr.index_list(new_clause_loc - index_loc + 1); merging_ptr.index_list(new_clause_loc - index_loc + 1);
@@ -650,13 +664,13 @@ pub(crate) fn merge_clause_index(
} }
pub(crate) fn remove_constant_indices( pub(crate) fn remove_constant_indices(
constant: &Constant, constant: Literal,
overlapping_constants: &[Constant], overlapping_constants: &[Literal],
indexing_code: &mut Vec<IndexingLine>, indexing_code: &mut Vec<IndexingLine>,
offset: usize, offset: usize,
) { ) {
let mut index = 0; let mut index = 0;
let iter = once(constant).chain(overlapping_constants.iter()); let iter = once(&constant).chain(overlapping_constants.iter());
match &mut indexing_code[index] { match &mut indexing_code[index] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..)) => { IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..)) => {
@@ -688,11 +702,13 @@ pub(crate) fn remove_constant_indices(
)) => { )) => {
constants_index = index; constants_index = index;
match constants.get(constant).cloned() { let constant = *constant;
Some(IndexingCodePtr::DynamicExternal(_)) |
Some(IndexingCodePtr::External(_)) | match constants.get(&constant).cloned() {
Some(IndexingCodePtr::Fail) => { Some(IndexingCodePtr::DynamicExternal(_))
constants.remove(constant); | Some(IndexingCodePtr::External(_))
| Some(IndexingCodePtr::Fail) => {
constants.remove(&constant);
break; break;
} }
Some(IndexingCodePtr::Internal(o)) => { Some(IndexingCodePtr::Internal(o)) => {
@@ -704,13 +720,14 @@ pub(crate) fn remove_constant_indices(
} }
} }
IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => { IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => {
StaticCodeIndices::remove_instruction_with_offset(indexed_choice_instrs, offset); StaticCodeIndices::remove_instruction_with_offset(
indexed_choice_instrs,
offset,
);
if indexed_choice_instrs.len() == 1 { if indexed_choice_instrs.len() == 1 {
if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() { if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() {
let ext = IndexingCodePtr::External( let ext = IndexingCodePtr::External(indexed_choice_instr.offset());
indexed_choice_instr.offset()
);
match &mut indexing_code[constants_index] { match &mut indexing_code[constants_index] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm( IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(
@@ -724,7 +741,7 @@ pub(crate) fn remove_constant_indices(
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant( IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
ref mut constants, ref mut constants,
)) => { )) => {
constants.insert(constant.clone(), ext); constants.insert(*constant, ext);
} }
_ => { _ => {
unreachable!() unreachable!()
@@ -736,7 +753,10 @@ pub(crate) fn remove_constant_indices(
break; break;
} }
IndexingLine::DynamicIndexedChoice(ref mut indexed_choice_instrs) => { IndexingLine::DynamicIndexedChoice(ref mut indexed_choice_instrs) => {
DynamicCodeIndices::remove_instruction_with_offset(indexed_choice_instrs, offset); DynamicCodeIndices::remove_instruction_with_offset(
indexed_choice_instrs,
offset,
);
if indexed_choice_instrs.len() == 1 { if indexed_choice_instrs.len() == 1 {
if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() { if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() {
@@ -754,7 +774,7 @@ pub(crate) fn remove_constant_indices(
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant( IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
ref mut constants, ref mut constants,
)) => { )) => {
constants.insert(constant.clone(), ext); constants.insert(*constant, ext);
} }
_ => { _ => {
unreachable!() unreachable!()
@@ -790,7 +810,7 @@ pub(crate) fn remove_constant_indices(
} }
pub(crate) fn remove_structure_index( pub(crate) fn remove_structure_index(
name: &ClauseName, name: Atom,
arity: usize, arity: usize,
indexing_code: &mut Vec<IndexingLine>, indexing_code: &mut Vec<IndexingLine>,
offset: usize, offset: usize,
@@ -825,7 +845,8 @@ pub(crate) fn remove_structure_index(
structures_index = index; structures_index = index;
match structures.get(&(name.clone(), arity)).cloned() { match structures.get(&(name.clone(), arity)).cloned() {
Some(IndexingCodePtr::DynamicExternal(_)) | Some(IndexingCodePtr::External(_)) => { Some(IndexingCodePtr::DynamicExternal(_))
| Some(IndexingCodePtr::External(_)) => {
structures.remove(&(name.clone(), arity)); structures.remove(&(name.clone(), arity));
break; break;
} }
@@ -1012,27 +1033,14 @@ pub(crate) fn remove_index(
clause_loc: usize, clause_loc: usize,
) { ) {
match opt_arg_index_key { match opt_arg_index_key {
OptArgIndexKey::Constant(_, _, ref constant, ref overlapping_constants) => { OptArgIndexKey::Literal(_, _, constant, ref overlapping_constants) => {
remove_constant_indices( remove_constant_indices(*constant, overlapping_constants, indexing_code, clause_loc);
constant,
overlapping_constants,
indexing_code,
clause_loc,
);
} }
OptArgIndexKey::Structure(_, _, ref name, ref arity) => { OptArgIndexKey::Structure(_, _, name, arity) => {
remove_structure_index( remove_structure_index(*name, *arity, indexing_code, clause_loc);
name,
*arity,
indexing_code,
clause_loc,
);
} }
OptArgIndexKey::List(..) => { OptArgIndexKey::List(..) => {
remove_list_index( remove_list_index(indexing_code, clause_loc);
indexing_code,
clause_loc,
);
} }
OptArgIndexKey::None => { OptArgIndexKey::None => {
unreachable!() unreachable!()
@@ -1076,49 +1084,52 @@ fn uncap_choice_seq_with_try(prelude: &mut [IndexedChoiceInstruction]) {
}); });
} }
pub(crate) fn constant_key_alternatives(constant: &Constant, atom_tbl: TabledData<Atom>) -> Vec<Constant> { pub(crate) fn constant_key_alternatives(
constant: Literal,
atom_tbl: &mut AtomTable,
// arena: &mut Arena,
) -> Vec<Literal> {
let mut constants = vec![]; let mut constants = vec![];
match constant { match constant {
Constant::Atom(ref name, ref op) => { Literal::Atom(ref name) => {
if name.is_char() { if let Some(c) = name.as_char() {
let c = name.as_str().chars().next().unwrap(); constants.push(Literal::Char(c));
constants.push(Constant::Char(c));
} }
}
Literal::Char(c) => {
let atom = atom_tbl.build_with(&c.to_string());
constants.push(Literal::Atom(atom));
}
/*
Literal::Fixnum(ref n) => {
constants.push(Literal::Integer(arena_alloc!(n, arena))); //Rc::new(Integer::from(*n))));
if op.is_some() { /*
constants.push(Constant::Atom(name.clone(), None));
}
}
Constant::Char(c) => {
let atom = clause_name!(c.to_string(), atom_tbl);
constants.push(Constant::Atom(atom, None));
}
Constant::Fixnum(ref n) => {
constants.push(Constant::Integer(Rc::new(Integer::from(*n))));
if *n >= 0 { if *n >= 0 {
if let Ok(n) = usize::try_from(*n) { if let Ok(n) = usize::try_from(*n) {
constants.push(Constant::Usize(n)); constants.push(Literal::Usize(n));
} }
} }
*/
} }
Constant::Integer(ref n) => { */
Literal::Integer(ref n) => {
if let Some(n) = n.to_isize() { if let Some(n) = n.to_isize() {
constants.push(Constant::Fixnum(n)); Fixnum::build_with_checked(n as i64).map(|n| {
} constants.push(Literal::Fixnum(n));
}).unwrap();
if let Some(n) = n.to_usize() {
constants.push(Constant::Usize(n));
} }
} }
Constant::Usize(n) => { /*
constants.push(Constant::Integer(Rc::new(Integer::from(*n)))); Literal::Usize(n) => {
constants.push(Literal::Integer(Rc::new(Integer::from(*n))));
if let Ok(n) = isize::try_from(*n) { if let Ok(n) = isize::try_from(*n) {
constants.push(Constant::Fixnum(n)); constants.push(Literal::Fixnum(n));
} }
} }
*/
_ => {} _ => {}
} }
@@ -1127,16 +1138,16 @@ pub(crate) fn constant_key_alternatives(constant: &Constant, atom_tbl: TabledDat
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct StaticCodeIndices { pub(crate) struct StaticCodeIndices {
constants: IndexMap<Constant, SliceDeque<IndexedChoiceInstruction>>, constants: IndexMap<Literal, SliceDeque<IndexedChoiceInstruction>>,
lists: SliceDeque<IndexedChoiceInstruction>, lists: SliceDeque<IndexedChoiceInstruction>,
structures: IndexMap<(ClauseName, usize), SliceDeque<IndexedChoiceInstruction>>, structures: IndexMap<(Atom, usize), SliceDeque<IndexedChoiceInstruction>>,
} }
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct DynamicCodeIndices { pub(crate) struct DynamicCodeIndices {
constants: IndexMap<Constant, SliceDeque<usize>>, constants: IndexMap<Literal, SliceDeque<usize>>,
lists: SliceDeque<usize>, lists: SliceDeque<usize>,
structures: IndexMap<(ClauseName, usize), SliceDeque<usize>>, structures: IndexMap<(Atom, usize), SliceDeque<usize>>,
} }
pub(crate) trait Indexer { pub(crate) trait Indexer {
@@ -1144,9 +1155,9 @@ pub(crate) trait Indexer {
fn new() -> Self; fn new() -> Self;
fn constants(&mut self) -> &mut IndexMap<Constant, SliceDeque<Self::ThirdLevelIndex>>; fn constants(&mut self) -> &mut IndexMap<Literal, SliceDeque<Self::ThirdLevelIndex>>;
fn lists(&mut self) -> &mut SliceDeque<Self::ThirdLevelIndex>; fn lists(&mut self) -> &mut SliceDeque<Self::ThirdLevelIndex>;
fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque<Self::ThirdLevelIndex>>; fn structures(&mut self) -> &mut IndexMap<(Atom, usize), SliceDeque<Self::ThirdLevelIndex>>;
fn compute_index(is_initial_index: bool, index: usize) -> Self::ThirdLevelIndex; fn compute_index(is_initial_index: bool, index: usize) -> Self::ThirdLevelIndex;
@@ -1166,10 +1177,7 @@ pub(crate) trait Indexer {
prelude: &mut SliceDeque<IndexingLine>, prelude: &mut SliceDeque<IndexingLine>,
) -> IndexingCodePtr; ) -> IndexingCodePtr;
fn remove_instruction_with_offset( fn remove_instruction_with_offset(code: &mut SliceDeque<Self::ThirdLevelIndex>, offset: usize);
code: &mut SliceDeque<Self::ThirdLevelIndex>,
offset: usize,
);
fn var_offset_wrapper(var_offset: usize) -> IndexingCodePtr; fn var_offset_wrapper(var_offset: usize) -> IndexingCodePtr;
} }
@@ -1187,7 +1195,7 @@ impl Indexer for StaticCodeIndices {
} }
#[inline] #[inline]
fn constants(&mut self) -> &mut IndexMap<Constant, SliceDeque<IndexedChoiceInstruction>> { fn constants(&mut self) -> &mut IndexMap<Literal, SliceDeque<IndexedChoiceInstruction>> {
&mut self.constants &mut self.constants
} }
@@ -1197,7 +1205,7 @@ impl Indexer for StaticCodeIndices {
} }
#[inline] #[inline]
fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque<IndexedChoiceInstruction>> { fn structures(&mut self) -> &mut IndexMap<(Atom, usize), SliceDeque<IndexedChoiceInstruction>> {
&mut self.structures &mut self.structures
} }
@@ -1271,7 +1279,10 @@ impl Indexer for StaticCodeIndices {
} }
#[inline] #[inline]
fn remove_instruction_with_offset(code: &mut SliceDeque<IndexedChoiceInstruction>, offset: usize) { fn remove_instruction_with_offset(
code: &mut SliceDeque<IndexedChoiceInstruction>,
offset: usize,
) {
for (index, line) in code.iter().enumerate() { for (index, line) in code.iter().enumerate() {
if offset == line.offset() { if offset == line.offset() {
code.remove(index); code.remove(index);
@@ -1300,7 +1311,7 @@ impl Indexer for DynamicCodeIndices {
} }
#[inline] #[inline]
fn constants(&mut self) -> &mut IndexMap<Constant, SliceDeque<usize>> { fn constants(&mut self) -> &mut IndexMap<Literal, SliceDeque<usize>> {
&mut self.constants &mut self.constants
} }
@@ -1310,7 +1321,7 @@ impl Indexer for DynamicCodeIndices {
} }
#[inline] #[inline]
fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque<usize>> { fn structures(&mut self) -> &mut IndexMap<(Atom, usize), SliceDeque<usize>> {
&mut self.structures &mut self.structures
} }
@@ -1395,19 +1406,13 @@ impl Indexer for DynamicCodeIndices {
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct CodeOffsets<I: Indexer> { pub(crate) struct CodeOffsets<I: Indexer> {
atom_tbl: TabledData<Atom>,
indices: I, indices: I,
optimal_index: usize, optimal_index: usize,
} }
impl<I: Indexer> CodeOffsets<I> { impl<I: Indexer> CodeOffsets<I> {
pub(crate) fn new( pub(crate) fn new(indices: I, optimal_index: usize) -> Self {
atom_tbl: TabledData<Atom>,
indices: I,
optimal_index: usize,
) -> Self {
CodeOffsets { CodeOffsets {
atom_tbl,
indices, indices,
optimal_index, optimal_index,
} }
@@ -1419,15 +1424,24 @@ impl<I: Indexer> CodeOffsets<I> {
self.indices.lists().push_back(index); self.indices.lists().push_back(index);
} }
fn index_constant(&mut self, constant: &Constant, index: usize) -> Vec<Constant> { fn index_constant(
let overlapping_constants = constant_key_alternatives(constant, self.atom_tbl.clone()); &mut self,
let code = self.indices.constants().entry(constant.clone()).or_insert(sdeq![]); atom_tbl: &mut AtomTable,
constant: Literal,
index: usize,
) -> Vec<Literal> {
let overlapping_constants = constant_key_alternatives(constant, atom_tbl);
let code = self.indices.constants().entry(constant).or_insert(sdeq![]);
let is_initial_index = code.is_empty(); let is_initial_index = code.is_empty();
code.push_back(I::compute_index(is_initial_index, index)); code.push_back(I::compute_index(is_initial_index, index));
for constant in &overlapping_constants { for constant in &overlapping_constants {
let code = self.indices.constants().entry(constant.clone()).or_insert(sdeq![]); let code = self
.indices
.constants()
.entry(*constant)
.or_insert(sdeq![]);
let is_initial_index = code.is_empty(); let is_initial_index = code.is_empty();
let index = I::compute_index(is_initial_index, index); let index = I::compute_index(is_initial_index, index);
@@ -1438,8 +1452,9 @@ impl<I: Indexer> CodeOffsets<I> {
overlapping_constants overlapping_constants
} }
fn index_structure(&mut self, name: &ClauseName, arity: usize, index: usize) -> usize { fn index_structure(&mut self, name: Atom, arity: usize, index: usize) -> usize {
let code = self.indices let code = self
.indices
.structures() .structures()
.entry((name.clone(), arity)) .entry((name.clone(), arity))
.or_insert(sdeq![]); .or_insert(sdeq![]);
@@ -1456,28 +1471,25 @@ impl<I: Indexer> CodeOffsets<I> {
optimal_arg: &Term, optimal_arg: &Term,
index: usize, index: usize,
clause_index_info: &mut ClauseIndexInfo, clause_index_info: &mut ClauseIndexInfo,
atom_tbl: &mut AtomTable,
) { ) {
match optimal_arg { match optimal_arg {
&Term::Clause(_, ref name, ref terms, _) => { &Term::Clause(_, name, ref terms) => {
clause_index_info.opt_arg_index_key = clause_index_info.opt_arg_index_key =
OptArgIndexKey::Structure(self.optimal_index, 0, name.clone(), terms.len()); OptArgIndexKey::Structure(self.optimal_index, 0, name.clone(), terms.len());
self.index_structure(name, terms.len(), index); self.index_structure(name, terms.len(), index);
} }
&Term::Cons(..) | &Term::Constant(_, Constant::String(_)) => { &Term::Cons(..) | &Term::Literal(_, Literal::String(_)) | &Term::PartialString(..) => {
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0); clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
self.index_list(index); self.index_list(index);
} }
&Term::Constant(_, ref constant) => { &Term::Literal(_, constant) => {
let overlapping_constants = self.index_constant(constant, index); let overlapping_constants = self.index_constant(atom_tbl, constant, index);
clause_index_info.opt_arg_index_key = OptArgIndexKey::Constant( clause_index_info.opt_arg_index_key =
self.optimal_index, OptArgIndexKey::Literal(self.optimal_index, 0, constant, overlapping_constants);
0,
constant.clone(),
overlapping_constants,
);
} }
_ => {} _ => {}
} }

View File

@@ -1,847 +0,0 @@
use prolog_parser::ast::*;
use prolog_parser::clause_name;
use crate::clause_types::*;
use crate::forms::*;
use crate::indexing::IndexingCodePtr;
use crate::machine::heap::*;
use crate::machine::machine_errors::MachineStub;
use crate::machine::machine_indices::*;
use crate::rug::Integer;
use indexmap::IndexMap;
use slice_deque::SliceDeque;
use std::rc::Rc;
fn reg_type_into_functor(r: RegType) -> MachineStub {
match r {
RegType::Temp(r) => functor!("x", [integer(r)]),
RegType::Perm(r) => functor!("y", [integer(r)]),
}
}
impl Level {
fn into_functor(self) -> MachineStub {
match self {
Level::Root => functor!("level", [atom("root")]),
Level::Shallow => functor!("level", [atom("shallow")]),
Level::Deep => functor!("level", [atom("deep")]),
}
}
}
impl ArithmeticTerm {
fn into_functor(&self) -> MachineStub {
match self {
&ArithmeticTerm::Reg(r) => reg_type_into_functor(r),
&ArithmeticTerm::Interm(i) => {
functor!("intermediate", [integer(i)])
}
&ArithmeticTerm::Number(ref n) => {
vec![n.clone().into()]
}
}
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum NextOrFail {
Next(usize),
Fail(usize),
}
impl NextOrFail {
#[inline]
pub fn is_next(&self) -> bool {
if let NextOrFail::Next(_) = self {
true
} else {
false
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) enum Death {
Finite(usize),
Infinity,
}
#[derive(Debug)]
pub(crate) enum ChoiceInstruction {
DynamicElse(usize, Death, NextOrFail),
DynamicInternalElse(usize, Death, NextOrFail),
DefaultRetryMeElse(usize),
DefaultTrustMe(usize),
RetryMeElse(usize),
TrustMe(usize),
TryMeElse(usize),
}
impl ChoiceInstruction {
pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
match self {
&ChoiceInstruction::DynamicElse(birth, death, next_or_fail) => {
match (death, next_or_fail) {
(Death::Infinity, NextOrFail::Next(i)) => {
functor!(
"dynamic_else",
[integer(birth), atom("inf"), integer(i)]
)
}
(Death::Infinity, NextOrFail::Fail(i)) => {
let next_functor = functor!("fail", [integer(i)]);
functor!(
"dynamic_else",
[integer(birth), atom("inf"), aux(h, 0)],
[next_functor]
)
}
(Death::Finite(d), NextOrFail::Fail(i)) => {
let next_functor = functor!("fail", [integer(i)]);
functor!(
"dynamic_else",
[integer(birth), integer(d), aux(h, 0)],
[next_functor]
)
}
(Death::Finite(d), NextOrFail::Next(i)) => {
functor!(
"dynamic_else",
[integer(birth), integer(d), integer(i)]
)
}
}
}
&ChoiceInstruction::DynamicInternalElse(birth, death, next_or_fail) => {
match (death, next_or_fail) {
(Death::Infinity, NextOrFail::Next(i)) => {
functor!(
"dynamic_internal_else",
[integer(birth), atom("inf"), integer(i)]
)
}
(Death::Infinity, NextOrFail::Fail(i)) => {
let next_functor = functor!("fail", [integer(i)]);
functor!(
"dynamic_internal_else",
[integer(birth), atom("inf"), aux(h, 0)],
[next_functor]
)
}
(Death::Finite(d), NextOrFail::Fail(i)) => {
let next_functor = functor!("fail", [integer(i)]);
functor!(
"dynamic_internal_else",
[integer(birth), integer(d), aux(h, 0)],
[next_functor]
)
}
(Death::Finite(d), NextOrFail::Next(i)) => {
functor!(
"dynamic_internal_else",
[integer(birth), integer(d), integer(i)]
)
}
}
}
&ChoiceInstruction::TryMeElse(offset) => {
functor!("try_me_else", [integer(offset)])
}
&ChoiceInstruction::RetryMeElse(offset) => {
functor!("retry_me_else", [integer(offset)])
}
&ChoiceInstruction::TrustMe(offset) => {
functor!("trust_me", [integer(offset)])
}
&ChoiceInstruction::DefaultRetryMeElse(offset) => {
functor!("default_retry_me_else", [integer(offset)])
}
&ChoiceInstruction::DefaultTrustMe(offset) => {
functor!("default_trust_me", [integer(offset)])
}
}
}
}
#[derive(Debug)]
pub(crate) enum CutInstruction {
Cut(RegType),
GetLevel(RegType),
GetLevelAndUnify(RegType),
NeckCut,
}
impl CutInstruction {
pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
match self {
&CutInstruction::Cut(r) => {
let rt_stub = reg_type_into_functor(r);
functor!("cut", [aux(h, 0)], [rt_stub])
}
&CutInstruction::GetLevel(r) => {
let rt_stub = reg_type_into_functor(r);
functor!("get_level", [aux(h, 0)], [rt_stub])
}
&CutInstruction::GetLevelAndUnify(r) => {
let rt_stub = reg_type_into_functor(r);
functor!("get_level_and_unify", [aux(h, 0)], [rt_stub])
}
&CutInstruction::NeckCut => {
functor!("neck_cut")
}
}
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) enum IndexedChoiceInstruction {
Retry(usize),
Trust(usize),
Try(usize),
}
impl IndexedChoiceInstruction {
pub(crate) fn offset(&self) -> usize {
match self {
&IndexedChoiceInstruction::Retry(offset) => offset,
&IndexedChoiceInstruction::Trust(offset) => offset,
&IndexedChoiceInstruction::Try(offset) => offset,
}
}
pub(crate) fn to_functor(&self) -> MachineStub {
match self {
&IndexedChoiceInstruction::Try(offset) => {
functor!("try", [integer(offset)])
}
&IndexedChoiceInstruction::Trust(offset) => {
functor!("trust", [integer(offset)])
}
&IndexedChoiceInstruction::Retry(offset) => {
functor!("retry", [integer(offset)])
}
}
}
}
/// A `Line` is an instruction (cf. page 98 of wambook).
#[derive(Debug)]
pub(crate) enum IndexingLine {
Indexing(IndexingInstruction),
IndexedChoice(SliceDeque<IndexedChoiceInstruction>),
DynamicIndexedChoice(SliceDeque<usize>),
}
impl From<IndexingInstruction> for IndexingLine {
#[inline]
fn from(instr: IndexingInstruction) -> Self {
IndexingLine::Indexing(instr)
}
}
impl From<SliceDeque<IndexedChoiceInstruction>> for IndexingLine {
#[inline]
fn from(instrs: SliceDeque<IndexedChoiceInstruction>) -> Self {
IndexingLine::IndexedChoice(instrs)
}
}
#[derive(Debug)]
pub(crate) enum Line {
Arithmetic(ArithmeticInstruction),
Choice(ChoiceInstruction),
Control(ControlInstruction),
Cut(CutInstruction),
Fact(FactInstruction),
IndexingCode(Vec<IndexingLine>),
IndexedChoice(IndexedChoiceInstruction),
DynamicIndexedChoice(usize),
Query(QueryInstruction),
}
impl Line {
#[inline]
pub(crate) fn is_head_instr(&self) -> bool {
match self {
&Line::Fact(_) => true,
&Line::Query(_) => true,
_ => false,
}
}
pub(crate) fn enqueue_functors(&self, mut h: usize, functors: &mut Vec<MachineStub>) {
match self {
&Line::Arithmetic(ref arith_instr) => functors.push(arith_instr.to_functor(h)),
&Line::Choice(ref choice_instr) => functors.push(choice_instr.to_functor(h)),
&Line::Control(ref control_instr) => functors.push(control_instr.to_functor()),
&Line::Cut(ref cut_instr) => functors.push(cut_instr.to_functor(h)),
&Line::Fact(ref fact_instr) => functors.push(fact_instr.to_functor(h)),
&Line::IndexingCode(ref indexing_instrs) => {
for indexing_instr in indexing_instrs {
match indexing_instr {
IndexingLine::Indexing(indexing_instr) => {
let section = indexing_instr.to_functor(h);
h += section.len();
functors.push(section);
}
IndexingLine::IndexedChoice(indexed_choice_instrs) => {
for indexed_choice_instr in indexed_choice_instrs {
let section = indexed_choice_instr.to_functor();
h += section.len();
functors.push(section);
}
}
IndexingLine::DynamicIndexedChoice(indexed_choice_instrs) => {
for indexed_choice_instr in indexed_choice_instrs {
let section = functor!("dynamic", [integer(*indexed_choice_instr)]);
h += section.len();
functors.push(section);
}
}
}
}
}
&Line::IndexedChoice(ref indexed_choice_instr) => {
functors.push(indexed_choice_instr.to_functor())
}
&Line::DynamicIndexedChoice(ref indexed_choice_instr) => {
functors.push(functor!("dynamic", [integer(*indexed_choice_instr)]));
}
&Line::Query(ref query_instr) => functors.push(query_instr.to_functor(h)),
}
}
}
#[inline]
pub(crate) fn to_indexing_line_mut(line: &mut Line) -> Option<&mut Vec<IndexingLine>> {
match line {
Line::IndexingCode(ref mut indexing_code) => Some(indexing_code),
_ => None,
}
}
#[inline]
pub(crate) fn to_indexing_line(line: &Line) -> Option<&Vec<IndexingLine>> {
match line {
Line::IndexingCode(ref indexing_code) => Some(indexing_code),
_ => None,
}
}
#[derive(Debug, Clone)]
pub(crate) enum ArithmeticInstruction {
Add(ArithmeticTerm, ArithmeticTerm, usize),
Sub(ArithmeticTerm, ArithmeticTerm, usize),
Mul(ArithmeticTerm, ArithmeticTerm, usize),
Pow(ArithmeticTerm, ArithmeticTerm, usize),
IntPow(ArithmeticTerm, ArithmeticTerm, usize),
IDiv(ArithmeticTerm, ArithmeticTerm, usize),
Max(ArithmeticTerm, ArithmeticTerm, usize),
Min(ArithmeticTerm, ArithmeticTerm, usize),
IntFloorDiv(ArithmeticTerm, ArithmeticTerm, usize),
RDiv(ArithmeticTerm, ArithmeticTerm, usize),
Div(ArithmeticTerm, ArithmeticTerm, usize),
Shl(ArithmeticTerm, ArithmeticTerm, usize),
Shr(ArithmeticTerm, ArithmeticTerm, usize),
Xor(ArithmeticTerm, ArithmeticTerm, usize),
And(ArithmeticTerm, ArithmeticTerm, usize),
Or(ArithmeticTerm, ArithmeticTerm, usize),
Mod(ArithmeticTerm, ArithmeticTerm, usize),
Rem(ArithmeticTerm, ArithmeticTerm, usize),
Gcd(ArithmeticTerm, ArithmeticTerm, usize),
Sign(ArithmeticTerm, usize),
Cos(ArithmeticTerm, usize),
Sin(ArithmeticTerm, usize),
Tan(ArithmeticTerm, usize),
Log(ArithmeticTerm, usize),
Exp(ArithmeticTerm, usize),
ACos(ArithmeticTerm, usize),
ASin(ArithmeticTerm, usize),
ATan(ArithmeticTerm, usize),
ATan2(ArithmeticTerm, ArithmeticTerm, usize),
Sqrt(ArithmeticTerm, usize),
Abs(ArithmeticTerm, usize),
Float(ArithmeticTerm, usize),
Truncate(ArithmeticTerm, usize),
Round(ArithmeticTerm, usize),
Ceiling(ArithmeticTerm, usize),
Floor(ArithmeticTerm, usize),
Neg(ArithmeticTerm, usize),
Plus(ArithmeticTerm, usize),
BitwiseComplement(ArithmeticTerm, usize),
}
fn arith_instr_unary_functor(
h: usize,
name: &'static str,
at: &ArithmeticTerm,
t: usize,
) -> MachineStub {
let at_stub = at.into_functor();
functor!(name, [aux(h, 0), integer(t)], [at_stub])
}
fn arith_instr_bin_functor(
h: usize,
name: &'static str,
at_1: &ArithmeticTerm,
at_2: &ArithmeticTerm,
t: usize,
) -> MachineStub {
let at_1_stub = at_1.into_functor();
let at_2_stub = at_2.into_functor();
functor!(
name,
[aux(h, 0), aux(h, 1), integer(t)],
[at_1_stub, at_2_stub]
)
}
impl ArithmeticInstruction {
pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
match self {
&ArithmeticInstruction::Add(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "add", at_1, at_2, t)
}
&ArithmeticInstruction::Sub(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "sub", at_1, at_2, t)
}
&ArithmeticInstruction::Mul(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "mul", at_1, at_2, t)
}
&ArithmeticInstruction::IntPow(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "int_pow", at_1, at_2, t)
}
&ArithmeticInstruction::Pow(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "pow", at_1, at_2, t)
}
&ArithmeticInstruction::IDiv(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "idiv", at_1, at_2, t)
}
&ArithmeticInstruction::Max(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "max", at_1, at_2, t)
}
&ArithmeticInstruction::Min(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "min", at_1, at_2, t)
}
&ArithmeticInstruction::IntFloorDiv(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "int_floor_div", at_1, at_2, t)
}
&ArithmeticInstruction::RDiv(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "rdiv", at_1, at_2, t)
}
&ArithmeticInstruction::Div(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "div", at_1, at_2, t)
}
&ArithmeticInstruction::Shl(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "shl", at_1, at_2, t)
}
&ArithmeticInstruction::Shr(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "shr", at_1, at_2, t)
}
&ArithmeticInstruction::Xor(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "xor", at_1, at_2, t)
}
&ArithmeticInstruction::And(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "and", at_1, at_2, t)
}
&ArithmeticInstruction::Or(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "or", at_1, at_2, t)
}
&ArithmeticInstruction::Mod(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "mod", at_1, at_2, t)
}
&ArithmeticInstruction::Rem(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "rem", at_1, at_2, t)
}
&ArithmeticInstruction::ATan2(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "rem", at_1, at_2, t)
}
&ArithmeticInstruction::Gcd(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "gcd", at_1, at_2, t)
}
&ArithmeticInstruction::Sign(ref at, t) => arith_instr_unary_functor(h, "sign", at, t),
&ArithmeticInstruction::Cos(ref at, t) => arith_instr_unary_functor(h, "cos", at, t),
&ArithmeticInstruction::Sin(ref at, t) => arith_instr_unary_functor(h, "sin", at, t),
&ArithmeticInstruction::Tan(ref at, t) => arith_instr_unary_functor(h, "tan", at, t),
&ArithmeticInstruction::Log(ref at, t) => arith_instr_unary_functor(h, "log", at, t),
&ArithmeticInstruction::Exp(ref at, t) => arith_instr_unary_functor(h, "exp", at, t),
&ArithmeticInstruction::ACos(ref at, t) => arith_instr_unary_functor(h, "acos", at, t),
&ArithmeticInstruction::ASin(ref at, t) => arith_instr_unary_functor(h, "asin", at, t),
&ArithmeticInstruction::ATan(ref at, t) => arith_instr_unary_functor(h, "atan", at, t),
&ArithmeticInstruction::Sqrt(ref at, t) => arith_instr_unary_functor(h, "sqrt", at, t),
&ArithmeticInstruction::Abs(ref at, t) => arith_instr_unary_functor(h, "abs", at, t),
&ArithmeticInstruction::Float(ref at, t) => {
arith_instr_unary_functor(h, "float", at, t)
}
&ArithmeticInstruction::Truncate(ref at, t) => {
arith_instr_unary_functor(h, "truncate", at, t)
}
&ArithmeticInstruction::Round(ref at, t) => {
arith_instr_unary_functor(h, "round", at, t)
}
&ArithmeticInstruction::Ceiling(ref at, t) => {
arith_instr_unary_functor(h, "ceiling", at, t)
}
&ArithmeticInstruction::Floor(ref at, t) => {
arith_instr_unary_functor(h, "floor", at, t)
}
&ArithmeticInstruction::Neg(ref at, t) => arith_instr_unary_functor(h, "-", at, t),
&ArithmeticInstruction::Plus(ref at, t) => arith_instr_unary_functor(h, "+", at, t),
&ArithmeticInstruction::BitwiseComplement(ref at, t) => {
arith_instr_unary_functor(h, "\\", at, t)
}
}
}
}
#[derive(Debug)]
pub(crate) enum ControlInstruction {
Allocate(usize), // num_frames.
// name, arity, perm_vars after threshold, last call, use default call policy.
CallClause(ClauseType, usize, usize, bool, bool),
Deallocate,
JmpBy(usize, usize, usize, bool), // arity, global_offset, perm_vars after threshold, last call.
RevJmpBy(usize), // notice the lack of context change as in
// JmpBy. RevJmpBy is used only to patch extensible
// predicates together.
Proceed,
}
impl ControlInstruction {
pub(crate) fn perm_vars(&self) -> Option<usize> {
match self {
ControlInstruction::CallClause(_, _, num_cells, ..) => Some(*num_cells),
ControlInstruction::JmpBy(_, _, num_cells, ..) => Some(*num_cells),
_ => None,
}
}
pub(crate) fn to_functor(&self) -> MachineStub {
match self {
&ControlInstruction::Allocate(num_frames) => {
functor!("allocate", [integer(num_frames)])
}
&ControlInstruction::CallClause(ref ct, arity, _, false, _) => {
functor!("call", [clause_name(ct.name()), integer(arity)])
}
&ControlInstruction::CallClause(ref ct, arity, _, true, _) => {
functor!("execute", [clause_name(ct.name()), integer(arity)])
}
&ControlInstruction::Deallocate => {
functor!("deallocate")
}
&ControlInstruction::JmpBy(_, offset, ..) => {
functor!("jmp_by", [integer(offset)])
}
&ControlInstruction::RevJmpBy(offset) => {
functor!("rev_jmp_by", [integer(offset)])
}
&ControlInstruction::Proceed => {
functor!("proceed")
}
}
}
}
/// `IndexingInstruction` cf. page 110 of wambook.
#[derive(Debug)]
pub(crate) enum IndexingInstruction {
// The first index is the optimal argument being indexed.
SwitchOnTerm(
usize,
IndexingCodePtr,
IndexingCodePtr,
IndexingCodePtr,
IndexingCodePtr,
),
SwitchOnConstant(IndexMap<Constant, IndexingCodePtr>),
SwitchOnStructure(IndexMap<(ClauseName, usize), IndexingCodePtr>),
}
impl IndexingInstruction {
pub(crate) fn to_functor(&self, mut h: usize) -> MachineStub {
match self {
&IndexingInstruction::SwitchOnTerm(arg, vars, constants, lists, structures) => {
functor!(
"switch_on_term",
[
integer(arg),
indexing_code_ptr(h, vars),
indexing_code_ptr(h, constants),
indexing_code_ptr(h, lists),
indexing_code_ptr(h, structures)
]
)
}
&IndexingInstruction::SwitchOnConstant(ref constants) => {
let mut key_value_list_stub = vec![];
let orig_h = h;
h += 2; // skip the 2-cell "switch_on_constant" functor.
for (c, ptr) in constants.iter() {
let key_value_pair = functor!(
":",
SharedOpDesc::new(600, XFY),
[constant(c), indexing_code_ptr(h + 3, *ptr)]
);
key_value_list_stub.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
key_value_list_stub.push(HeapCellValue::Addr(Addr::Str(h + 3)));
key_value_list_stub.push(HeapCellValue::Addr(Addr::HeapCell(
h + 3 + key_value_pair.len(),
)));
h += key_value_pair.len() + 3;
key_value_list_stub.extend(key_value_pair.into_iter());
}
key_value_list_stub.push(HeapCellValue::Addr(Addr::EmptyList));
functor!(
"switch_on_constant",
[aux(orig_h, 0)],
[key_value_list_stub]
)
}
&IndexingInstruction::SwitchOnStructure(ref structures) => {
let mut key_value_list_stub = vec![];
let orig_h = h;
h += 2; // skip the 2-cell "switch_on_constant" functor.
for ((name, arity), ptr) in structures.iter() {
let predicate_indicator_stub = functor!(
"/",
SharedOpDesc::new(400, YFX),
[clause_name(name.clone()), integer(*arity)]
);
let key_value_pair = functor!(
":",
SharedOpDesc::new(600, XFY),
[aux(h + 3, 0), indexing_code_ptr(h + 3, *ptr)],
[predicate_indicator_stub]
);
key_value_list_stub.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
key_value_list_stub.push(HeapCellValue::Addr(Addr::Str(h + 3)));
key_value_list_stub.push(HeapCellValue::Addr(Addr::HeapCell(
h + 3 + key_value_pair.len(),
)));
h += key_value_pair.len() + 3;
key_value_list_stub.extend(key_value_pair.into_iter());
}
key_value_list_stub.push(HeapCellValue::Addr(Addr::EmptyList));
functor!(
"switch_on_structure",
[aux(orig_h, 0)],
[key_value_list_stub]
)
}
}
}
}
#[derive(Debug, Clone)]
pub(crate) enum FactInstruction {
GetConstant(Level, Constant, RegType),
GetList(Level, RegType),
GetPartialString(Level, String, RegType, bool),
GetStructure(ClauseType, usize, RegType),
GetValue(RegType, usize),
GetVariable(RegType, usize),
UnifyConstant(Constant),
UnifyLocalValue(RegType),
UnifyVariable(RegType),
UnifyValue(RegType),
UnifyVoid(usize),
}
impl FactInstruction {
pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
match self {
&FactInstruction::GetConstant(lvl, ref c, r) => {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
functor!(
"get_constant",
[aux(h, 0), constant(h, c), aux(h, 1)],
[lvl_stub, rt_stub]
)
}
&FactInstruction::GetList(lvl, r) => {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
functor!("get_list", [aux(h, 0), aux(h, 1)], [lvl_stub, rt_stub])
}
&FactInstruction::GetPartialString(lvl, ref s, r, has_tail) => {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
functor!(
"get_partial_string",
[aux(h, 0), string(h, s), aux(h, 1), boolean(has_tail)],
[lvl_stub, rt_stub]
)
}
&FactInstruction::GetStructure(ref ct, arity, r) => {
let rt_stub = reg_type_into_functor(r);
functor!(
"get_structure",
[clause_name(ct.name()), integer(arity), aux(h, 0)],
[rt_stub]
)
}
&FactInstruction::GetValue(r, arg) => {
let rt_stub = reg_type_into_functor(r);
functor!("get_value", [aux(h, 0), integer(arg)], [rt_stub])
}
&FactInstruction::GetVariable(r, arg) => {
let rt_stub = reg_type_into_functor(r);
functor!("get_variable", [aux(h, 0), integer(arg)], [rt_stub])
}
&FactInstruction::UnifyConstant(ref c) => {
functor!("unify_constant", [constant(h, c)], [])
}
&FactInstruction::UnifyLocalValue(r) => {
let rt_stub = reg_type_into_functor(r);
functor!("unify_local_value", [aux(h, 0)], [rt_stub])
}
&FactInstruction::UnifyVariable(r) => {
let rt_stub = reg_type_into_functor(r);
functor!("unify_variable", [aux(h, 0)], [rt_stub])
}
&FactInstruction::UnifyValue(r) => {
let rt_stub = reg_type_into_functor(r);
functor!("unify_value", [aux(h, 0)], [rt_stub])
}
&FactInstruction::UnifyVoid(vars) => {
functor!("unify_void", [integer(vars)])
}
}
}
}
#[derive(Debug, Clone)]
pub(crate) enum QueryInstruction {
GetVariable(RegType, usize),
PutConstant(Level, Constant, RegType),
PutList(Level, RegType),
PutPartialString(Level, String, RegType, bool),
PutStructure(ClauseType, usize, RegType),
PutUnsafeValue(usize, usize),
PutValue(RegType, usize),
PutVariable(RegType, usize),
SetConstant(Constant),
SetLocalValue(RegType),
SetVariable(RegType),
SetValue(RegType),
SetVoid(usize),
}
impl QueryInstruction {
pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
match self {
&QueryInstruction::PutUnsafeValue(norm, arg) => {
functor!("put_unsafe_value", [integer(norm), integer(arg)])
}
&QueryInstruction::PutConstant(lvl, ref c, r) => {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
functor!(
"put_constant",
[aux(h, 0), constant(h, c), aux(h, 1)],
[lvl_stub, rt_stub]
)
}
&QueryInstruction::PutList(lvl, r) => {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
functor!("put_list", [aux(h, 0), aux(h, 1)], [lvl_stub, rt_stub])
}
&QueryInstruction::PutPartialString(lvl, ref s, r, has_tail) => {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
functor!(
"put_partial_string",
[aux(h, 0), string(h, s), aux(h, 1), boolean(has_tail)],
[lvl_stub, rt_stub]
)
}
&QueryInstruction::PutStructure(ref ct, arity, r) => {
let rt_stub = reg_type_into_functor(r);
functor!(
"put_structure",
[clause_name(ct.name()), integer(arity), aux(h, 0)],
[rt_stub]
)
}
&QueryInstruction::PutValue(r, arg) => {
let rt_stub = reg_type_into_functor(r);
functor!("put_value", [aux(h, 0), integer(arg)], [rt_stub])
}
&QueryInstruction::GetVariable(r, arg) => {
let rt_stub = reg_type_into_functor(r);
functor!("get_variable", [aux(h, 0), integer(arg)], [rt_stub])
}
&QueryInstruction::PutVariable(r, arg) => {
let rt_stub = reg_type_into_functor(r);
functor!("put_variable", [aux(h, 0), integer(arg)], [rt_stub])
}
&QueryInstruction::SetConstant(ref c) => {
functor!("set_constant", [constant(h, c)], [])
}
&QueryInstruction::SetLocalValue(r) => {
let rt_stub = reg_type_into_functor(r);
functor!("set_local_value", [aux(h, 0)], [rt_stub])
}
&QueryInstruction::SetVariable(r) => {
let rt_stub = reg_type_into_functor(r);
functor!("set_variable", [aux(h, 0)], [rt_stub])
}
&QueryInstruction::SetValue(r) => {
let rt_stub = reg_type_into_functor(r);
functor!("set_value", [aux(h, 0)], [rt_stub])
}
&QueryInstruction::SetVoid(vars) => {
functor!("set_void", [integer(vars)])
}
}
}
}
pub(crate) type CompiledFact = Vec<FactInstruction>;
pub(crate) type Code = Vec<Line>;

View File

@@ -1,9 +1,8 @@
use prolog_parser::ast::*; use crate::atom_table::*;
use prolog_parser::rc_atom;
use crate::clause_types::*;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*;
use crate::machine::machine_indices::*; use crate::machine::machine_indices::*;
use crate::parser::ast::*;
use std::cell::Cell; use std::cell::Cell;
use std::collections::VecDeque; use std::collections::VecDeque;
@@ -16,10 +15,10 @@ use std::vec::Vec;
pub(crate) 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), Literal(Level, &'a Cell<RegType>, &'a Literal),
Clause(Level, &'a Cell<RegType>, ClauseType, &'a Vec<Box<Term>>), Clause(Level, &'a Cell<RegType>, ClauseType, &'a Vec<Term>),
PartialString(Level, &'a Cell<RegType>, String, Option<&'a Term>), PartialString(Level, &'a Cell<RegType>, Atom, &'a Option<Box<Term>>),
Var(Level, &'a Cell<VarReg>, Rc<Var>), Var(Level, &'a Cell<VarReg>, Rc<String>),
} }
impl<'a> TermRef<'a> { impl<'a> TermRef<'a> {
@@ -27,7 +26,7 @@ impl<'a> TermRef<'a> {
match self { match self {
TermRef::AnonVar(lvl) TermRef::AnonVar(lvl)
| TermRef::Cons(lvl, ..) | TermRef::Cons(lvl, ..)
| TermRef::Constant(lvl, ..) | TermRef::Literal(lvl, ..)
| TermRef::Var(lvl, ..) | TermRef::Var(lvl, ..)
| TermRef::Clause(lvl, ..) => lvl, | TermRef::Clause(lvl, ..) => lvl,
TermRef::PartialString(lvl, ..) => lvl, TermRef::PartialString(lvl, ..) => lvl,
@@ -38,82 +37,31 @@ impl<'a> TermRef<'a> {
#[derive(Debug)] #[derive(Debug)]
pub(crate) enum TermIterState<'a> { pub(crate) enum TermIterState<'a> {
AnonVar(Level), AnonVar(Level),
Constant(Level, &'a Cell<RegType>, &'a Constant), Literal(Level, &'a Cell<RegType>, &'a Literal),
Clause( Clause(Level, usize, &'a Cell<RegType>, ClauseType, &'a Vec<Term>),
Level,
usize,
&'a Cell<RegType>,
ClauseType,
&'a Vec<Box<Term>>,
),
InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term), InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term), FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
PartialString(Level, &'a Cell<RegType>, String, Option<&'a Term>), InitialPartialString(Level, &'a Cell<RegType>, Atom, &'a Option<Box<Term>>),
Var(Level, &'a Cell<VarReg>, Rc<Var>), FinalPartialString(Level, &'a Cell<RegType>, Atom, &'a Option<Box<Term>>),
} Var(Level, &'a Cell<VarReg>, Rc<String>),
fn is_partial_string<'a>(head: &'a Term, mut tail: &'a Term) -> Option<(String, Option<&'a Term>)> {
let mut string = match head {
&Term::Constant(_, Constant::Atom(ref atom, _)) if atom.is_char() => {
atom.as_str().chars().next().unwrap().to_string()
}
&Term::Constant(_, Constant::Char(c)) => c.to_string(),
_ => {
return None;
}
};
while let Term::Cons(_, ref head, ref succ) = tail {
match head.as_ref() {
&Term::Constant(_, Constant::Atom(ref atom, _)) if atom.is_char() => {
string.push(atom.as_str().chars().next().unwrap());
}
&Term::Constant(_, Constant::Char(c)) => {
string.push(c);
}
_ => {
return None;
}
};
tail = succ.as_ref();
}
match tail {
Term::AnonVar | Term::Var(..) => {
return Some((string, Some(tail)));
}
Term::Constant(_, Constant::EmptyList) => {
return Some((string, None));
}
Term::Constant(_, Constant::String(tail)) => {
string += &tail;
return Some((string, None));
}
_ => {
return None;
}
}
} }
impl<'a> TermIterState<'a> { impl<'a> TermIterState<'a> {
pub(crate) 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 => TermIterState::AnonVar(lvl), Term::AnonVar => TermIterState::AnonVar(lvl),
&Term::Clause(ref cell, ref name, ref subterms, ref spec) => { Term::Clause(cell, name, subterms) => {
let ct = if let Some(spec) = spec { let ct = ClauseType::Named(subterms.len(), *name, CodeIndex::default());
ClauseType::Op(name.clone(), spec.clone(), CodeIndex::default())
} else {
ClauseType::Named(name.clone(), subterms.len(), CodeIndex::default())
};
TermIterState::Clause(lvl, 0, cell, ct, subterms) TermIterState::Clause(lvl, 0, cell, ct, subterms)
} }
&Term::Cons(ref cell, ref head, ref tail) => { Term::Cons(cell, head, 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) => TermIterState::Constant(lvl, cell, constant), Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant),
&Term::Var(ref cell, ref var) => TermIterState::Var(lvl, cell, var.clone()), Term::PartialString(cell, string_buf, tail) => {
TermIterState::InitialPartialString(lvl, cell, *string_buf, tail)
}
Term::Var(cell, var) => TermIterState::Var(lvl, cell, var.clone()),
} }
} }
} }
@@ -129,11 +77,11 @@ impl<'a> QueryIterator<'a> {
.push(TermIterState::subterm_to_state(lvl, term)); .push(TermIterState::subterm_to_state(lvl, term));
} }
fn from_rule_head_clause(terms: &'a Vec<Box<Term>>) -> Self { fn from_rule_head_clause(terms: &'a Vec<Term>) -> Self {
let state_stack = terms let state_stack = terms
.iter() .iter()
.rev() .rev()
.map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt.as_ref())) .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt))
.collect(); .collect();
QueryIterator { state_stack } QueryIterator { state_stack }
@@ -141,29 +89,19 @@ impl<'a> QueryIterator<'a> {
fn from_term(term: &'a Term) -> Self { fn from_term(term: &'a Term) -> Self {
let state = match term { let state = match term {
&Term::AnonVar => { Term::AnonVar | Term::Cons(..) | Term::Literal(..) | Term::PartialString(..) => {
return QueryIterator { return QueryIterator {
state_stack: vec![], state_stack: vec![],
} }
} }
&Term::Clause(ref r, ref name, ref terms, ref fixity) => TermIterState::Clause( Term::Clause(r, name, terms) => TermIterState::Clause(
Level::Root, Level::Root,
0, 0,
r, r,
ClauseType::from(name.clone(), terms.len(), fixity.clone()), ClauseType::from(*name, terms.len()),
terms, terms,
), ),
&Term::Cons(..) => { Term::Var(cell, var) => TermIterState::Var(Level::Root, cell, var.clone()),
return QueryIterator {
state_stack: vec![],
}
}
&Term::Constant(_, _) => {
return QueryIterator {
state_stack: vec![],
}
}
&Term::Var(ref cell, ref var) => TermIterState::Var(Level::Root, cell, (*var).clone()),
}; };
QueryIterator { QueryIterator {
@@ -173,8 +111,8 @@ impl<'a> QueryIterator<'a> {
fn new(term: &'a QueryTerm) -> Self { fn new(term: &'a QueryTerm) -> Self {
match term { match term {
&QueryTerm::Clause(ref cell, ClauseType::CallN, ref terms, _) => { &QueryTerm::Clause(ref cell, ClauseType::CallN(arity), ref terms, _) => {
let state = TermIterState::Clause(Level::Root, 1, cell, ClauseType::CallN, terms); let state = TermIterState::Clause(Level::Root, 1, cell, ClauseType::CallN(arity), terms);
QueryIterator { QueryIterator {
state_stack: vec![state], state_stack: vec![state],
} }
@@ -186,7 +124,7 @@ impl<'a> QueryIterator<'a> {
} }
} }
&QueryTerm::UnblockedCut(ref cell) => { &QueryTerm::UnblockedCut(ref cell) => {
let state = TermIterState::Var(Level::Root, cell, rc_atom!("!")); let state = TermIterState::Var(Level::Root, cell, Rc::new("!".to_string()));
QueryIterator { QueryIterator {
state_stack: vec![state], state_stack: vec![state],
} }
@@ -225,10 +163,10 @@ impl<'a> Iterator for QueryIterator<'a> {
TermIterState::Clause(lvl, child_num, cell, ct, child_terms) => { TermIterState::Clause(lvl, child_num, cell, ct, child_terms) => {
if child_num == child_terms.len() { if child_num == child_terms.len() {
match ct { match ct {
ClauseType::CallN => { ClauseType::CallN(_) => {
self.push_subterm(Level::Shallow, child_terms[0].as_ref()) self.push_subterm(Level::Shallow, &child_terms[0]);
} }
ClauseType::Named(..) | ClauseType::Op(..) => { ClauseType::Named(..) => {
return match lvl { return match lvl {
Level::Root => None, Level::Root => None,
lvl => Some(TermRef::Clause(lvl, cell, ct, child_terms)), lvl => Some(TermRef::Clause(lvl, cell, ct, child_terms)),
@@ -247,33 +185,30 @@ impl<'a> Iterator for QueryIterator<'a> {
child_terms, child_terms,
)); ));
self.push_subterm(lvl.child_level(), child_terms[child_num].as_ref()); self.push_subterm(lvl.child_level(), &child_terms[child_num]);
} }
} }
TermIterState::InitialCons(lvl, cell, head, tail) => { TermIterState::InitialCons(lvl, cell, head, tail) => {
if let Some((string, tail)) = is_partial_string(head, tail) { self.state_stack.push(TermIterState::FinalCons(lvl, cell, head, tail));
self.state_stack
.push(TermIterState::PartialString(lvl, cell, string, tail));
if let Some(tail) = tail {
self.push_subterm(lvl.child_level(), tail);
}
} else {
self.state_stack
.push(TermIterState::FinalCons(lvl, cell, head, tail));
self.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);
} }
TermIterState::InitialPartialString(lvl, cell, string, tail) => {
self.state_stack.push(TermIterState::FinalPartialString(lvl, cell, string, tail));
if let Some(tail) = tail {
self.push_subterm(lvl.child_level(), tail);
} }
TermIterState::PartialString(lvl, cell, string, tail) => { }
TermIterState::FinalPartialString(lvl, cell, string, tail) => {
return Some(TermRef::PartialString(lvl, cell, string, tail)); return Some(TermRef::PartialString(lvl, cell, string, tail));
} }
TermIterState::FinalCons(lvl, cell, head, tail) => { TermIterState::FinalCons(lvl, cell, head, tail) => {
return Some(TermRef::Cons(lvl, cell, head, tail)); return Some(TermRef::Cons(lvl, cell, head, tail));
} }
TermIterState::Constant(lvl, cell, constant) => { TermIterState::Literal(lvl, cell, constant) => {
return Some(TermRef::Constant(lvl, cell, constant)); return Some(TermRef::Literal(lvl, cell, constant));
} }
TermIterState::Var(lvl, cell, var) => { TermIterState::Var(lvl, cell, var) => {
return Some(TermRef::Var(lvl, cell, var)); return Some(TermRef::Var(lvl, cell, var));
@@ -297,10 +232,10 @@ impl<'a> FactIterator<'a> {
.push_back(TermIterState::subterm_to_state(lvl, term)); .push_back(TermIterState::subterm_to_state(lvl, term));
} }
pub(crate) fn from_rule_head_clause(terms: &'a Vec<Box<Term>>) -> Self { pub(crate) fn from_rule_head_clause(terms: &'a Vec<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))
.collect(); .collect();
FactIterator { FactIterator {
@@ -311,23 +246,31 @@ impl<'a> FactIterator<'a> {
fn new(term: &'a Term, iterable_root: bool) -> Self { fn new(term: &'a Term, iterable_root: bool) -> Self {
let states = match term { let states = match term {
&Term::AnonVar => { Term::AnonVar => {
vec![TermIterState::AnonVar(Level::Root)] vec![TermIterState::AnonVar(Level::Root)]
} }
&Term::Clause(ref cell, ref name, ref terms, ref fixity) => { Term::Clause(cell, name, terms) => {
let ct = ClauseType::from(name.clone(), terms.len(), fixity.clone()); let ct = ClauseType::from(*name, terms.len());
vec![TermIterState::Clause(Level::Root, 0, cell, ct, terms)] vec![TermIterState::Clause(Level::Root, 0, cell, ct, terms)]
} }
&Term::Cons(ref cell, ref head, ref tail) => vec![TermIterState::InitialCons( Term::Cons(cell, head, tail) => vec![TermIterState::InitialCons(
Level::Root, Level::Root,
cell, cell,
head.as_ref(), head.as_ref(),
tail.as_ref(), tail.as_ref(),
)], )],
&Term::Constant(ref cell, ref constant) => { Term::PartialString(cell, string_buf, tail_opt) => {
vec![TermIterState::Constant(Level::Root, cell, constant)] vec![TermIterState::InitialPartialString(
Level::Root,
cell,
*string_buf,
tail_opt,
)]
} }
&Term::Var(ref cell, ref var) => { Term::Literal(cell, constant) => {
vec![TermIterState::Literal(Level::Root, cell, constant)]
}
Term::Var(cell, var) => {
vec![TermIterState::Var(Level::Root, cell, var.clone())] vec![TermIterState::Var(Level::Root, cell, var.clone())]
} }
}; };
@@ -359,21 +302,20 @@ impl<'a> Iterator for FactIterator<'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(tail) = tail {
self.push_subterm(Level::Deep, tail);
}
return Some(TermRef::PartialString(lvl, cell, string, tail));
} else {
self.push_subterm(Level::Deep, head); self.push_subterm(Level::Deep, head);
self.push_subterm(Level::Deep, tail); self.push_subterm(Level::Deep, tail);
return Some(TermRef::Cons(lvl, cell, head, tail)); return Some(TermRef::Cons(lvl, cell, head, tail));
} }
TermIterState::InitialPartialString(lvl, cell, string_buf, tail_opt) => {
if let Some(tail) = tail_opt {
self.push_subterm(Level::Deep, tail);
} }
TermIterState::Constant(lvl, cell, constant) => {
return Some(TermRef::Constant(lvl, cell, constant)) return Some(TermRef::PartialString(lvl, cell, string_buf, tail_opt));
}
TermIterState::Literal(lvl, cell, constant) => {
return Some(TermRef::Literal(lvl, cell, constant))
} }
TermIterState::Var(lvl, cell, var) => { TermIterState::Var(lvl, cell, var) => {
return Some(TermRef::Var(lvl, cell, var)); return Some(TermRef::Var(lvl, cell, var));
@@ -386,17 +328,17 @@ impl<'a> Iterator for FactIterator<'a> {
} }
} }
pub(crate) fn post_order_iter(term: &Term) -> QueryIterator { pub(crate) fn post_order_iter<'a>(term: &'a Term) -> QueryIterator<'a> {
QueryIterator::from_term(term) QueryIterator::from_term(term)
} }
pub(crate) fn breadth_first_iter(term: &Term, iterable_root: bool) -> FactIterator { pub(crate) fn breadth_first_iter<'a>(term: &'a Term, iterable_root: bool) -> FactIterator<'a> {
FactIterator::new(term, iterable_root) FactIterator::new(term, iterable_root)
} }
#[derive(Debug)] #[derive(Debug)]
pub(crate) enum ChunkedTerm<'a> { pub(crate) enum ChunkedTerm<'a> {
HeadClause(ClauseName, &'a Vec<Box<Term>>), HeadClause(Atom, &'a Vec<Term>),
BodyTerm(&'a QueryTerm), BodyTerm(&'a QueryTerm),
} }
@@ -407,7 +349,7 @@ pub(crate) fn query_term_post_order_iter<'a>(query_term: &'a QueryTerm) -> Query
impl<'a> ChunkedTerm<'a> { impl<'a> ChunkedTerm<'a> {
pub(crate) 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(qt) => QueryIterator::new(qt),
&ChunkedTerm::HeadClause(_, terms) => QueryIterator::from_rule_head_clause(terms), &ChunkedTerm::HeadClause(_, terms) => QueryIterator::from_rule_head_clause(terms),
} }
} }
@@ -517,7 +459,7 @@ impl<'a> ChunkedIterator<'a> {
while let Some(term) = item { while let Some(term) = item {
match term { match term {
ChunkedTerm::HeadClause(_, terms) => { ChunkedTerm::HeadClause(_, terms) => {
if contains_cut_var(terms.iter().map(|t| t.as_ref())) { if contains_cut_var(terms.iter()) {
self.cut_var_in_head = true; self.cut_var_in_head = true;
} }
@@ -547,13 +489,16 @@ impl<'a> ChunkedIterator<'a> {
arity = 1; arity = 1;
break; break;
} }
ChunkedTerm::BodyTerm(&QueryTerm::UnblockedCut(..)) => result.push(term), ChunkedTerm::BodyTerm(&QueryTerm::UnblockedCut(..)) => {
self.deep_cut_encountered = true;
result.push(term);
}
ChunkedTerm::BodyTerm(&QueryTerm::Clause(_, ClauseType::Inlined(_), ..)) => { ChunkedTerm::BodyTerm(&QueryTerm::Clause(_, ClauseType::Inlined(_), ..)) => {
result.push(term) result.push(term)
} }
ChunkedTerm::BodyTerm(&QueryTerm::Clause( ChunkedTerm::BodyTerm(&QueryTerm::Clause(
_, _,
ClauseType::CallN, ClauseType::CallN(_),
ref subterms, ref subterms,
_, _,
)) => { )) => {

View File

@@ -1,25 +1,31 @@
#[cfg(feature = "num-rug-adapter")] #![recursion_limit = "4112"]
use num_rug_adapter as rug;
#[cfg(feature = "rug")]
use rug;
#[macro_use] #[macro_use]
mod macros; extern crate static_assertions;
#[macro_use]
pub mod macros;
#[macro_use]
pub mod atom_table;
#[macro_use]
pub mod arena;
#[macro_use]
pub mod parser;
mod allocator; mod allocator;
mod arithmetic; mod arithmetic;
mod clause_types; pub mod codegen;
mod codegen;
mod debray_allocator; mod debray_allocator;
mod fixtures; mod fixtures;
mod forms; mod forms;
mod heap_iter; mod heap_iter;
mod heap_print; pub mod heap_print;
mod indexing; mod indexing;
mod instructions; #[macro_use]
pub mod instructions;
mod iterators; mod iterators;
pub mod machine; pub mod machine;
mod raw_block;
pub mod read; pub mod read;
mod targets; mod targets;
mod write; pub mod types;
pub mod write;
use machine::*;

View File

@@ -24,30 +24,42 @@
'$absent_from_list'(Ls, Attr). '$absent_from_list'(Ls, Attr).
'$absent_from_list'(X, Attr) :- '$absent_from_list'(X, Attr) :-
( var(X) -> true ( var(X) ->
; X = [L|Ls], L \= Attr -> '$absent_from_list'(Ls, Attr) true
; X = [L|Ls],
L \= Attr ->
'$absent_from_list'(Ls, Attr)
). ).
'$get_attr'(V, Attr) :- '$get_attr'(V, Attr) :-
'$get_attr_list'(V, Ls), nonvar(Ls), '$get_from_list'(Ls, V, Attr). '$get_attr_list'(V, Ls),
nonvar(Ls),
'$get_from_list'(Ls, V, Attr).
'$get_from_list'([L|Ls], V, Attr) :- '$get_from_list'([L|Ls], V, Attr) :-
nonvar(L), nonvar(L),
( L \= Attr -> nonvar(Ls), '$get_from_list'(Ls, V, Attr) ( L \= Attr ->
; L = Attr, '$enqueue_attr_var'(V) nonvar(Ls),
'$get_from_list'(Ls, V, Attr)
; L = Attr,
'$enqueue_attr_var'(V)
). ).
'$put_attr'(V, Attr) :- '$put_attr'(V, Attr) :-
'$get_attr_list'(V, Ls), '$add_to_list'(Ls, V, Attr). '$get_attr_list'(V, Ls),
'$add_to_list'(Ls, V, Attr).
'$add_to_list'(Ls, V, Attr) :- '$add_to_list'(Ls, V, Attr) :-
( var(Ls) -> ( var(Ls) ->
Ls = [Attr | _], '$enqueue_attr_var'(V) Ls = [Attr | _],
; Ls = [_ | Ls0], '$add_to_list'(Ls0, V, Attr) '$enqueue_attr_var'(V)
; Ls = [_ | Ls0],
'$add_to_list'(Ls0, V, Attr)
). ).
'$del_attr'(Ls0, _, _) :- '$del_attr'(Ls0, _, _) :-
var(Ls0), !. var(Ls0),
!.
'$del_attr'(Ls0, V, Attr) :- '$del_attr'(Ls0, V, Attr) :-
Ls0 = [Att | Ls1], Ls0 = [Att | Ls1],
nonvar(Att), nonvar(Att),

View File

@@ -12,17 +12,18 @@ between(Lower, Upper, X) :-
( nonvar(X) -> ( nonvar(X) ->
Lower =< X, Lower =< X,
X =< Upper X =< Upper
; compare(Ord, Lower, Upper), ; Lower =< Upper,
between_(Ord, Lower, Upper, X) between_(Lower, Upper, X)
). ).
between_(<, Lower0, Upper, X) :- between_(Lower, Lower, Lower) :- !.
( X = Lower0 between_(Lower, Upper, Lower1) :-
; Lower1 is Lower0 + 1, ( Lower < Upper,
compare(Ord, Lower1, Upper), ( Lower1 = Lower
between_(Ord, Lower1, Upper, X) ; Lower0 is Lower + 1,
between_(Lower0, Upper, Lower1)
)
). ).
between_(=, Upper, Upper, Upper).
enumerate_nats(I, I). enumerate_nats(I, I).
enumerate_nats(I0, N) :- enumerate_nats(I0, N) :-

View File

@@ -1,4 +1,4 @@
:- module(builtins, [(=)/2, (\=)/2, (\+)/1, (',')/2, (->)/2, (;)/2, :- module(builtins, [(=)/2, (\=)/2, (\+)/1, !/0, (',')/2, (->)/2, (;)/2,
(=..)/2, (:)/2, (:)/3, (:)/4, (:)/5, (:)/6, (=..)/2, (:)/2, (:)/3, (:)/4, (:)/5, (:)/6,
(:)/7, (:)/8, (:)/9, (:)/10, (:)/11, (:)/12, (:)/7, (:)/8, (:)/9, (:)/10, (:)/11, (:)/12,
abolish/1, asserta/1, assertz/1, abolish/1, asserta/1, assertz/1,
@@ -59,19 +59,16 @@ call(G, A, B, C, D, E, F, G) :- '$call'(G, A, B, C, D, E, F, G).
call(G, A, B, C, D, E, F, G, H) :- '$call'(G, A, B, C, D, E, F, G, H). call(G, A, B, C, D, E, F, G, H) :- '$call'(G, A, B, C, D, E, F, G, H).
Module : Predicate :-
( atom(Module) ->
'$module_call'(Module, Predicate)
;
throw(error(type_error(atom, Module), (:)/2))
).
% dynamic module resolution. % dynamic module resolution.
Module : Predicate :-
( atom(Module) -> '$module_call'(Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1) :- :(Module, Predicate, A1) :-
( atom(Module) -> '$module_call'(A1, Module, Predicate) ( atom(Module) ->
'$module_call'(A1, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2)) ; throw(error(type_error(atom, Module), (:)/2))
). ).
@@ -205,143 +202,109 @@ repeat.
repeat :- repeat. repeat :- repeat.
:- meta_predicate ','(0,0). :- meta_predicate ','(0,0).
:- meta_predicate ','(0, +, +).
:- meta_predicate ;(0,0). :- meta_predicate ;(0,0).
:- meta_predicate ;(0, 0, +).
:- meta_predicate ->(0,0). :- meta_predicate ->(0,0).
:- meta_predicate ->(0, 0, +). ! :- '$get_staggered_cp'(B), '$set_cp'(B).
G1 -> G2 :- '$get_staggered_cp'(B), call('$call'(G1)), '$set_cp'(B), call('$call'(G2)).
','(G1, G2) :- G ; _ :- call('$call'(G)).
'$get_b_value'(B), _ ; G :- call('$call'(G)).
( '$call_with_default_policy'(var(G1)) ->
throw(error(instantiation_error, (',')/2))
; '$call_with_default_policy'(','(G1, G2, B))
).
','(G1, G2) :- '$get_staggered_cp'(B), comma_dispatch(G1,G2,B).
';'(G1, G2) :- set_cp(B) :- '$set_cp'(B).
'$get_b_value'(B),
( '$call_with_default_policy'(var(G1)) ->
throw(error(instantiation_error, (';')/2))
; '$call_with_default_policy'(';'(G1, G2, B))
).
:- non_counted_backtracking comma_dispatch/3.
G1 -> G2 :- comma_dispatch(G1, G2, B) :-
'$get_b_value'(B), comma_dispatch_prep((G1, G2), B, Conts),
( '$call_with_default_policy'(var(G1)) -> comma_dispatch_call_list(Conts).
throw(error(instantiation_error, (->)/2))
; '$call_with_default_policy'(->(G1, G2, B))
).
:- non_counted_backtracking comma_dispatch_prep/3.
:-non_counted_backtracking call_or_cut/3. comma_dispatch_prep(Gs, B, [Cont|Conts]) :-
( callable(Gs) ->
call_or_cut(G, B, ErrorPI) :- ( functor(Gs, ',', 2) ->
( '$call_with_default_policy'(var(G)) -> arg(1, Gs, G1),
throw(error(instantiation_error, ErrorPI)) arg(2, Gs, G2),
; '$call_with_default_policy'(call_or_cut(G, B)) ( nonvar(G1), ( G1 = ! ; G1 = _:! ) ->
). Cont = builtins:set_cp(B)
; Cont = G1
),
:- non_counted_backtracking control_functor/1. comma_dispatch_prep(G2, B, Conts)
; ( Gs = ! ; Gs = _:! ) ->
control_functor(_:G) :- nonvar(G), control_functor(G). Cont = builtins:set_cp(B),
control_functor(call(_:C)) :- C == !. Conts = []
control_functor(!). ; Cont = Gs,
control_functor((_,_)). Conts = []
control_functor((_;_)).
control_functor((_->_)).
:- non_counted_backtracking call_or_cut/2.
call_or_cut(G, B) :-
( nonvar(G),
'$call_with_default_policy'(control_functor(G)) ->
'$call_with_default_policy'(call_or_cut_interp(G, B))
; call(G)
).
:- non_counted_backtracking call_or_cut_interp/2.
call_or_cut_interp(_ : G, B) :-
call_or_cut_interp(G, B).
call_or_cut_interp(call(_ : !), B) :-
!. % '$set_cp'(B).
call_or_cut_interp(!, B) :-
'$set_cp'(B).
call_or_cut_interp((G1, G2), B) :-
'$call_with_default_policy'(','(G1, G2, B)).
call_or_cut_interp((G1 ; G2), B) :-
'$call_with_default_policy'(';'(G1, G2, B)).
call_or_cut_interp((G1 -> G2), B) :-
'$call_with_default_policy'(->(G1, G2, B)).
:- non_counted_backtracking (',')/3.
','(G1, G2, B) :-
( nonvar(G1),
'$call_with_default_policy'(control_functor(G1)) ->
'$call_with_default_policy'(call_or_cut_interp(G1, B)),
'$call_with_default_policy'(call_or_cut(G2, B, (',')/2))
; call(G1),
'$call_with_default_policy'(call_or_cut(G2, B, (',')/2))
).
:- non_counted_backtracking (;)/3.
';'(G1, G2, B) :-
( nonvar(G1),
'$call_with_default_policy'(control_functor(G1)) ->
'$call_with_default_policy'(';-interp'(G1, G2, B))
; call(G1)
; '$call_with_default_policy'(call_or_cut(G2, B, (;)/2))
).
:- non_counted_backtracking ';-interp'/3.
';-interp'((G1 -> G2), G3, B) :-
!,
( '$call_with_default_policy'(call_or_cut(G1, B, (->)/2)) ->
'$call_with_default_policy'(call_or_cut(G2, B, (->)/2))
; '$call_with_default_policy'(call_or_cut(G3, B, (;)/2))
).
';-interp'(_:(G1 -> G2), G3, B) :-
!,
( '$call_with_default_policy'(call_or_cut(G1, B, (->)/2)) ->
'$call_with_default_policy'(call_or_cut(G2, B, (->)/2))
; '$call_with_default_policy'(call_or_cut(G3, B, (;)/2))
).
';-interp'(G1, G2, B) :-
( '$call_with_default_policy'(call_or_cut_interp(G1, B))
; '$call_with_default_policy'(call_or_cut(G2, B, (;)/2))
).
:- non_counted_backtracking (->)/3.
->(G1, G2, B) :-
( nonvar(G1),
'$call_with_default_policy'(control_functor(G1)) ->
( '$call_with_default_policy'(call_or_cut_interp(G1, B)) ->
'$call_with_default_policy'(call_or_cut(G2, B, (->)/2))
) )
; call(G1) -> ; Cont = Gs,
'$call_with_default_policy'(call_or_cut(G2, B, (->)/2)) Conts = []
). ).
:- non_counted_backtracking comma_dispatch_call_list/1.
comma_dispatch_call_list([]).
comma_dispatch_call_list([G1,G2,G3,G4,G5,G6,G7,G8|Gs]) :-
!,
'$call'(G1),
'$call'(G2),
'$call'(G3),
'$call'(G4),
'$call'(G5),
'$call'(G6),
'$call'(G7),
'$call'(G8),
'$call_with_default_policy'(comma_dispatch_call_list(Gs)).
comma_dispatch_call_list([G1,G2,G3,G4,G5,G6,G7]) :-
!,
'$call'(G1),
'$call'(G2),
'$call'(G3),
'$call'(G4),
'$call'(G5),
'$call'(G6),
'$call'(G7).
comma_dispatch_call_list([G1,G2,G3,G4,G5,G6]) :-
!,
'$call'(G1),
'$call'(G2),
'$call'(G3),
'$call'(G4),
'$call'(G5),
'$call'(G6).
comma_dispatch_call_list([G1,G2,G3,G4,G5]) :-
!,
'$call'(G1),
'$call'(G2),
'$call'(G3),
'$call'(G4),
'$call'(G5).
comma_dispatch_call_list([G1,G2,G3,G4]) :-
!,
'$call'(G1),
'$call'(G2),
'$call'(G3),
'$call'(G4).
comma_dispatch_call_list([G1,G2,G3]) :-
!,
'$call'(G1),
'$call'(G2),
'$call'(G3).
comma_dispatch_call_list([G1,G2]) :-
!,
'$call'(G1),
'$call'(G2).
comma_dispatch_call_list([G1]) :-
'$call'(G1).
% univ. % univ.
:- non_counted_backtracking univ_errors/3. :- non_counted_backtracking univ_errors/3.
@@ -388,9 +351,10 @@ univ_worker(Term, List, _) :-
!, !,
'$call_with_default_policy'(List = [Term]). '$call_with_default_policy'(List = [Term]).
univ_worker(Term, [Name|Args], N) :- univ_worker(Term, [Name|Args], N) :-
var(Term), !, var(Term),
!,
'$call_with_default_policy'(Arity is N-1), '$call_with_default_policy'(Arity is N-1),
'$call_with_default_policy'(functor(Term, Name, Arity)), '$call_with_default_policy'(functor(Term, Name, Arity)), % Term = {var}, Name = nonvar, Arity = 0.
'$call_with_default_policy'(get_args(Args, Term, 1, Arity)). '$call_with_default_policy'(get_args(Args, Term, 1, Arity)).
univ_worker(Term, List, _) :- univ_worker(Term, List, _) :-
'$call_with_default_policy'(functor(Term, Name, Arity)), '$call_with_default_policy'(functor(Term, Name, Arity)),
@@ -620,9 +584,11 @@ throw(Ball) :-
), ),
'$unwind_stack'. '$unwind_stack'.
:- non_counted_backtracking '$iterate_find_all'/4. :- non_counted_backtracking '$iterate_find_all'/4.
'$iterate_find_all'(Template, Goal, _, LhOffset) :- '$iterate_find_all'(Template, Goal, _, LhOffset) :-
call(Goal), '$call'(Goal),
'$copy_to_lh'(LhOffset, Template), '$copy_to_lh'(LhOffset, Template),
'$fail'. '$fail'.
'$iterate_find_all'(_, _, Solutions, LhOffset) :- '$iterate_find_all'(_, _, Solutions, LhOffset) :-
@@ -636,7 +602,7 @@ truncate_lh_to(LhLength) :- '$truncate_lh_to'(LhLength).
:- meta_predicate findall(?, 0, ?). :- meta_predicate findall(?, 0, ?).
findall(Template, Goal, Solutions) :- findall(Template, Goal, Solutions) :-
error:can_be(list, Solutions), '$call_with_default_policy'(error:can_be(list, Solutions)),
'$lh_length'(LhLength), '$lh_length'(LhLength),
'$call_with_default_policy'( '$call_with_default_policy'(
catch(builtins:'$iterate_find_all'(Template, Goal, Solutions, LhLength), catch(builtins:'$iterate_find_all'(Template, Goal, Solutions, LhLength),
@@ -644,7 +610,6 @@ findall(Template, Goal, Solutions) :-
( builtins:truncate_lh_to(LhLength), builtins:throw(Error) )) ( builtins:truncate_lh_to(LhLength), builtins:throw(Error) ))
). ).
:- non_counted_backtracking '$iterate_find_all_diff'/5. :- non_counted_backtracking '$iterate_find_all_diff'/5.
'$iterate_find_all_diff'(Template, Goal, _, _, LhOffset) :- '$iterate_find_all_diff'(Template, Goal, _, _, LhOffset) :-
@@ -659,8 +624,8 @@ findall(Template, Goal, Solutions) :-
:- meta_predicate findall(?, 0, ?, ?). :- meta_predicate findall(?, 0, ?, ?).
findall(Template, Goal, Solutions0, Solutions1) :- findall(Template, Goal, Solutions0, Solutions1) :-
error:can_be(list, Solutions0), '$call_with_default_policy'(error:can_be(list, Solutions0)),
error:can_be(list, Solutions1), '$call_with_default_policy'(error:can_be(list, Solutions1)),
'$lh_length'(LhLength), '$lh_length'(LhLength),
'$call_with_default_policy'( '$call_with_default_policy'(
catch(builtins:'$iterate_find_all_diff'(Template, Goal, Solutions0, catch(builtins:'$iterate_find_all_diff'(Template, Goal, Solutions0,
@@ -679,9 +644,9 @@ set_difference([], _, []) :- !.
set_difference(Xs, [], Xs). set_difference(Xs, [], Xs).
group_by_variant([V2-S2 | Pairs], V1-S1, [S2 | Solutions], Pairs0) :- group_by_variant([V2-S2 | Pairs], V1-S1, [S2 | Solutions], Pairs0) :-
iso_ext:variant(V1, V2), V1 = V2, % \+ \+ (V1 = V2), % (2) % iso_ext:variant(V1, V2), % (1)
!, !,
V1 = V2, % V1 = V2, % (3)
group_by_variant(Pairs, V2-S2, Solutions, Pairs0). group_by_variant(Pairs, V2-S2, Solutions, Pairs0).
group_by_variant(Pairs, _, [], Pairs). group_by_variant(Pairs, _, [], Pairs).
@@ -779,11 +744,11 @@ setof(Template, Goal, Solution) :-
( var(H) -> ( var(H) ->
throw(error(instantiation_error, clause/2)) throw(error(instantiation_error, clause/2))
; callable(H), functor(H, Name, Arity) -> ; callable(H), functor(H, Name, Arity) ->
( '$head_is_dynamic'(Module, H) -> ( '$no_such_predicate'(Module, H) ->
'$fail'
; '$head_is_dynamic'(Module, H) ->
'$clause_body_is_valid'(B), '$clause_body_is_valid'(B),
Module:'$clause'(H, B) Module:'$clause'(H, B)
; '$no_such_predicate'(Module, H) ->
'$fail'
; throw(error(permission_error(access, private_procedure, Name/Arity), ; throw(error(permission_error(access, private_procedure, Name/Arity),
clause/2)) clause/2))
) )
@@ -800,12 +765,11 @@ clause(H, B) :-
arg(1, H, Module), arg(1, H, Module),
arg(2, H, F), arg(2, H, F),
'$module_clause'(F, B, Module) '$module_clause'(F, B, Module)
; '$no_such_predicate'(user, H) ->
'$fail'
; '$head_is_dynamic'(user, H) -> ; '$head_is_dynamic'(user, H) ->
'$clause_body_is_valid'(B), '$clause_body_is_valid'(B),
'$clause'(H, B) '$clause'(H, B)
; '$no_such_predicate'(user, H) -> %% '$no_such_predicate' fails if
%% H is not callable.
'$fail'
; throw(error(permission_error(access, private_procedure, Name/Arity), ; throw(error(permission_error(access, private_procedure, Name/Arity),
clause/2)) clause/2))
) )
@@ -854,13 +818,14 @@ asserta_clause(Head, Body) :-
:- meta_predicate asserta(0). :- meta_predicate asserta(0).
asserta(Clause) :- asserta(Clause0) :-
loader:strip_module(Clause0, Module, Clause),
( Clause \= (_ :- _) -> ( Clause \= (_ :- _) ->
Head = Clause, Head = Clause,
Body = true, Body = true,
asserta_clause(Head, Body) module_asserta_clause(Head, Body, Module)
; Clause = (Head :- Body) -> ; Clause = (Head :- Body) ->
asserta_clause(Head, Body) module_asserta_clause(Head, Body, Module)
). ).
module_assertz_clause(Head, Body, Module) :- module_assertz_clause(Head, Body, Module) :-
@@ -909,13 +874,14 @@ assertz_clause(Head, Body) :-
:- meta_predicate assertz(0). :- meta_predicate assertz(0).
assertz(Clause) :- assertz(Clause0) :-
loader:strip_module(Clause0, Module, Clause),
( Clause \= (_ :- _) -> ( Clause \= (_ :- _) ->
Head = Clause, Head = Clause,
Body = true, Body = true,
assertz_clause(Head, Body) module_assertz_clause(Head, Body, Module)
; Clause = (Head :- Body) -> ; Clause = (Head :- Body) ->
assertz_clause(Head, Body) module_assertz_clause(Head, Body, Module)
). ).
@@ -999,13 +965,14 @@ retract_clause(Head, Body) :-
:- meta_predicate retract(0). :- meta_predicate retract(0).
retract(Clause0) :- retract(Clause0) :-
strip_module(Clause0, Module, Clause), loader:strip_module(Clause0, Module, Clause),
( Clause = (Head :- Body) -> ( Clause \= (_ :- _) ->
true Head = Clause,
; Head = Clause, Body = true,
Body = true retract_module_clause(Head, Body, Module)
), ; Clause = (Head :- Body) ->
retract_clause(Module:Head, Body). retract_module_clause(Head, Body, Module)
).
:- meta_predicate retractall(0). :- meta_predicate retractall(0).
@@ -1022,6 +989,8 @@ module_abolish(Pred, Module) :-
; Pred = Name/Arity -> ; Pred = Name/Arity ->
( var(Name) -> ( var(Name) ->
throw(error(instantiation_error, abolish/1)) throw(error(instantiation_error, abolish/1))
; var(Arity) ->
throw(error(instantiation_error, abolish/1))
; integer(Arity) -> ; integer(Arity) ->
(\+ atom(Name) -> (\+ atom(Name) ->
throw(error(type_error(atom, Name), abolish/1)) throw(error(type_error(atom, Name), abolish/1))
@@ -1075,17 +1044,16 @@ abolish(Pred) :-
; throw(error(type_error(predicate_indicator, Pred), abolish/1)) ; throw(error(type_error(predicate_indicator, Pred), abolish/1))
). ).
'$iterate_db_refs'(Ref, Name/Arity) :- '$iterate_db_refs'(Name, Arity, Name/Arity). % :-
'$lookup_db_ref'(Ref, Name, Arity). % '$lookup_db_ref'(Ref, Name, Arity).
'$iterate_db_refs'(Ref, Name/Arity) :- '$iterate_db_refs'(RName, RArity, Name/Arity) :-
'$get_next_db_ref'(Ref, NextRef), '$get_next_db_ref'(RName, RArity, RRName, RRArity),
'$iterate_db_refs'(NextRef, Name/Arity). '$iterate_db_refs'(RRName, RRArity, Name/Arity).
current_predicate(Pred) :- current_predicate(Pred) :-
( var(Pred) -> ( var(Pred) ->
'$get_next_db_ref'(Ref, _), '$get_next_db_ref'(RN, RA, _, _),
'$iterate_db_refs'(Ref, Pred) '$iterate_db_refs'(RN, RA, Pred)
; Pred \= _/_ -> ; Pred \= _/_ ->
throw(error(type_error(predicate_indicator, Pred), current_predicate/1)) throw(error(type_error(predicate_indicator, Pred), current_predicate/1))
; Pred = Name/Arity, ; Pred = Name/Arity,
@@ -1094,15 +1062,14 @@ current_predicate(Pred) :-
; integer(Arity), Arity < 0 ; integer(Arity), Arity < 0
) -> ) ->
throw(error(type_error(predicate_indicator, Pred), current_predicate/1)) throw(error(type_error(predicate_indicator, Pred), current_predicate/1))
; '$get_next_db_ref'(Ref, _), ; '$get_next_db_ref'(RN, RA, _, _),
'$iterate_db_refs'(Ref, Pred) '$iterate_db_refs'(RN, RA, Pred)
). ).
'$iterate_op_db_refs'(Ref, Priority, Spec, Op) :- '$iterate_op_db_refs'(RPriority, RSpec, ROp, _, RPriority, RSpec, ROp).
'$lookup_op_db_ref'(Ref, Priority, Spec, Op). '$iterate_op_db_refs'(RPriority, RSpec, ROp, OssifiedOpDir, Priority, Spec, Op) :-
'$iterate_op_db_refs'(Ref, Priority, Spec, Op) :- '$get_next_op_db_ref'(RPriority, RSpec, ROp, OssifiedOpDir, RRPriority, RRSpec, RROp),
'$get_next_op_db_ref'(Ref, NextRef), '$iterate_op_db_refs'(RRPriority, RRSpec, RROp, OssifiedOpDir, Priority, Spec, Op).
'$iterate_op_db_refs'(NextRef, Priority, Spec, Op).
can_be_op_priority(Priority) :- var(Priority). can_be_op_priority(Priority) :- var(Priority).
can_be_op_priority(Priority) :- op_priority(Priority). can_be_op_priority(Priority) :- op_priority(Priority).
@@ -1114,8 +1081,8 @@ current_op(Priority, Spec, Op) :-
( can_be_op_priority(Priority), ( can_be_op_priority(Priority),
can_be_op_specifier(Spec), can_be_op_specifier(Spec),
error:can_be(atom, Op) -> error:can_be(atom, Op) ->
'$get_next_op_db_ref'(Ref, _), '$get_next_op_db_ref'(RPriority, RSpec, ROp, OssifiedOpDir, _, _, Op),
'$iterate_op_db_refs'(Ref, Priority, Spec, Op) '$iterate_op_db_refs'(RPriority, RSpec, ROp, OssifiedOpDir, Priority, Spec, Op)
). ).
list_of_op_atoms(Var) :- list_of_op_atoms(Var) :-

View File

@@ -8,9 +8,18 @@
]). ]).
:- use_module(library(error)). :- use_module(library(error)).
:- use_module(library(lists), [append/3]). :- use_module(library(lists), [append/3, member/2]).
:- use_module(library(loader), [strip_module/3]). :- use_module(library(loader), [strip_module/3]).
load_context(GRBody, Module, GRBody0) :-
strip_module(GRBody, Module, GRBody0),
( nonvar(Module) ->
true
; prolog_load_context(module, Module) ->
true
; true
).
:- meta_predicate phrase(2, ?). :- meta_predicate phrase(2, ?).
:- meta_predicate phrase(2, ?, ?). :- meta_predicate phrase(2, ?, ?).
@@ -18,77 +27,78 @@
phrase(GRBody, S0) :- phrase(GRBody, S0) :-
phrase(GRBody, S0, []). phrase(GRBody, S0, []).
phrase(GRBody, S0, S) :- phrase(GRBody, S0, S) :-
( var(GRBody) -> ( var(GRBody) ->
throw(error(instantiation_error, phrase/3)) throw(error(instantiation_error, phrase/3))
; strip_module(GRBody, Module, GRBody0), ; load_context(GRBody, Module, GRBody0),
dcg_constr(GRBody0) -> dcg_constr(GRBody0) ->
( var(Module) -> ( var(Module) ->
phrase_(GRBody0, S0, S) phrase_(GRBody0, S0, S)
; phrase_(Module:GRBody0, S0, S) ; phrase_(GRBody0, S0, S, Module)
) )
; functor(GRBody, _, _) -> ; functor(GRBody, _, _) ->
call(GRBody, S0, S) 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_((A, B), S0, S, M) :-
phrase_(_:!, S, S) :- !. phrase(M:A, S0, S1),
phrase_((A, B), S0, S) :- phrase(M:B, S1, S).
phrase(A, S0, S1), phrase(B, S1, S). phrase_((A -> B ; C), S0, S, M) :-
phrase_(M:(A, B), S0, S) :-
!,
phrase(M:A, S0, S1), phrase(M:B, S1, S).
phrase_((A -> B ; C), S0, S) :-
!,
( phrase(A, S0, S1) ->
phrase(B, S1, S)
; phrase(C, S0, S)
).
phrase_(M:(A -> B ; C), S0, S) :-
!,
( phrase(M:A, S0, S1) -> ( phrase(M:A, S0, S1) ->
phrase(M:B, S1, S) phrase(M:B, S1, S)
; phrase(M:C, S0, S) ; phrase(M:C, S0, S)
). ).
phrase_((A ; B), S0, S) :- phrase_((A ; B), S0, S, M) :-
( phrase(A, S0, S) ; phrase(B, S0, S) ). ( phrase(M:A, S0, S)
phrase_(M:(A ; B), S0, S) :- ; phrase(M:B, S0, S)
!, ).
( phrase(M:A, S0, S) ; phrase(M:B, S0, S) ). phrase_((A | B), S0, S, M) :-
phrase_((A | B), S0, S) :- ( phrase(M:A, S0, S)
( phrase(A, S0, S) ; phrase(B, S0, S) ). ; phrase(M:B, S0, S)
phrase_(M:(A | B), S0, S) :- ).
!, phrase_({G}, S, S, M) :-
( phrase(M:A, S0, S) ; phrase(M:B, S0, S) ). call(M:G).
phrase_({G}, S0, S) :- phrase_(call(G), S0, S, M) :-
( call(G), S0 = S ).
phrase_(M:{G}, S0, S) :-
!,
( call(M:G), S0 = S ).
phrase_(call(G), S0, S) :-
call(G, S0, S).
phrase_(M:call(G), S0, S) :-
!,
call(M:G, S0, S). call(M:G, S0, S).
phrase_((A -> B), S0, S) :- phrase_((A -> B), S0, S, M) :-
phrase((A -> B ; fail), S0, S). ( phrase(M:A, S0, S1) ->
phrase_(M:(A -> B), S0, S) :- phrase(M:B, S1, S)
!, ; fail
phrase((M:A -> M:B ; fail), S0, S). ).
phrase_(phrase(NonTerminal), S0, S) :- phrase_(phrase(NonTerminal), S0, S, M) :-
phrase(NonTerminal, S0, S). phrase(NonTerminal, S0, S, M).
phrase_(M:phrase(NonTerminal), S0, S) :- phrase_([T|Ts], S0, S, _) :-
!,
phrase(M:NonTerminal, S0, S).
phrase_([T|Ts], S0, S) :-
append([T|Ts], S, S0).
phrase_(_:[T|Ts], S0, S) :-
append([T|Ts], S, S0). append([T|Ts], S, S0).
phrase_([], S, S).
phrase_(!, S, S).
phrase_(M:G, S0, S) :-
phrase_(G, S0, S, M).
phrase_((A, B), S0, S) :-
phrase(A, S0, S1),
phrase(B, S1, S).
phrase_((A -> B ; C), S0, S) :-
( phrase(A, S0, S1) ->
phrase(B, S1, S)
; phrase(C, S0, S)
).
phrase_((A ; B), S0, S) :-
( phrase(A, S0, S) ; phrase(B, S0, S) ).
phrase_((A | B), S0, S) :-
( phrase(A, S0, S) ; phrase(B, S0, S) ).
phrase_({G}, S0, S) :-
( call(G), S0 = S ).
phrase_(call(G), S0, S) :-
call(G, S0, S).
phrase_((A -> B), S0, S) :-
phrase((A -> B ; fail), S0, S).
phrase_(phrase(NonTerminal), S0, S) :-
phrase(NonTerminal, S0, S).
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 )) :-
@@ -193,3 +203,25 @@ seqq([Es|Ess]) --> seq(Es), seqq(Ess).
% Describes an arbitrary number of elements % Describes an arbitrary number of elements
... --> [] | [_], ... . ... --> [] | [_], ... .
user:goal_expansion(phrase(GRBody, S, S0), phrase(GRBody1, S, S0)) :-
strip_module(GRBody, M, GRBody0),
var(M),
prolog_load_context(module, M),
( nonvar(GRBody0) ->
GRBody0 \== [],
dcg_constr(GRBody0),
predicate_property(GRBody0, meta_predicate(_))
),
GRBody1 = M:GRBody0.
user:goal_expansion(phrase(GRBody, S), phrase(GRBody1, S, [])) :-
strip_module(GRBody, M, GRBody0),
var(M),
prolog_load_context(module, M),
( nonvar(GRBody0) ->
GRBody0 \== [],
dcg_constr(GRBody0),
predicate_property(GRBody0, meta_predicate(_))
),
GRBody1 = M:GRBody0.

View File

@@ -14,7 +14,7 @@
partial_string_tail/2, partial_string_tail/2,
setup_call_cleanup/3, setup_call_cleanup/3,
call_nth/2, call_nth/2,
variant/2, % variant/2,
copy_term_nat/2]). copy_term_nat/2]).
:- use_module(library(error), [can_be/2, :- use_module(library(error), [can_be/2,
@@ -22,10 +22,7 @@
instantiation_error/1, instantiation_error/1,
type_error/3]). type_error/3]).
:- use_module(library(lists), [maplist/3]).
:- meta_predicate(call_cleanup(0, 0)).
:- meta_predicate(setup_call_cleanup(0, 0, 0)).
:- meta_predicate(forall(0, 0)). :- meta_predicate(forall(0, 0)).
@@ -55,14 +52,17 @@ bb_get(Key, Value) :-
). ).
% setup_call_cleanup.
:- meta_predicate(call_cleanup(0, 0)).
call_cleanup(G, C) :- setup_call_cleanup(true, G, C). call_cleanup(G, C) :- setup_call_cleanup(true, G, C).
:- meta_predicate(setup_call_cleanup(0, 0, 0)).
% setup_call_cleanup.
setup_call_cleanup(S, G, C) :- setup_call_cleanup(S, G, C) :-
'$get_b_value'(B), '$get_b_value'(B),
call(S), '$call'(S),
'$set_cp_by_default'(B), '$set_cp_by_default'(B),
'$get_current_block'(Bb), '$get_current_block'(Bb),
( C = _:CC, ( C = _:CC,
@@ -71,6 +71,8 @@ setup_call_cleanup(S, G, C) :-
; '$call_with_default_policy'(scc_helper(C, G, Bb)) ; '$call_with_default_policy'(scc_helper(C, G, Bb))
). ).
:- meta_predicate(scc_helper(?,0,?)).
:- non_counted_backtracking scc_helper/3. :- non_counted_backtracking scc_helper/3.
scc_helper(C, G, Bb) :- scc_helper(C, G, Bb) :-
'$get_cp'(Cp), '$get_cp'(Cp),
@@ -96,7 +98,8 @@ scc_helper(_, _, _) :-
:- non_counted_backtracking run_cleaners_with_handling/0. :- non_counted_backtracking run_cleaners_with_handling/0.
run_cleaners_with_handling :- run_cleaners_with_handling :-
'$get_scc_cleaner'(C), '$get_level'(B), '$get_scc_cleaner'(C),
'$get_level'(B),
'$call_with_default_policy'(catch(C, _, true)), '$call_with_default_policy'(catch(C, _, true)),
'$set_cp_by_default'(B), '$set_cp_by_default'(B),
'$call_with_default_policy'(run_cleaners_with_handling). '$call_with_default_policy'(run_cleaners_with_handling).
@@ -139,11 +142,17 @@ call_with_inference_limit(G, L, R) :-
'$call_with_default_policy'(call_with_inference_limit(G, L, R, Bb, B)), '$call_with_default_policy'(call_with_inference_limit(G, L, R, Bb, B)),
'$remove_call_policy_check'(B). '$remove_call_policy_check'(B).
install_inference_counter(B, L, Count0) :-
'$install_inference_counter'(B, L, Count0).
:- meta_predicate(call_with_inference_limit(0,?,?,?,?)).
:- non_counted_backtracking call_with_inference_limit/5. :- non_counted_backtracking call_with_inference_limit/5.
call_with_inference_limit(G, L, R, Bb, B) :- call_with_inference_limit(G, L, R, Bb, B) :-
'$install_new_block'(NBb), '$install_new_block'(NBb),
'$install_inference_counter'(B, L, Count0), '$install_inference_counter'(B, L, Count0),
call(G), '$call'(G),
'$inference_level'(R, B), '$inference_level'(R, B),
'$remove_inference_counter'(B, Count1), '$remove_inference_counter'(B, Count1),
'$call_with_default_policy'(is(Diff, L - (Count1 - Count0))), '$call_with_default_policy'(is(Diff, L - (Count1 - Count0))),
@@ -160,8 +169,6 @@ call_with_inference_limit(_, _, R, Bb, B) :-
'$erase_ball', '$erase_ball',
'$call_with_default_policy'(handle_ile(B, Ball, R)). '$call_with_default_policy'(handle_ile(B, Ball, R)).
variant(X, Y) :- '$variant'(X, Y).
partial_string(String, L, L0) :- partial_string(String, L, L0) :-
( String == [] -> ( String == [] ->
L = L0 L = L0

View File

@@ -56,13 +56,16 @@ length(Xs, 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)
).
length(Xs, N) :- length(Xs, N) :-
integer(N), integer(N),
N >= 0, !, N >= 0,
!,
'$skip_max_list'(M, N, Xs, Xs0), '$skip_max_list'(M, N, Xs, Xs0),
( Xs0 == [] -> N = M ( Xs0 == [] -> N = M
; var(Xs0) -> R is N-M, length_rundown(Xs0, R)). ; var(Xs0) -> R is N-M, length_rundown(Xs0, R)
).
length(_, N) :- length(_, N) :-
integer(N), !, integer(N), !,
domain_error(not_less_than_zero, N, length/2). domain_error(not_less_than_zero, N, length/2).

View File

@@ -41,6 +41,8 @@
trie_get_all_values/2 % +Trie, -Value trie_get_all_values/2 % +Trie, -Value
]). ]).
:- use_module(library(format)).
:- use_module(library(assoc)). :- use_module(library(assoc)).
:- use_module(library(atts)). :- use_module(library(atts)).
:- use_module(library(lists)). :- use_module(library(lists)).

View File

@@ -1,4 +1,3 @@
:- module(loader, [consult/1, :- module(loader, [consult/1,
expand_goal/3, expand_goal/3,
expand_term/2, expand_term/2,
@@ -90,6 +89,7 @@ unload_evacuable(Evacuable) :-
run_initialization_goals(Module) :- run_initialization_goals(Module) :-
( predicate_property(Module:'$initialization_goals'(_), dynamic) -> ( predicate_property(Module:'$initialization_goals'(_), dynamic) ->
% FIXME: failing here. also, see add_module.
findall(Module:Goal, '$call'(builtins:retract(Module:'$initialization_goals'(Goal))), Goals), findall(Module:Goal, '$call'(builtins:retract(Module:'$initialization_goals'(Goal))), Goals),
abolish(Module:'$initialization_goals'/1), abolish(Module:'$initialization_goals'/1),
( maplist(Module:call, Goals) -> ( maplist(Module:call, Goals) ->
@@ -258,8 +258,8 @@ expand_term_goals(Terms0, Terms) :-
Terms = (Module:Head2 :- Body1) Terms = (Module:Head2 :- Body1)
; type_error(atom, Module, load/1) ; type_error(atom, Module, load/1)
) )
; prolog_load_context(module, Target), ; module_expanded_head_variables(Head1, HeadVars),
module_expanded_head_variables(Head1, HeadVars), prolog_load_context(module, Target),
expand_goal(Body0, Target, Body1, HeadVars), expand_goal(Body0, Target, Body1, HeadVars),
Terms = (Head1 :- Body1) Terms = (Head1 :- Body1)
) )
@@ -316,6 +316,7 @@ compile_dispatch(user:goal_expansion(Term, Terms), Evacuable) :-
compile_dispatch((user:goal_expansion(Term, Terms) :- Body), Evacuable) :- compile_dispatch((user:goal_expansion(Term, Terms) :- Body), Evacuable) :-
'$add_goal_expansion_clause'(user, (goal_expansion(Term, Terms) :- Body), Evacuable). '$add_goal_expansion_clause'(user, (goal_expansion(Term, Terms) :- Body), Evacuable).
remove_module(Module, Evacuable) :- remove_module(Module, Evacuable) :-
( nonvar(Module), ( nonvar(Module),
Module = library(ModuleName), Module = library(ModuleName),
@@ -508,7 +509,8 @@ open_file(Path, Stream) :-
; catch(open(Path, read, Stream), ; catch(open(Path, read, Stream),
error(existence_error(source_sink, _), _), error(existence_error(source_sink, _), _),
( atom_concat(Path, '.pl', ExtendedPath), ( atom_concat(Path, '.pl', ExtendedPath),
open(ExtendedPath, read, Stream) ) open(ExtendedPath, read, Stream)
)
) )
). ).
@@ -540,15 +542,15 @@ use_module(Module, Exports, Evacuable) :-
check_predicate_property(meta_predicate, Module, Name, Arity, MetaPredicateTerm) :- check_predicate_property(meta_predicate, Module, Name, Arity, MetaPredicateTerm) :-
'$cpp_meta_predicate_property'(Module, Name, Arity, MetaPredicateTerm). '$meta_predicate_property'(Module, Name, Arity, MetaPredicateTerm).
check_predicate_property(built_in, _, Name, Arity, built_in) :- check_predicate_property(built_in, _, Name, Arity, built_in) :-
'$cpp_built_in_property'(Name, Arity). '$built_in_property'(Name, Arity).
check_predicate_property(dynamic, Module, Name, Arity, dynamic) :- check_predicate_property(dynamic, Module, Name, Arity, dynamic) :-
'$cpp_dynamic_property'(Module, Name, Arity). '$dynamic_property'(Module, Name, Arity).
check_predicate_property(multifile, Module, Name, Arity, multifile) :- check_predicate_property(multifile, Module, Name, Arity, multifile) :-
'$cpp_multifile_property'(Module, Name, Arity). '$multifile_property'(Module, Name, Arity).
check_predicate_property(discontiguous, Module, Name, Arity, discontiguous) :- check_predicate_property(discontiguous, Module, Name, Arity, discontiguous) :-
'$cpp_discontiguous_property'(Module, Name, Arity). '$discontiguous_property'(Module, Name, Arity).
@@ -629,6 +631,8 @@ expand_module_name(ESG0, M, ESG) :-
ESG = M:ESG0 ESG = M:ESG0
; ESG0 = _:_ -> ; ESG0 = _:_ ->
ESG = ESG0 ESG = ESG0
; predicate_property(ESG0, built_in) ->
ESG = ESG0
; ESG = M:ESG0 ; ESG = M:ESG0
). ).
@@ -638,6 +642,7 @@ expand_meta_predicate_subgoals([SG | SGs], [MS | MSs], M, [ESG | ESGs], HeadVars
MS >= 0 MS >= 0
) -> ) ->
( var(SG), ( var(SG),
MS =:= 0,
pairs:same_key(SG, HeadVars, [_|_], _) -> pairs:same_key(SG, HeadVars, [_|_], _) ->
expand_subgoal(SG, MS, M, ESG, HeadVars) expand_subgoal(SG, MS, M, ESG, HeadVars)
; expand_subgoal(SG, MS, M, ESG0, HeadVars), ; expand_subgoal(SG, MS, M, ESG0, HeadVars),
@@ -656,7 +661,8 @@ expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars) :-
( GoalFunctor == (:), ( GoalFunctor == (:),
SubGoals = [M, SubGoal] -> SubGoals = [M, SubGoal] ->
expand_module_names(SubGoal, MetaSpecs, M, ExpandedSubGoal, HeadVars), expand_module_names(SubGoal, MetaSpecs, M, ExpandedSubGoal, HeadVars),
ExpandedGoals = M:ExpandedSubGoal expand_module_name(ExpandedSubGoal, M, ExpandedGoals)
% ExpandedGoals = M:ExpandedSubGoal
; expand_meta_predicate_subgoals(SubGoals, MetaSpecs, Module, ExpandedGoalList, HeadVars), ; expand_meta_predicate_subgoals(SubGoals, MetaSpecs, Module, ExpandedGoalList, HeadVars),
ExpandedGoals =.. [GoalFunctor | ExpandedGoalList] ExpandedGoals =.. [GoalFunctor | ExpandedGoalList]
). ).
@@ -705,19 +711,6 @@ expand_goal(UnexpandedGoals, Module, ExpandedGoals, HeadVars) :-
) )
). ).
thread_goals(Goals0, Goals1, Functor) :-
( var(Goals0) ->
Goals0 = Goals1
; ( Goals0 = [G | Gs] ->
( Gs = [] ->
Goals1 = G
; Goals1 =.. [Functor, G, Goals2],
thread_goals(Gs, Goals2, Functor)
)
; Goals1 = Goals0
)
).
thread_goals(Goals0, Goals1, Hole, Functor) :- thread_goals(Goals0, Goals1, Hole, Functor) :-
( var(Goals0) -> ( var(Goals0) ->
Goals1 =.. [Functor, Goals0, Hole] Goals1 =.. [Functor, Goals0, Hole]
@@ -731,6 +724,18 @@ thread_goals(Goals0, Goals1, Hole, Functor) :-
) )
). ).
thread_goals(Goals0, Goals1, Functor) :-
( var(Goals0) ->
Goals0 = Goals1
; ( Goals0 = [G | Gs] ->
( Gs = [] ->
Goals1 = G
; Goals1 =.. [Functor, G, Goals2],
thread_goals(Gs, Goals2, Functor)
)
; Goals1 = Goals0
)
).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +1,23 @@
use crate::heap_iter::*; use crate::heap_iter::*;
use crate::machine::*; use crate::machine::*;
use prolog_parser::temp_v; use crate::parser::ast::*;
use crate::temp_v;
use crate::types::*;
use indexmap::IndexSet; use indexmap::IndexSet;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::vec::IntoIter; use std::vec::IntoIter;
pub(super) type Bindings = Vec<(usize, Addr)>; pub(super) type Bindings = Vec<(usize, HeapCellValue)>;
#[derive(Debug)] #[derive(Debug)]
pub(super) struct AttrVarInitializer { pub(super) struct AttrVarInitializer {
pub(super) attr_var_queue: Vec<usize>, pub(super) attr_var_queue: Vec<usize>,
pub(super) bindings: Bindings, pub(super) bindings: Bindings,
pub(super) cp: LocalCodePtr, pub(super) p: usize,
pub(super) instigating_p: LocalCodePtr, pub(super) cp: usize,
// pub(super) instigating_p: usize,
pub(super) verify_attrs_loc: usize, pub(super) verify_attrs_loc: usize,
} }
@@ -23,8 +26,8 @@ impl AttrVarInitializer {
AttrVarInitializer { AttrVarInitializer {
attr_var_queue: vec![], attr_var_queue: vec![],
bindings: vec![], bindings: vec![],
instigating_p: LocalCodePtr::default(), p: 0,
cp: LocalCodePtr::default(), cp: 0,
verify_attrs_loc, verify_attrs_loc,
} }
} }
@@ -37,44 +40,39 @@ impl AttrVarInitializer {
} }
impl MachineState { impl MachineState {
pub(super) fn push_attr_var_binding(&mut self, h: usize, addr: Addr) { pub(super) fn push_attr_var_binding(&mut self, h: usize, addr: HeapCellValue) {
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(); // save self.p and self.cp and ensure that the next
// instruction is InstallVerifyAttrInterrupt.
if self.last_call { self.attr_var_init.p = self.p;
self.attr_var_init.cp = self.cp; self.attr_var_init.cp = self.cp;
} else {
self.attr_var_init.cp = self.p.local() + 1;
}
self.p = CodePtr::VerifyAttrInterrupt(self.attr_var_init.verify_attrs_loc); self.p = INSTALL_VERIFY_ATTR_INTERRUPT - 1;
self.cp = INSTALL_VERIFY_ATTR_INTERRUPT;
} }
self.attr_var_init.bindings.push((h, addr)); self.attr_var_init.bindings.push((h, addr));
} }
fn populate_var_and_value_lists(&mut self) -> (Addr, Addr) { fn populate_var_and_value_lists(&mut self) -> (HeapCellValue, HeapCellValue) {
let iter = self let iter = self
.attr_var_init .attr_var_init
.bindings .bindings
.iter() .iter()
.map(|(ref h, _)| HeapCellValue::Addr(Addr::AttrVar(*h))); .map(|(ref h, _)| attr_var_as_cell!(*h));
let var_list_addr = Addr::HeapCell(self.heap.to_list(iter)); let var_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter));
let iter = self let iter = self.attr_var_init.bindings.drain(0..).map(|(_, ref v)| *v);
.attr_var_init
.bindings
.drain(0..)
.map(|(_, addr)| HeapCellValue::Addr(addr));
let value_list_addr = Addr::HeapCell(self.heap.to_list(iter)); let value_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter));
(var_list_addr, value_list_addr) (var_list_addr, value_list_addr)
} }
fn verify_attributes(&mut self) { fn verify_attributes(&mut self) {
for (h, _) in &self.attr_var_init.bindings { for (h, _) in &self.attr_var_init.bindings {
self.heap[*h] = HeapCellValue::Addr(Addr::AttrVar(*h)); self.heap[*h] = attr_var_as_cell!(*h);
} }
let (var_list_addr, value_list_addr) = self.populate_var_and_value_lists(); let (var_list_addr, value_list_addr) = self.populate_var_and_value_lists();
@@ -83,69 +81,104 @@ impl MachineState {
self[temp_v!(2)] = value_list_addr; self[temp_v!(2)] = value_list_addr;
} }
pub(super) fn gather_attr_vars_created_since(&self, b: usize) -> IntoIter<Addr> { pub(super) fn gather_attr_vars_created_since(&mut self, b: usize) -> IntoIter<HeapCellValue> {
let mut attr_vars: Vec<_> = self.attr_var_init.attr_var_queue[b..] let mut attr_vars: Vec<_> = if b >= self.attr_var_init.attr_var_queue.len() {
vec![]
} else {
self.attr_var_init.attr_var_queue[b..]
.iter() .iter()
.filter_map(|h| match self.store(self.deref(Addr::HeapCell(*h))) { .filter_map(|h| {
Addr::AttrVar(h) => Some(Addr::AttrVar(h)), read_heap_cell!(self.store(self.deref(heap_loc_as_cell!(*h))),
_ => None, (HeapCellValueTag::AttrVar, h) => {
Some(attr_var_as_cell!(h))
}
_ => {
None
}
)
}) })
.collect(); .collect()
};
attr_vars attr_vars.sort_unstable_by(|a1, a2| {
.sort_unstable_by(|a1, a2| self.compare_term_test(a1, a2).unwrap_or(Ordering::Less)); compare_term_test!(self, *a1, *a2).unwrap_or(Ordering::Less)
});
self.term_dedup(&mut attr_vars); attr_vars.dedup();
attr_vars.into_iter() attr_vars.into_iter()
} }
pub(super) fn verify_attr_interrupt(&mut self, p: usize) { pub(super) fn verify_attr_interrupt(&mut self, p: usize) {
self.allocate(self.num_of_args + 2); self.allocate(self.num_of_args + 3);
let e = self.e; let e = self.e;
self.stack.index_and_frame_mut(e).prelude.interrupt_cp = self.attr_var_init.cp; let and_frame = self.stack.index_and_frame_mut(e);
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)]; and_frame[i] = self.registers[i];
} }
self.stack.index_and_frame_mut(e)[self.num_of_args + 1] = Addr::CutPoint(self.b0); and_frame[self.num_of_args + 1] =
self.stack.index_and_frame_mut(e)[self.num_of_args + 2] = Addr::Usize(self.num_of_args); fixnum_as_cell!(Fixnum::build_with(self.b0 as i64));
and_frame[self.num_of_args + 2] =
fixnum_as_cell!(Fixnum::build_with(self.num_of_args as i64));
and_frame[self.num_of_args + 3] =
fixnum_as_cell!(Fixnum::build_with(self.attr_var_init.cp as i64));
self.verify_attributes(); self.verify_attributes();
self.num_of_args = 2; self.num_of_args = 3;
self.b0 = self.b; self.b0 = self.b;
self.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); self.p = p;
} }
pub(super) fn attr_vars_of_term(&self, addr: Addr) -> Vec<Addr> { pub(super) fn attr_vars_of_term(&mut self, cell: HeapCellValue) -> Vec<HeapCellValue> {
let mut seen_set = IndexSet::new(); let mut seen_set = IndexSet::new();
let mut seen_vars = vec![]; let mut seen_vars = vec![];
let mut iter = self.acyclic_pre_order_iter(addr); let mut iter = stackful_preorder_iter(&mut self.heap, cell);
while let Some(addr) = iter.next() { while let Some(value) = iter.next() {
if let HeapCellValue::Addr(Addr::AttrVar(h)) = self.heap.index_addr(&addr).as_ref() { read_heap_cell!(value,
if seen_set.contains(h) { (HeapCellValueTag::AttrVar, h) => {
if seen_set.contains(&h) {
continue; continue;
} }
seen_vars.push(addr); let value = unmark_cell_bits!(value);
seen_set.insert(*h);
seen_vars.push(value);
seen_set.insert(h);
let mut l = h + 1; let mut l = h + 1;
let mut list_elements = vec![]; // let mut list_elements = vec![];
// let iter_stack_len = iter.stack_len();
while let Addr::Lis(elem) = self.store(self.deref(Addr::HeapCell(l))) { loop {
list_elements.push(self.heap[elem].as_addr(elem)); read_heap_cell!(iter.heap[l],
l = elem + 1; (HeapCellValueTag::Lis) => {
iter.push_stack(l);
// l = elem + 1;
break;
}
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
if h == l {
break;
} else {
l = h;
}
}
_ => {
break;
}
)
} }
for element in list_elements.into_iter().rev() { // iter.stack_slice_from(iter_stack_len ..).reverse();
iter.stack().push(element);
} }
_ => {
} }
);
} }
seen_vars seen_vars

View File

@@ -1,177 +0,0 @@
use crate::clause_types::*;
use crate::instructions::*;
use crate::machine::machine_indices::*;
#[derive(Debug)]
pub(crate) struct CodeRepo {
pub(super) code: Code,
}
impl CodeRepo {
#[inline]
pub(super) fn new() -> Self {
CodeRepo { code: Code::new() }
}
#[inline]
pub(super) fn lookup_local_instr<'a>(&'a self, p: LocalCodePtr) -> RefOrOwned<'a, Line> {
match p {
LocalCodePtr::Halt => {
// exit with the interrupt exit code.
std::process::exit(1);
}
LocalCodePtr::DirEntry(p) => RefOrOwned::Borrowed(&self.code[p as usize]),
LocalCodePtr::IndexingBuf(p, o, i) => match &self.code[p] {
&Line::IndexingCode(ref indexing_lines) => match &indexing_lines[o] {
&IndexingLine::IndexedChoice(ref indexed_choice_instrs) => {
RefOrOwned::Owned(Line::IndexedChoice(indexed_choice_instrs[i]))
}
&IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => {
RefOrOwned::Owned(Line::DynamicIndexedChoice(indexed_choice_instrs[i]))
}
_ => {
unreachable!()
}
},
_ => {
unreachable!()
}
},
}
}
pub(super) fn lookup_instr<'a>(
&'a self,
last_call: bool,
p: &CodePtr,
) -> Option<RefOrOwned<'a, Line>> {
match p {
&CodePtr::Local(local) => {
return Some(self.lookup_local_instr(local));
}
&CodePtr::REPL(..) => None,
&CodePtr::BuiltInClause(ref built_in, _) => {
let call_clause = call_clause!(
ClauseType::BuiltIn(built_in.clone()),
built_in.arity(),
0,
last_call
);
Some(RefOrOwned::Owned(call_clause))
}
&CodePtr::CallN(arity, _, last_call) => {
let call_clause = call_clause!(ClauseType::CallN, arity, 0, last_call);
Some(RefOrOwned::Owned(call_clause))
}
&CodePtr::VerifyAttrInterrupt(p) => Some(RefOrOwned::Borrowed(&self.code[p])),
}
}
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

@@ -2,45 +2,47 @@ use crate::instructions::*;
use indexmap::IndexSet; use indexmap::IndexSet;
fn capture_offset(line: &Line, index: usize, stack: &mut Vec<usize>) -> bool { fn capture_offset(line: &Instruction, index: usize, stack: &mut Vec<usize>) -> bool {
match line { match line {
&Line::Choice(ChoiceInstruction::TryMeElse(offset)) if offset > 0 => { &Instruction::TryMeElse(offset) if offset > 0 => {
stack.push(index + offset); stack.push(index + offset);
} }
&Line::Choice(ChoiceInstruction::DefaultRetryMeElse(offset)) &Instruction::DefaultRetryMeElse(offset) |
| &Line::Choice(ChoiceInstruction::RetryMeElse(offset)) &Instruction::RetryMeElse(offset)
if offset > 0 => if offset > 0 =>
{ {
stack.push(index + offset); stack.push(index + offset);
} }
&Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(offset))) &Instruction::DynamicElse(_, _, NextOrFail::Next(offset))
if offset > 0 => if offset > 0 =>
{ {
stack.push(index + offset); stack.push(index + offset);
} }
&Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(offset))) &Instruction::DynamicInternalElse(_, _, NextOrFail::Next(offset))
if offset > 0 => if offset > 0 =>
{ {
stack.push(index + offset); stack.push(index + offset);
} }
&Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => { &Instruction::JmpByCall(_, offset, _) => {
stack.push(index + offset); stack.push(index + offset);
} }
&Line::Control(ControlInstruction::JmpBy(_, offset, _, true)) => { &Instruction::JmpByExecute(_, offset, _) => {
stack.push(index + offset); stack.push(index + offset);
return true; return true;
} }
&Line::Control(ControlInstruction::Proceed) &Instruction::Proceed => {
| &Line::Control(ControlInstruction::CallClause(_, _, _, true, _)) => {
return true; return true;
} }
&Line::Control(ControlInstruction::RevJmpBy(offset)) => { &Instruction::RevJmpBy(offset) => {
if offset > 0 { if offset > 0 {
stack.push(index - offset); stack.push(index - offset);
} else { } else {
return true; return true;
} }
} }
instr if instr.is_execute() => {
return true;
}
_ => {} _ => {}
}; };
@@ -51,7 +53,7 @@ fn capture_offset(line: &Line, index: usize, stack: &mut Vec<usize>) -> bool {
* 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(crate) 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(&Instruction)) {
let mut stack = vec![p]; let mut stack = vec![p];
let mut visited_indices = IndexSet::new(); let mut visited_indices = IndexSet::new();

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,6 @@
use crate::machine::machine_indices::*; use crate::atom_table::*;
use crate::machine::stack::*; use crate::machine::stack::*;
use crate::types::*;
use std::mem; use std::mem;
use std::ops::IndexMut; use std::ops::IndexMut;
@@ -7,20 +8,24 @@ use std::ops::IndexMut;
type Trail = Vec<(Ref, HeapCellValue)>; type Trail = Vec<(Ref, HeapCellValue)>;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) enum AttrVarPolicy { pub enum AttrVarPolicy {
DeepCopy, DeepCopy,
StripAttributes, StripAttributes,
} }
pub(crate) trait CopierTarget: IndexMut<usize, Output = HeapCellValue> { pub trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
fn deref(&self, val: Addr) -> Addr; fn store(&self, value: HeapCellValue) -> HeapCellValue;
fn push(&mut self, val: HeapCellValue); fn deref(&self, value: HeapCellValue) -> HeapCellValue;
fn push(&mut self, value: HeapCellValue);
fn stack(&mut self) -> &mut Stack; fn stack(&mut self) -> &mut Stack;
fn store(&self, val: Addr) -> Addr;
fn threshold(&self) -> usize; fn threshold(&self) -> usize;
} }
pub(crate) fn copy_term<T: CopierTarget>(target: T, addr: Addr, attr_var_policy: AttrVarPolicy) { pub(crate) fn copy_term<T: CopierTarget>(
target: T,
addr: HeapCellValue,
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);
} }
@@ -47,50 +52,51 @@ impl<T: CopierTarget> CopyTermState<T> {
#[inline] #[inline]
fn value_at_scan(&mut self) -> &mut HeapCellValue { fn value_at_scan(&mut self) -> &mut HeapCellValue {
let scan = self.scan; &mut self.target[self.scan]
&mut self.target[scan]
} }
fn trail_list_cell(&mut self, addr: usize, threshold: usize) { fn trail_list_cell(&mut self, addr: usize, threshold: usize) {
let trail_item = mem::replace( let trail_item = mem::replace(&mut self.target[addr], list_loc_as_cell!(threshold));
&mut self.target[addr], self.trail.push((Ref::heap_cell(addr), trail_item));
HeapCellValue::Addr(Addr::Lis(threshold)),
);
self.trail.push((Ref::HeapCell(addr), trail_item));
} }
fn copy_list(&mut self, addr: usize) { fn copy_list(&mut self, addr: usize) {
for offset in 0..2 { for offset in 0..2 {
if let Addr::Lis(h) = self.target[addr + offset].as_addr(addr + offset) { read_heap_cell!(self.target[addr + offset],
(HeapCellValueTag::Lis, h) => {
if h >= self.old_h { if h >= self.old_h {
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(h)); *self.value_at_scan() = list_loc_as_cell!(h);
self.scan += 1; self.scan += 1;
return; return;
} }
} }
_ => {
}
)
} }
let threshold = self.target.threshold(); let threshold = self.target.threshold();
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(threshold)); *self.value_at_scan() = list_loc_as_cell!(threshold);
for i in 0..2 { for i in 0..2 {
let hcv = self.target[addr + i].context_free_clone(); let hcv = self.target[addr + i];
self.target.push(hcv); self.target.push(hcv);
} }
let cdr = self let cdr = self
.target .target
.store(self.target.deref(Addr::HeapCell(addr + 1))); .store(self.target.deref(heap_loc_as_cell!(addr + 1)));
if !cdr.is_ref() { if !cdr.is_var() {
self.trail_list_cell(addr + 1, threshold); self.trail_list_cell(addr + 1, threshold);
} else { } else {
let car = self.target.store(self.target.deref(Addr::HeapCell(addr))); let car = self
.target
.store(self.target.deref(heap_loc_as_cell!(addr)));
if !car.is_ref() { if !car.is_var() {
self.trail_list_cell(addr, threshold); self.trail_list_cell(addr, threshold);
} }
} }
@@ -98,187 +104,190 @@ impl<T: CopierTarget> CopyTermState<T> {
self.scan += 1; self.scan += 1;
} }
fn copy_partial_string(&mut self, addr: usize, n: usize) { fn copy_partial_string(&mut self, scan_tag: HeapCellValueTag, pstr_loc: usize) {
if let &HeapCellValue::Addr(Addr::PStrLocation(h, _)) = &self.target[addr] { read_heap_cell!(self.target[pstr_loc],
if h >= self.old_h { (HeapCellValueTag::PStrLoc, h) => {
*self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(h, n)); debug_assert!(h >= self.old_h);
*self.value_at_scan() = match scan_tag {
HeapCellValueTag::PStrLoc => {
pstr_loc_as_cell!(h)
}
tag => {
debug_assert_eq!(tag, HeapCellValueTag::PStrOffset);
pstr_offset_as_cell!(h)
}
};
self.scan += 1;
return;
}
(HeapCellValueTag::Var, h) => {
debug_assert!(h >= self.old_h);
debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset);
*self.value_at_scan() = pstr_offset_as_cell!(h);
self.scan += 1; self.scan += 1;
return; return;
} }
} _ => {}
);
let threshold = self.target.threshold(); let threshold = self.target.threshold();
*self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(threshold, n)); let replacement = read_heap_cell!(self.target[pstr_loc],
(HeapCellValueTag::CStr) => {
debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset);
*self.value_at_scan() = pstr_offset_as_cell!(threshold);
self.target.push(self.target[pstr_loc]);
heap_loc_as_cell!(threshold)
}
_ => {
*self.value_at_scan() = if scan_tag == HeapCellValueTag::PStrLoc {
pstr_loc_as_cell!(threshold)
} else {
debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset);
pstr_offset_as_cell!(threshold)
};
self.target.push(self.target[pstr_loc]);
self.target.push(self.target[pstr_loc + 1]);
pstr_loc_as_cell!(threshold)
}
);
self.scan += 1; self.scan += 1;
let (pstr, has_tail) = match &self.target[addr] { let trail_item = mem::replace(&mut self.target[pstr_loc], replacement);
&HeapCellValue::PartialString(ref pstr, has_tail) => { self.trail.push((Ref::heap_cell(pstr_loc), trail_item));
(pstr.clone_from_offset(0), has_tail)
}
_ => {
unreachable!()
}
};
self.target
.push(HeapCellValue::PartialString(pstr, has_tail));
let replacement = HeapCellValue::Addr(Addr::PStrLocation(threshold, n));
let trail_item = mem::replace(&mut self.target[addr], replacement);
self.trail.push((Ref::HeapCell(addr), trail_item));
if has_tail {
let tail_addr = self.target[addr + 1].as_addr(addr + 1);
self.target.push(HeapCellValue::Addr(tail_addr));
}
} }
fn reinstantiate_var(&mut self, addr: Addr, frontier: usize) { fn reinstantiate_var(&mut self, addr: HeapCellValue, frontier: usize) {
match addr { read_heap_cell!(addr,
Addr::HeapCell(h) => { (HeapCellValueTag::Var, h) => {
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier)); self.target[frontier] = heap_loc_as_cell!(frontier);
self.target[h] = HeapCellValue::Addr(Addr::HeapCell(frontier)); self.target[h] = heap_loc_as_cell!(frontier);
self.trail self.trail.push((Ref::heap_cell(h), heap_loc_as_cell!(h)));
.push((Ref::HeapCell(h), HeapCellValue::Addr(Addr::HeapCell(h))));
} }
Addr::StackCell(fr, sc) => { (HeapCellValueTag::StackVar, s) => {
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier)); self.target[frontier] = heap_loc_as_cell!(frontier);
self.target.stack().index_and_frame_mut(fr)[sc] = Addr::HeapCell(frontier); self.target.stack()[s] = heap_loc_as_cell!(frontier);
self.trail.push(( self.trail.push((Ref::stack_cell(s), stack_loc_as_cell!(s)));
Ref::StackCell(fr, sc),
HeapCellValue::Addr(Addr::StackCell(fr, sc)),
));
} }
Addr::AttrVar(h) => { (HeapCellValueTag::AttrVar, h) => {
let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy { let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
self.target.threshold() self.target.threshold()
} else { } else {
frontier frontier
}; };
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(threshold)); self.target[frontier] = heap_loc_as_cell!(threshold);
self.target[h] = HeapCellValue::Addr(Addr::HeapCell(threshold)); self.target[h] = heap_loc_as_cell!(threshold);
self.trail self.trail.push((Ref::attr_var(h), attr_var_as_cell!(h)));
.push((Ref::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 self.target.push(attr_var_as_cell!(threshold));
.push(HeapCellValue::Addr(Addr::AttrVar(threshold)));
let list_val = self.target[h + 1].context_free_clone(); let list_val = self.target[h + 1];
self.target.push(list_val); self.target.push(list_val);
} }
} }
_ => { _ => {
unreachable!() unreachable!()
} }
} );
} }
fn copy_var(&mut self, addr: Addr) { fn copy_var(&mut self, addr: HeapCellValue) {
let rd = self.target.store(self.target.deref(addr)); let rd = self.target.deref(addr);
let ra = self.target.store(rd);
match rd { read_heap_cell!(ra,
Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => { (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
*self.value_at_scan() = HeapCellValue::Addr(rd); if h >= self.old_h {
*self.value_at_scan() = ra;
self.scan += 1; self.scan += 1;
return;
} }
_ if addr == rd => { }
self.reinstantiate_var(addr, self.scan); _ => {}
);
if rd == ra {
self.reinstantiate_var(ra, self.scan);
self.scan += 1; self.scan += 1;
} } else {
_ => { *self.value_at_scan() = ra;
*self.value_at_scan() = HeapCellValue::Addr(rd);
}
} }
} }
fn copy_structure(&mut self, addr: usize) { fn copy_structure(&mut self, addr: usize) {
match self.target[addr].context_free_clone() { read_heap_cell!(self.target[addr],
HeapCellValue::NamedStr(arity, name, fixity) => { (HeapCellValueTag::Atom, (name, arity)) => {
let threshold = self.target.threshold(); let threshold = self.target.threshold();
*self.value_at_scan() = HeapCellValue::Addr(Addr::Str(threshold)); *self.value_at_scan() = str_loc_as_cell!(threshold);
let trail_item = mem::replace( let trail_item = mem::replace(
&mut self.target[addr], &mut self.target[addr],
HeapCellValue::Addr(Addr::Str(threshold)), str_loc_as_cell!(threshold),
); );
self.trail.push((Ref::HeapCell(addr), trail_item)); self.trail.push((Ref::heap_cell(addr), trail_item));
self.target.push(atom_as_cell!(name, arity));
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];
self.target.push(hcv); self.target.push(hcv);
} }
} }
HeapCellValue::Addr(Addr::Str(addr)) => { (HeapCellValueTag::Str, h) => {
*self.value_at_scan() = HeapCellValue::Addr(Addr::Str(addr)) *self.value_at_scan() = str_loc_as_cell!(h);
} }
_ => { _ => {
unreachable!() unreachable!()
} }
} );
self.scan += 1; self.scan += 1;
} }
fn copy_term_impl(&mut self, addr: Addr) { fn copy_term_impl(&mut self, addr: HeapCellValue) {
self.scan = self.target.threshold(); self.scan = self.target.threshold();
self.target.push(HeapCellValue::Addr(addr)); self.target.push(addr);
while self.scan < self.target.threshold() { while self.scan < self.target.threshold() {
match self.value_at_scan() { let addr = *self.value_at_scan();
&mut HeapCellValue::Addr(addr) => match addr {
Addr::Con(h) => {
let addr = self.target[h].as_addr(h);
if addr == Addr::Con(h) { read_heap_cell!(addr,
*self.value_at_scan() = self.target[h].context_free_clone(); (HeapCellValueTag::Lis, h) => {
} else {
*self.value_at_scan() = HeapCellValue::Addr(addr);
}
}
Addr::Lis(h) => {
if h >= self.old_h { if h >= self.old_h {
self.scan += 1; self.scan += 1;
} else { } else {
self.copy_list(h); self.copy_list(h);
} }
} }
addr @ Addr::AttrVar(_) (HeapCellValueTag::AttrVar | HeapCellValueTag::Var) => {
| addr @ Addr::HeapCell(_)
| addr @ Addr::StackCell(..) => {
self.copy_var(addr); self.copy_var(addr);
} }
Addr::Str(addr) => { (HeapCellValueTag::Str, h) => {
self.copy_structure(addr); self.copy_structure(h);
} }
Addr::PStrLocation(addr, n) => { (HeapCellValueTag::PStrLoc | HeapCellValueTag::PStrOffset, pstr_loc) => {
self.copy_partial_string(addr, n); self.copy_partial_string(addr.get_tag(), pstr_loc);
}
Addr::Stream(h) => {
*self.value_at_scan() = self.target[h].context_free_clone();
} }
_ => { _ => {
self.scan += 1; self.scan += 1;
} }
}, );
_ => {
self.scan += 1;
}
}
} }
self.unwind_trail(); self.unwind_trail();
@@ -286,12 +295,117 @@ 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 { let index = r.get_value() as usize;
Ref::AttrVar(h) | Ref::HeapCell(h) => self.target[h] = value,
Ref::StackCell(fr, sc) => { match r.get_tag() {
self.target.stack().index_and_frame_mut(fr)[sc] = value.as_addr(0) RefTag::AttrVar | RefTag::HeapCell => self.target[index] = value,
RefTag::StackCell => self.target.stack()[index] = value,
} }
} }
} }
} }
#[cfg(test)]
mod tests {
use super::*;
use crate::machine::mock_wam::*;
#[test]
fn copier_tests() {
let mut wam = MockWAM::new();
let f_atom = atom!("f");
let a_atom = atom!("a");
let b_atom = atom!("b");
wam.machine_st.heap
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 2));
assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom));
assert_eq!(wam.machine_st.heap[2], atom_as_cell!(b_atom));
{
let wam = TermCopyingMockWAM { wam: &mut wam };
copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy);
}
// check that the original heap state is still intact.
assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 2));
assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom));
assert_eq!(wam.machine_st.heap[2], atom_as_cell!(b_atom));
assert_eq!(wam.machine_st.heap[3], str_loc_as_cell!(4));
assert_eq!(wam.machine_st.heap[4], atom_as_cell!(f_atom, 2));
assert_eq!(wam.machine_st.heap[5], atom_as_cell!(a_atom));
assert_eq!(wam.machine_st.heap[6], atom_as_cell!(b_atom));
wam.machine_st.heap.clear();
let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl);
let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
wam.machine_st.heap.pop();
wam.machine_st.heap.push(pstr_loc_as_cell!(2));
let pstr_second_var_cell = put_partial_string(&mut wam.machine_st.heap, "def", &mut wam.machine_st.atom_tbl);
let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize];
wam.machine_st.heap.pop();
wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1));
wam.machine_st.heap.push(pstr_offset_as_cell!(0));
wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0i64)));
{
let wam = TermCopyingMockWAM { wam: &mut wam };
copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy);
}
print_heap_terms(wam.machine_st.heap[6..].iter(), 6);
assert_eq!(wam.machine_st.heap[0], pstr_cell);
assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(2));
assert_eq!(wam.machine_st.heap[2], pstr_second_cell);
assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(4));
assert_eq!(wam.machine_st.heap[4], pstr_offset_as_cell!(0));
assert_eq!(wam.machine_st.heap[5], fixnum_as_cell!(Fixnum::build_with(0i64)));
assert_eq!(wam.machine_st.heap[7], pstr_cell);
assert_eq!(wam.machine_st.heap[8], pstr_loc_as_cell!(9));
assert_eq!(wam.machine_st.heap[9], pstr_second_cell);
assert_eq!(wam.machine_st.heap[10], pstr_loc_as_cell!(11));
assert_eq!(wam.machine_st.heap[11], pstr_offset_as_cell!(7));
assert_eq!(wam.machine_st.heap[12], fixnum_as_cell!(Fixnum::build_with(0i64)));
wam.machine_st.heap.clear();
wam.machine_st.heap.extend(functor!(
f_atom,
[
atom(a_atom),
atom(b_atom),
atom(a_atom),
cell(str_loc_as_cell!(0))
]
));
{
let wam = TermCopyingMockWAM { wam: &mut wam };
copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy);
}
assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 4));
assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom));
assert_eq!(wam.machine_st.heap[2], atom_as_cell!(b_atom));
assert_eq!(wam.machine_st.heap[3], atom_as_cell!(a_atom));
assert_eq!(wam.machine_st.heap[4], str_loc_as_cell!(0));
assert_eq!(wam.machine_st.heap[5], str_loc_as_cell!(6));
assert_eq!(wam.machine_st.heap[6], atom_as_cell!(f_atom, 4));
assert_eq!(wam.machine_st.heap[7], atom_as_cell!(a_atom));
assert_eq!(wam.machine_st.heap[8], atom_as_cell!(b_atom));
assert_eq!(wam.machine_st.heap[9], atom_as_cell!(a_atom));
assert_eq!(wam.machine_st.heap[10], str_loc_as_cell!(6));
}
} }

4874
src/machine/dispatch.rs Normal file

File diff suppressed because it is too large Load Diff

1100
src/machine/gc.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,295 +1,196 @@
use core::marker::PhantomData; use crate::arena::*;
use crate::atom_table::*;
use prolog_parser::ast::Constant; use crate::forms::*;
use crate::machine::machine_indices::*;
use crate::machine::partial_string::*; use crate::machine::partial_string::*;
use crate::machine::raw_block::*; use crate::parser::ast::*;
use crate::types::*;
use ordered_float::OrderedFloat;
use rug::{Integer, Rational};
use std::convert::TryFrom; use std::convert::TryFrom;
use std::mem;
use std::ops::{Index, IndexMut};
use std::ptr;
#[derive(Debug)] pub(crate) type Heap = Vec<HeapCellValue>;
pub(crate) struct StandardHeapTraits {}
impl RawBlockTraits for StandardHeapTraits { impl From<Literal> for HeapCellValue {
#[inline] #[inline]
fn init_size() -> usize { fn from(literal: Literal) -> Self {
256 * mem::size_of::<HeapCellValue>() match literal {
Literal::Atom(name) => atom_as_cell!(name),
Literal::Char(c) => char_as_cell!(c),
Literal::Fixnum(n) => fixnum_as_cell!(n),
Literal::Integer(bigint_ptr) => {
typed_arena_ptr_as_cell!(bigint_ptr)
} }
Literal::Rational(bigint_ptr) => {
#[inline] typed_arena_ptr_as_cell!(bigint_ptr)
fn align() -> usize {
mem::align_of::<HeapCellValue>()
} }
} Literal::Float(f) => HeapCellValue::from(f),
Literal::String(s) => {
#[derive(Debug)] if s == atom!("") {
pub(crate) struct HeapTemplate<T: RawBlockTraits> { empty_list_as_cell!()
buf: RawBlock<T>,
_marker: PhantomData<HeapCellValue>,
}
pub(crate) type Heap = HeapTemplate<StandardHeapTraits>;
impl<T: RawBlockTraits> Drop for HeapTemplate<T> {
fn drop(&mut self) {
self.clear();
self.buf.deallocate();
}
}
#[derive(Debug)]
pub(crate) struct HeapIntoIter<T: RawBlockTraits> {
offset: usize,
buf: RawBlock<T>,
}
impl<T: RawBlockTraits> Drop for HeapIntoIter<T> {
fn drop(&mut self) {
let mut heap = HeapTemplate {
buf: self.buf.take(),
_marker: PhantomData,
};
heap.truncate(self.offset / mem::size_of::<HeapCellValue>());
heap.buf.deallocate();
}
}
impl<T: RawBlockTraits> Iterator for HeapIntoIter<T> {
type Item = HeapCellValue;
fn next(&mut self) -> Option<Self::Item> {
let ptr = self.buf.base as usize + self.offset;
self.offset += mem::size_of::<HeapCellValue>();
if ptr < self.buf.top as usize {
unsafe { Some(ptr::read(ptr as *const HeapCellValue)) }
} else { } else {
None string_as_cstr_cell!(s)
} }
} }
} }
#[derive(Debug)]
pub(crate) struct HeapIter<'a, T: RawBlockTraits> {
offset: usize,
buf: &'a RawBlock<T>,
}
impl<'a, T: RawBlockTraits> HeapIter<'a, T> {
pub(crate) fn new(buf: &'a RawBlock<T>, offset: usize) -> Self {
HeapIter { buf, offset }
} }
} }
impl<'a, T: RawBlockTraits> Iterator for HeapIter<'a, T> { impl TryFrom<HeapCellValue> for Literal {
type Item = &'a HeapCellValue; type Error = ();
fn next(&mut self) -> Option<Self::Item> { fn try_from(value: HeapCellValue) -> Result<Literal, ()> {
let ptr = self.buf.base as usize + self.offset; read_heap_cell!(value,
self.offset += mem::size_of::<HeapCellValue>(); (HeapCellValueTag::Atom, (name, arity)) => {
if arity == 0 {
if ptr < self.buf.top as usize { Ok(Literal::Atom(name))
unsafe { Some(&*(ptr as *const _)) }
} else { } else {
None Err(())
} }
} }
(HeapCellValueTag::Char, c) => {
Ok(Literal::Char(c))
}
(HeapCellValueTag::Fixnum, n) => {
Ok(Literal::Fixnum(n))
}
(HeapCellValueTag::F64, f) => {
Ok(Literal::Float(f))
}
(HeapCellValueTag::Cons, cons_ptr) => {
match_untyped_arena_ptr!(cons_ptr,
(ArenaHeaderTag::Integer, n) => {
Ok(Literal::Integer(n))
}
(ArenaHeaderTag::Rational, n) => {
Ok(Literal::Rational(n))
}
(ArenaHeaderTag::F64, f) => {
// remove this redundancy.
Ok(Literal::Float(F64Ptr(f)))
}
_ => {
Err(())
}
)
}
(HeapCellValueTag::CStr, cstr_atom) => {
Ok(Literal::String(cstr_atom))
}
_ => {
Err(())
}
)
}
}
// sometimes we need to dereference variables that are found only in
// the heap without access to the full WAM (e.g., while detecting
// cycles in terms), and which therefore may only point other cells in
// the heap (thanks to the design of the WAM).
pub fn heap_bound_deref(heap: &[HeapCellValue], mut value: HeapCellValue) -> HeapCellValue {
loop {
let new_value = read_heap_cell!(value,
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
heap[h]
}
_ => {
value
}
);
if new_value != value && new_value.is_var() {
value = new_value;
continue;
}
return value;
}
}
pub fn heap_bound_store(heap: &[HeapCellValue], value: HeapCellValue) -> HeapCellValue {
read_heap_cell!(value,
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
heap[h]
}
_ => {
value
}
)
} }
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) fn print_heap_terms<'a, I: Iterator<Item = &'a HeapCellValue>>(heap: I, h: usize) { pub 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)] #[inline]
pub(crate) struct HeapIterMut<'a, T: RawBlockTraits> { pub(crate) fn put_complete_string(
offset: usize, heap: &mut Heap,
buf: &'a mut RawBlock<T>, s: &str,
} atom_tbl: &mut AtomTable,
) -> HeapCellValue {
match allocate_pstr(heap, s, atom_tbl) {
Some(h) => {
heap.pop(); // pop the trailing variable cell from the heap planted by allocate_pstr.
impl<'a, T: RawBlockTraits> HeapIterMut<'a, T> { if heap.len() == h + 1 {
pub(crate) fn new(buf: &'a mut RawBlock<T>, offset: usize) -> Self { let pstr_atom = cell_as_atom!(heap[h]);
HeapIterMut { buf, offset } heap[h] = atom_as_cstr_cell!(pstr_atom);
} heap_loc_as_cell!(h)
}
impl<'a, T: RawBlockTraits> Iterator for HeapIterMut<'a, T> {
type Item = &'a mut HeapCellValue;
fn next(&mut self) -> Option<Self::Item> {
let ptr = self.buf.base as usize + self.offset;
self.offset += mem::size_of::<HeapCellValue>();
if ptr < self.buf.top as usize {
unsafe { Some(&mut *(ptr as *mut _)) }
} else { } else {
None heap.push(empty_list_as_cell!());
pstr_loc_as_cell!(h)
} }
} }
None => {
empty_list_as_cell!()
} }
impl<T: RawBlockTraits> HeapTemplate<T> {
#[inline]
pub(crate) fn new() -> Self {
HeapTemplate {
buf: RawBlock::new(),
_marker: PhantomData,
} }
} }
#[inline] #[inline]
pub(crate) fn clone(&self, h: usize) -> HeapCellValue { pub(crate) fn put_partial_string(
match &self[h] { heap: &mut Heap,
&HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr), s: &str,
&HeapCellValue::Atom(ref name, ref op) => HeapCellValue::Atom(name.clone(), op.clone()), atom_tbl: &mut AtomTable,
&HeapCellValue::DBRef(ref db_ref) => HeapCellValue::DBRef(db_ref.clone()), ) -> HeapCellValue {
&HeapCellValue::Integer(ref n) => HeapCellValue::Integer(n.clone()), match allocate_pstr(heap, s, atom_tbl) {
&HeapCellValue::LoadStatePayload(_) => HeapCellValue::Addr(Addr::LoadStatePayload(h)), Some(h) => {
&HeapCellValue::NamedStr(arity, ref name, ref op) => { pstr_loc_as_cell!(h)
HeapCellValue::NamedStr(arity, name.clone(), op.clone()) }
None => {
empty_list_as_cell!()
} }
&HeapCellValue::PartialString(..) => HeapCellValue::Addr(Addr::PStrLocation(h, 0)),
&HeapCellValue::Rational(ref r) => HeapCellValue::Rational(r.clone()),
&HeapCellValue::Stream(_) => HeapCellValue::Addr(Addr::Stream(h)),
&HeapCellValue::TcpListener(_) => HeapCellValue::Addr(Addr::TcpListener(h)),
} }
} }
#[inline] #[inline]
pub(crate) fn put_complete_string(&mut self, s: &str) -> Addr { pub(crate) fn allocate_pstr(
if s.is_empty() { heap: &mut Heap,
return Addr::EmptyList; mut src: &str,
} atom_tbl: &mut AtomTable,
) -> Option<usize> {
let addr = self.allocate_pstr(s); let orig_h = heap.len();
self.pop();
let h = self.h();
match &mut self[h - 1] {
&mut HeapCellValue::PartialString(_, ref mut has_tail) => {
*has_tail = false;
}
_ => {
unreachable!()
}
}
addr
}
#[inline]
pub(crate) fn put_constant(&mut self, c: Constant) -> Addr {
match c {
Constant::Atom(name, op) => Addr::Con(self.push(HeapCellValue::Atom(name, op))),
Constant::Char(c) => Addr::Char(c),
Constant::EmptyList => Addr::EmptyList,
Constant::Fixnum(n) => Addr::Fixnum(n),
Constant::Integer(n) => Addr::Con(self.push(HeapCellValue::Integer(n))),
Constant::Rational(r) => Addr::Con(self.push(HeapCellValue::Rational(r))),
Constant::Float(f) => Addr::Float(f),
Constant::String(s) => {
if s.is_empty() {
Addr::EmptyList
} else {
self.put_complete_string(&s)
}
}
Constant::Usize(n) => Addr::Usize(n),
}
}
#[inline]
pub(crate) fn is_empty(&self) -> bool {
self.h() == 0
}
#[inline]
pub(crate) fn pop(&mut self) {
let h = self.h();
if h > 0 {
self.truncate(h - 1);
}
}
#[inline]
pub(crate) fn push(&mut self, val: HeapCellValue) -> usize {
let h = self.h();
unsafe {
let new_top = self.buf.new_block(mem::size_of::<HeapCellValue>());
ptr::write(self.buf.top as *mut _, val);
self.buf.top = new_top;
}
h
}
#[inline]
pub(crate) fn atom_at(&self, h: usize) -> bool {
if let HeapCellValue::Atom(..) = &self[h] {
true
} else {
false
}
}
#[inline]
pub(crate) fn to_unifiable(&mut self, non_heap_value: HeapCellValue) -> Addr {
match non_heap_value {
HeapCellValue::Addr(addr) => addr,
val @ HeapCellValue::Atom(..)
| val @ HeapCellValue::Integer(_)
| val @ HeapCellValue::DBRef(_)
| val @ HeapCellValue::Rational(_) => Addr::Con(self.push(val)),
val @ HeapCellValue::LoadStatePayload(_) => Addr::LoadStatePayload(self.push(val)),
val @ HeapCellValue::NamedStr(..) => Addr::Str(self.push(val)),
HeapCellValue::PartialString(pstr, has_tail) => {
let h = self.push(HeapCellValue::PartialString(pstr, has_tail));
if has_tail {
self.push(HeapCellValue::Addr(Addr::EmptyList));
}
Addr::Con(h)
}
val @ HeapCellValue::Stream(..) => Addr::Stream(self.push(val)),
val @ HeapCellValue::TcpListener(..) => Addr::TcpListener(self.push(val)),
}
}
#[inline]
pub(crate) fn allocate_pstr(&mut self, src: &str) -> Addr {
self.write_pstr(src).unwrap_or_else(|| Addr::EmptyList)
}
#[inline]
fn write_pstr(&mut self, mut src: &str) -> Option<Addr> {
let orig_h = self.h();
loop { loop {
if src == "" { if src == "" {
return if orig_h == self.h() { return if orig_h == heap.len() {
None None
} else { } else {
let tail_h = self.h() - 1; let tail_h = heap.len() - 1;
self[tail_h] = HeapCellValue::Addr(Addr::HeapCell(tail_h)); heap[tail_h] = heap_loc_as_cell!(tail_h);
Some(Addr::PStrLocation(orig_h, 0)) Some(orig_h)
}; };
} }
let h = self.h(); let h = heap.len();
let (pstr, rest_src) = match PartialString::new(src) { let (pstr, rest_src) = match PartialString::new(src, atom_tbl) {
Some(tuple) => tuple, Some(tuple) => tuple,
None => { None => {
if src.len() > '\u{0}'.len_utf8() { if src.len() > '\u{0}'.len_utf8() {
@@ -298,165 +199,82 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
} else if orig_h == h { } else if orig_h == h {
return None; return None;
} else { } else {
self[h - 1] = HeapCellValue::Addr(Addr::HeapCell(h - 1)); heap[h - 1] = heap_loc_as_cell!(h - 1);
return Some(Addr::PStrLocation(orig_h, 0)); return Some(orig_h);
} }
} }
}; };
self.push(HeapCellValue::PartialString(pstr, true)); heap.push(string_as_pstr_cell!(pstr));
if rest_src != "" { if rest_src != "" {
self.push(HeapCellValue::Addr(Addr::PStrLocation(h + 2, 0))); heap.push(pstr_loc_as_cell!(h + 2));
src = rest_src; src = rest_src;
} else { } else {
self.push(HeapCellValue::Addr(Addr::HeapCell(h + 1))); heap.push(heap_loc_as_cell!(h + 1));
return Some(Addr::PStrLocation(orig_h, 0)); return Some(orig_h);
} }
} }
} }
#[inline] pub fn filtered_iter_to_heap_list<SrcT: Into<HeapCellValue>>(
pub(crate) fn truncate(&mut self, h: usize) { heap: &mut Heap,
let new_top = h * mem::size_of::<HeapCellValue>() + self.buf.base as usize; values: impl Iterator<Item = SrcT>,
let mut h = new_top; filter_fn: impl Fn(&Heap, HeapCellValue) -> bool,
) -> usize {
unsafe { let head_addr = heap.len();
while h as *const _ < self.buf.top {
let val = h as *mut HeapCellValue;
ptr::drop_in_place(val);
h += mem::size_of::<HeapCellValue>();
}
}
self.buf.top = new_top as *const _;
}
#[inline]
pub(crate) fn h(&self) -> usize {
(self.buf.top as usize - self.buf.base as usize) / mem::size_of::<HeapCellValue>()
}
pub(crate) fn append(&mut self, vals: Vec<HeapCellValue>) {
for val in vals {
self.push(val);
}
}
pub(crate) fn clear(&mut self) {
if !self.buf.base.is_null() {
self.truncate(0);
self.buf.top = self.buf.base;
}
}
pub(crate) fn to_list<Iter, SrcT>(&mut self, values: Iter) -> usize
where
Iter: Iterator<Item = SrcT>,
SrcT: Into<HeapCellValue>,
{
let head_addr = self.h();
let mut h = head_addr; let mut h = head_addr;
for value in values.map(|v| v.into()) { for value in values {
self.push(HeapCellValue::Addr(Addr::Lis(h + 1))); let value = value.into();
self.push(value);
if filter_fn(heap, value) {
heap.push(list_loc_as_cell!(h + 1));
heap.push(value);
h += 2; h += 2;
} }
}
self.push(HeapCellValue::Addr(Addr::EmptyList)); heap.push(empty_list_as_cell!());
head_addr head_addr
} }
/* Create an iterator starting from the passed offset. */ #[inline(always)]
pub(crate) fn iter_from<'a>(&'a self, offset: usize) -> HeapIter<'a, T> { pub fn iter_to_heap_list<Iter, SrcT>(heap: &mut Heap, values: Iter) -> usize
HeapIter::new(&self.buf, offset * mem::size_of::<HeapCellValue>()) where
Iter: Iterator<Item = SrcT>,
SrcT: Into<HeapCellValue>,
{
filtered_iter_to_heap_list(heap, values, |_, _| true)
} }
pub(crate) fn iter_mut_from<'a>(&'a mut self, offset: usize) -> HeapIterMut<'a, T> { pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option<usize> {
HeapIterMut::new(&mut self.buf, offset * mem::size_of::<HeapCellValue>())
}
pub(crate) fn into_iter(mut self) -> HeapIntoIter<T> {
HeapIntoIter {
buf: self.buf.take(),
offset: 0,
}
}
pub(crate) fn extend<Iter: Iterator<Item = HeapCellValue>>(&mut self, iter: Iter) {
for hcv in iter {
self.push(hcv);
}
}
pub(crate) fn to_local_code_ptr(&self, addr: &Addr) -> Option<LocalCodePtr> {
let extract_integer = |s: usize| -> Option<usize> { let extract_integer = |s: usize| -> Option<usize> {
match &self[s] { match Number::try_from(heap[s]) {
&HeapCellValue::Addr(Addr::Fixnum(n)) => usize::try_from(n).ok(), Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
&HeapCellValue::Integer(ref n) => n.to_usize(), Ok(Number::Integer(n)) => n.to_usize(),
_ => None, _ => None,
} }
}; };
match addr { read_heap_cell!(addr,
Addr::Str(s) => { (HeapCellValueTag::Str, s) => {
match &self[*s] { let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();
HeapCellValue::NamedStr(arity, ref name, _) => {
match (name.as_str(), *arity) {
("dir_entry", 1) => extract_integer(s + 1).map(LocalCodePtr::DirEntry),
/*
("top_level", 2) => {
if let Some(chunk_num) = extract_integer(s+1) {
if let Some(p) = extract_integer(s+2) {
return Some(LocalCodePtr::TopLevel(chunk_num, p));
}
}
if name == atom!("dir_entry") && arity == 1 {
extract_integer(s+1)
} else {
panic!(
"to_local_code_ptr crashed with p.i. {}/{}",
name.as_str(),
arity,
);
}
}
_ => {
None None
} }
*/ )
_ => None,
}
}
_ => unreachable!(),
}
}
_ => None,
}
}
#[inline]
pub(crate) fn index_addr<'a>(&'a self, addr: &Addr) -> RefOrOwned<'a, HeapCellValue> {
match addr {
&Addr::Con(h) | &Addr::Str(h) | &Addr::Stream(h) | &Addr::TcpListener(h) => {
RefOrOwned::Borrowed(&self[h])
}
addr => RefOrOwned::Owned(HeapCellValue::Addr(*addr)),
}
}
}
impl<T: RawBlockTraits> Index<usize> for HeapTemplate<T> {
type Output = HeapCellValue;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
unsafe {
let ptr = self.buf.base as usize + index * mem::size_of::<HeapCellValue>();
&*(ptr as *const HeapCellValue)
}
}
}
impl<T: RawBlockTraits> IndexMut<usize> for HeapTemplate<T> {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
unsafe {
let ptr = self.buf.base as usize + index * mem::size_of::<HeapCellValue>();
&mut *(ptr as *mut HeapCellValue)
}
}
} }

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,53 +1,38 @@
use prolog_parser::ast::*; use crate::parser::ast::*;
use prolog_parser::clause_name;
use crate::clause_types::*; use crate::arena::*;
use crate::atom_table::*;
use crate::fixtures::*; use crate::fixtures::*;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*; use crate::instructions::*;
use crate::machine::code_repo::CodeRepo; use crate::machine::loader::*;
use crate::machine::heap::*;
use crate::machine::machine_state::*; use crate::machine::machine_state::*;
use crate::machine::partial_string::*;
use crate::machine::raw_block::RawBlockTraits;
use crate::machine::streams::Stream; use crate::machine::streams::Stream;
use crate::machine::term_stream::LoadStatePayload;
use crate::machine::CompilationTarget;
use crate::rug::{Integer, Rational};
use ordered_float::OrderedFloat;
use fxhash::FxBuildHasher;
use indexmap::IndexMap; use indexmap::IndexMap;
use std::cell::Cell; use std::cell::Cell;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::{BTreeMap, BTreeSet}; use std::collections::BTreeSet;
use std::convert::TryFrom; use std::ops::Deref;
use std::fmt;
// use std::mem;
use std::net::TcpListener;
use std::ops::{Add, AddAssign, Deref, Sub, SubAssign};
use std::rc::Rc; use std::rc::Rc;
use crate::types::*;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct OrderedOpDirKey(pub(crate) ClauseName, pub(crate) Fixity); pub(crate) struct OrderedOpDirKey(pub(crate) Atom, pub(crate) Fixity);
pub(crate) type OssifiedOpDir = BTreeMap<OrderedOpDirKey, (usize, Specifier)>; pub(crate) type OssifiedOpDir = IndexMap<(Atom, Fixity), (usize, Specifier)>;
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum DBRef { pub enum DBRef {
NamedPred(ClauseName, usize, Option<SharedOpDesc>), NamedPred(Atom, usize),
Op( Op(Atom, Fixity, TypedArenaPtr<OssifiedOpDir>),
usize,
Specifier,
ClauseName,
Rc<OssifiedOpDir>,
SharedOpDesc,
),
} }
// 7.2 // 7.2
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) enum TermOrderCategory { pub enum TermOrderCategory {
Variable, Variable,
FloatingPoint, FloatingPoint,
Integer, Integer,
@@ -55,322 +40,45 @@ pub(crate) enum TermOrderCategory {
Compound, Compound,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] impl PartialEq<Ref> for HeapCellValue {
pub(crate) enum Addr {
AttrVar(usize),
Char(char),
Con(usize),
CutPoint(usize),
EmptyList,
Fixnum(isize),
Float(OrderedFloat<f64>),
Lis(usize),
LoadStatePayload(usize),
HeapCell(usize),
PStrLocation(usize, usize), // location of pstr in heap, offset into string in bytes.
StackCell(usize, usize),
Str(usize),
Stream(usize),
TcpListener(usize),
Usize(usize),
}
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, PartialOrd)]
pub(crate) enum Ref {
AttrVar(usize),
HeapCell(usize),
StackCell(usize, usize),
}
impl Ref {
pub(crate) fn as_addr(self) -> Addr {
match self {
Ref::AttrVar(h) => Addr::AttrVar(h),
Ref::HeapCell(h) => Addr::HeapCell(h),
Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc),
}
}
}
impl Ord for Ref {
fn cmp(&self, other: &Ref) -> Ordering {
match (self, other) {
(Ref::AttrVar(h1), Ref::AttrVar(h2))
| (Ref::HeapCell(h1), Ref::HeapCell(h2))
| (Ref::HeapCell(h1), Ref::AttrVar(h2))
| (Ref::AttrVar(h1), Ref::HeapCell(h2)) => h1.cmp(&h2),
(Ref::StackCell(fr1, sc1), Ref::StackCell(fr2, sc2)) => {
fr1.cmp(&fr2).then_with(|| sc1.cmp(&sc2))
}
(Ref::StackCell(..), _) => Ordering::Greater,
(_, Ref::StackCell(..)) => Ordering::Less,
}
}
}
impl PartialEq<Ref> for Addr {
fn eq(&self, r: &Ref) -> bool { fn eq(&self, r: &Ref) -> bool {
self.as_var() == Some(*r) self.as_var() == Some(*r)
} }
} }
// for use crate::in MachineState::bind. impl PartialOrd<Ref> for HeapCellValue {
impl PartialOrd<Ref> for Addr {
fn partial_cmp(&self, r: &Ref) -> Option<Ordering> { fn partial_cmp(&self, r: &Ref) -> Option<Ordering> {
match self { read_heap_cell!(*self,
&Addr::StackCell(fr, sc) => match *r { (HeapCellValueTag::StackVar, s1) => {
Ref::AttrVar(_) | Ref::HeapCell(_) => Some(Ordering::Greater), match r.get_tag() {
Ref::StackCell(fr1, sc1) => { RefTag::StackCell => {
if fr1 < fr || (fr1 == fr && sc1 < sc) { let s2 = r.get_value() as usize;
Some(Ordering::Greater) s1.partial_cmp(&s2)
} else if fr1 == fr && sc1 == sc { }
Some(Ordering::Equal) _ => Some(Ordering::Greater),
} else {
Some(Ordering::Less)
}
}
},
&Addr::HeapCell(h) | &Addr::AttrVar(h) => match r {
Ref::StackCell(..) => Some(Ordering::Less),
Ref::AttrVar(h1) | Ref::HeapCell(h1) => h.partial_cmp(h1),
},
_ => None,
}
} }
} }
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h1) => {
// _ if self.is_ref() => {
// let h1 = self.get_value();
impl Addr { match r.get_tag() {
#[inline] RefTag::StackCell => Some(Ordering::Less),
pub(crate) fn is_heap_bound(&self) -> bool {
match self {
Addr::Char(_)
| Addr::EmptyList
| Addr::CutPoint(_)
| Addr::Usize(_)
| Addr::Fixnum(_)
| Addr::Float(_) => false,
_ => true,
}
}
#[inline]
pub(crate) fn is_ref(&self) -> bool {
match self {
Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::AttrVar(_) => true,
_ => false,
}
}
#[inline]
pub(crate) fn as_var(&self) -> Option<Ref> {
match self {
&Addr::AttrVar(h) => Some(Ref::AttrVar(h)),
&Addr::HeapCell(h) => Some(Ref::HeapCell(h)),
&Addr::StackCell(fr, sc) => Some(Ref::StackCell(fr, sc)),
_ => None,
}
}
pub(super) fn order_category(&self, heap: &Heap) -> Option<TermOrderCategory> {
match Number::try_from((*self, heap)) {
Ok(Number::Integer(_)) | Ok(Number::Fixnum(_)) | Ok(Number::Rational(_)) => {
Some(TermOrderCategory::Integer)
}
Ok(Number::Float(_)) => Some(TermOrderCategory::FloatingPoint),
_ => match self {
Addr::HeapCell(_) | Addr::AttrVar(_) | Addr::StackCell(..) => {
Some(TermOrderCategory::Variable)
}
Addr::Float(_) => Some(TermOrderCategory::FloatingPoint),
&Addr::Con(h) => match &heap[h] {
HeapCellValue::Atom(..) => Some(TermOrderCategory::Atom),
HeapCellValue::DBRef(_) => None,
_ => { _ => {
unreachable!() let h2 = r.get_value() as usize;
} h1.partial_cmp(&h2)
},
Addr::Char(_) | Addr::EmptyList => Some(TermOrderCategory::Atom),
Addr::Fixnum(_) | Addr::Usize(_) => Some(TermOrderCategory::Integer),
Addr::Lis(_) | Addr::PStrLocation(..) | Addr::Str(_) => {
Some(TermOrderCategory::Compound)
}
Addr::CutPoint(_)
| Addr::LoadStatePayload(_)
| Addr::Stream(_)
| Addr::TcpListener(_) => None,
},
}
}
pub(crate) fn as_constant_index(&self, machine_st: &MachineState) -> Option<Constant> {
match self {
&Addr::Char(c) => Some(Constant::Char(c)),
&Addr::Con(h) => match &machine_st.heap[h] {
&HeapCellValue::Atom(ref name, _) if name.is_char() => {
Some(Constant::Char(name.as_str().chars().next().unwrap()))
}
&HeapCellValue::Atom(ref name, _) => Some(Constant::Atom(name.clone(), None)),
&HeapCellValue::Integer(ref n) => Some(Constant::Integer(n.clone())),
&HeapCellValue::Rational(ref n) => Some(Constant::Rational(n.clone())),
_ => None,
},
&Addr::EmptyList => Some(Constant::EmptyList),
&Addr::Fixnum(n) => Some(Constant::Fixnum(n)),
&Addr::Float(f) => Some(Constant::Float(f)),
&Addr::Usize(n) => Some(Constant::Usize(n)),
_ => None,
}
}
pub(crate) fn is_protected(&self, e: usize) -> bool {
match self {
&Addr::StackCell(addr, _) if addr >= e => false,
_ => true,
} }
} }
} }
_ => {
impl Add<usize> for Addr { None
type Output = Addr;
fn add(self, rhs: usize) -> Self::Output {
match self {
Addr::Stream(h) => Addr::Stream(h + rhs),
Addr::Con(h) => Addr::Con(h + rhs),
Addr::Lis(a) => Addr::Lis(a + rhs),
Addr::AttrVar(h) => Addr::AttrVar(h + rhs),
Addr::HeapCell(h) => Addr::HeapCell(h + rhs),
Addr::Str(s) => Addr::Str(s + rhs),
Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs, n),
_ => self,
} }
} )
}
impl Sub<i64> for Addr {
type Output = Addr;
fn sub(self, rhs: i64) -> Self::Output {
if rhs < 0 {
match self {
Addr::Stream(h) => Addr::Stream(h + rhs.abs() as usize),
Addr::Con(h) => Addr::Con(h + rhs.abs() as usize),
Addr::Lis(a) => Addr::Lis(a + rhs.abs() as usize),
Addr::AttrVar(h) => Addr::AttrVar(h + rhs.abs() as usize),
Addr::HeapCell(h) => Addr::HeapCell(h + rhs.abs() as usize),
Addr::Str(s) => Addr::Str(s + rhs.abs() as usize),
Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs.abs() as usize, n),
_ => self,
}
} else {
self.sub(rhs as usize)
}
}
}
impl Sub<usize> for Addr {
type Output = Addr;
fn sub(self, rhs: usize) -> Self::Output {
match self {
Addr::Stream(h) => Addr::Stream(h - rhs),
Addr::Con(h) => Addr::Con(h - rhs),
Addr::Lis(a) => Addr::Lis(a - rhs),
Addr::AttrVar(h) => Addr::AttrVar(h - rhs),
Addr::HeapCell(h) => Addr::HeapCell(h - rhs),
Addr::Str(s) => Addr::Str(s - rhs),
Addr::PStrLocation(h, n) => Addr::PStrLocation(h - rhs, n),
_ => self,
}
}
}
impl SubAssign<usize> for Addr {
fn sub_assign(&mut self, rhs: usize) {
*self = self.clone() - rhs;
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum TrailRef {
Ref(Ref),
AttrVarHeapLink(usize),
AttrVarListLink(usize, usize),
BlackboardEntry(usize),
BlackboardOffset(usize, usize), // key atom heap location, key value heap location
}
impl From<Ref> for TrailRef {
fn from(r: Ref) -> Self {
TrailRef::Ref(r)
}
}
#[derive(Debug)]
pub(crate) enum HeapCellValue {
Addr(Addr),
Atom(ClauseName, Option<SharedOpDesc>),
DBRef(DBRef),
Integer(Rc<Integer>),
LoadStatePayload(Box<LoadStatePayload>),
NamedStr(usize, ClauseName, Option<SharedOpDesc>), // arity, name, precedence/Specifier if it has one.
Rational(Rc<Rational>),
PartialString(PartialString, bool), // the partial string, a bool indicating whether it came from a Constant.
Stream(Stream),
TcpListener(TcpListener),
}
impl HeapCellValue {
#[inline]
pub(crate) fn as_addr(&self, focus: usize) -> Addr {
match self {
HeapCellValue::Addr(ref a) => *a,
HeapCellValue::Atom(..)
| HeapCellValue::DBRef(..)
| HeapCellValue::Integer(..)
| HeapCellValue::Rational(..) => Addr::Con(focus),
HeapCellValue::LoadStatePayload(_) => Addr::LoadStatePayload(focus),
HeapCellValue::NamedStr(_, _, _) => Addr::Str(focus),
HeapCellValue::PartialString(..) => Addr::PStrLocation(focus, 0),
HeapCellValue::Stream(_) => Addr::Stream(focus),
HeapCellValue::TcpListener(_) => Addr::TcpListener(focus),
}
}
#[inline]
pub(crate) fn context_free_clone(&self) -> HeapCellValue {
match self {
&HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr),
&HeapCellValue::Atom(ref name, ref op) => HeapCellValue::Atom(name.clone(), op.clone()),
&HeapCellValue::DBRef(ref db_ref) => HeapCellValue::DBRef(db_ref.clone()),
&HeapCellValue::Integer(ref n) => HeapCellValue::Integer(n.clone()),
&HeapCellValue::LoadStatePayload(_) => {
HeapCellValue::Atom(clause_name!("$live_term_stream"), None)
}
&HeapCellValue::NamedStr(arity, ref name, ref op) => {
HeapCellValue::NamedStr(arity, name.clone(), op.clone())
}
&HeapCellValue::Rational(ref r) => HeapCellValue::Rational(r.clone()),
&HeapCellValue::PartialString(ref pstr, has_tail) => {
HeapCellValue::PartialString(pstr.clone(), has_tail)
}
&HeapCellValue::Stream(ref stream) => HeapCellValue::Stream(stream.clone()),
&HeapCellValue::TcpListener(_) => {
HeapCellValue::Atom(clause_name!("$tcp_listener"), None)
}
}
}
}
impl From<Addr> for HeapCellValue {
#[inline]
fn from(value: Addr) -> HeapCellValue {
HeapCellValue::Addr(value)
} }
} }
#[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)] #[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub(crate) enum IndexPtr { pub enum IndexPtr {
DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined. DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined.
DynamicIndex(usize), DynamicIndex(usize),
Index(usize), Index(usize),
@@ -378,7 +86,7 @@ pub(crate) enum IndexPtr {
} }
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)] #[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub(crate) struct CodeIndex(pub(crate) Rc<Cell<IndexPtr>>); pub struct CodeIndex(pub(crate) Rc<Cell<IndexPtr>>);
impl Deref for CodeIndex { impl Deref for CodeIndex {
type Target = Cell<IndexPtr>; type Target = Cell<IndexPtr>;
@@ -418,8 +126,9 @@ impl Default for CodeIndex {
} }
} }
/*
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
pub(crate) enum REPLCodePtr { pub enum REPLCodePtr {
AddDiscontiguousPredicate, AddDiscontiguousPredicate,
AddDynamicPredicate, AddDynamicPredicate,
AddMultifilePredicate, AddMultifilePredicate,
@@ -456,170 +165,32 @@ pub(crate) enum REPLCodePtr {
AddNonCountedBacktracking, AddNonCountedBacktracking,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub(crate) enum CodePtr { pub enum CodePtr {
BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call. BuiltInClause(BuiltInClauseType, usize), // local is the successor call.
CallN(usize, LocalCodePtr, bool), // arity, local, last call. CallN(usize, usize, bool), // arity, local, last call.
Local(LocalCodePtr), Local(usize),
// DynamicTransaction(DynamicTransactionType, LocalCodePtr), // the type of transaction, the return pointer. REPL(REPLCodePtr, usize), // the REPL code, the return pointer.
REPL(REPLCodePtr, LocalCodePtr), // the REPL code, the return pointer.
VerifyAttrInterrupt(usize), // location of the verify attribute interrupt code in the CodeDir. VerifyAttrInterrupt(usize), // location of the verify attribute interrupt code in the CodeDir.
} }
impl CodePtr { impl CodePtr {
pub(crate) fn local(&self) -> LocalCodePtr { pub(crate) fn local(&self) -> usize {
match self { match self {
&CodePtr::BuiltInClause(_, ref local) &CodePtr::BuiltInClause(_, ref local) |
| &CodePtr::CallN(_, ref local, _) &CodePtr::CallN(_, ref local, _) |
| &CodePtr::Local(ref local) => local.clone(), &CodePtr::Local(ref local) => *local,
&CodePtr::VerifyAttrInterrupt(p) => LocalCodePtr::DirEntry(p), &CodePtr::VerifyAttrInterrupt(p) => p,
&CodePtr::REPL(_, p) => p, // | &CodePtr::DynamicTransaction(_, p) => p, &CodePtr::REPL(_, p) => p,
} }
} }
#[inline] pub fn assign_if_local(&self, cp: &mut usize) {
pub(crate) fn is_halt(&self) -> bool { match self {
if let CodePtr::Local(LocalCodePtr::Halt) = self { CodePtr::Local(local) => *cp = *local,
true
} else {
false
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub(crate) enum LocalCodePtr {
DirEntry(usize), // offset
Halt,
IndexingBuf(usize, usize, usize), // DirEntry offset, first internal offset, second internal offset
// TopLevel(usize, usize), // chunk_num, offset
}
impl LocalCodePtr {
pub(crate) fn assign_if_local(&mut self, cp: CodePtr) {
match cp {
CodePtr::Local(local) => *self = local,
_ => {} _ => {}
} }
} }
#[inline]
pub(crate) fn abs_loc(&self) -> usize {
match self {
LocalCodePtr::DirEntry(ref p) => *p,
LocalCodePtr::IndexingBuf(ref p, ..) => *p,
LocalCodePtr::Halt => unreachable!(),
}
}
pub(crate) fn is_reset_cont_marker(&self, code_repo: &CodeRepo, last_call: bool) -> bool {
match code_repo.lookup_instr(last_call, &CodePtr::Local(*self)) {
Some(line) => match line.as_ref() {
Line::Control(ControlInstruction::CallClause(ref ct, ..)) => {
if let ClauseType::System(SystemClauseType::ResetContinuationMarker) = *ct {
return true;
}
}
_ => {}
},
None => {}
}
false
}
pub(crate) fn as_functor<T: RawBlockTraits>(&self, heap: &mut HeapTemplate<T>) -> Addr {
let addr = Addr::HeapCell(heap.h());
match self {
LocalCodePtr::DirEntry(p) => {
heap.append(functor!("dir_entry", [integer(*p)]));
}
LocalCodePtr::Halt => {
heap.append(functor!("halt"));
}
/*
LocalCodePtr::TopLevel(chunk_num, offset) => {
heap.append(functor!(
"top_level",
[integer(*chunk_num), integer(*offset)]
));
}
*/
LocalCodePtr::IndexingBuf(p, o, i) => {
heap.append(functor!(
"indexed_buf",
[integer(*p), integer(*o), integer(*i)]
));
}
}
addr
}
}
impl Default for CodePtr {
#[inline]
fn default() -> Self {
CodePtr::Local(LocalCodePtr::default())
}
}
impl Default for LocalCodePtr {
#[inline]
fn default() -> Self {
LocalCodePtr::DirEntry(0)
}
}
impl Add<usize> for LocalCodePtr {
type Output = LocalCodePtr;
#[inline]
fn add(self, rhs: usize) -> Self::Output {
match self {
LocalCodePtr::DirEntry(p) => LocalCodePtr::DirEntry(p + rhs),
LocalCodePtr::Halt => unreachable!(),
LocalCodePtr::IndexingBuf(p, o, i) => LocalCodePtr::IndexingBuf(p, o, i + rhs),
}
}
}
impl Sub<usize> for LocalCodePtr {
type Output = Option<LocalCodePtr>;
#[inline]
fn sub(self, rhs: usize) -> Self::Output {
match self {
LocalCodePtr::DirEntry(p) => p.checked_sub(rhs).map(LocalCodePtr::DirEntry),
LocalCodePtr::Halt => unreachable!(),
LocalCodePtr::IndexingBuf(p, o, i) => i
.checked_sub(rhs)
.map(|r| LocalCodePtr::IndexingBuf(p, o, r)),
}
}
}
impl SubAssign<usize> for LocalCodePtr {
#[inline]
fn sub_assign(&mut self, rhs: usize) {
match self {
LocalCodePtr::DirEntry(ref mut p) => *p -= rhs,
LocalCodePtr::Halt | LocalCodePtr::IndexingBuf(..) => unreachable!(),
}
}
}
impl AddAssign<usize> for LocalCodePtr {
#[inline]
fn add_assign(&mut self, rhs: usize) {
match self {
&mut LocalCodePtr::DirEntry(ref mut p) /* |
&mut LocalCodePtr::TopLevel(_, ref mut p) */ => *p += rhs,
&mut LocalCodePtr::IndexingBuf(_, _, ref mut i) => *i += rhs,
&mut LocalCodePtr::Halt => unreachable!(),
}
}
} }
impl Add<usize> for CodePtr { impl Add<usize> for CodePtr {
@@ -628,8 +199,6 @@ impl Add<usize> for CodePtr {
fn add(self, rhs: usize) -> Self::Output { fn add(self, rhs: usize) -> Self::Output {
match self { match self {
p @ CodePtr::REPL(..) | p @ CodePtr::VerifyAttrInterrupt(_) => { p @ CodePtr::REPL(..) | p @ CodePtr::VerifyAttrInterrupt(_) => {
// |
// p @ CodePtr::DynamicTransaction(..) => {
p p
} }
CodePtr::Local(local) => CodePtr::Local(local + rhs), CodePtr::Local(local) => CodePtr::Local(local + rhs),
@@ -660,23 +229,33 @@ impl SubAssign<usize> for CodePtr {
} }
} }
pub(crate) type HeapVarDict = IndexMap<Rc<Var>, Addr>; impl Default for CodePtr {
pub(crate) type AllocVarDict = IndexMap<Rc<Var>, VarData>; #[inline]
fn default() -> Self {
CodePtr::Local(0)
}
}
*/
pub(crate) type GlobalVarDir = IndexMap<ClauseName, (Ball, Option<Addr>)>; pub(crate) type HeapVarDict = IndexMap<Rc<String>, HeapCellValue, FxBuildHasher>;
pub(crate) type AllocVarDict = IndexMap<Rc<String>, VarData, FxBuildHasher>;
pub(crate) type StreamAliasDir = IndexMap<ClauseName, Stream>; pub(crate) type GlobalVarDir = IndexMap<Atom, (Ball, Option<HeapCellValue>), FxBuildHasher>;
pub(crate) type StreamAliasDir = IndexMap<Atom, Stream, FxBuildHasher>;
pub(crate) type StreamDir = BTreeSet<Stream>; pub(crate) type StreamDir = BTreeSet<Stream>;
pub(crate) type MetaPredicateDir = IndexMap<PredicateKey, Vec<MetaSpec>>; pub(crate) type MetaPredicateDir = IndexMap<PredicateKey, Vec<MetaSpec>, FxBuildHasher>;
pub(crate) type ExtensiblePredicates = IndexMap<PredicateKey, PredicateSkeleton>; pub(crate) type ExtensiblePredicates = IndexMap<PredicateKey, PredicateSkeleton, FxBuildHasher>;
pub(crate) type LocalExtensiblePredicates = pub(crate) type LocalExtensiblePredicates =
IndexMap<(CompilationTarget, PredicateKey), LocalPredicateSkeleton>; IndexMap<(CompilationTarget, PredicateKey), LocalPredicateSkeleton, FxBuildHasher>;
pub(crate) type CodeDir = IndexMap<PredicateKey, CodeIndex, FxBuildHasher>;
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct IndexStore { pub struct IndexStore {
pub(super) code_dir: CodeDir, pub(super) code_dir: CodeDir,
pub(super) extensible_predicates: ExtensiblePredicates, pub(super) extensible_predicates: ExtensiblePredicates,
pub(super) local_extensible_predicates: LocalExtensiblePredicates, pub(super) local_extensible_predicates: LocalExtensiblePredicates,
@@ -688,22 +267,13 @@ pub(crate) struct IndexStore {
pub(super) stream_aliases: StreamAliasDir, pub(super) stream_aliases: StreamAliasDir,
} }
impl Default for IndexStore {
#[inline]
fn default() -> Self {
index_store!(CodeDir::new(), default_op_dir(), ModuleDir::new())
}
}
impl IndexStore { impl IndexStore {
pub(crate) fn get_predicate_skeleton_mut( pub(crate) fn get_predicate_skeleton_mut(
&mut self, &mut self,
compilation_target: &CompilationTarget, compilation_target: &CompilationTarget,
key: &PredicateKey, key: &PredicateKey,
) -> Option<&mut PredicateSkeleton> { ) -> Option<&mut PredicateSkeleton> {
match (key.0.as_str(), key.1) { match compilation_target {
// ("term_expansion", 2) => self.extensible_predicates.get_mut(key),
_ => match compilation_target {
CompilationTarget::User => self.extensible_predicates.get_mut(key), CompilationTarget::User => self.extensible_predicates.get_mut(key),
CompilationTarget::Module(ref module_name) => { CompilationTarget::Module(ref module_name) => {
if let Some(module) = self.modules.get_mut(module_name) { if let Some(module) = self.modules.get_mut(module_name) {
@@ -712,7 +282,6 @@ impl IndexStore {
None None
} }
} }
},
} }
} }
@@ -737,7 +306,7 @@ impl IndexStore {
&mut self, &mut self,
mut src_compilation_target: CompilationTarget, mut src_compilation_target: CompilationTarget,
local_compilation_target: CompilationTarget, local_compilation_target: CompilationTarget,
listing_src_file_name: Option<ClauseName>, listing_src_file_name: Option<Atom>,
key: PredicateKey, key: PredicateKey,
) -> Option<&mut LocalPredicateSkeleton> { ) -> Option<&mut LocalPredicateSkeleton> {
if let Some(filename) = listing_src_file_name { if let Some(filename) = listing_src_file_name {
@@ -748,8 +317,8 @@ impl IndexStore {
CompilationTarget::User => self CompilationTarget::User => self
.local_extensible_predicates .local_extensible_predicates
.get_mut(&(local_compilation_target, key)), .get_mut(&(local_compilation_target, key)),
CompilationTarget::Module(ref module_name) => { CompilationTarget::Module(module_name) => {
if let Some(module) = self.modules.get_mut(module_name) { if let Some(module) = self.modules.get_mut(&module_name) {
module module
.local_extensible_predicates .local_extensible_predicates
.get_mut(&(local_compilation_target, key)) .get_mut(&(local_compilation_target, key))
@@ -764,7 +333,7 @@ impl IndexStore {
&self, &self,
mut src_compilation_target: CompilationTarget, mut src_compilation_target: CompilationTarget,
local_compilation_target: CompilationTarget, local_compilation_target: CompilationTarget,
listing_src_file_name: Option<ClauseName>, listing_src_file_name: Option<Atom>,
key: PredicateKey, key: PredicateKey,
) -> Option<&LocalPredicateSkeleton> { ) -> Option<&LocalPredicateSkeleton> {
if let Some(filename) = listing_src_file_name { if let Some(filename) = listing_src_file_name {
@@ -775,8 +344,8 @@ impl IndexStore {
CompilationTarget::User => self CompilationTarget::User => self
.local_extensible_predicates .local_extensible_predicates
.get(&(local_compilation_target, key)), .get(&(local_compilation_target, key)),
CompilationTarget::Module(ref module_name) => { CompilationTarget::Module(module_name) => {
if let Some(module) = self.modules.get(module_name) { if let Some(module) = self.modules.get(&module_name) {
module module
.local_extensible_predicates .local_extensible_predicates
.get(&(local_compilation_target, key)) .get(&(local_compilation_target, key))
@@ -806,35 +375,30 @@ impl IndexStore {
pub(crate) fn get_predicate_code_index( pub(crate) fn get_predicate_code_index(
&self, &self,
name: ClauseName, name: Atom,
arity: usize, arity: usize,
module: ClauseName, module: Atom,
op_spec: Option<SharedOpDesc>,
) -> Option<CodeIndex> { ) -> Option<CodeIndex> {
if module.as_str() == "user" { if module == atom!("user") {
match ClauseType::from(name, arity, op_spec) { match ClauseType::from(name, arity) {
ClauseType::Named(name, arity, _) => self.code_dir.get(&(name, arity)).cloned(), ClauseType::Named(arity, name, _) => self.code_dir.get(&(name, arity)).cloned(),
ClauseType::Op(name, spec, ..) => self.code_dir.get(&(name, spec.arity())).cloned(),
_ => None, _ => None,
} }
} else { } else {
self.modules.get(&module).and_then(|module| { self.modules
match ClauseType::from(name, arity, op_spec) { .get(&module)
ClauseType::Named(name, arity, _) => { .and_then(|module| match ClauseType::from(name, arity) {
ClauseType::Named(arity, name, _) => {
module.code_dir.get(&(name, arity)).cloned() module.code_dir.get(&(name, arity)).cloned()
} }
ClauseType::Op(name, spec, ..) => {
module.code_dir.get(&(name, spec.arity())).cloned()
}
_ => None, _ => None,
}
}) })
} }
} }
pub(crate) fn get_meta_predicate_spec( pub(crate) fn get_meta_predicate_spec(
&self, &self,
name: ClauseName, name: Atom,
arity: usize, arity: usize,
compilation_target: &CompilationTarget, compilation_target: &CompilationTarget,
) -> Option<&Vec<MetaSpec>> { ) -> Option<&Vec<MetaSpec>> {
@@ -850,9 +414,13 @@ impl IndexStore {
} }
} }
pub(crate) fn is_dynamic_predicate(&self, module_name: ClauseName, key: PredicateKey) -> bool { pub(crate) fn is_dynamic_predicate(
match module_name.as_str() { &self,
"user" => self module_name: Atom,
key: PredicateKey,
) -> bool {
match module_name {
atom!("user") => self
.extensible_predicates .extensible_predicates
.get(&key) .get(&key)
.map(|skeleton| skeleton.core.is_dynamic) .map(|skeleton| skeleton.core.is_dynamic)
@@ -870,62 +438,10 @@ impl IndexStore {
#[inline] #[inline]
pub(super) fn new() -> Self { pub(super) fn new() -> Self {
IndexStore::default() index_store!(
} CodeDir::with_hasher(FxBuildHasher::default()),
default_op_dir(),
pub(super) fn get_cleaner_sites(&self) -> (usize, usize) { ModuleDir::with_hasher(FxBuildHasher::default())
let r_w_h = clause_name!("run_cleaners_with_handling"); )
let r_wo_h = clause_name!("run_cleaners_without_handling");
let iso_ext = clause_name!("iso_ext");
let r_w_h = self
.get_predicate_code_index(r_w_h, 0, iso_ext.clone(), None)
.and_then(|item| item.local());
let r_wo_h = self
.get_predicate_code_index(r_wo_h, 1, iso_ext, None)
.and_then(|item| item.local());
if let Some(r_w_h) = r_w_h {
if let Some(r_wo_h) = r_wo_h {
return (r_w_h, r_wo_h);
}
}
return (0, 0);
}
}
pub(crate) type CodeDir = BTreeMap<PredicateKey, CodeIndex>;
pub(crate) enum RefOrOwned<'a, T: 'a> {
Borrowed(&'a T),
Owned(T),
}
impl<'a, T: 'a + fmt::Debug> fmt::Debug for RefOrOwned<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&RefOrOwned::Borrowed(ref borrowed) => write!(f, "Borrowed({:?})", borrowed),
&RefOrOwned::Owned(ref owned) => write!(f, "Owned({:?})", owned),
}
}
}
impl<'a, T> RefOrOwned<'a, T> {
pub(crate) fn as_ref(&'a self) -> &'a T {
match self {
&RefOrOwned::Borrowed(r) => r,
&RefOrOwned::Owned(ref r) => r,
}
}
pub(crate) fn to_owned(self) -> T
where
T: Clone,
{
match self {
RefOrOwned::Borrowed(item) => item.clone(),
RefOrOwned::Owned(item) => item,
}
} }
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

851
src/machine/mock_wam.rs Normal file
View File

@@ -0,0 +1,851 @@
pub use crate::arena::*;
pub use crate::atom_table::*;
use crate::heap_print::*;
pub use crate::machine::heap::*;
pub use crate::machine::*;
pub use crate::machine::machine_state::*;
pub use crate::machine::stack::*;
pub use crate::machine::streams::*;
pub use crate::macros::*;
pub use crate::parser::ast::*;
use crate::read::*;
pub use crate::types::*;
#[cfg(test)]
use crate::machine::copier::CopierTarget;
#[cfg(test)]
use std::ops::{Deref, DerefMut, Index, IndexMut};
// a mini-WAM for test purposes.
pub struct MockWAM {
pub machine_st: MachineState,
pub op_dir: OpDir,
pub flags: MachineFlags,
}
impl MockWAM {
pub fn new() -> Self {
let op_dir = default_op_dir();
Self {
machine_st: MachineState::new(),
op_dir,
flags: MachineFlags::default(),
}
}
pub fn write_parsed_term_to_heap(
&mut self,
input_stream: Stream,
) -> Result<TermWriteResult, ParserError> {
self.machine_st.read(input_stream, &self.op_dir)
}
pub fn parse_and_write_parsed_term_to_heap(
&mut self,
term_string: &'static str,
) -> Result<TermWriteResult, ParserError> {
let stream = Stream::from_static_string(term_string, &mut self.machine_st.arena);
self.write_parsed_term_to_heap(stream)
}
pub fn parse_and_print_term(
&mut self,
term_string: &'static str,
) -> Result<String, ParserError> {
let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?;
print_heap_terms(self.machine_st.heap.iter(), term_write_result.heap_loc);
let mut printer = HCPrinter::new(
&mut self.machine_st.heap,
&mut self.machine_st.arena,
&self.op_dir,
PrinterOutputter::new(),
heap_loc_as_cell!(term_write_result.heap_loc),
);
printer.var_names = term_write_result
.var_dict
.into_iter()
.map(|(var, cell)| (cell, var))
.collect();
Ok(printer.print().result())
}
}
#[cfg(test)]
pub struct TermCopyingMockWAM<'a> {
pub wam: &'a mut MockWAM,
}
#[cfg(test)]
impl<'a> Index<usize> for TermCopyingMockWAM<'a> {
type Output = HeapCellValue;
fn index(&self, index: usize) -> &HeapCellValue {
&self.wam.machine_st.heap[index]
}
}
#[cfg(test)]
impl<'a> IndexMut<usize> for TermCopyingMockWAM<'a> {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut HeapCellValue {
&mut self.wam.machine_st.heap[index]
}
}
#[cfg(test)]
impl<'a> Deref for TermCopyingMockWAM<'a> {
type Target = MockWAM;
fn deref(&self) -> &Self::Target {
&self.wam
}
}
#[cfg(test)]
impl<'a> DerefMut for TermCopyingMockWAM<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.wam
}
}
#[cfg(test)]
impl<'a> CopierTarget for TermCopyingMockWAM<'a> {
fn store(&self, val: HeapCellValue) -> HeapCellValue {
read_heap_cell!(val,
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
self.wam.machine_st.heap[h]
}
(HeapCellValueTag::StackVar, s) => {
self.wam.machine_st.stack[s]
}
_ => {
val
}
)
}
fn deref(&self, mut val: HeapCellValue) -> HeapCellValue {
loop {
let value = self.store(val);
if value.is_var() && value != val {
val = value;
continue;
}
return val;
}
}
fn push(&mut self, val: HeapCellValue) {
self.wam.machine_st.heap.push(val);
}
fn stack(&mut self) -> &mut Stack {
&mut self.wam.machine_st.stack
}
fn threshold(&self) -> usize {
self.wam.machine_st.heap.len()
}
}
#[cfg(test)]
pub fn all_cells_marked_and_unforwarded(heap: &[HeapCellValue]) {
for (idx, cell) in heap.iter().enumerate() {
assert_eq!(
cell.get_mark_bit(),
true,
"cell {:?} at index {} is not marked",
cell,
idx
);
assert!(
cell.get_forwarding_bit() != Some(true),
"cell {:?} at index {} is forwarded",
cell,
idx
);
}
}
#[cfg(test)]
pub fn all_cells_unmarked(heap: &Heap) {
for (idx, cell) in heap.iter().enumerate() {
assert!(
!cell.get_mark_bit(),
"cell {:?} at index {} is still marked",
cell,
idx
);
assert!(
cell.get_forwarding_bit() != Some(true),
"cell {:?} at index {} is still forwarded",
cell,
idx
);
}
}
#[cfg(test)]
pub(crate) fn write_parsed_term_to_heap(
machine_st: &mut MachineState,
input_stream: Stream,
op_dir: &OpDir,
) -> Result<TermWriteResult, ParserError> {
machine_st.read(input_stream, op_dir)
}
#[cfg(test)]
pub(crate) fn parse_and_write_parsed_term_to_heap(
machine_st: &mut MachineState,
term_string: &'static str,
op_dir: &OpDir,
) -> Result<TermWriteResult, ParserError> {
let stream = Stream::from_static_string(term_string, &mut machine_st.arena);
write_parsed_term_to_heap(machine_st, stream, op_dir)
}
impl Machine {
pub fn with_test_streams() -> Self {
use ref_thread_local::RefThreadLocal;
let mut machine_st = MachineState::new();
let user_input = Stream::Null(StreamOptions::default());
let user_output = Stream::from_owned_string("".to_owned(), &mut machine_st.arena);
let user_error = Stream::stderr(&mut machine_st.arena);
let mut wam = Machine {
machine_st,
indices: IndexStore::new(),
code: Code::new(),
user_input,
user_output,
user_error,
load_contexts: vec![],
};
let mut lib_path = current_dir();
lib_path.pop();
lib_path.push("lib");
wam.add_impls_to_indices();
bootstrapping_compile(
Stream::from_static_string(
LIBRARIES.borrow()["ops_and_meta_predicates"],
&mut wam.machine_st.arena,
),
&mut wam,
ListingSource::from_file_and_path(
atom!("ops_and_meta_predicates.pl"),
lib_path.clone(),
),
)
.unwrap();
bootstrapping_compile(
Stream::from_static_string(
LIBRARIES.borrow()["builtins"],
&mut wam.machine_st.arena,
),
&mut wam,
ListingSource::from_file_and_path(atom!("builtins.pl"), lib_path.clone()),
)
.unwrap();
if let Some(ref mut builtins) = wam.indices.modules.get_mut(&atom!("builtins")) {
load_module(
&mut wam.indices.code_dir,
&mut wam.indices.op_dir,
&mut wam.indices.meta_predicates,
&CompilationTarget::User,
builtins,
);
import_builtin_impls(&wam.indices.code_dir, builtins);
} else {
unreachable!()
}
lib_path.pop(); // remove the "lib" at the end
bootstrapping_compile(
Stream::from_static_string(include_str!("../loader.pl"), &mut wam.machine_st.arena),
&mut wam,
ListingSource::from_file_and_path(atom!("loader.pl"), lib_path.clone()),
)
.unwrap();
wam.configure_modules();
if let Some(loader) = wam.indices.modules.get(&atom!("loader")) {
load_module(
&mut wam.indices.code_dir,
&mut wam.indices.op_dir,
&mut wam.indices.meta_predicates,
&CompilationTarget::User,
loader,
);
} else {
unreachable!()
}
wam.load_special_forms();
wam.load_top_level();
wam.configure_streams();
wam
}
pub fn test_load_file(&mut self, file: &str) -> Vec<u8> {
use std::io::Read;
let stream = Stream::from_owned_string(
std::fs::read_to_string(AsRef::<std::path::Path>::as_ref(file)).unwrap(),
&mut self.machine_st.arena,
);
self.load_file(file.into(), stream);
self.user_output.bytes().map(|b| b.unwrap()).collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unify_tests() {
let mut wam = MachineState::new();
let mut op_dir = default_op_dir();
op_dir.insert(
(atom!("+"), Fixity::In),
OpDesc::build_with(500, YFX as u8),
);
op_dir.insert(
(atom!("-"), Fixity::In),
OpDesc::build_with(500, YFX as u8),
);
op_dir.insert(
(atom!("*"), Fixity::In),
OpDesc::build_with(500, YFX as u8),
);
op_dir.insert(
(atom!("/"), Fixity::In),
OpDesc::build_with(400, YFX as u8),
);
op_dir.insert(
(atom!("="), Fixity::In),
OpDesc::build_with(700, XFX as u8),
);
{
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_2 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(b,a).", &op_dir).unwrap();
unify!(
wam,
str_loc_as_cell!(0),
str_loc_as_cell!(term_write_result_2.heap_loc)
);
assert!(wam.fail);
}
all_cells_unmarked(&wam.heap);
wam.fail = false;
wam.heap.clear();
{
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_2 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(b,b).", &op_dir).unwrap();
unify!(
wam,
str_loc_as_cell!(1),
heap_loc_as_cell!(term_write_result_2.heap_loc)
);
assert!(!wam.fail);
}
all_cells_unmarked(&wam.heap);
wam.fail = false;
wam.heap.clear();
{
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_2 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap();
unify!(
wam,
heap_loc_as_cell!(0),
heap_loc_as_cell!(term_write_result_2.heap_loc)
);
assert!(!wam.fail);
}
all_cells_unmarked(&wam.heap);
wam.fail = false;
wam.heap.clear();
{
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_2 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap();
unify!(
wam,
heap_loc_as_cell!(0),
heap_loc_as_cell!(term_write_result_2.heap_loc)
);
assert!(!wam.fail);
}
all_cells_unmarked(&wam.heap);
wam.fail = false;
wam.heap.clear();
{
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_2 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),A).", &op_dir).unwrap();
unify!(
wam,
heap_loc_as_cell!(0),
heap_loc_as_cell!(term_write_result_2.heap_loc)
);
assert!(!wam.fail);
}
all_cells_unmarked(&wam.heap);
wam.fail = false;
wam.heap.clear();
{
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_2 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap();
all_cells_unmarked(&wam.heap);
unify!(
wam,
heap_loc_as_cell!(0),
heap_loc_as_cell!(term_write_result_2.heap_loc)
);
assert!(!wam.fail);
}
all_cells_unmarked(&wam.heap);
wam.heap.clear();
wam.heap.push(pstr_as_cell!(atom!("this is a string")));
wam.heap.push(heap_loc_as_cell!(1));
wam.heap.push(pstr_as_cell!(atom!("this is a string")));
wam.heap.push(pstr_loc_as_cell!(4));
wam.heap.push(pstr_offset_as_cell!(0));
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(6)));
unify!(wam, pstr_loc_as_cell!(0), pstr_loc_as_cell!(2));
assert!(!wam.fail);
assert_eq!(wam.heap[1], pstr_loc_as_cell!(4));
all_cells_unmarked(&wam.heap);
wam.heap.clear();
wam.heap.push(list_loc_as_cell!(1));
wam.heap.push(atom_as_cell!(atom!("a")));
wam.heap.push(list_loc_as_cell!(3));
wam.heap.push(atom_as_cell!(atom!("b")));
wam.heap.push(heap_loc_as_cell!(0));
wam.heap.push(list_loc_as_cell!(6));
wam.heap.push(atom_as_cell!(atom!("a")));
wam.heap.push(list_loc_as_cell!(8));
wam.heap.push(atom_as_cell!(atom!("b")));
wam.heap.push(heap_loc_as_cell!(5));
unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
assert!(!wam.fail);
all_cells_unmarked(&wam.heap);
wam.heap.clear();
wam.heap.push(list_loc_as_cell!(1));
wam.heap.push(atom_as_cell!(atom!("a")));
wam.heap.push(list_loc_as_cell!(3));
wam.heap.push(atom_as_cell!(atom!("b")));
wam.heap.push(heap_loc_as_cell!(0));
wam.heap.push(list_loc_as_cell!(6));
wam.heap.push(atom_as_cell!(atom!("a")));
wam.heap.push(list_loc_as_cell!(8));
wam.heap.push(atom_as_cell!(atom!("c")));
wam.heap.push(heap_loc_as_cell!(5));
unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
assert!(wam.fail);
wam.fail = false;
all_cells_unmarked(&wam.heap);
wam.heap.clear();
wam.heap.push(list_loc_as_cell!(1));
wam.heap.push(atom_as_cell!(atom!("a")));
wam.heap.push(list_loc_as_cell!(3));
wam.heap.push(atom_as_cell!(atom!("b")));
wam.heap.push(heap_loc_as_cell!(5));
wam.heap.push(list_loc_as_cell!(6));
wam.heap.push(atom_as_cell!(atom!("a")));
wam.heap.push(list_loc_as_cell!(8));
wam.heap.push(atom_as_cell!(atom!("b")));
wam.heap.push(heap_loc_as_cell!(0));
unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
assert!(!wam.fail);
all_cells_unmarked(&wam.heap);
wam.heap.clear();
{
let term_write_result_1 =
parse_and_write_parsed_term_to_heap(&mut wam, "X = g(X,y).", &op_dir).unwrap();
print_heap_terms(wam.heap.iter(), term_write_result_1.heap_loc);
unify!(wam, heap_loc_as_cell!(2), str_loc_as_cell!(4));
assert_eq!(wam.heap[2], str_loc_as_cell!(4));
}
}
#[test]
fn test_unify_with_occurs_check() {
let mut wam = MachineState::new();
let mut op_dir = default_op_dir();
op_dir.insert(
(atom!("+"), Fixity::In),
OpDesc::build_with(500, YFX as u8),
);
op_dir.insert(
(atom!("-"), Fixity::In),
OpDesc::build_with(500, YFX as u8),
);
op_dir.insert(
(atom!("*"), Fixity::In),
OpDesc::build_with(400, YFX as u8),
);
op_dir.insert(
(atom!("/"), Fixity::In),
OpDesc::build_with(400, YFX as u8),
);
{
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_2 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap();
all_cells_unmarked(&wam.heap);
unify_with_occurs_check!(
wam,
str_loc_as_cell!(0),
str_loc_as_cell!(term_write_result_2.heap_loc)
);
assert!(wam.fail);
}
}
#[test]
fn test_term_compare() {
use ordered_float::OrderedFloat;
use std::cmp::Ordering;
let mut wam = MachineState::new();
wam.heap.push(heap_loc_as_cell!(0));
wam.heap.push(heap_loc_as_cell!(1));
assert_eq!(
compare_term_test!(wam, wam.heap[0], wam.heap[1]),
Some(Ordering::Less)
);
assert_eq!(
compare_term_test!(wam, wam.heap[1], wam.heap[0]),
Some(Ordering::Greater)
);
assert_eq!(
compare_term_test!(wam, wam.heap[0], wam.heap[0]),
Some(Ordering::Equal)
);
assert_eq!(
compare_term_test!(wam, wam.heap[1], wam.heap[1]),
Some(Ordering::Equal)
);
assert_eq!(
compare_term_test!(
wam,
atom_as_cell!(atom!("atom")),
atom_as_cstr_cell!(atom!("string"))
),
Some(Ordering::Less)
);
assert_eq!(
compare_term_test!(
wam,
atom_as_cell!(atom!("atom")),
atom_as_cell!(atom!("atom"))
),
Some(Ordering::Equal)
);
assert_eq!(
compare_term_test!(
wam,
atom_as_cell!(atom!("atom")),
atom_as_cell!(atom!("aaa"))
),
Some(Ordering::Greater)
);
assert_eq!(
compare_term_test!(
wam,
fixnum_as_cell!(Fixnum::build_with(6)),
heap_loc_as_cell!(1)
),
Some(Ordering::Greater)
);
wam.heap.clear();
wam.heap.push(atom_as_cell!(atom!("f"), 1));
wam.heap.push(heap_loc_as_cell!(1));
assert_eq!(
compare_term_test!(
wam,
heap_loc_as_cell!(0),
heap_loc_as_cell!(0)
),
Some(Ordering::Equal)
);
assert_eq!(
compare_term_test!(
wam,
heap_loc_as_cell!(0),
atom_as_cell!(atom!("a"))
),
Some(Ordering::Greater)
);
wam.heap.clear();
// [1,2,3]
wam.heap.push(list_loc_as_cell!(1));
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1)));
wam.heap.push(list_loc_as_cell!(3));
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2)));
wam.heap.push(list_loc_as_cell!(5));
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(3)));
wam.heap.push(empty_list_as_cell!());
// [1,2]
wam.heap.push(list_loc_as_cell!(8));
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1)));
wam.heap.push(list_loc_as_cell!(10));
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2)));
wam.heap.push(empty_list_as_cell!());
assert_eq!(
compare_term_test!(
wam,
heap_loc_as_cell!(7),
heap_loc_as_cell!(7)
),
Some(Ordering::Equal)
);
assert_eq!(
compare_term_test!(
wam,
heap_loc_as_cell!(0),
heap_loc_as_cell!(7)
),
Some(Ordering::Greater)
);
assert_eq!(
compare_term_test!(
wam,
empty_list_as_cell!(),
heap_loc_as_cell!(7)
),
Some(Ordering::Less)
);
assert_eq!(
compare_term_test!(
wam,
empty_list_as_cell!(),
fixnum_as_cell!(Fixnum::build_with(1))
),
Some(Ordering::Greater)
);
assert_eq!(
compare_term_test!(
wam,
empty_list_as_cell!(),
atom_as_cstr_cell!(atom!("string"))
),
Some(Ordering::Less)
);
assert_eq!(
compare_term_test!(
wam,
empty_list_as_cell!(),
atom_as_cell!(atom!("atom"))
),
Some(Ordering::Less)
);
assert_eq!(
compare_term_test!(
wam,
atom_as_cell!(atom!("atom")),
empty_list_as_cell!()
),
Some(Ordering::Greater)
);
let one_p_one = typed_arena_ptr_as_cell!(
arena_alloc!(OrderedFloat(1.1), &mut wam.arena)
);
assert_eq!(
compare_term_test!(
wam,
one_p_one,
fixnum_as_cell!(Fixnum::build_with(1))
),
Some(Ordering::Less)
);
assert_eq!(
compare_term_test!(
wam,
fixnum_as_cell!(Fixnum::build_with(1)),
one_p_one
),
Some(Ordering::Greater)
);
}
#[test]
fn is_cyclic_term_tests() {
let mut wam = MachineState::new();
assert!(!wam.is_cyclic_term(atom_as_cell!(atom!("f"))));
assert!(!wam.is_cyclic_term(fixnum_as_cell!(Fixnum::build_with(555))));
wam.heap.push(heap_loc_as_cell!(0));
assert!(!wam.is_cyclic_term(heap_loc_as_cell!(0)));
all_cells_unmarked(&wam.heap);
wam.heap.clear();
wam.heap.extend(functor!(atom!("f"), [atom(atom!("a")), atom(atom!("b"))]));
assert!(!wam.is_cyclic_term(str_loc_as_cell!(0)));
all_cells_unmarked(&wam.heap);
assert!(!wam.is_cyclic_term(heap_loc_as_cell!(1)));
all_cells_unmarked(&wam.heap);
assert!(!wam.is_cyclic_term(heap_loc_as_cell!(2)));
all_cells_unmarked(&wam.heap);
wam.heap[2] = str_loc_as_cell!(0);
print_heap_terms(wam.heap.iter(), 0);
assert!(wam.is_cyclic_term(str_loc_as_cell!(0)));
all_cells_unmarked(&wam.heap);
wam.heap[2] = atom_as_cell!(atom!("b"));
wam.heap[1] = str_loc_as_cell!(0);
assert!(wam.is_cyclic_term(str_loc_as_cell!(0)));
all_cells_unmarked(&wam.heap);
assert!(wam.is_cyclic_term(heap_loc_as_cell!(1)));
all_cells_unmarked(&wam.heap);
wam.heap.clear();
wam.heap.push(pstr_as_cell!(atom!("a string")));
wam.heap.push(empty_list_as_cell!());
assert!(!wam.is_cyclic_term(pstr_loc_as_cell!(0)));
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,10 @@
use prolog_parser::ast::*; use crate::atom_table::*;
use prolog_parser::tabled_rc::*;
use prolog_parser::{atom, clause_name, rc_atom};
use crate::forms::*; use crate::forms::*;
use crate::instructions::*;
use crate::iterators::*; use crate::iterators::*;
use crate::machine::load_state::*; use crate::machine::loader::*;
use crate::machine::machine_errors::*; use crate::machine::machine_errors::*;
use crate::machine::*; use crate::parser::ast::*;
use indexmap::IndexSet; use indexmap::IndexSet;
@@ -30,89 +28,81 @@ pub(crate) enum CutContext {
HasCutVariable, HasCutVariable,
} }
pub(crate) fn fold_by_str<I>(terms: I, mut term: Term, sym: ClauseName) -> Term pub(crate) fn fold_by_str<I>(terms: I, mut term: Term, sym: Atom) -> Term
where where
I: DoubleEndedIterator<Item = Term>, I: DoubleEndedIterator<Item = Term>,
{ {
for prec in terms.rev() { for prec in terms.rev() {
term = Term::Clause( term = Term::Clause(Cell::default(), sym, vec![prec, term]);
Cell::default(),
sym.clone(),
vec![Box::new(prec), Box::new(term)],
None,
);
} }
term term
} }
pub(crate) fn to_op_decl( pub(crate) fn to_op_decl(
prec: usize, prec: u16,
spec: &str, spec: Atom,
name: ClauseName, name: Atom,
) -> Result<OpDecl, CompilationError> { ) -> Result<OpDecl, CompilationError> {
match spec { match spec {
"xfx" => Ok(OpDecl::new(prec, XFX, name)), atom!("xfx") => Ok(OpDecl::new(OpDesc::build_with(prec, XFX as u8), name)),
"xfy" => Ok(OpDecl::new(prec, XFY, name)), atom!("xfy") => Ok(OpDecl::new(OpDesc::build_with(prec, XFY as u8), name)),
"yfx" => Ok(OpDecl::new(prec, YFX, name)), atom!("yfx") => Ok(OpDecl::new(OpDesc::build_with(prec, YFX as u8), name)),
"fx" => Ok(OpDecl::new(prec, FX, name)), atom!("fx") => Ok(OpDecl::new(OpDesc::build_with(prec, FX as u8), name)),
"fy" => Ok(OpDecl::new(prec, FY, name)), atom!("fy") => Ok(OpDecl::new(OpDesc::build_with(prec, FY as u8), name)),
"xf" => Ok(OpDecl::new(prec, XF, name)), atom!("xf") => Ok(OpDecl::new(OpDesc::build_with(prec, XF as u8), name)),
"yf" => Ok(OpDecl::new(prec, YF, name)), atom!("yf") => Ok(OpDecl::new(OpDesc::build_with(prec, YF as u8), name)),
_ => Err(CompilationError::InconsistentEntry), _ => Err(CompilationError::InconsistentEntry),
} }
} }
fn setup_op_decl( fn setup_op_decl(
mut terms: Vec<Box<Term>>, mut terms: Vec<Term>,
atom_tbl: TabledData<Atom>, atom_tbl: &mut AtomTable,
) -> Result<OpDecl, CompilationError> { ) -> Result<OpDecl, CompilationError> {
let name = match *terms.pop().unwrap() { let name = match terms.pop().unwrap() {
Term::Constant(_, Constant::Atom(name, _)) => name, Term::Literal(_, Literal::Atom(name)) => name,
Term::Constant(_, Constant::Char(c)) => clause_name!(c.to_string(), atom_tbl), Term::Literal(_, Literal::Char(c)) => atom_tbl.build_with(&c.to_string()),
_ => return Err(CompilationError::InconsistentEntry), _ => return Err(CompilationError::InconsistentEntry),
}; };
let spec = match *terms.pop().unwrap() { let spec = match terms.pop().unwrap() {
Term::Constant(_, Constant::Atom(name, _)) => name, Term::Literal(_, Literal::Atom(name)) => name,
Term::Constant(_, Constant::Char(c)) => clause_name!(c.to_string(), atom_tbl), Term::Literal(_, Literal::Char(c)) => atom_tbl.build_with(&c.to_string()),
_ => return Err(CompilationError::InconsistentEntry), _ => return Err(CompilationError::InconsistentEntry),
}; };
let prec = match *terms.pop().unwrap() { let prec = match terms.pop().unwrap() {
Term::Constant(_, Constant::Fixnum(bi)) => match usize::try_from(bi) { Term::Literal(_, Literal::Fixnum(bi)) => match u16::try_from(bi.get_num()) {
Ok(n) if n <= 1200 => n, Ok(n) if n <= 1200 => n,
_ => return Err(CompilationError::InconsistentEntry), _ => return Err(CompilationError::InconsistentEntry),
}, },
_ => return Err(CompilationError::InconsistentEntry), _ => return Err(CompilationError::InconsistentEntry),
}; };
to_op_decl(prec, spec.as_str(), name) to_op_decl(prec, spec, name)
} }
fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, CompilationError> { fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, CompilationError> {
match term { match term {
Term::Clause(_, ref slash, ref mut terms, Some(_)) Term::Clause(_, slash, ref mut terms)
if (slash.as_str() == "/" || slash.as_str() == "//") && terms.len() == 2 => if (*slash == atom!("/") || *slash == atom!("//")) && terms.len() == 2 =>
{ {
let arity = *terms.pop().unwrap(); let arity = terms.pop().unwrap();
let name = *terms.pop().unwrap(); let name = terms.pop().unwrap();
let arity = arity let arity = match arity {
.into_constant() Term::Literal(_, Literal::Integer(n)) => n.to_usize(),
.and_then(|c| match c { Term::Literal(_, Literal::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
Constant::Integer(n) => n.to_usize(),
Constant::Fixnum(n) => usize::try_from(n).ok(),
_ => None, _ => None,
}) }.ok_or(CompilationError::InvalidModuleExport)?;
.ok_or(CompilationError::InvalidModuleExport)?;
let name = name let name = match name {
.into_constant() Term::Literal(_, Literal::Atom(name)) => Some(name),
.and_then(|c| c.to_atom()) _ => None,
.ok_or(CompilationError::InvalidModuleExport)?; }.ok_or(CompilationError::InvalidModuleExport)?;
if slash.as_str() == "/" { if *slash == atom!("/") {
Ok((name, arity)) Ok((name, arity))
} else { } else {
Ok((name, arity + 2)) Ok((name, arity + 2))
@@ -148,13 +138,13 @@ fn setup_scoped_predicate_indicator(term: &mut Term) -> Result<ScopedPredicateKe
fn setup_module_export( fn setup_module_export(
mut term: Term, mut term: Term,
atom_tbl: TabledData<Atom>, atom_tbl: &mut AtomTable,
) -> Result<ModuleExport, CompilationError> { ) -> Result<ModuleExport, CompilationError> {
setup_predicate_indicator(&mut term) setup_predicate_indicator(&mut term)
.map(ModuleExport::PredicateKey) .map(ModuleExport::PredicateKey)
.or_else(|_| { .or_else(|_| {
if let Term::Clause(_, name, terms, _) = term { if let Term::Clause(_, name, terms) = term {
if terms.len() == 3 && name.as_str() == "op" { if terms.len() == 3 && name == atom!("op") {
Ok(ModuleExport::OpDecl(setup_op_decl(terms, atom_tbl)?)) Ok(ModuleExport::OpDecl(setup_op_decl(terms, atom_tbl)?))
} else { } else {
Err(CompilationError::InvalidModuleDecl) Err(CompilationError::InvalidModuleDecl)
@@ -167,18 +157,18 @@ fn setup_module_export(
pub(super) fn setup_module_export_list( pub(super) fn setup_module_export_list(
mut export_list: Term, mut export_list: Term,
atom_tbl: TabledData<Atom>, atom_tbl: &mut AtomTable,
) -> Result<Vec<ModuleExport>, CompilationError> { ) -> Result<Vec<ModuleExport>, CompilationError> {
let mut exports = vec![]; let mut exports = vec![];
while let Term::Cons(_, t1, t2) = export_list { while let Term::Cons(_, t1, t2) = export_list {
let module_export = setup_module_export(*t1, atom_tbl.clone())?; let module_export = setup_module_export(*t1, atom_tbl)?;
exports.push(module_export); exports.push(module_export);
export_list = *t2; export_list = *t2;
} }
if let Term::Constant(_, Constant::EmptyList) = export_list { if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list {
Ok(exports) Ok(exports)
} else { } else {
Err(CompilationError::InvalidModuleDecl) Err(CompilationError::InvalidModuleDecl)
@@ -186,98 +176,65 @@ pub(super) fn setup_module_export_list(
} }
fn setup_module_decl( fn setup_module_decl(
mut terms: Vec<Box<Term>>, mut terms: Vec<Term>,
atom_tbl: TabledData<Atom>, atom_tbl: &mut AtomTable,
) -> Result<ModuleDecl, CompilationError> { ) -> Result<ModuleDecl, CompilationError> {
let export_list = *terms.pop().unwrap(); let export_list = terms.pop().unwrap();
let name = terms let name = terms.pop().unwrap();
.pop()
.unwrap() let name = match name {
.into_constant() Term::Literal(_, Literal::Atom(name)) => Some(name),
.and_then(|c| c.to_atom()) _ => None,
.ok_or(CompilationError::InvalidModuleDecl)?; }.ok_or(CompilationError::InvalidModuleDecl)?;
let exports = setup_module_export_list(export_list, atom_tbl)?; let exports = setup_module_export_list(export_list, atom_tbl)?;
Ok(ModuleDecl { name, exports }) Ok(ModuleDecl { name, exports })
} }
fn setup_use_module_decl(mut terms: Vec<Box<Term>>) -> Result<ModuleSource, CompilationError> { fn setup_use_module_decl(mut terms: Vec<Term>) -> Result<ModuleSource, CompilationError> {
match *terms.pop().unwrap() { match terms.pop().unwrap() {
Term::Clause(_, ref name, ref mut terms, None) Term::Clause(_, name, mut terms)
if name.as_str() == "library" && terms.len() == 1 => if name == atom!("library") && terms.len() == 1 =>
{ {
terms match terms.pop().unwrap() {
.pop() Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)),
.unwrap() _ => Err(CompilationError::InvalidModuleDecl),
.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())), }
Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)),
_ => Err(CompilationError::InvalidUseModuleDecl), _ => 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>); type UseModuleExport = (ModuleSource, IndexSet<ModuleExport>);
fn setup_qualified_import( fn setup_qualified_import(
mut terms: Vec<Box<Term>>, mut terms: Vec<Term>,
atom_tbl: TabledData<Atom>, atom_tbl: &mut AtomTable,
) -> Result<UseModuleExport, CompilationError> { ) -> Result<UseModuleExport, CompilationError> {
let mut export_list = *terms.pop().unwrap(); let mut export_list = terms.pop().unwrap();
let module_src = match *terms.pop().unwrap() { let module_src = match terms.pop().unwrap() {
Term::Clause(_, ref name, ref mut terms, None) Term::Clause(_, name, mut terms)
if name.as_str() == "library" && terms.len() == 1 => if name == atom!("library") && terms.len() == 1 =>
{ {
terms match terms.pop().unwrap() {
.pop() Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)),
.unwrap() _ => Err(CompilationError::InvalidModuleDecl),
.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())), }
Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)),
_ => Err(CompilationError::InvalidUseModuleDecl), _ => Err(CompilationError::InvalidUseModuleDecl),
}?; }?;
let mut exports = IndexSet::new(); let mut exports = IndexSet::new();
while let Term::Cons(_, t1, t2) = export_list { while let Term::Cons(_, t1, t2) = export_list {
exports.insert(setup_module_export(*t1, atom_tbl.clone())?); exports.insert(setup_module_export(*t1, atom_tbl)?);
export_list = *t2; export_list = *t2;
} }
if let Term::Constant(_, Constant::EmptyList) = export_list { if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list {
Ok((module_src, exports)) Ok((module_src, exports))
} else { } else {
Err(CompilationError::InvalidModuleDecl) Err(CompilationError::InvalidModuleDecl)
@@ -322,29 +279,29 @@ fn setup_qualified_import(
* - * -
* ? * ?
*/ */
fn setup_meta_predicate<'a>( fn setup_meta_predicate<'a, LS: LoadState<'a>>(
mut terms: Vec<Box<Term>>, mut terms: Vec<Term>,
load_state: &LoadState<'a>, loader: &mut Loader<'a, LS>,
) -> Result<(ClauseName, ClauseName, Vec<MetaSpec>), CompilationError> { ) -> Result<(Atom, Atom, Vec<MetaSpec>), CompilationError> {
fn get_name_and_meta_specs( fn get_name_and_meta_specs(
name: ClauseName, name: Atom,
terms: &mut [Box<Term>], terms: &mut [Term],
) -> Result<(ClauseName, Vec<MetaSpec>), CompilationError> { ) -> Result<(Atom, Vec<MetaSpec>), CompilationError> {
let mut meta_specs = vec![]; let mut meta_specs = vec![];
for meta_spec in terms.into_iter() { for meta_spec in terms.into_iter() {
match &**meta_spec { match meta_spec {
Term::Constant(_, Constant::Atom(meta_spec, _)) => { Term::Literal(_, Literal::Atom(meta_spec)) => {
let meta_spec = match meta_spec.as_str() { let meta_spec = match meta_spec {
"+" => MetaSpec::Plus, atom!("+") => MetaSpec::Plus,
"-" => MetaSpec::Minus, atom!("-") => MetaSpec::Minus,
"?" => MetaSpec::Either, atom!("?") => MetaSpec::Either,
_ => return Err(CompilationError::InvalidMetaPredicateDecl), _ => return Err(CompilationError::InvalidMetaPredicateDecl),
}; };
meta_specs.push(meta_spec); meta_specs.push(meta_spec);
} }
Term::Constant(_, Constant::Fixnum(n)) => match usize::try_from(*n) { Term::Literal(_, Literal::Fixnum(n)) => match usize::try_from(n.get_num()) {
Ok(n) if n <= MAX_ARITY => { Ok(n) if n <= MAX_ARITY => {
meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n)); meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n));
} }
@@ -361,16 +318,15 @@ fn setup_meta_predicate<'a>(
Ok((name, meta_specs)) Ok((name, meta_specs))
} }
match *terms.pop().unwrap() { match terms.pop().unwrap() {
Term::Clause(_, name, mut terms, _) if name.as_str() == ":" && terms.len() == 2 => { Term::Clause(_, name, mut terms) if name == atom!(":") && terms.len() == 2 => {
let spec = *terms.pop().unwrap(); let spec = terms.pop().unwrap();
let module_name = *terms.pop().unwrap(); let module_name = terms.pop().unwrap();
match module_name { match module_name {
Term::Constant(_, Constant::Atom(module_name, _)) => match spec { Term::Literal(_, Literal::Atom(module_name)) => match spec {
Term::Clause(_, name, mut terms, _) => { Term::Clause(_, name, mut terms) => {
let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?; let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?;
Ok((module_name, name, meta_specs)) Ok((module_name, name, meta_specs))
} }
_ => Err(CompilationError::InvalidMetaPredicateDecl), _ => Err(CompilationError::InvalidMetaPredicateDecl),
@@ -378,10 +334,10 @@ fn setup_meta_predicate<'a>(
_ => Err(CompilationError::InvalidMetaPredicateDecl), _ => Err(CompilationError::InvalidMetaPredicateDecl),
} }
} }
Term::Clause(_, name, mut terms, _) => { Term::Clause(_, name, mut terms) => {
let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?; let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?;
Ok(( Ok((
load_state.compilation_target.module_name(), loader.payload.compilation_target.module_name(),
name, name,
meta_specs, meta_specs,
)) ))
@@ -420,11 +376,11 @@ fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, CompilationEr
} }
} }
fn mark_cut_variables_as(terms: &mut Vec<Term>, name: ClauseName) { fn mark_cut_variables_as(terms: &mut Vec<Term>, name: Atom) {
for term in terms.iter_mut() { for term in terms.iter_mut() {
match term { match term {
&mut Term::Constant(_, Constant::Atom(ref mut var, _)) if var.as_str() == "!" => { &mut Term::Literal(_, Literal::Atom(ref mut var)) if *var == atom!("!") => {
*var = name.clone() *var = name;
} }
_ => {} _ => {}
} }
@@ -433,12 +389,12 @@ fn mark_cut_variables_as(terms: &mut Vec<Term>, name: ClauseName) {
fn mark_cut_variable(term: &mut Term) -> bool { fn mark_cut_variable(term: &mut Term) -> bool {
let cut_var_found = match term { let cut_var_found = match term {
&mut Term::Constant(_, Constant::Atom(ref var, _)) if var.as_str() == "!" => true, &mut Term::Literal(_, Literal::Atom(ref var)) if *var == atom!("!") => true,
_ => false, _ => false,
}; };
if cut_var_found { if cut_var_found {
*term = Term::Var(Cell::default(), rc_atom!("!")); *term = Term::Var(Cell::default(), Rc::new(String::from("!")));
true true
} else { } else {
false false
@@ -463,21 +419,21 @@ fn check_for_internal_if_then(terms: &mut Vec<Term>) {
return; return;
} }
if let Some(Term::Clause(_, ref name, ref subterms, _)) = terms.last() { if let Some(Term::Clause(_, name, ref subterms)) = terms.last() {
if name.as_str() != "->" || subterms.len() != 2 { if *name != atom!("->") || subterms.len() != 2 {
return; return;
} }
} else { } else {
return; return;
} }
if let Some(Term::Clause(_, _, mut subterms, _)) = terms.pop() { if let Some(Term::Clause(_, _, mut subterms)) = terms.pop() {
let mut conq_terms = VecDeque::from(unfold_by_str(*subterms.pop().unwrap(), ",")); let mut conq_terms = VecDeque::from(unfold_by_str(subterms.pop().unwrap(), atom!(",")));
let mut pre_cut_terms = VecDeque::from(unfold_by_str(*subterms.pop().unwrap(), ",")); let mut pre_cut_terms = VecDeque::from(unfold_by_str(subterms.pop().unwrap(), atom!(",")));
conq_terms.push_front(Term::Constant( conq_terms.push_front(Term::Literal(
Cell::default(), Cell::default(),
Constant::Atom(clause_name!("blocked_!"), None), Literal::Atom(atom!("blocked_!")),
)); ));
while let Some(term) = pre_cut_terms.pop_back() { while let Some(term) = pre_cut_terms.pop_back() {
@@ -489,37 +445,44 @@ fn check_for_internal_if_then(terms: &mut Vec<Term>) {
terms.push(fold_by_str( terms.push(fold_by_str(
conq_terms.into_iter(), conq_terms.into_iter(),
tail_term, tail_term,
clause_name!(","), atom!(","),
)); ));
} }
} }
pub(super) fn setup_declaration<'a>( pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
load_state: &LoadState<'a>, loader: &mut Loader<'a, LS>,
mut terms: Vec<Box<Term>>, mut terms: Vec<Term>,
) -> Result<Declaration, CompilationError> { ) -> Result<Declaration, CompilationError> {
let term = *terms.pop().unwrap(); let term = terms.pop().unwrap();
let atom_tbl = load_state.wam.machine_st.atom_tbl.clone();
match term { match term {
Term::Clause(_, name, mut terms, _) => match (name.as_str(), terms.len()) { Term::Clause(_, name, mut terms) => match (name, terms.len()) {
("dynamic", 1) => { (atom!("dynamic"), 1) => {
let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?; let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
Ok(Declaration::Dynamic(name, arity)) Ok(Declaration::Dynamic(name, arity))
} }
("module", 2) => Ok(Declaration::Module(setup_module_decl(terms, atom_tbl)?)), (atom!("module"), 2) => {
("op", 3) => Ok(Declaration::Op(setup_op_decl(terms, atom_tbl)?)), let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl;
("non_counted_backtracking", 1) => { Ok(Declaration::Module(setup_module_decl(terms, atom_tbl)?))
let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?; }
(atom!("op"), 3) => {
let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl;
Ok(Declaration::Op(setup_op_decl(terms, atom_tbl)?))
}
(atom!("non_counted_backtracking"), 1) => {
let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
Ok(Declaration::NonCountedBacktracking(name, arity)) Ok(Declaration::NonCountedBacktracking(name, arity))
} }
("use_module", 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)), (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)),
("use_module", 2) => { (atom!("use_module"), 2) => {
let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl;
let (name, exports) = setup_qualified_import(terms, atom_tbl)?; let (name, exports) = setup_qualified_import(terms, atom_tbl)?;
Ok(Declaration::UseQualifiedModule(name, exports)) Ok(Declaration::UseQualifiedModule(name, exports))
} }
("meta_predicate", 1) => { (atom!("meta_predicate"), 1) => {
let (module_name, name, meta_specs) = setup_meta_predicate(terms, load_state)?; let (module_name, name, meta_specs) = setup_meta_predicate(terms, loader)?;
Ok(Declaration::MetaPredicate(module_name, name, meta_specs)) Ok(Declaration::MetaPredicate(module_name, name, meta_specs))
} }
_ => Err(CompilationError::InconsistentEntry), _ => Err(CompilationError::InconsistentEntry),
@@ -529,25 +492,23 @@ pub(super) fn setup_declaration<'a>(
} }
#[inline] #[inline]
fn clause_to_query_term<'a>( fn clause_to_query_term<'a, LS: LoadState<'a>>(
load_state: &mut LoadState<'a>, loader: &mut Loader<'a, LS>,
name: ClauseName, name: Atom,
terms: Vec<Box<Term>>, terms: Vec<Term>,
fixity: Option<SharedOpDesc>,
) -> QueryTerm { ) -> QueryTerm {
let ct = load_state.get_clause_type(name, terms.len(), fixity); let ct = loader.get_clause_type(name, terms.len());
QueryTerm::Clause(Cell::default(), ct, terms, false) QueryTerm::Clause(Cell::default(), ct, terms, false)
} }
#[inline] #[inline]
fn qualified_clause_to_query_term<'a>( fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
load_state: &mut LoadState<'a>, loader: &mut Loader<'a, LS>,
module_name: ClauseName, module_name: Atom,
name: ClauseName, name: Atom,
terms: Vec<Box<Term>>, terms: Vec<Term>,
fixity: Option<SharedOpDesc>,
) -> QueryTerm { ) -> QueryTerm {
let ct = load_state.get_qualified_clause_type(module_name, name, terms.len(), fixity); let ct = loader.get_qualified_clause_type(module_name, name, terms.len());
QueryTerm::Clause(Cell::default(), ct, terms, false) QueryTerm::Clause(Cell::default(), ct, terms, false)
} }
@@ -565,7 +526,7 @@ impl Preprocessor {
fn setup_fact(&mut self, term: Term) -> Result<Term, CompilationError> { fn setup_fact(&mut self, term: Term) -> Result<Term, CompilationError> {
match term { match term {
Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => Ok(term), Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => Ok(term),
_ => Err(CompilationError::InadmissibleFact), _ => Err(CompilationError::InadmissibleFact),
} }
} }
@@ -579,20 +540,17 @@ impl Preprocessor {
} }
} }
vars.insert(rc_atom!("!")); vars.insert(Rc::new(String::from("!")));
vars.into_iter() vars.into_iter()
.map(|v| Term::Var(Cell::default(), v)) .map(|v| Term::Var(Cell::default(), v))
.collect() .collect()
} }
fn fabricate_rule_body(&self, vars: &Vec<Term>, body_term: Term) -> Term { 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(), atom!(""), vars.clone());
let head_term = Term::Clause(Cell::default(), clause_name!(""), vars_of_head, None); let rule = vec![head_term, body_term];
let rule = vec![Box::new(head_term), Box::new(body_term)]; Term::Clause(Cell::default(), atom!(":-"), rule)
let turnstile = clause_name!(":-");
Term::Clause(Cell::default(), turnstile, rule, None)
} }
// the terms form the body of the rule. We create a head, by // the terms form the body of the rule. We create a head, by
@@ -609,16 +567,16 @@ impl Preprocessor {
fn fabricate_disjunct(&self, body_term: Term) -> (JumpStub, VecDeque<Term>) { fn fabricate_disjunct(&self, body_term: Term) -> (JumpStub, VecDeque<Term>) {
let vars = self.compute_head(&body_term); let vars = self.compute_head(&body_term);
let results = unfold_by_str(body_term, ";") let results = unfold_by_str(body_term, atom!(";"))
.into_iter() .into_iter()
.map(|term| { .map(|term| {
let mut subterms = unfold_by_str(term, ","); let mut subterms = unfold_by_str(term, atom!(","));
mark_cut_variables(&mut subterms); mark_cut_variables(&mut subterms);
check_for_internal_if_then(&mut subterms); check_for_internal_if_then(&mut subterms);
let term = subterms.pop().unwrap(); let term = subterms.pop().unwrap();
let clause = fold_by_str(subterms.into_iter(), term, clause_name!(",")); let clause = fold_by_str(subterms.into_iter(), term, atom!(","));
self.fabricate_rule_body(&vars, clause) self.fabricate_rule_body(&vars, clause)
}) })
@@ -628,80 +586,78 @@ impl Preprocessor {
} }
fn fabricate_if_then(&self, prec: Term, conq: Term) -> (JumpStub, VecDeque<Term>) { fn fabricate_if_then(&self, prec: Term, conq: Term) -> (JumpStub, VecDeque<Term>) {
let mut prec_seq = unfold_by_str(prec, ","); let mut prec_seq = unfold_by_str(prec, atom!(","));
let comma_sym = clause_name!(","); let comma_sym = atom!(",");
let cut_sym = atom!("!"); let cut_sym = Literal::Atom(atom!("!"));
prec_seq.push(Term::Constant(Cell::default(), cut_sym)); prec_seq.push(Term::Literal(Cell::default(), cut_sym));
mark_cut_variables_as(&mut prec_seq, clause_name!("blocked_!")); mark_cut_variables_as(&mut prec_seq, atom!("blocked_!"));
let mut conq_seq = unfold_by_str(conq, ","); let mut conq_seq = unfold_by_str(conq, atom!(","));
mark_cut_variables(&mut conq_seq); mark_cut_variables(&mut conq_seq);
prec_seq.extend(conq_seq.into_iter()); prec_seq.extend(conq_seq.into_iter());
let back_term = Box::new(prec_seq.pop().unwrap()); let back_term = prec_seq.pop().unwrap();
let front_term = Box::new(prec_seq.pop().unwrap()); let front_term = prec_seq.pop().unwrap();
let body_term = Term::Clause( let body_term = Term::Clause(
Cell::default(), Cell::default(),
comma_sym.clone(), comma_sym,
vec![front_term, back_term], vec![front_term, back_term],
None,
); );
self.fabricate_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym)) self.fabricate_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym))
} }
fn to_query_term<'a>( fn to_query_term<'a, LS: LoadState<'a>>(
&mut self, &mut self,
load_state: &mut LoadState<'a>, loader: &mut Loader<'a, LS>,
term: Term, term: Term,
) -> Result<QueryTerm, CompilationError> { ) -> Result<QueryTerm, CompilationError> {
match term { match term {
Term::Constant(_, Constant::Atom(name, fixity)) => { Term::Literal(_, Literal::Atom(name)) => {
if name.as_str() == "!" || name.as_str() == "blocked_!" { if name == atom!("!") || name == atom!("blocked_!") {
Ok(QueryTerm::BlockedCut) Ok(QueryTerm::BlockedCut)
} else { } else {
Ok(clause_to_query_term(load_state, name, vec![], fixity)) Ok(clause_to_query_term(loader, name, vec![]))
} }
} }
Term::Constant(_, Constant::Char('!')) => Ok(QueryTerm::BlockedCut), Term::Literal(_, Literal::Char('!')) => Ok(QueryTerm::BlockedCut),
Term::Var(_, ref v) if v.as_str() == "!" => { Term::Var(_, ref v) if v.as_str() == "!" => {
Ok(QueryTerm::UnblockedCut(Cell::default())) Ok(QueryTerm::UnblockedCut(Cell::default()))
} }
Term::Clause(r, name, mut terms, fixity) => match (name.as_str(), terms.len()) { Term::Clause(r, name, mut terms) => match (name, terms.len()) {
(";", 2) => { (atom!(";"), 2) => {
let term = Term::Clause(r, name.clone(), terms, fixity); let term = Term::Clause(r, name, terms);
let (stub, clauses) = self.fabricate_disjunct(term); let (stub, clauses) = self.fabricate_disjunct(term);
self.queue.push_back(clauses); self.queue.push_back(clauses);
Ok(QueryTerm::Jump(stub)) Ok(QueryTerm::Jump(stub))
} }
("->", 2) => { (atom!("->"), 2) => {
let conq = *terms.pop().unwrap(); let conq = terms.pop().unwrap();
let prec = *terms.pop().unwrap(); let prec = terms.pop().unwrap();
let (stub, clauses) = self.fabricate_if_then(prec, conq); let (stub, clauses) = self.fabricate_if_then(prec, conq);
self.queue.push_back(clauses); self.queue.push_back(clauses);
Ok(QueryTerm::Jump(stub)) Ok(QueryTerm::Jump(stub))
} }
("\\+", 1) => { (atom!("\\+"), 1) => {
terms.push(Box::new(Term::Constant( terms.push(Term::Literal(
Cell::default(), Cell::default(),
Constant::Atom(clause_name!("$fail"), None), Literal::Atom(atom!("$fail")),
))); ));
let conq = let conq = Term::Literal(Cell::default(), Literal::Atom(atom!("true")));
Term::Constant(Cell::default(), Constant::Atom(clause_name!("true"), None));
let prec = Term::Clause(Cell::default(), clause_name!("->"), terms, None); let prec = Term::Clause(Cell::default(), atom!("->"), terms);
let terms = vec![Box::new(prec), Box::new(conq)]; let terms = vec![prec, conq];
let term = Term::Clause(Cell::default(), clause_name!(";"), terms, None); let term = Term::Clause(Cell::default(), atom!(";"), terms);
let (stub, clauses) = self.fabricate_disjunct(term); let (stub, clauses) = self.fabricate_disjunct(term);
debug_assert!(clauses.len() > 0); debug_assert!(clauses.len() > 0);
@@ -709,104 +665,102 @@ impl Preprocessor {
Ok(QueryTerm::Jump(stub)) Ok(QueryTerm::Jump(stub))
} }
("$get_level", 1) => { (atom!("$get_level"), 1) => {
if let Term::Var(_, ref var) = *terms[0] { if let Term::Var(_, ref var) = &terms[0] {
Ok(QueryTerm::GetLevelAndUnify(Cell::default(), var.clone())) Ok(QueryTerm::GetLevelAndUnify(Cell::default(), var.clone()))
} else { } else {
Err(CompilationError::InadmissibleQueryTerm) Err(CompilationError::InadmissibleQueryTerm)
} }
} }
(":", 2) => { (atom!(":"), 2) => {
let predicate_name = *terms.pop().unwrap(); let predicate_name = terms.pop().unwrap();
let module_name = *terms.pop().unwrap(); let module_name = terms.pop().unwrap();
match (module_name, predicate_name) { match (module_name, predicate_name) {
( (
Term::Constant(_, Constant::Atom(module_name, _)), Term::Literal(_, Literal::Atom(module_name)),
Term::Constant(_, Constant::Atom(predicate_name, fixity)), Term::Literal(_, Literal::Atom(predicate_name)),
) => Ok(qualified_clause_to_query_term( ) => Ok(qualified_clause_to_query_term(
load_state, loader,
module_name, module_name,
predicate_name, predicate_name,
vec![], vec![],
fixity,
)), )),
( (
Term::Constant(_, Constant::Atom(module_name, _)), Term::Literal(_, Literal::Atom(module_name)),
Term::Clause(_, name, terms, fixity), Term::Clause(_, name, terms),
) => Ok(qualified_clause_to_query_term( ) => Ok(qualified_clause_to_query_term(
load_state, loader,
module_name, module_name,
name, name,
terms, terms,
fixity,
)), )),
(module_name, predicate_name) => { (module_name, predicate_name) => {
terms.push(Box::new(module_name)); terms.push(module_name);
terms.push(Box::new(predicate_name)); terms.push(predicate_name);
Ok(clause_to_query_term(load_state, name, terms, fixity)) Ok(clause_to_query_term(loader, name, terms))
} }
} }
} }
_ => Ok(clause_to_query_term(load_state, name, terms, fixity)), _ => Ok(clause_to_query_term(loader, name, terms)),
}, },
Term::Var(..) => Ok(QueryTerm::Clause( Term::Var(..) => Ok(QueryTerm::Clause(
Cell::default(), Cell::default(),
ClauseType::CallN, ClauseType::CallN(1),
vec![Box::new(term)], vec![term],
false, false,
)), )),
_ => Err(CompilationError::InadmissibleQueryTerm), _ => Err(CompilationError::InadmissibleQueryTerm),
} }
} }
fn pre_query_term<'a>( fn pre_query_term<'a, LS: LoadState<'a>>(
&mut self, &mut self,
load_state: &mut LoadState<'a>, loader: &mut Loader<'a, LS>,
term: Term, term: Term,
) -> Result<QueryTerm, CompilationError> { ) -> Result<QueryTerm, CompilationError> {
match term { match term {
Term::Clause(r, name, mut subterms, fixity) => { Term::Clause(r, name, mut subterms) => {
if subterms.len() == 1 && name.as_str() == "$call_with_default_policy" { if subterms.len() == 1 && name == atom!("$call_with_default_policy") {
self.to_query_term(load_state, *subterms.pop().unwrap()) self.to_query_term(loader, subterms.pop().unwrap())
.map(|mut query_term| { .map(|mut query_term| {
query_term.set_default_caller(); query_term.set_default_caller();
query_term query_term
}) })
} else { } else {
let clause = Term::Clause(r, name, subterms, fixity); let clause = Term::Clause(r, name, subterms);
self.to_query_term(load_state, clause) self.to_query_term(loader, clause)
} }
} }
_ => self.to_query_term(load_state, term), _ => self.to_query_term(loader, term),
} }
} }
fn setup_query<'a>( fn setup_query<'a, LS: LoadState<'a>>(
&mut self, &mut self,
load_state: &mut LoadState<'a>, loader: &mut Loader<'a, LS>,
terms: Vec<Box<Term>>, terms: Vec<Term>,
cut_context: CutContext, cut_context: CutContext,
) -> Result<Vec<QueryTerm>, CompilationError> { ) -> Result<Vec<QueryTerm>, CompilationError> {
let mut query_terms = vec![]; let mut query_terms = vec![];
let mut work_queue = VecDeque::from(terms); let mut work_queue = VecDeque::from(terms);
while let Some(term) = work_queue.pop_front() { while let Some(term) = work_queue.pop_front() {
let mut term = *term; let mut term = term;
if let Term::Clause(cell, name, terms, op_spec) = term { if let Term::Clause(cell, name, terms) = term {
if name.as_str() == "," && terms.len() == 2 { if name == atom!(",") && terms.len() == 2 {
let term = Term::Clause(cell, name, terms, op_spec); let term = Term::Clause(cell, name, terms);
let mut subterms = unfold_by_str(term, ","); let mut subterms = unfold_by_str(term, atom!(","));
while let Some(subterm) = subterms.pop() { while let Some(subterm) = subterms.pop() {
work_queue.push_front(Box::new(subterm)); work_queue.push_front(subterm);
} }
continue; continue;
} else { } else {
term = Term::Clause(cell, name, terms, op_spec); term = Term::Clause(cell, name, terms);
} }
} }
@@ -814,30 +768,30 @@ impl Preprocessor {
mark_cut_variable(&mut term); mark_cut_variable(&mut term);
} }
query_terms.push(self.pre_query_term(load_state, term)?); query_terms.push(self.pre_query_term(loader, term)?);
} }
Ok(query_terms) Ok(query_terms)
} }
fn setup_rule<'a>( fn setup_rule<'a, LS: LoadState<'a>>(
&mut self, &mut self,
load_state: &mut LoadState<'a>, loader: &mut Loader<'a, LS>,
mut terms: Vec<Box<Term>>, mut terms: Vec<Term>,
cut_context: CutContext, cut_context: CutContext,
) -> Result<Rule, CompilationError> { ) -> Result<Rule, CompilationError> {
let post_head_terms: Vec<_> = terms.drain(1..).collect(); let post_head_terms: Vec<_> = terms.drain(1..).collect();
let mut query_terms = self.setup_query(load_state, post_head_terms, cut_context)?; let mut query_terms = self.setup_query(loader, post_head_terms, cut_context)?;
let clauses = query_terms.drain(1..).collect(); let clauses = query_terms.drain(1..).collect();
let qt = query_terms.pop().unwrap(); let qt = query_terms.pop().unwrap();
match *terms.pop().unwrap() { match terms.pop().unwrap() {
Term::Clause(_, name, terms, _) => Ok(Rule { Term::Clause(_, name, terms) => Ok(Rule {
head: (name, terms, qt), head: (name, terms, qt),
clauses, clauses,
}), }),
Term::Constant(_, Constant::Atom(name, _)) => Ok(Rule { Term::Literal(_, Literal::Atom(name)) => Ok(Rule {
head: (name, vec![], qt), head: (name, vec![], qt),
clauses, clauses,
}), }),
@@ -845,37 +799,37 @@ impl Preprocessor {
} }
} }
fn try_term_to_query<'a>( fn try_term_to_query<'a, LS: LoadState<'a>>(
&mut self, &mut self,
load_state: &mut LoadState<'a>, loader: &mut Loader<'a, LS>,
terms: Vec<Box<Term>>, terms: Vec<Term>,
cut_context: CutContext, cut_context: CutContext,
) -> Result<TopLevel, CompilationError> { ) -> Result<TopLevel, CompilationError> {
Ok(TopLevel::Query(self.setup_query( Ok(TopLevel::Query(self.setup_query(
load_state, loader,
terms, terms,
cut_context, cut_context,
)?)) )?))
} }
pub(super) fn try_term_to_tl<'a>( pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>(
&mut self, &mut self,
load_state: &mut LoadState<'a>, loader: &mut Loader<'a, LS>,
term: Term, term: Term,
cut_context: CutContext, cut_context: CutContext,
) -> Result<TopLevel, CompilationError> { ) -> Result<TopLevel, CompilationError> {
match term { match term {
Term::Clause(r, name, terms, fixity) => { Term::Clause(r, name, terms) => {
if name.as_str() == "?-" { if name == atom!("?-") {
self.try_term_to_query(load_state, terms, cut_context) self.try_term_to_query(loader, terms, cut_context)
} else if name.as_str() == ":-" && terms.len() == 2 { } else if name == atom!(":-") && terms.len() == 2 {
Ok(TopLevel::Rule(self.setup_rule( Ok(TopLevel::Rule(self.setup_rule(
load_state, loader,
terms, terms,
cut_context, cut_context,
)?)) )?))
} else { } else {
let term = Term::Clause(r, name, terms, fixity); let term = Term::Clause(r, name, terms);
Ok(TopLevel::Fact(self.setup_fact(term)?)) Ok(TopLevel::Fact(self.setup_fact(term)?))
} }
} }
@@ -883,30 +837,30 @@ impl Preprocessor {
} }
} }
fn try_terms_to_tls<'a, I: IntoIterator<Item = Term>>( fn try_terms_to_tls<'a, I: IntoIterator<Item = Term>, LS: LoadState<'a>>(
&mut self, &mut self,
load_state: &mut LoadState<'a>, loader: &mut Loader<'a, LS>,
terms: I, terms: I,
cut_context: CutContext, cut_context: CutContext,
) -> Result<VecDeque<TopLevel>, CompilationError> { ) -> Result<VecDeque<TopLevel>, CompilationError> {
let mut results = VecDeque::new(); let mut results = VecDeque::new();
for term in terms.into_iter() { for term in terms.into_iter() {
results.push_back(self.try_term_to_tl(load_state, term, cut_context)?); results.push_back(self.try_term_to_tl(loader, term, cut_context)?);
} }
Ok(results) Ok(results)
} }
pub(super) fn parse_queue<'a>( pub(super) fn parse_queue<'a, LS: LoadState<'a>>(
&mut self, &mut self,
load_state: &mut LoadState<'a>, loader: &mut Loader<'a, LS>,
) -> Result<VecDeque<TopLevel>, CompilationError> { ) -> Result<VecDeque<TopLevel>, CompilationError> {
let mut queue = VecDeque::new(); let mut queue = VecDeque::new();
while let Some(terms) = self.queue.pop_front() { while let Some(terms) = self.queue.pop_front() {
let clauses = merge_clauses(&mut self.try_terms_to_tls( let clauses = merge_clauses(&mut self.try_terms_to_tls(
load_state, loader,
terms, terms,
CutContext::HasCutVariable, CutContext::HasCutVariable,
)?)?; )?)?;

View File

@@ -1,16 +1,13 @@
use core::marker::PhantomData; use core::marker::PhantomData;
use crate::machine::machine_indices::*; use crate::raw_block::*;
use crate::machine::raw_block::*; use crate::types::*;
use std::mem; use std::mem;
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
use std::ptr; use std::ptr;
#[derive(Debug)] impl RawBlockTraits for Stack {
struct StackTraits {}
impl RawBlockTraits for StackTraits {
#[inline] #[inline]
fn init_size() -> usize { fn init_size() -> usize {
10 * 1024 * 1024 10 * 1024 * 1024
@@ -18,31 +15,23 @@ impl RawBlockTraits for StackTraits {
#[inline] #[inline]
fn align() -> usize { fn align() -> usize {
mem::align_of::<Addr>() mem::align_of::<HeapCellValue>()
}
#[inline]
fn base_offset(base: *const u8) -> *const u8 {
unsafe { base.offset(Self::align() as isize) }
} }
} }
const fn prelude_size<Prelude>() -> usize { #[inline(always)]
let size = mem::size_of::<Prelude>(); pub const fn prelude_size<Prelude>() -> usize {
let align = mem::align_of::<Addr>(); mem::size_of::<Prelude>()
(size & !(align - 1)) + align
} }
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct Stack { pub struct Stack {
buf: RawBlock<StackTraits>, buf: RawBlock<Stack>,
_marker: PhantomData<Addr>, _marker: PhantomData<HeapCellValue>,
} }
impl Drop for Stack { impl Drop for Stack {
fn drop(&mut self) { fn drop(&mut self) {
self.drop_in_place();
self.buf.deallocate(); self.buf.deallocate();
} }
} }
@@ -56,8 +45,7 @@ pub(crate) struct FramePrelude {
pub(crate) struct AndFramePrelude { pub(crate) struct AndFramePrelude {
pub(crate) univ_prelude: FramePrelude, pub(crate) univ_prelude: FramePrelude,
pub(crate) e: usize, pub(crate) e: usize,
pub(crate) cp: LocalCodePtr, pub(crate) cp: usize,
pub(crate) interrupt_cp: LocalCodePtr,
} }
#[derive(Debug)] #[derive(Debug)]
@@ -67,22 +55,22 @@ pub(crate) struct AndFrame {
impl AndFrame { impl AndFrame {
pub(crate) 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::<HeapCellValue>()
} }
} }
impl Index<usize> for AndFrame { impl Index<usize> for AndFrame {
type Output = Addr; type Output = HeapCellValue;
fn index(&self, index: usize) -> &Self::Output { fn index(&self, index: usize) -> &Self::Output {
let prelude_offset = prelude_size::<AndFramePrelude>(); let prelude_offset = prelude_size::<AndFramePrelude>();
let index_offset = (index - 1) * mem::size_of::<Addr>(); let index_offset = (index - 1) * mem::size_of::<HeapCellValue>();
unsafe { unsafe {
let ptr = mem::transmute::<&AndFrame, *const u8>(self); let ptr = mem::transmute::<&AndFrame, *const u8>(self);
let ptr = ptr as usize + prelude_offset + index_offset; let ptr = ptr as usize + prelude_offset + index_offset;
&*(ptr as *const Addr) &*(ptr as *const HeapCellValue)
} }
} }
} }
@@ -90,13 +78,35 @@ impl Index<usize> for AndFrame {
impl IndexMut<usize> for AndFrame { impl IndexMut<usize> for AndFrame {
fn index_mut(&mut self, index: usize) -> &mut Self::Output { fn index_mut(&mut self, index: usize) -> &mut Self::Output {
let prelude_offset = prelude_size::<AndFramePrelude>(); let prelude_offset = prelude_size::<AndFramePrelude>();
let index_offset = (index - 1) * mem::size_of::<Addr>(); let index_offset = (index - 1) * mem::size_of::<HeapCellValue>();
unsafe { unsafe {
let ptr = mem::transmute::<&mut AndFrame, *const u8>(self); let ptr = mem::transmute::<&mut AndFrame, *const u8>(self);
let ptr = ptr as usize + prelude_offset + index_offset; let ptr = ptr as usize + prelude_offset + index_offset;
&mut *(ptr as *mut Addr) &mut *(ptr as *mut HeapCellValue)
}
}
}
impl Index<usize> for Stack {
type Output = HeapCellValue;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
unsafe {
let ptr = self.buf.base as usize + index;
&*(ptr as *const HeapCellValue)
}
}
}
impl IndexMut<usize> for Stack {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
unsafe {
let ptr = self.buf.base as usize + index;
&mut *(ptr as *mut HeapCellValue)
} }
} }
} }
@@ -105,9 +115,11 @@ impl IndexMut<usize> for AndFrame {
pub(crate) struct OrFramePrelude { pub(crate) struct OrFramePrelude {
pub(crate) univ_prelude: FramePrelude, pub(crate) univ_prelude: FramePrelude,
pub(crate) e: usize, pub(crate) e: usize,
pub(crate) cp: LocalCodePtr, pub(crate) cp: usize,
pub(crate) b: usize, pub(crate) b: usize,
pub(crate) bp: LocalCodePtr, pub(crate) bp: usize,
pub(crate) boip: u32,
pub(crate) biip: u32,
pub(crate) tr: usize, pub(crate) tr: usize,
pub(crate) h: usize, pub(crate) h: usize,
pub(crate) b0: usize, pub(crate) b0: usize,
@@ -119,18 +131,18 @@ pub(crate) struct OrFrame {
} }
impl Index<usize> for OrFrame { impl Index<usize> for OrFrame {
type Output = Addr; type Output = HeapCellValue;
#[inline] #[inline]
fn index(&self, index: usize) -> &Self::Output { fn index(&self, index: usize) -> &Self::Output {
let prelude_offset = prelude_size::<OrFramePrelude>(); let prelude_offset = prelude_size::<OrFramePrelude>();
let index_offset = index * mem::size_of::<Addr>(); let index_offset = index * mem::size_of::<HeapCellValue>();
unsafe { unsafe {
let ptr = mem::transmute::<&OrFrame, *const u8>(self); let ptr = mem::transmute::<&OrFrame, *const u8>(self);
let ptr = ptr as usize + prelude_offset + index_offset; let ptr = ptr as usize + prelude_offset + index_offset;
&*(ptr as *const Addr) &*(ptr as *const HeapCellValue)
} }
} }
} }
@@ -139,20 +151,20 @@ impl IndexMut<usize> for OrFrame {
#[inline] #[inline]
fn index_mut(&mut self, index: usize) -> &mut Self::Output { fn index_mut(&mut self, index: usize) -> &mut Self::Output {
let prelude_offset = prelude_size::<OrFramePrelude>(); let prelude_offset = prelude_size::<OrFramePrelude>();
let index_offset = index * mem::size_of::<Addr>(); let index_offset = index * mem::size_of::<HeapCellValue>();
unsafe { unsafe {
let ptr = mem::transmute::<&mut OrFrame, *const u8>(self); let ptr = mem::transmute::<&mut OrFrame, *const u8>(self);
let ptr = ptr as usize + prelude_offset + index_offset; let ptr = ptr as usize + prelude_offset + index_offset;
&mut *(ptr as *mut Addr) &mut *(ptr as *mut HeapCellValue)
} }
} }
} }
impl OrFrame { impl OrFrame {
pub(crate) 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::<HeapCellValue>()
} }
} }
@@ -164,26 +176,39 @@ impl Stack {
} }
} }
#[inline(always)]
unsafe fn alloc(&mut self, frame_size: usize) -> *mut u8 {
loop {
let ptr = self.buf.alloc(frame_size);
if ptr.is_null() {
self.buf.grow();
} else {
return ptr;
}
}
}
pub(crate) 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 {
let new_top = self.buf.new_block(frame_size); let e = self.buf.ptr as usize - self.buf.base as usize;
let e = self.buf.top as usize - self.buf.base as usize; let new_ptr = self.alloc(frame_size);
let mut offset = prelude_size::<AndFramePrelude>();
for idx in 0..num_cells { for idx in 0..num_cells {
let offset = prelude_size::<AndFramePrelude>() + idx * mem::size_of::<Addr>();
ptr::write( ptr::write(
(self.buf.top as usize + offset) as *mut Addr, (new_ptr as usize + offset) as *mut HeapCellValue,
Addr::StackCell(e, idx + 1), stack_loc_as_cell!(AndFrame, e, idx + 1),
); );
offset += mem::size_of::<HeapCellValue>();
} }
let and_frame = &mut *(self.buf.top as *mut AndFrame); let and_frame = &mut *(new_ptr as *mut AndFrame);
and_frame.prelude.univ_prelude.num_cells = num_cells; and_frame.prelude.univ_prelude.num_cells = num_cells;
self.buf.top = new_top;
e e
} }
} }
@@ -192,27 +217,27 @@ impl Stack {
let frame_size = OrFrame::size_of(num_cells); let frame_size = OrFrame::size_of(num_cells);
unsafe { unsafe {
let new_top = self.buf.new_block(frame_size); let b = self.buf.ptr as usize - self.buf.base as usize;
let b = self.buf.top as usize - self.buf.base as usize; let new_ptr = self.alloc(frame_size);
let mut offset = prelude_size::<OrFramePrelude>();
for idx in 0..num_cells { for idx in 0..num_cells {
let offset = prelude_size::<OrFramePrelude>() + idx * mem::size_of::<Addr>();
ptr::write( ptr::write(
(self.buf.top as usize + offset) as *mut Addr, (new_ptr as usize + offset) as *mut HeapCellValue,
Addr::StackCell(b, idx), stack_loc_as_cell!(OrFrame, b, idx),
); );
offset += mem::size_of::<HeapCellValue>();
} }
let or_frame = &mut *(self.buf.top as *mut OrFrame); let or_frame = &mut *(new_ptr as *mut OrFrame);
or_frame.prelude.univ_prelude.num_cells = num_cells; or_frame.prelude.univ_prelude.num_cells = num_cells;
self.buf.top = new_top;
b b
} }
} }
#[inline] #[inline(always)]
pub(crate) 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;
@@ -220,7 +245,7 @@ impl Stack {
} }
} }
#[inline] #[inline(always)]
pub(crate) 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;
@@ -228,7 +253,7 @@ impl Stack {
} }
} }
#[inline] #[inline(always)]
pub(crate) 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;
@@ -236,7 +261,7 @@ impl Stack {
} }
} }
#[inline] #[inline(always)]
pub(crate) 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;
@@ -244,31 +269,65 @@ impl Stack {
} }
} }
#[inline] #[inline(always)]
pub(crate) fn truncate(&mut self, b: usize) { pub(crate) fn truncate(&mut self, b: usize) {
if b == 0 { let base = self.buf.base as usize + b;
self.inner_truncate(mem::align_of::<Addr>());
} else { if base < self.buf.ptr as usize {
self.inner_truncate(b); self.buf.ptr = base as *mut _;
}
} }
} }
#[inline] #[cfg(test)]
fn inner_truncate(&mut self, b: usize) { mod tests {
let base = b + self.buf.base as usize; use super::*;
if base < self.buf.top as usize { use crate::machine::mock_wam::*;
self.buf.top = base as *const _;
} #[test]
fn stack_tests() {
let mut wam = MockWAM::new();
let e = wam.machine_st.stack.allocate_and_frame(10); // create an AND frame!
let and_frame = wam.machine_st.stack.index_and_frame_mut(e);
assert_eq!(
e,
0// 10 * mem::size_of::<HeapCellValue>() + prelude_size::<AndFrame>()
);
assert_eq!(and_frame.prelude.univ_prelude.num_cells, 10);
for idx in 0..10 {
assert_eq!(and_frame[idx + 1], stack_loc_as_cell!(AndFrame, e, idx + 1));
} }
pub(crate) fn drop_in_place(&mut self) { and_frame[5] = empty_list_as_cell!();
self.truncate(mem::align_of::<Addr>());
debug_assert!(if self.buf.top.is_null() { assert_eq!(and_frame[5], empty_list_as_cell!());
self.buf.top == self.buf.base
} else { let b = wam.machine_st.stack.allocate_or_frame(5);
self.buf.top as usize == self.buf.base as usize + mem::align_of::<Addr>()
}); let or_frame = wam.machine_st.stack.index_or_frame_mut(b);
for idx in 0..5 {
assert_eq!(or_frame[idx], stack_loc_as_cell!(OrFrame, b, idx));
}
let next_e = wam.machine_st.stack.allocate_and_frame(9); // create an AND frame!
let and_frame = wam.machine_st.stack.index_and_frame_mut(next_e);
for idx in 0..9 {
assert_eq!(and_frame[idx + 1], stack_loc_as_cell!(AndFrame, next_e, idx + 1));
}
let and_frame = wam.machine_st.stack.index_and_frame(e);
assert_eq!(and_frame[5], empty_list_as_cell!());
assert_eq!(
wam.machine_st.stack[stack_loc!(AndFrame, e, 5)],
empty_list_as_cell!()
);
} }
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,48 +1,53 @@
use prolog_parser::ast::*; use crate::forms::*;
use prolog_parser::parser::*;
use crate::machine::machine_errors::CompilationError;
use crate::machine::*; use crate::machine::*;
use crate::machine::load_state::*;
use crate::machine::loader::*;
use crate::machine::machine_errors::*;
use crate::parser::ast::*;
use crate::parser::parser::*;
use crate::predicate_queue;
use indexmap::IndexSet; use indexmap::IndexSet;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fmt; use std::fmt;
pub(crate) trait TermStream: Sized { pub struct LoadStatePayload<TS> {
type Evacuable; pub term_stream: TS,
pub(super) compilation_target: CompilationTarget,
pub(super) retraction_info: RetractionInfo,
pub(super) module_op_exports: ModuleOpExports,
pub(super) non_counted_bt_preds: IndexSet<PredicateKey>,
pub(super) predicates: PredicateQueue,
pub(super) clause_clauses: Vec<(Term, Term)>,
}
pub trait TermStream: Sized {
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError>; fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError>;
fn eof(&mut self) -> Result<bool, CompilationError>; fn eof(&mut self) -> Result<bool, CompilationError>;
fn listing_src(&self) -> &ListingSource; fn listing_src(&self) -> &ListingSource;
fn evacuate<'a>(loader: Loader<'a, Self>) -> Result<Self::Evacuable, SessionError>;
} }
#[derive(Debug)] #[derive(Debug)]
pub(super) struct BootstrappingTermStream<'a> { pub struct BootstrappingTermStream<'a> {
listing_src: ListingSource, listing_src: ListingSource,
parser: Parser<'a, Stream>, pub(super) parser: Parser<'a, Stream>,
} }
impl<'a> BootstrappingTermStream<'a> { impl<'a> BootstrappingTermStream<'a> {
#[inline] #[inline]
pub(super) fn from_prolog_stream( pub(super) fn from_char_reader(
stream: &'a mut PrologStream, stream: Stream,
atom_tbl: TabledData<Atom>, machine_st: &'a mut MachineState,
flags: MachineFlags,
listing_src: ListingSource, listing_src: ListingSource,
) -> Self { ) -> Self {
let parser = Parser::new(stream, atom_tbl, flags); let parser = Parser::new(stream, machine_st);
Self { Self { parser, listing_src }
parser,
listing_src,
}
} }
} }
impl<'a> TermStream for BootstrappingTermStream<'a> { impl<'a> TermStream for BootstrappingTermStream<'a> {
type Evacuable = CompilationTarget;
#[inline] #[inline]
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError> { fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError> {
self.parser.reset(); self.parser.reset();
@@ -61,24 +66,9 @@ impl<'a> TermStream for BootstrappingTermStream<'a> {
fn listing_src(&self) -> &ListingSource { fn listing_src(&self) -> &ListingSource {
&self.listing_src &self.listing_src
} }
fn evacuate(mut loader: Loader<Self>) -> Result<Self::Evacuable, SessionError> {
if !loader.predicates.is_empty() {
loader.compile_and_submit()?;
} }
loader pub struct LiveTermStream {
.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) term_queue: VecDeque<Term>,
pub(super) listing_src: ListingSource, pub(super) listing_src: ListingSource,
} }
@@ -93,28 +83,18 @@ impl LiveTermStream {
} }
} }
pub(crate) struct LoadStatePayload { impl<TS> fmt::Debug for LoadStatePayload<TS> {
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 { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "LoadStatePayload") write!(fmt, "LoadStatePayload")
} }
} }
impl LoadStatePayload { impl<TS> LoadStatePayload<TS> {
pub(super) fn new(wam: &Machine) -> Self { pub(super) fn new(code_repo_len: usize, term_stream: TS) -> Self {
Self { Self {
term_stream: LiveTermStream::new(ListingSource::User), term_stream,
compilation_target: CompilationTarget::default(), compilation_target: CompilationTarget::default(),
retraction_info: RetractionInfo::new(wam.code_repo.code.len()), retraction_info: RetractionInfo::new(code_repo_len),
module_op_exports: vec![], module_op_exports: vec![],
non_counted_bt_preds: IndexSet::new(), non_counted_bt_preds: IndexSet::new(),
predicates: predicate_queue![], predicates: predicate_queue![],
@@ -124,8 +104,6 @@ impl LoadStatePayload {
} }
impl TermStream for LiveTermStream { impl TermStream for LiveTermStream {
type Evacuable = LoadStatePayload;
#[inline] #[inline]
fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> { fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
Ok(self.term_queue.pop_front().unwrap()) Ok(self.term_queue.pop_front().unwrap())
@@ -140,9 +118,4 @@ impl TermStream for LiveTermStream {
fn listing_src(&self) -> &ListingSource { fn listing_src(&self) -> &ListingSource {
&self.listing_src &self.listing_src
} }
#[inline]
fn evacuate(loader: Loader<Self>) -> Result<LoadStatePayload, SessionError> {
Ok(loader.to_load_state_payload())
}
} }

View File

@@ -1,9 +1,3 @@
macro_rules! interm {
($n: expr) => {
ArithmeticTerm::Interm($n)
};
}
/* A simple macro to count the arguments in a variadic list /* A simple macro to count the arguments in a variadic list
* of token trees. * of token trees.
*/ */
@@ -13,53 +7,420 @@ macro_rules! count_tt {
($($a:tt $even:tt)*) => { count_tt!($($a)*) << 1 }; ($($a:tt $even:tt)*) => { count_tt!($($a)*) << 1 };
} }
macro_rules! char_as_cell {
($c: expr) => {
HeapCellValue::build_with(HeapCellValueTag::Char, $c as u64)
};
}
macro_rules! fixnum_as_cell {
($n: expr) => {
HeapCellValue::from_bytes($n.into_bytes()) //HeapCellValueTag::Fixnum, $n.get_num() as u64)
};
}
macro_rules! cell_as_fixnum {
($cell:expr) => {
Fixnum::from_bytes($cell.into_bytes())
};
}
macro_rules! integer_as_cell {
($n: expr) => {{
match $n {
Number::Float(_) => unreachable!(),
Number::Fixnum(n) => fixnum_as_cell!(n),
Number::Rational(r) => typed_arena_ptr_as_cell!(r),
Number::Integer(n) => typed_arena_ptr_as_cell!(n),
}
}};
}
macro_rules! empty_list_as_cell {
() => {
// the empty list atom has the fixed index of 8 (8 >> 3 == 1 in the condensed atom representation).
atom_as_cell!(atom!("[]"))
};
}
macro_rules! atom_as_cell {
($atom:expr) => {
HeapCellValue::from_bytes(
AtomCell::build_with($atom.flat_index(), 0, HeapCellValueTag::Atom).into_bytes(),
)
};
($atom:expr, $arity:expr) => {
HeapCellValue::from_bytes(
AtomCell::build_with($atom.flat_index(), $arity as u16, HeapCellValueTag::Atom)
.into_bytes(),
)
};
}
macro_rules! cell_as_ossified_op_dir {
($cell:expr) => {{
let ptr_u64 = cell_as_untyped_arena_ptr!($cell);
TypedArenaPtr::new(ptr_u64.payload_offset() as *mut OssifiedOpDir)
}};
}
macro_rules! cell_as_string {
($cell:expr) => {
PartialString::from(cell_as_atom!($cell))
};
}
macro_rules! cell_as_atom {
($cell:expr) => {{
let cell = AtomCell::from_bytes($cell.into_bytes());
let name = cell.get_index() << 3;
Atom::from(name as usize)
}};
}
macro_rules! cell_as_atom_cell {
($cell:expr) => {
AtomCell::from_bytes($cell.into_bytes())
};
}
macro_rules! cell_as_f64_ptr {
($cell:expr) => {{
let ptr_u64 = ConsPtr::from_bytes($cell.into_bytes());
F64Ptr(TypedArenaPtr::new(
ptr_u64.as_ptr() as *mut OrderedFloat<f64>
))
}};
}
macro_rules! cell_as_untyped_arena_ptr {
($cell:expr) => {
UntypedArenaPtr::from(u64::from($cell) as *const ArenaHeader)
};
}
macro_rules! pstr_as_cell {
($atom:expr) => {
HeapCellValue::from_bytes(
AtomCell::build_with($atom.flat_index(), 0, HeapCellValueTag::PStr).into_bytes(),
)
};
}
macro_rules! pstr_loc_as_cell {
($h:expr) => {
HeapCellValue::build_with(HeapCellValueTag::PStrLoc, $h as u64)
};
}
macro_rules! pstr_offset_as_cell {
($h:expr) => {
HeapCellValue::build_with(HeapCellValueTag::PStrOffset, $h as u64)
};
}
macro_rules! list_loc_as_cell {
($h:expr) => {
HeapCellValue::build_with(HeapCellValueTag::Lis, $h as u64)
};
}
macro_rules! str_loc_as_cell {
($h:expr) => {
HeapCellValue::build_with(HeapCellValueTag::Str, $h as u64)
};
}
macro_rules! stack_loc {
(OrFrame, $b:expr, $idx:expr) => ({
$b + prelude_size::<OrFrame>() + $idx * std::mem::size_of::<HeapCellValue>()
});
(AndFrame, $e:expr, $idx:expr) => ({
$e + prelude_size::<AndFrame>() + ($idx - 1) * std::mem::size_of::<HeapCellValue>()
});
}
macro_rules! stack_loc_as_cell {
(OrFrame, $b:expr, $idx:expr) => {
stack_loc_as_cell!(stack_loc!(OrFrame, $b, $idx))
};
(AndFrame, $b:expr, $idx:expr) => {
stack_loc_as_cell!(stack_loc!(AndFrame, $b, $idx))
};
($h:expr) => {
HeapCellValue::build_with(HeapCellValueTag::StackVar, $h as u64)
};
}
#[macro_export]
macro_rules! heap_loc_as_cell {
($h:expr) => {
HeapCellValue::build_with(HeapCellValueTag::Var, $h as u64)
};
}
macro_rules! attr_var_as_cell {
($h:expr) => {
HeapCellValue::build_with(HeapCellValueTag::AttrVar, $h as u64)
};
}
#[allow(unused)]
macro_rules! attr_var_loc_as_cell {
($h:expr) => {
HeapCellValue::build_with(HeapCellValueTag::AttrVar, $h as u64)
};
}
macro_rules! typed_arena_ptr_as_cell {
($ptr:expr) => {
untyped_arena_ptr_as_cell!($ptr.header_ptr())
};
}
macro_rules! untyped_arena_ptr_as_cell {
($ptr:expr) => {
HeapCellValue::from_bytes(unsafe { std::mem::transmute($ptr) })
};
}
macro_rules! atom_as_cstr_cell {
($atom:expr) => {{
let offset = $atom.flat_index();
HeapCellValue::from_bytes(
AtomCell::build_with(offset as u64, 0, HeapCellValueTag::CStr).into_bytes(),
)
}};
}
macro_rules! string_as_cstr_cell {
($ptr:expr) => {{
let atom: Atom = $ptr.into();
let offset = atom.flat_index();
HeapCellValue::from_bytes(
AtomCell::build_with(offset as u64, 0, HeapCellValueTag::CStr).into_bytes(),
)
}};
}
macro_rules! string_as_pstr_cell {
($ptr:expr) => {{
let atom: Atom = $ptr.into();
let offset = atom.flat_index();
HeapCellValue::from_bytes(
AtomCell::build_with(offset as u64, 0, HeapCellValueTag::PStr).into_bytes(),
)
}};
}
macro_rules! stream_as_cell {
($ptr:expr) => {
untyped_arena_ptr_as_cell!($ptr.as_ptr())
};
}
macro_rules! cell_as_stream {
($cell:expr) => {{
let ptr = cell_as_untyped_arena_ptr!($cell);
Stream::from_tag(ptr.get_tag(), ptr.payload_offset())
}};
}
macro_rules! cell_as_load_state_payload {
($cell:expr) => { unsafe {
let ptr = cell_as_untyped_arena_ptr!($cell);
let ptr = std::mem::transmute::<_, *mut LiveLoadState>(ptr.payload_offset());
TypedArenaPtr::new(ptr)
}};
}
macro_rules! match_untyped_arena_ptr_pat_body {
($ptr:ident, Integer, $n:ident, $code:expr) => {{
let payload_ptr = unsafe { std::mem::transmute::<_, *mut Integer>($ptr.payload_offset()) };
let $n = TypedArenaPtr::new(payload_ptr);
#[allow(unused_braces)]
$code
}};
($ptr:ident, F64, $n:ident, $code:expr) => {{
let payload_ptr =
unsafe { std::mem::transmute::<_, *mut OrderedFloat<f64>>($ptr.payload_offset()) };
let $n = TypedArenaPtr::new(payload_ptr);
#[allow(unused_braces)]
$code
}};
($ptr:ident, Rational, $n:ident, $code:expr) => {{
let payload_ptr = unsafe { std::mem::transmute::<_, *mut Rational>($ptr.payload_offset()) };
let $n = TypedArenaPtr::new(payload_ptr);
#[allow(unused_braces)]
$code
}};
($cell:ident, OssifiedOpDir, $n:ident, $code:expr) => {{
let $n = cell_as_ossified_op_dir!($cell);
#[allow(unused_braces)]
$code
}};
($cell:ident, LiveLoadState, $n:ident, $code:expr) => {{
let $n = cell_as_load_state_payload!($cell);
#[allow(unused_braces)]
$code
}};
($ptr:ident, Stream, $s:ident, $code:expr) => {{
let $s = Stream::from_tag($ptr.get_tag(), $ptr.payload_offset());
#[allow(unused_braces)]
$code
}};
($ptr:ident, TcpListener, $listener:ident, $code:expr) => {{
let payload_ptr = unsafe { std::mem::transmute::<_, *mut TcpListener>($ptr.payload_offset()) };
#[allow(unused_mut)]
let mut $listener = TypedArenaPtr::new(payload_ptr);
#[allow(unused_braces)]
$code
}};
($ptr:ident, $($tags:tt)|+, $s:ident, $code:expr) => {{
let $s = Stream::from_tag($ptr.get_tag(), $ptr.payload_offset());
#[allow(unused_braces)]
$code
}};
}
macro_rules! match_untyped_arena_ptr_pat {
(Stream) => {
ArenaHeaderTag::InputFileStream
| ArenaHeaderTag::OutputFileStream
| ArenaHeaderTag::NamedTcpStream
| ArenaHeaderTag::NamedTlsStream
| ArenaHeaderTag::ReadlineStream
| ArenaHeaderTag::StaticStringStream
| ArenaHeaderTag::ByteStream
| ArenaHeaderTag::StandardOutputStream
| ArenaHeaderTag::StandardErrorStream
};
($tag:ident) => {
ArenaHeaderTag::$tag
};
}
macro_rules! match_untyped_arena_ptr {
($ptr:expr, $( ($(ArenaHeaderTag::$tag:tt)|+, $n:ident) => $code:block $(,)?)+ $(_ => $misc_code:expr $(,)?)?) => ({
let ptr_id = $ptr;
match ptr_id.get_tag() {
$($(match_untyped_arena_ptr_pat!($tag) => {
match_untyped_arena_ptr_pat_body!(ptr_id, $tag, $n, $code)
})+)+
$(_ => $misc_code)?
}
});
}
macro_rules! read_heap_cell_pat_body {
($cell:ident, Cons, $n:ident, $code:expr) => ({
let $n = cell_as_untyped_arena_ptr!($cell);
#[allow(unused_braces)]
$code
});
($cell:ident, F64, $n:ident, $code:expr) => ({
let $n = cell_as_f64_ptr!($cell);
#[allow(unused_braces)]
$code
});
($cell:ident, Atom, ($name:ident, $arity:ident), $code:expr) => ({
let ($name, $arity) = cell_as_atom_cell!($cell).get_name_and_arity();
#[allow(unused_braces)]
$code
});
($cell:ident, PStr, $atom:ident, $code:expr) => ({
let $atom = cell_as_atom!($cell);
#[allow(unused_braces)]
$code
});
($cell:ident, CStr, $atom:ident, $code:expr) => ({
let $atom = cell_as_atom!($cell);
#[allow(unused_braces)]
$code
});
($cell:ident, CStr | PStr, $atom:ident, $code:expr) => ({
let $atom = cell_as_atom!($cell);
#[allow(unused_braces)]
$code
});
($cell:ident, PStr | CStr, $atom:ident, $code:expr) => ({
let $atom = cell_as_atom!($cell);
#[allow(unused_braces)]
$code
});
($cell:ident, Fixnum, $value:ident, $code:expr) => ({
let $value = Fixnum::from_bytes($cell.into_bytes());
#[allow(unused_braces)]
$code
});
($cell:ident, Char, $value:ident, $code:expr) => ({
let $value = unsafe { char::from_u32_unchecked($cell.get_value() as u32) };
#[allow(unused_braces)]
$code
});
($cell:ident, $($tags:tt)|+, $value:ident, $code:expr) => ({
let $value = $cell.get_value() as usize;
#[allow(unused_braces)]
$code
});
}
macro_rules! read_heap_cell_pat {
(($(HeapCellValueTag::$tag:tt)|+, $n:tt)) => {
$(HeapCellValueTag::$tag)|+
};
(($(HeapCellValueTag::$tag:tt)|+)) => {
$(HeapCellValueTag::$tag)|+
};
(_) => { _ };
}
macro_rules! read_heap_cell_pat_expander {
($cell_id:ident, ($(HeapCellValueTag::$tag:tt)|+, $n:tt), $code:block) => ({
read_heap_cell_pat_body!($cell_id, $($tag)|+, $n, $code)
});
($cell_id:ident, ($(HeapCellValueTag::$tag:tt)|+), $code:block) => ({
$code
});
($cell_id:ident, _, $code:block) => ({
$code
});
}
macro_rules! read_heap_cell {
($cell:expr, $($pat:tt $(if $guard_expr:expr)? => $code:block $(,)?)+) => ({
let cell_id = $cell;
match cell_id.get_tag() {
$(read_heap_cell_pat!($pat) $(if $guard_expr)? => {
read_heap_cell_pat_expander!(cell_id, $pat, $code)
})+
}
});
}
macro_rules! functor { macro_rules! functor {
($name:expr, $fixity:expr, [$($dt:ident($($value:expr),*)),+], [$($aux:ident),*]) => ({
{
#[allow(unused_variables, unused_mut)]
let mut addendum = Heap::new();
let arity = count_tt!($($dt) +);
let aux_lens = [$($aux.len()),*];
let mut result =
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), Some($fixity)),
$(functor_term!( $dt($($value),*), arity, aux_lens, addendum ),)+ ];
$(
result.extend($aux.into_iter());
)*
result.extend(addendum.into_iter());
result
}
});
($name:expr, $fixity:expr, [$($dt:ident($($value:expr),*)),+]) => ({
{
#[allow(unused_variables, unused_mut)]
let mut addendum = Heap::new();
let arity = count_tt!($($dt) +);
let mut result =
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), Some($fixity)),
$(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ];
result.extend(addendum.into_iter());
result
}
});
($name:expr, [$($dt:ident($($value:expr),*)),+], [$($aux:ident),*]) => ({ ($name:expr, [$($dt:ident($($value:expr),*)),+], [$($aux:ident),*]) => ({
{ {
#[allow(unused_variables, unused_mut)] #[allow(unused_variables, unused_mut)]
let mut addendum = Heap::new(); let mut addendum = Heap::new();
let arity = count_tt!($($dt) +); let arity: usize = count_tt!($($dt) +);
let aux_lens = [$($aux.len()),*];
#[allow(unused_variables)]
let aux_lens: [usize; count_tt!($($aux) *)] = [$($aux.len()),*];
let mut result = let mut result =
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None), vec![ atom_as_cell!($name, arity as u16),
$(functor_term!( $dt($($value),*), arity, aux_lens, addendum ),)+ ]; $(functor_term!( $dt($($value),*), arity, aux_lens, addendum ),)+ ];
$( $(
result.extend($aux.into_iter()); result.extend($aux.iter());
)* )*
result.extend(addendum.into_iter()); result.extend(addendum.into_iter());
@@ -68,383 +429,183 @@ macro_rules! functor {
}); });
($name:expr, [$($dt:ident($($value:expr),*)),+]) => ({ ($name:expr, [$($dt:ident($($value:expr),*)),+]) => ({
{ {
use crate::machine::heap::*; let arity: usize = count_tt!($($dt) +);
let arity = count_tt!($($dt) +);
#[allow(unused_variables, unused_mut)] #[allow(unused_variables, unused_mut)]
let mut addendum = Heap::new(); let mut addendum = Heap::new();
let mut result = let mut result =
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None), vec![ atom_as_cell!($name, arity as u16),
$(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ]; $(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ];
result.extend(addendum.into_iter()); result.extend(addendum.into_iter());
result result
} }
}); });
($name:expr, $fixity:expr) => ( ($name:expr) => ({
vec![ HeapCellValue::Atom(clause_name!($name), Some($fixity)) ] vec![ atom_as_cell!($name) ]
); });
(clause_name($name:expr)) => (
vec![ HeapCellValue::Atom($name, None) ]
);
($name:expr) => (
vec![ HeapCellValue::Atom(clause_name!($name), None) ]
);
} }
macro_rules! functor_term { macro_rules! functor_term {
(aux(0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ (str(0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
HeapCellValue::Addr(Addr::HeapCell($arity + 1)) str_loc_as_cell!($arity + 1)
}); });
(aux($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ (str($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
let len: usize = $aux_lens[0 .. $e].iter().sum(); let len: usize = $aux_lens[0 .. $e].iter().sum();
HeapCellValue::Addr(Addr::HeapCell($arity + 1 + len)) str_loc_as_cell!($arity + 1 + len)
}); });
(aux($h:expr, 0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ (str($h:expr, 0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
HeapCellValue::Addr(Addr::HeapCell($arity + $h + 1)) str_loc_as_cell!($arity + $h + 1)
}); });
(aux($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ (str($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
let len: usize = $aux_lens[0 .. $e].iter().sum(); let len: usize = $aux_lens[0 .. $e].iter().sum();
HeapCellValue::Addr(Addr::HeapCell($arity + $h + 1 + len)) str_loc_as_cell!($arity + $h + 1 + len)
}); });
(addr($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( (literal($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
HeapCellValue::Addr($e) HeapCellValue::from($e)
); );
(constant($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( (integer($e:expr, $arena:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
from_constant!($e, $h, $arity, $aux_lens, $addendum) HeapCellValue::arena_from(Number::arena_from($e, $arena), $arena)
); );
(constant($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( (fixnum($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
from_constant!($e, 0, $arity, $aux_lens, $addendum) fixnum_as_cell!(Fixnum::build_with($e as i64))
);
(number($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
$e.into()
);
(integer($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
HeapCellValue::Integer(Rc::new(Integer::from($e)))
); );
(indexing_code_ptr($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ (indexing_code_ptr($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
let stub = let stub =
match $e { match $e {
IndexingCodePtr::DynamicExternal(o) => functor!("dynamic_external", [integer(o)]), IndexingCodePtr::DynamicExternal(o) => functor!(atom!("dynamic_external"), [fixnum(o)]),
IndexingCodePtr::External(o) => functor!("external", [integer(o)]), IndexingCodePtr::External(o) => functor!(atom!("external"), [fixnum(o)]),
IndexingCodePtr::Internal(o) => functor!("internal", [integer(o)]), IndexingCodePtr::Internal(o) => functor!(atom!("internal"), [fixnum(o)]),
IndexingCodePtr::Fail => vec![HeapCellValue::Atom(clause_name!("fail"), None)], IndexingCodePtr::Fail => {
vec![atom_as_cell!(atom!("fail"))]
},
}; };
let len: usize = $aux_lens.iter().sum(); let len: usize = $aux_lens.iter().sum();
let h = len + $arity + 1 + $addendum.h() + $h; let h = len + $arity + 1 + $addendum.len() + $h;
$addendum.extend(stub.into_iter()); $addendum.extend(stub.into_iter());
HeapCellValue::Addr(Addr::HeapCell(h)) str_loc_as_cell!(h)
}); });
(clause_name($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( (number($arena:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
HeapCellValue::Atom($e, None) HeapCellValue::from(($e, $arena))
); );
(atom($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( (atom($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
HeapCellValue::Atom(clause_name!($e), None) atom_as_cell!($e)
);
(value($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
$e
); );
(string($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({ (string($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({
let len: usize = $aux_lens.iter().sum(); let len: usize = $aux_lens.iter().sum();
let h = len + $arity + 1 + $addendum.h() + $h; let h = len + $arity + 1 + $addendum.len() + $h;
$addendum.put_complete_string(&$e); let cell = string_as_pstr_cell!($e);
HeapCellValue::Addr(Addr::PStrLocation(h, 0)) $addendum.push(cell);
$addendum.push(empty_list_as_cell!());
heap_loc_as_cell!(h)
}); });
(boolean($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({ (boolean($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({
if $e { if $e {
functor_term!(atom("true"), $arity, $aux_lens, $addendum) functor_term!(atom(atom!("true")), $arity, $aux_lens, $addendum)
} else { } else {
functor_term!(atom("false"), $arity, $aux_lens, $addendum) functor_term!(atom(atom!("false")), $arity, $aux_lens, $addendum)
} }
}); });
($e:expr, $arity:expr, $aux_lens:expr, $addendum:ident) => ( (cell($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
$e $e
); );
} }
macro_rules! from_constant {
($e:expr, $over_h:expr, $arity:expr, $aux_lens:expr, $addendum:ident) => ({
match $e {
&Constant::Atom(ref name, ref op) => {
HeapCellValue::Atom(name.clone(), op.clone())
}
&Constant::Char(c) => {
HeapCellValue::Addr(Addr::Char(c))
}
&Constant::Fixnum(n) => {
HeapCellValue::Addr(Addr::Fixnum(n))
}
&Constant::Integer(ref n) => {
HeapCellValue::Integer(n.clone())
}
&Constant::Rational(ref r) => {
HeapCellValue::Rational(r.clone())
}
&Constant::Float(f) => {
HeapCellValue::Addr(Addr::Float(f))
}
&Constant::String(ref s) => {
let len: usize = $aux_lens.iter().sum();
let h = len + $arity + 1 + $addendum.h() + $over_h;
$addendum.put_complete_string(&s);
HeapCellValue::Addr(Addr::PStrLocation(h, 0))
}
&Constant::Usize(u) => {
HeapCellValue::Addr(Addr::Usize(u))
}
&Constant::EmptyList => {
HeapCellValue::Addr(Addr::EmptyList)
}
}
})
}
macro_rules! is_atom {
($r:expr) => {
call_clause!(ClauseType::Inlined(InlinedClauseType::IsAtom($r)), 1, 0)
};
}
macro_rules! is_atomic {
($r:expr) => {
call_clause!(ClauseType::Inlined(InlinedClauseType::IsAtomic($r)), 1, 0)
};
}
macro_rules! is_integer {
($r:expr) => {
call_clause!(ClauseType::Inlined(InlinedClauseType::IsInteger($r)), 1, 0)
};
}
macro_rules! is_compound {
($r:expr) => {
call_clause!(ClauseType::Inlined(InlinedClauseType::IsCompound($r)), 1, 0)
};
}
macro_rules! is_float {
($r:expr) => {
call_clause!(ClauseType::Inlined(InlinedClauseType::IsFloat($r)), 1, 0)
};
}
macro_rules! is_rational {
($r:expr) => {
call_clause!(ClauseType::Inlined(InlinedClauseType::IsRational($r)), 1, 0)
};
}
macro_rules! is_number {
($r:expr) => {
call_clause!(ClauseType::Inlined(InlinedClauseType::IsNumber($r)), 1, 0)
};
}
macro_rules! is_nonvar {
($r:expr) => {
call_clause!(ClauseType::Inlined(InlinedClauseType::IsNonVar($r)), 1, 0)
};
}
macro_rules! is_var {
($r:expr) => {
call_clause!(ClauseType::Inlined(InlinedClauseType::IsVar($r)), 1, 0)
};
}
macro_rules! call_clause {
($ct:expr, $arity:expr, $pvs:expr) => {
Line::Control(ControlInstruction::CallClause(
$ct, $arity, $pvs, false, false,
))
};
($ct:expr, $arity:expr, $pvs:expr, $lco:expr) => {
Line::Control(ControlInstruction::CallClause(
$ct, $arity, $pvs, $lco, false,
))
};
}
macro_rules! call_clause_by_default {
($ct:expr, $arity:expr, $pvs:expr) => {
Line::Control(ControlInstruction::CallClause(
$ct, $arity, $pvs, false, true,
))
};
($ct:expr, $arity:expr, $pvs:expr, $lco:expr) => {
Line::Control(ControlInstruction::CallClause(
$ct, $arity, $pvs, $lco, true,
))
};
}
macro_rules! proceed {
() => {
Line::Control(ControlInstruction::Proceed)
};
}
macro_rules! is_call {
($r:expr, $at:expr) => {
call_clause!(ClauseType::BuiltIn(BuiltInClauseType::Is($r, $at)), 2, 0)
};
}
macro_rules! is_call_by_default {
($r:expr, $at:expr) => {
call_clause_by_default!(ClauseType::BuiltIn(BuiltInClauseType::Is($r, $at)), 2, 0)
};
}
macro_rules! set_cp {
($r:expr) => {
call_clause!(ClauseType::System(SystemClauseType::SetCutPoint($r)), 1, 0)
};
}
macro_rules! succeed {
() => {
call_clause!(ClauseType::System(SystemClauseType::Succeed), 0, 0)
};
}
macro_rules! fail {
() => {
call_clause!(ClauseType::System(SystemClauseType::Fail), 0, 0)
};
}
macro_rules! compare_number_instr { macro_rules! compare_number_instr {
($cmp: expr, $at_1: expr, $at_2: expr) => {{ ($cmp: expr, $at_1: expr, $at_2: expr) => {{
let ct = ClauseType::Inlined(InlinedClauseType::CompareNumber($cmp, $at_1, $at_2)); $cmp.set_terms($at_1, $at_2);
call_clause!(ct, 2, 0) call_clause!(ClauseType::Inlined(InlinedClauseType::CompareNumber($cmp)), 0)
}}; }};
} }
macro_rules! jmp_call { macro_rules! call_clause {
($arity:expr, $offset:expr, $pvs:expr) => { ($clause_type:expr, $pvs:expr) => {{
Line::Control(ControlInstruction::JmpBy($arity, $offset, $pvs, false)) let mut instr = $clause_type.to_instr();
}; instr.perm_vars_mut().map(|pvs| *pvs = $pvs);
} instr
macro_rules! return_from_clause {
($lco:expr, $machine_st:expr) => {{
if let CodePtr::VerifyAttrInterrupt(_) = $machine_st.p {
return Ok(());
}
if $lco {
$machine_st.p = CodePtr::Local($machine_st.cp);
} else {
$machine_st.p += 1;
}
Ok(())
}}; }};
} }
macro_rules! dir_entry { macro_rules! call_clause_by_default {
($idx:expr) => { ($clause_type:expr, $pvs:expr) => {{
LocalCodePtr::DirEntry($idx) let mut instr = $clause_type.to_instr().to_default();
instr.perm_vars_mut().map(|pvs| *pvs = $pvs);
instr
}};
}
macro_rules! interm {
($n: expr) => {
ArithmeticTerm::Interm($n)
}; };
} }
macro_rules! index_store {
($code_dir:expr, $op_dir:expr, $modules:expr) => {
IndexStore {
code_dir: $code_dir,
extensible_predicates: ExtensiblePredicates::new(),
local_extensible_predicates: LocalExtensiblePredicates::new(),
global_variables: GlobalVarDir::new(),
meta_predicates: MetaPredicateDir::new(),
modules: $modules,
op_dir: $op_dir,
streams: StreamDir::new(),
stream_aliases: StreamAliasDir::new(),
}
};
}
macro_rules! put_constant {
($lvl:expr, $cons:expr, $r:expr) => {
QueryInstruction::PutConstant($lvl, $cons, $r)
};
}
macro_rules! get_level_and_unify {
($r: expr) => {
Line::Cut(CutInstruction::GetLevelAndUnify($r))
};
}
/*
macro_rules! unwind_protect {
($e: expr, $protected: expr) => {
match $e {
Err(e) => {
$protected;
return Err(e);
}
_ => {}
}
};
}
*/
/*
macro_rules! discard_result {
($f: expr) => {
match $f {
_ => (),
}
};
}
*/
macro_rules! ar_reg { macro_rules! ar_reg {
($r: expr) => { ($r: expr) => {
ArithmeticTerm::Reg($r) ArithmeticTerm::Reg($r)
}; };
} }
macro_rules! atom_from { macro_rules! unmark_cell_bits {
($self:expr, $e:expr) => { ($e:expr) => {{
match $e { let mut result = $e;
Addr::Con(h) if $self.heap.atom_at(h) => {
match &$self.heap[h] {
HeapCellValue::Atom(ref atom, _) => {
atom.clone()
}
_ => {
unreachable!()
}
}
}
Addr::Char(c) => {
clause_name!(c.to_string(), $self.atom_tbl)
}
_ => {
unreachable!()
}
}
}
}
macro_rules! try_or_fail { result.set_mark_bit(false);
($s:expr, $e:expr) => {{ result.set_forwarding_bit(false);
match $e {
Ok(val) => val, result
Err(msg) => { }};
$s.throw_exception(msg); }
return;
} macro_rules! index_store {
} ($code_dir:expr, $op_dir:expr, $modules:expr) => {
IndexStore {
code_dir: $code_dir,
extensible_predicates: ExtensiblePredicates::with_hasher(FxBuildHasher::default()),
local_extensible_predicates: LocalExtensiblePredicates::with_hasher(FxBuildHasher::default()),
global_variables: GlobalVarDir::with_hasher(FxBuildHasher::default()),
meta_predicates: MetaPredicateDir::with_hasher(FxBuildHasher::default()),
modules: $modules,
op_dir: $op_dir,
streams: StreamDir::new(),
stream_aliases: StreamAliasDir::with_hasher(FxBuildHasher::default()),
}
};
}
macro_rules! unify {
($machine_st:expr, $($value:expr),*) => {{
$($machine_st.pdl.push($value);)*
$machine_st.unify()
}};
}
macro_rules! unify_fn {
($machine_st:expr, $($value:expr),*) => {{
$($machine_st.pdl.push($value);)*
($machine_st.unify_fn)(&mut $machine_st)
}};
}
macro_rules! unify_with_occurs_check {
($machine_st:expr, $($value:expr),*) => {{
$($machine_st.pdl.push($value);)*
$machine_st.unify_with_occurs_check()
}};
}
macro_rules! compare_term_test {
($machine_st:expr, $e1:expr, $e2:expr) => {{
$machine_st.pdl.push($e2);
$machine_st.pdl.push($e1);
$machine_st.compare_term_test()
}}; }};
} }

632
src/parser/ast.rs Normal file
View File

@@ -0,0 +1,632 @@
use crate::arena::*;
use crate::atom_table::*;
use crate::parser::char_reader::*;
use crate::types::HeapCellValueTag;
use std::cell::Cell;
use std::fmt;
use std::hash::Hash;
use std::io::{Error as IOError};
use std::ops::Neg;
use std::rc::Rc;
use std::vec::Vec;
use rug::{Integer, Rational};
use fxhash::FxBuildHasher;
use indexmap::IndexMap;
use modular_bitfield::error::OutOfBounds;
use modular_bitfield::prelude::*;
pub type Specifier = u32;
pub const MAX_ARITY: usize = 1023;
pub const XFX: u32 = 0x0001;
pub const XFY: u32 = 0x0002;
pub const YFX: u32 = 0x0004;
pub const XF: u32 = 0x0010;
pub const YF: u32 = 0x0020;
pub const FX: u32 = 0x0040;
pub const FY: u32 = 0x0080;
pub const DELIMITER: u32 = 0x0100;
pub const TERM: u32 = 0x1000;
pub const LTERM: u32 = 0x3000;
pub const NEGATIVE_SIGN: u32 = 0x0200;
#[macro_export]
macro_rules! fixnum {
($wrapper:tt, $n:expr, $arena:expr) => {
Fixnum::build_with_checked($n)
.map(<$wrapper>::Fixnum)
.unwrap_or_else(|_| <$wrapper>::Integer(arena_alloc!(Integer::from($n), $arena)))
};
}
macro_rules! is_term {
($x:expr) => {
($x as u32 & $crate::parser::ast::TERM) != 0
};
}
macro_rules! is_lterm {
($x:expr) => {
($x as u32 & $crate::parser::ast::LTERM) != 0
};
}
macro_rules! is_op {
($x:expr) => {
$x as u32
& ($crate::parser::ast::XF
| $crate::parser::ast::YF
| $crate::parser::ast::FX
| $crate::parser::ast::FY
| $crate::parser::ast::XFX
| $crate::parser::ast::XFY
| $crate::parser::ast::YFX)
!= 0
};
}
macro_rules! is_negate {
($x:expr) => {
($x as u32 & $crate::parser::ast::NEGATIVE_SIGN) != 0
};
}
#[macro_export]
macro_rules! is_prefix {
($x:expr) => {
$x as u32 & ($crate::parser::ast::FX | $crate::parser::ast::FY) != 0
};
}
#[macro_export]
macro_rules! is_postfix {
($x:expr) => {
$x as u32 & ($crate::parser::ast::XF | $crate::parser::ast::YF) != 0
};
}
#[macro_export]
macro_rules! is_infix {
($x:expr) => {
($x as u32
& ($crate::parser::ast::XFX | $crate::parser::ast::XFY | $crate::parser::ast::YFX))
!= 0
};
}
#[macro_export]
macro_rules! is_xfx {
($x:expr) => {
($x as u32 & $crate::parser::ast::XFX) != 0
};
}
#[macro_export]
macro_rules! is_xfy {
($x:expr) => {
($x as u32 & $crate::parser::ast::XFY) != 0
};
}
#[macro_export]
macro_rules! is_yfx {
($x:expr) => {
($x as u32 & $crate::parser::ast::YFX) != 0
};
}
#[macro_export]
macro_rules! is_yf {
($x:expr) => {
($x as u32 & $crate::parser::ast::YF) != 0
};
}
#[macro_export]
macro_rules! is_xf {
($x:expr) => {
($x as u32 & $crate::parser::ast::XF) != 0
};
}
#[macro_export]
macro_rules! is_fx {
($x:expr) => {
($x as u32 & $crate::parser::ast::FX) != 0
};
}
#[macro_export]
macro_rules! is_fy {
($x:expr) => {
($x as u32 & $crate::parser::ast::FY) != 0
};
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum RegType {
Perm(usize),
Temp(usize),
}
impl Default for RegType {
fn default() -> Self {
RegType::Temp(0)
}
}
impl RegType {
pub fn reg_num(self) -> usize {
match self {
RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num,
}
}
pub fn is_perm(self) -> bool {
matches!(self, RegType::Perm(_))
}
}
impl fmt::Display for RegType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
RegType::Perm(val) => write!(f, "Y{}", val),
RegType::Temp(val) => write!(f, "X{}", val),
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum VarReg {
ArgAndNorm(RegType, usize),
Norm(RegType),
}
impl VarReg {
pub fn norm(self) -> RegType {
match self {
VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg,
}
}
}
impl fmt::Display for VarReg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg),
VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg),
VarReg::ArgAndNorm(RegType::Perm(reg), arg) => write!(f, "Y{} A{}", reg, arg),
VarReg::ArgAndNorm(RegType::Temp(reg), arg) => write!(f, "X{} A{}", reg, arg),
}
}
}
impl Default for VarReg {
fn default() -> Self {
VarReg::Norm(RegType::default())
}
}
#[macro_export]
macro_rules! temp_v {
($x:expr) => {
$crate::parser::ast::RegType::Temp($x)
};
}
#[macro_export]
macro_rules! perm_v {
($x:expr) => {
$crate::parser::ast::RegType::Perm($x)
};
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum GenContext {
Head,
Mid(usize),
Last(usize), // Mid & Last: chunk_num
}
impl GenContext {
pub fn chunk_num(self) -> usize {
match self {
GenContext::Head => 0,
GenContext::Mid(cn) | GenContext::Last(cn) => cn,
}
}
}
#[bitfield]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
pub struct OpDesc {
prec: B11,
spec: B8,
#[allow(unused)] padding: B13,
}
impl OpDesc {
#[inline]
pub fn build_with(prec: u16, spec: u8) -> Self {
OpDesc::new().with_spec(spec).with_prec(prec)
}
#[inline]
pub fn get(self) -> (u16, u8) {
(self.prec(), self.spec())
}
pub fn set(&mut self, prec: u16, spec: u8) {
self.set_prec(prec);
self.set_spec(spec);
}
#[inline]
pub fn get_prec(self) -> u16 {
self.prec()
}
#[inline]
pub fn get_spec(self) -> u8 {
self.spec()
}
#[inline]
pub fn arity(self) -> usize {
if self.spec() as u32 & (XFX | XFY | YFX) == 0 {
1
} else {
2
}
}
}
// name and fixity -> operator type and precedence.
pub type OpDir = IndexMap<(Atom, Fixity), OpDesc, FxBuildHasher>;
#[derive(Debug, Clone, Copy)]
pub struct MachineFlags {
pub double_quotes: DoubleQuotes,
}
impl Default for MachineFlags {
fn default() -> Self {
MachineFlags {
double_quotes: DoubleQuotes::default(),
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum DoubleQuotes {
Atom,
Chars,
Codes,
}
impl DoubleQuotes {
pub fn is_chars(self) -> bool {
matches!(self, DoubleQuotes::Chars)
}
pub fn is_atom(self) -> bool {
matches!(self, DoubleQuotes::Atom)
}
pub fn is_codes(self) -> bool {
matches!(self, DoubleQuotes::Codes)
}
}
impl Default for DoubleQuotes {
fn default() -> Self {
DoubleQuotes::Chars
}
}
pub fn default_op_dir() -> OpDir {
let mut op_dir = OpDir::with_hasher(FxBuildHasher::default());
op_dir.insert(
(atom!(":-"), Fixity::In),
OpDesc::build_with(1200, XFX as u8),
);
op_dir.insert(
(atom!(":-"), Fixity::Pre),
OpDesc::build_with(1200, FX as u8),
);
op_dir.insert(
(atom!("?-"), Fixity::Pre),
OpDesc::build_with(1200, FX as u8),
);
op_dir.insert(
(atom!(","), Fixity::In),
OpDesc::build_with(1000, XFY as u8),
);
op_dir
}
#[derive(Debug, Clone)]
pub enum ArithmeticError {
NonEvaluableFunctor(Literal, usize),
UninstantiatedVar,
}
#[derive(Debug)]
pub enum ParserError {
BackQuotedString(usize, usize),
UnexpectedChar(char, usize, usize),
UnexpectedEOF,
IO(IOError),
IncompleteReduction(usize, usize),
InvalidSingleQuotedCharacter(char),
MissingQuote(usize, usize),
NonPrologChar(usize, usize),
ParseBigInt(usize, usize),
LexicalError(lexical::Error),
Utf8Error(usize, usize),
}
impl ParserError {
pub fn line_and_col_num(&self) -> Option<(usize, usize)> {
match self {
&ParserError::BackQuotedString(line_num, col_num)
| &ParserError::UnexpectedChar(_, line_num, col_num)
| &ParserError::IncompleteReduction(line_num, col_num)
| &ParserError::MissingQuote(line_num, col_num)
| &ParserError::NonPrologChar(line_num, col_num)
| &ParserError::ParseBigInt(line_num, col_num)
| &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)),
_ => None,
}
}
pub fn as_atom(&self) -> Atom {
match self {
ParserError::BackQuotedString(..) => atom!("back_quoted_string"),
ParserError::UnexpectedChar(..) => atom!("unexpected_char"),
ParserError::UnexpectedEOF => atom!("unexpected_end_of_file"),
ParserError::IncompleteReduction(..) => atom!("incomplete_reduction"),
ParserError::InvalidSingleQuotedCharacter(..) => atom!("invalid_single_quoted_character"),
ParserError::IO(_) => atom!("input_output_error"),
ParserError::LexicalError(_) => atom!("lexical_error"), // TODO: ?
ParserError::MissingQuote(..) => atom!("missing_quote"),
ParserError::NonPrologChar(..) => atom!("non_prolog_character"),
ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"),
ParserError::Utf8Error(..) => atom!("utf8_conversion_error"),
}
}
}
impl From<lexical::Error> for ParserError {
fn from(e: lexical::Error) -> ParserError {
ParserError::LexicalError(e)
}
}
impl From<IOError> for ParserError {
fn from(e: IOError) -> ParserError {
ParserError::IO(e)
}
}
impl From<&IOError> for ParserError {
fn from(error: &IOError) -> ParserError {
if error.get_ref().filter(|e| e.is::<BadUtf8Error>()).is_some() {
ParserError::Utf8Error(0, 0)
} else {
ParserError::IO(error.kind().into())
}
}
}
#[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: Atom, fixity: Fixity) -> Option<OpDesc> {
let entry = if let Some(ref primary_op_dir) = &self.primary_op_dir {
primary_op_dir.get(&(name, fixity))
} else {
None
};
entry
.or_else(move || self.secondary_op_dir.get(&(name, fixity)))
.cloned()
}
}
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub enum Fixity {
In,
Post,
Pre,
}
#[bitfield]
#[repr(u64)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct Fixnum {
num: B57,
#[allow(unused)] m: bool,
#[allow(unused)] tag: B6,
}
impl Fixnum {
#[inline]
pub fn build_with(num: i64) -> Self {
Fixnum::new()
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 57) - 1))
.with_tag(HeapCellValueTag::Fixnum as u8)
.with_m(false)
//num as u64).with__m(false)
}
#[inline]
pub fn build_with_checked(num: i64) -> Result<Self, OutOfBounds> {
const UPPER_BOUND: i64 = (1 << 56) - 1;
const LOWER_BOUND: i64 = -(1 << 56);
if LOWER_BOUND <= num && num <= UPPER_BOUND {
Ok(Fixnum::new()
.with_m(false)
.with_tag(HeapCellValueTag::Fixnum as u8)
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 57) - 1))) //num as u64 & ((1 << 57) - 1)))
} else {
Err(OutOfBounds {})
}
}
#[inline]
pub fn get_num(self) -> i64 {
let n = self.num() as i64;
let (n, overflowed) = (n << 7).overflowing_shr(7); // sign-extend the 57-bit signed fixnum.
debug_assert_eq!(overflowed, false);
n
}
}
impl Neg for Fixnum {
type Output = Self;
#[inline]
fn neg(self) -> Self::Output {
Fixnum::build_with(-self.get_num())
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Literal {
Atom(Atom),
Char(char),
Fixnum(Fixnum),
Integer(TypedArenaPtr<Integer>),
Rational(TypedArenaPtr<Rational>),
Float(F64Ptr),
String(Atom),
}
impl fmt::Display for Literal {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Literal::Atom(ref atom) => {
// if atom.as_str().chars().any(|c| "`.$'\" ".contains(c)) {
// write!(f, "'{}'", atom)
// } else {
write!(f, "{}", atom.flat_index())
// }
}
Literal::Char(c) => write!(f, "'{}'", *c as u32),
Literal::Fixnum(n) => write!(f, "{}", n.get_num()),
Literal::Integer(ref n) => write!(f, "{}", n),
Literal::Rational(ref n) => write!(f, "{}", n),
Literal::Float(ref n) => write!(f, "{}", *n),
Literal::String(ref s) => write!(f, "\"{}\"", s.as_str()),
// Literal::Usize(integer) => write!(f, "u{}", integer),
}
}
}
impl Literal {
pub fn to_atom(&self, atom_tbl: &mut AtomTable) -> Option<Atom> {
match self {
Literal::Atom(atom) => Some(atom.defrock_brackets(atom_tbl)),
_ => None,
}
}
}
#[derive(Debug, Clone)]
pub enum Term {
AnonVar,
Clause(Cell<RegType>, Atom, Vec<Term>),
Cons(Cell<RegType>, Box<Term>, Box<Term>),
Literal(Cell<RegType>, Literal),
PartialString(Cell<RegType>, Atom, Option<Box<Term>>),
Var(Cell<VarReg>, Rc<String>),
}
impl Term {
pub fn into_literal(self) -> Option<Literal> {
match self {
Term::Literal(_, c) => Some(c),
_ => None,
}
}
pub fn first_arg(&self) -> Option<&Term> {
match self {
Term::Clause(_, _, ref terms) => terms.first(),
_ => None,
}
}
pub fn set_name(&mut self, new_name: Atom) {
match self {
Term::Literal(_, Literal::Atom(ref mut atom)) | Term::Clause(_, ref mut atom, ..) => {
*atom = new_name;
}
_ => {}
}
}
pub fn name(&self) -> Option<Atom> {
match self {
&Term::Literal(_, Literal::Atom(ref atom)) | &Term::Clause(_, ref atom, ..) => {
Some(*atom)
}
_ => None,
}
}
pub fn arity(&self) -> usize {
match self {
Term::Clause(_, _, ref child_terms, ..) => child_terms.len(),
_ => 0,
}
}
}
fn unfold_by_str_once(term: &mut Term, s: Atom) -> Option<(Term, Term)> {
if let Term::Clause(_, ref name, ref mut subterms) = term {
if name == &s && subterms.len() == 2 {
let snd = subterms.pop().unwrap();
let fst = subterms.pop().unwrap();
return Some((fst, snd));
}
}
None
}
pub fn unfold_by_str(mut term: Term, s: Atom) -> Vec<Term> {
let mut terms = vec![];
while let Some((fst, snd)) = unfold_by_str_once(&mut term, s) {
terms.push(fst);
term = snd;
}
terms.push(term);
terms
}

747
src/parser/char_reader.rs Normal file
View File

@@ -0,0 +1,747 @@
/*
* CharReader is a not entirely redundant flattening/chimera of std's
* BufReader and unicode_reader's CodePoints, introduced to allow
* peekable buffered UTF-8 codepoints and access to the underlying
* reader.
*
* Unlike CodePoints, it doesn't make the reader inaccessible by
* wrapping it a Bytes struct.
*
* Unlike BufReader, its buffer is peekable as a char.
*/
use smallvec::*;
use std::error::Error;
use std::fmt;
use std::io;
use std::io::{ErrorKind, IoSliceMut, Read};
use std::str;
pub struct CharReader<R> {
inner: R,
buf: SmallVec<[u8;4]>,
pos: usize,
}
/// An error raised when parsing a UTF-8 byte stream fails.
#[derive(Debug)]
pub struct BadUtf8Error {
/// The bytes that could not be parsed as a code point.
pub bytes: Vec<u8>,
}
impl Error for BadUtf8Error {
fn description(&self) -> &str {
"BadUtf8Error"
}
}
impl fmt::Display for BadUtf8Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Bad UTF-8: {:?}", self.bytes)
}
}
impl<R> CharReader<R> {
pub fn new(inner: R) -> CharReader<R> {
Self {
inner,
buf: SmallVec::new(),
pos: 0,
}
}
#[inline]
pub fn inner(&self) -> &R {
&self.inner
}
#[inline]
pub fn inner_mut(&mut self) -> &mut R {
&mut self.inner
}
}
pub trait CharRead {
fn read_char(&mut self) -> Option<io::Result<char>> {
match self.peek_char() {
Some(Ok(c)) => {
self.consume(c.len_utf8());
Some(Ok(c))
}
result => result
}
}
fn peek_char(&mut self) -> Option<io::Result<char>>;
fn put_back_char(&mut self, c: char);
fn consume(&mut self, nread: usize);
}
impl<R> CharReader<R> {
pub fn get_ref(&self) -> &R {
&self.inner
}
pub fn get_mut(&mut self) -> &mut R {
&mut self.inner
}
pub fn buffer(&self) -> &[u8] {
&self.buf[self.pos..]
}
pub fn into_inner(self) -> R {
self.inner
}
fn reset_buffer(&mut self) {
self.buf.clear();
self.pos = 0;
}
}
impl<R: Read> CharReader<R> {
fn refresh_buffer(&mut self) -> io::Result<&[u8]> {
// If we've reached the end of our internal buffer then we need to fetch
// some more data from the underlying reader.
// Branch using `>=` instead of the more correct `==`
// to tell the compiler that the pos..cap slice is always valid.
if self.pos >= self.buf.len() {
debug_assert!(self.pos == self.buf.len());
self.buf.clear();
let mut word = [0u8;4];
let nread = self.inner.read(&mut word)?;
self.buf.extend_from_slice(&word[..nread]);
self.pos = 0;
}
Ok(&self.buf[self.pos..])
}
}
impl<R: Read> CharRead for CharReader<R> {
fn peek_char(&mut self) -> Option<io::Result<char>> {
match self.refresh_buffer() {
Ok(_buf) => {}
Err(e) => return Some(Err(e)),
}
loop {
let buf = &self.buf[self.pos..];
if !buf.is_empty() {
let e = match str::from_utf8(buf) {
Ok(s) => {
let mut chars = s.chars();
let c = chars.next().unwrap();
return Some(Ok(c));
}
Err(e) => {
e
}
};
if buf.len() - e.valid_up_to() >= 4 {
// If we have 4 bytes that still don't make up
// a valid code point, then we have garbage.
// We have bad data in the buffer. Remove
// leading bytes until either the buffer is
// empty, or we have a valid code point.
let mut split_point = 1;
let mut badbytes = vec![];
loop {
let (bad, rest) = buf.split_at(split_point);
if rest.is_empty() || str::from_utf8(rest).is_ok() {
badbytes.extend_from_slice(bad);
break;
}
split_point += 1;
}
// Raise the error. If we still have data in
// the buffer, it will be returned on the next
// loop.
return Some(Err(io::Error::new(io::ErrorKind::InvalidData,
BadUtf8Error { bytes: badbytes })));
} else {
if self.pos >= self.buf.len() {
return None;
} else if self.buf.len() - self.pos >= 4 {
return match str::from_utf8(&self.buf[..e.valid_up_to()]) {
Ok(s) => {
let mut chars = s.chars();
let c = chars.next().unwrap();
Some(Ok(c))
}
Err(e) => {
let badbytes = self.buf[..e.valid_up_to()].to_vec();
Some(Err(io::Error::new(io::ErrorKind::InvalidData,
BadUtf8Error { bytes: badbytes })))
}
};
} else {
let buf_len = self.buf.len();
for (c, idx) in (self.pos..buf_len).enumerate() {
self.buf[c] = self.buf[idx];
}
self.buf.truncate(buf_len - self.pos);
let buf_len = self.buf.len();
let mut word = [0u8;4];
let word_slice = &mut word[buf_len..4];
match self.inner.read(word_slice) {
Err(e) => return Some(Err(e)),
Ok(nread) => {
self.buf.extend_from_slice(&word_slice[0..nread]);
}
}
self.pos = 0;
}
}
} else {
return None;
}
}
}
#[inline(always)]
fn put_back_char(&mut self, c: char) {
let src_len = self.buf.len() - self.pos;
debug_assert!(src_len <= 4);
let c_len = c.len_utf8();
let mut shifted_slice = [0u8; 4];
shifted_slice[0..src_len].copy_from_slice(&self.buf[self.pos .. self.buf.len()]);
self.buf.resize(c_len, 0);
self.buf.extend_from_slice(&shifted_slice[0..src_len]);
self.pos = 0;
c.encode_utf8(&mut self.buf[0..c_len]);
}
#[inline(always)]
fn consume(&mut self, nread: usize) {
self.pos += nread;
}
}
/*
impl<R: Seek> BufReader<R> {
/// Seeks relative to the current position. If the new position lies within the buffer,
/// the buffer will not be flushed, allowing for more efficient seeks.
/// This method does not return the location of the underlying reader, so the caller
/// must track this information themselves if it is required.
#[stable(feature = "bufreader_seek_relative", since = "1.53.0")]
pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> {
let pos = self.pos as u64;
if offset < 0 {
if let Some(new_pos) = pos.checked_sub((-offset) as u64) {
self.pos = new_pos as usize;
return Ok(());
}
} else {
if let Some(new_pos) = pos.checked_add(offset as u64) {
if new_pos <= self.cap as u64 {
self.pos = new_pos as usize;
return Ok(());
}
}
}
self.seek(SeekFrom::Current(offset)).map(drop)
}
}
*/
impl<R: Read> Read for CharReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
// // If we don't have any buffered data and we're doing a massive read
// // (larger than our internal buffer), bypass our internal buffer
// // entirely.
// if self.pos == self.cap && buf.len() >= self.buf.len() {
// self.discard_buffer();
// return self.inner.read(buf);
// }
let mut inner_buf = self.refresh_buffer()?;
let nread = inner_buf.read(buf)?;
// let nread = {
// let mut rem = self.fill_buf()?;
// rem.read(buf)?
// };
self.consume(nread);
Ok(nread)
}
// Small read_exacts from a BufReader are extremely common when used with a deserializer.
// The default implementation calls read in a loop, which results in surprisingly poor code
// generation for the common path where the buffer has enough bytes to fill the passed-in
// buffer.
fn read_exact(&mut self, mut buf: &mut [u8]) -> io::Result<()> {
if self.buffer().len() >= buf.len() {
buf.copy_from_slice(&self.buffer()[..buf.len()]);
self.consume(buf.len());
return Ok(());
}
while !buf.is_empty() {
match self.read(buf) {
Ok(0) => break,
Ok(n) => {
let tmp = buf;
buf = &mut tmp[n..];
}
Err(e) if e.kind() == ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
}
if !buf.is_empty() {
Err(io::Error::new(ErrorKind::UnexpectedEof, "failed to fill whole buffer"))
} else {
Ok(())
}
}
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
if self.pos == self.buf.len() && total_len >= self.buf.len() {
self.reset_buffer(); // self.discard_buffer();
return self.inner.read_vectored(bufs);
}
let nread = {
self.refresh_buffer()?;
(&self.buf[self.pos..]).read_vectored(bufs)?
};
self.consume(nread);
Ok(nread)
}
}
/*
#[stable(feature = "rust1", since = "1.0.0")]
impl<R: Read> BufRead for BufReader<R> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
// If we've reached the end of our internal buffer then we need to fetch
// some more data from the underlying reader.
// Branch using `>=` instead of the more correct `==`
// to tell the compiler that the pos..cap slice is always valid.
if self.pos >= self.cap {
debug_assert!(self.pos == self.cap);
self.cap = self.inner.read(&mut self.buf)?;
self.pos = 0;
}
Ok(&self.buf[self.pos..self.cap])
}
fn consume(&mut self, amt: usize) {
self.pos = cmp::min(self.pos + amt, self.cap);
}
}
*/
impl<R> fmt::Debug for CharReader<R>
where
R: fmt::Debug,
{
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("CharReader")
.field("reader", &self.inner)
.field("buf", &format_args!("{}/{}", self.buf.capacity() - self.pos, self.buf.len()))
.finish()
}
}
/*
#[stable(feature = "rust1", since = "1.0.0")]
impl<R: Seek> Seek for BufReader<R> {
/// Seek to an offset, in bytes, in the underlying reader.
///
/// The position used for seeking with [`SeekFrom::Current`]`(_)` is the
/// position the underlying reader would be at if the `BufReader<R>` had no
/// internal buffer.
///
/// Seeking always discards the internal buffer, even if the seek position
/// would otherwise fall within it. This guarantees that calling
/// [`BufReader::into_inner()`] immediately after a seek yields the underlying reader
/// at the same position.
///
/// To seek without discarding the internal buffer, use [`BufReader::seek_relative`].
///
/// See [`std::io::Seek`] for more details.
///
/// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)`
/// where `n` minus the internal buffer length overflows an `i64`, two
/// seeks will be performed instead of one. If the second seek returns
/// [`Err`], the underlying reader will be left at the same position it would
/// have if you called `seek` with [`SeekFrom::Current`]`(0)`.
///
/// [`std::io::Seek`]: Seek
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
let result: u64;
if let SeekFrom::Current(n) = pos {
let remainder = (self.cap - self.pos) as i64;
// it should be safe to assume that remainder fits within an i64 as the alternative
// means we managed to allocate 8 exbibytes and that's absurd.
// But it's not out of the realm of possibility for some weird underlying reader to
// support seeking by i64::MIN so we need to handle underflow when subtracting
// remainder.
if let Some(offset) = n.checked_sub(remainder) {
result = self.inner.seek(SeekFrom::Current(offset))?;
} else {
// seek backwards by our remainder, and then by the offset
self.inner.seek(SeekFrom::Current(-remainder))?;
self.discard_buffer();
result = self.inner.seek(SeekFrom::Current(n))?;
}
} else {
// Seeking with Start/End doesn't care about our buffer length.
result = self.inner.seek(pos)?;
}
self.discard_buffer();
Ok(result)
}
/// Returns the current seek position from the start of the stream.
///
/// The value returned is equivalent to `self.seek(SeekFrom::Current(0))`
/// but does not flush the internal buffer. Due to this optimization the
/// function does not guarantee that calling `.into_inner()` immediately
/// afterwards will yield the underlying reader at the same position. Use
/// [`BufReader::seek`] instead if you require that guarantee.
///
/// # Panics
///
/// This function will panic if the position of the inner reader is smaller
/// than the amount of buffered data. That can happen if the inner reader
/// has an incorrect implementation of [`Seek::stream_position`], or if the
/// position has gone out of sync due to calling [`Seek::seek`] directly on
/// the underlying reader.
///
/// # Example
///
/// ```no_run
/// use std::{
/// io::{self, BufRead, BufReader, Seek},
/// fs::File,
/// };
///
/// fn main() -> io::Result<()> {
/// let mut f = BufReader::new(File::open("foo.txt")?);
///
/// let before = f.stream_position()?;
/// f.read_line(&mut String::new())?;
/// let after = f.stream_position()?;
///
/// println!("The first line was {} bytes long", after - before);
/// Ok(())
/// }
/// ```
fn stream_position(&mut self) -> io::Result<u64> {
let remainder = (self.cap - self.pos) as u64;
self.inner.stream_position().map(|pos| {
pos.checked_sub(remainder).expect(
"overflow when subtracting remaining buffer size from inner stream position",
)
})
}
}
*/
/*
impl<T> SizeHint for CharReader<T> {
fn lower_bound(&self) -> usize {
self.buffer().len()
}
}
*/
#[cfg(test)]
mod tests {
use crate::parser::char_reader::*;
use std::io::Cursor;
#[test]
fn plain_string() {
let mut read_string = CharReader::new(Cursor::new("a string"));
for c in "a string".chars() {
assert_eq!(read_string.peek_char().unwrap().ok(), Some(c));
assert_eq!(read_string.read_char().unwrap().ok(), Some(c));
}
assert!(read_string.read_char().is_none());
}
#[test]
fn greek_string() {
let mut read_string = CharReader::new(Cursor::new("λέξη"));
for c in "λέξη".chars() {
assert_eq!(read_string.peek_char().unwrap().ok(), Some(c));
assert_eq!(read_string.read_char().unwrap().ok(), Some(c));
}
assert!(read_string.read_char().is_none());
}
#[test]
fn russian_string() {
let mut read_string = CharReader::new(Cursor::new("слово"));
for c in "слово".chars() {
assert_eq!(read_string.peek_char().unwrap().ok(), Some(c));
assert_eq!(read_string.read_char().unwrap().ok(), Some(c));
}
assert!(read_string.read_char().is_none());
}
#[test]
fn greek_lorem_ipsum() {
let lorem_ipsum = "Λορεμ ιπσθμ δολορ σιτ αμετ, οφφενδιτ
εφφιcιενδι σιτ ει, ηαρθμ λεγερε qθαερενδθμ ιθσ νε. Ηασ νο εροσ
σιγνιφερθμqθε, σεδ ετ μθτατ jθστο, ει cθμ ελιγενδι σcριπτορεμ
ρεπρεηενδθντ. Εοσ ατ αμετ μαλισ ελειφενδ. Ιν cθμ εριπθιτ
νομινατι. Θσθ ιν cετεροσ μαιορθμ, μθνερε ατομορθμ ινcιδεριντ θτ
ηασ. Αν ηασ λιβρισ πραεσεντ πατριοqθε, ηινc θτιναμ πριμισ νε
cθμ. Cθ μοδο ερρεμ σcριβεντθρ cθμ. Ει vισ δεcορε μαλορθμ
σεντεντιαε, σεδ νο λιβερ εvερτι μεντιτθμ. Προ φαρ vολθτπατ
σαπιεντεμ ιν. Cθ εροσ περσεqθερισ πρι, εα ποσσιτ cετεροσ δθο. Πρι
εα μαλισ μθνερε.
ισστο μαλορθμ cθ qθο. Νεc ατ οδιο σολετ μαιεστατισ, νε
φορενσιβθσ σαδιπσcινγ ιθσ, ανι ειθσ βρθτε σαπιεντεμ. Cομμθνε
περcιπιτθρ ιθσ αδ, μθνερε δολορθμ ιμπεδιτ ηισ νε. Νεc ετιαμ
προπριαε vιτθπερατα ιν. Σονετ νεμορε ιθσ cθ, ιν αφφερτ ινερμισ
cοτιδιεqθε vισ.
Ηασ ιδ νονθμυ δοcτθσ cοτιδιεqθε. Σινγθλισ πηιλοσοπηια εξ δθο. Εστ
νο ιρανδια cονσεqθθντθρ. Τε διασ επιρει εφφιcιαντθρ δθο, εοσ
νε νθλλα νομιναvι. Εθμ cθ ελιτρ λιβεραvισσε, σιτ περσεqθερισ
cομπλεcτιτθρ εξ, πονδερθμ σιμιλιqθε ηασ νο.
Σολθμ ποσσιμ λαβιτθρ εξ ηισ, ει δομινγ εξπετενδισ vελ, διαμ μινιμ
σcριπσεριτ ει περ. Αθδιαμ ορρερετ προ εξ, δομινγ vολθπταρια ετ
ο. Cονσθλ σανcτθσ αccθμσαν νο ιθσ, αδ εαμ αλβθcιθσ
ηονεστατισ. Ετ vιξ φαcιλισαλισqθε ερροριβθσ, ηισ εθ πθρτο
ασσεντιορ. Ιθσ βονορθμ ηονεστατισ σcριπσεριτ ατ, ιν ναμ εσσε μοvετ
γραεcο. Αθγθε cονσεcτετθερ εστ ατ.
Αδ ταλε σθασ μθνερε σεδ, vισ φεθγαιτ αντιοπαμ ιδ. Προ εθ ινερμισ
σαλθτατθσ, σαεπε qθαεστιο θρβανιτασ cθ περ. Ιν μαλορθμ σαλθτατθσ
δετερρθισσετ περ, νε παρτεμ vολθτπατ ινστρθcτιορ vιξ. Νο vισ
δεμοcριτθμ εφφιcιαντθρ, επιρει αδολεσνσ εστ cθ, ιδ vιξ
λθcιλιθσ αδιπισcινγ. Σεα τε cλιτα ιρανδια. Σεα αν σιμθλ
εσσεντ. Vοcιβθσ ελειφενδ cονσεqθθντθρ περ αδ, αν ναμ πονδερθμ
vολθπταρια.
Λιβερ ερθδιτι αccθσαμθσ θτ ναμ. Σιτ αντιοπαμ γθβεργρεν νε. Αμετ
ανcιλλαε ετ qθι, μεα σολθμ λαθδεμ εα. Εθ μελ παρτεμ οβλιqθε
πηαεδρθμ. Εξ μελ jθστο αccομμοδαρε, νε νολθισσε σινγθλισ σενσιβθσ
cθμ, vισ εθ τιμεαμ αδιπισcινγ.
Τε νολθισσε vολθπτατθμ εστ. Ασσθμ νομιναvι πρι νε, ει νοστρθμ
επιρει μεα. Σεδ cθ ελιτ δεσερθντ, γραεcε ερροριβθσ προ θτ, περ
νε εθισμοδ vολθπταρια. Νο εθμ διcατ ποσσιμ, νεc πρινcιπεσ
cονcεπταμ νε. Εθ αππαρεατ ιντελλεγατ σεα. Μελ θτ ελιτ λαθδεμ, θσθ
δολορεμ cομπλεcτιτθρ ετ, νε μεα δολορεσ μολεστιαε.
Θσθ λεγενδοσ vολθπτατιβθσ cθ. Qθο νε αδηθc ρεφερρεντθρ, αλια
μεδιοcρεμ δθο νε, σεδ ερρεμ δολορθμ αccομμοδαρε νε. Ετιαμ εqθιδεμ
δετερρθισσετ cθ μει, ετ εροσ cετεροσ σεα, εξ vιξ ενιμ cασε
δετραξιτ. Σεδ σολθτα λιβρισ ειρμοδ τε, νοvθμ ποπθλο νε εθμ. Σθμμο
αδμοδθμ δεσερθντ εστ εξ, εστ διcαμ εqθιδεμ cθ.
Ιλλθμ cορπορα ινvιδθντ εαμ ετ. Σεδ μαλισ ταcιματεσ εvερτιτθρ εα,
μαζιμ νθλλαμ vοcιβθσ μεα ει. Μεα ορνατθσ λθπτατθμ αδιπισcινγ
αδ. Μεα αφφερτ νοστερ ατ, ναμ αν σολεατ ερροριβθσ. Εξ σεα αεqθε
μθνερε cετερο, εοσ ηινc ελειφενδ δεμοcριτθμ.";
let mut lorem_ipsum_reader = CharReader::new(Cursor::new(lorem_ipsum));
for c in lorem_ipsum.chars() {
assert_eq!(lorem_ipsum_reader.peek_char().unwrap().ok(), Some(c));
assert_eq!(lorem_ipsum_reader.read_char().unwrap().ok(), Some(c));
}
assert!(lorem_ipsum_reader.read_char().is_none());
}
#[test]
fn armenian_lorem_ipsum() {
let lorem_ipsum = "լոռեմ իպսում դոլոռ սիթ ամեթ, նովում գռաեծո
սեա եա, աբհոռռեանթ դիսպութանդո եի քուի. իդ քուոդ ինդոծթում
եսթ, մեա թե ծոմմոդո ծոռպոռա. եթ ծոնսուլ ադիպիսծինգ ռեֆոռմիդանս
պեռ, ինեռմիս ֆեուգաիթ նո քուո, թալե սալե պռո եա. եթ նիբհ
աուգուե վոլումուս դուո, նե ծում եխեռծի սալութաթուս գլոռիաթուռ,
ծու թաթիոն պռաեսենթ մեդիոծռեմ վիս.
վիխ եռոս ռեֆեռռենթուռ եու. պեռսիուս վիթուպեռաթոռիբուս ութ սեա,
վիդե ինվիդունթ պռոբաթուս նո քուո. մեի եռոս մելիուս նոմինավի
իդ, ութ պռո քուաս քուաեսթիո. եթ նաթում պեթենթիում սուավիթաթե
հիս. քուի ծոնսթիթութո մեդիոծռիթաթեմ թե. ծեթեռո դեթռածթո
ծոնծեպթամ սեա եթ. դիսսենթիեթ ելոքուենթիամ թհեոպհռասթուս նեծ
աթ, աթ ֆածեթե եռիպուիթ վիխ.
ասսուեվեռիթ սծռիպսեռիթ եսթ եթ, վիդիթ դեբեթ եվեռթի եխ
եսթ. աութեմ լաուդեմ պոսիդոնիում մեի եի. ռեբում դիծամ ծեթեռոս
եում ծու. նիհիլ եխպեթենդա ասսուեվեռիթ ուսու ան. ւիսի թաթիոն
դելենիթ նո իուս, սեդ եխ իդքուե սիգնիֆեռումքուե, բռութե զռիլ
ալբուծիուս ան պռի.
մովեթ իռիուռե սալութանդի պեռ նո, եի ոմնիս աֆֆեռթ պեռսեքուեռիս
իուս, եթ պռաեսենթ մալուիսսեթ եսթ. եսթ պռոբո գուբեռգռեն եթ, հաս
ին դիամ նումքուամ. ֆեուգաիթ ինվենիռե ռեպուդիանդաե աթ սեդ,
իուվառեթ ծոնսուլաթու եֆֆիծիանթուռ ուսու եի. ութ մեա ածծումսան
նոմինավի թինծիդունթ, մեի դիծթա ածծումսան ութ. վիմ ոմնիում
ելիգենդի սծռիպթոռեմ եու.
իդ վիս եռռոռ ալիքուիպ ելոքուենթիամ, ադ դելենիթի պեռծիպիթ
դեֆինիթիոնես իուս. վիմ իուդիծո դեմոծռիթում ծոմպռեհենսամ թե,
ութ նիհիլ լոբոռթիս վոլուպթաթիբուս վել, դիծունթ մենթիթում
ֆածիլիսիս եի եում. եսսե սալե մինիմ եոս նե. ագամ ոմնեսքուե ծում
ին.
իուվառեթ իուդիծաբիթ ծում աթ, ուսու նիբհ աթքուի դոմինգ եխ. եի
քուի սանծթուս սենսիբուս, նամ ուբիքուե ապպեթեռե պռոդեսսեթ
եու. ուսու եթ աուգուե ծոնվենիռե սծռիբենթուռ. ան ոմնիում վեռեառ
ութռոքուե դուո, եսթ եի լիբեռ մեդիոծռեմ եխպլիծառի, ոմնիս
աուդիռե թե պռի. վիմ մունեռե սոլեաթ ծու, եռոս ինվենիռե
դիսպութաթիոնի եի քուո, ան ալթեռա պութենթ լաբոռես պռո. անթիոպամ
դեմոծռիթում պեռ ին.
նե քուի ծիբո ելիթռ. նեծ նե լիբեռ վոլուպթուա. նիսլ ծոմմունե
եխպեթենդիս նամ եխ, իուդիծո պլածեռաթ պեռծիպիթուռ մել նո, եթ
պառթեմ պութանթ քուի. վիմ թինծիդունթ ածծոմմոդառե աթ, նե նամ
վիդիթ իռիուռե, պռո եա ելիգենդի պոսթուլանթ ծոնսթիթութո.
մել ութ ոդիո նուլլամ եխպլիծառի. պռոպռիաե թինծիդունթ
դելիծաթիսսիմի եամ ան, մոդո քուոդսի ապեռիռի եու եսթ, պեռ աթ
լաբոռես սենսեռիթ. վիմ ծոնգուե ռեպուդիանդաե եի, նեծ ագամ
դիծունթ դելիծաթիսսիմի աթ. պոսսիթ լիբեռավիսսե եոս եու.
աթ ալիա դեբեթ ելաբոռառեթ քուո, ին ալիի ածծումսան ծոնսթիթուամ
հաս, մել թոթա ոմիթթանթուռ ինսթռուծթիոռ նո. պեռ նե ծաուսաե
սապիենթեմ, պաուլո ոմնեսքուե եի քուո, եխ ոռաթիո պհիլոսոպհիա
սիթ. իգնոթա ծաուսաե աթ ուսու, եխ քուո դիծթաս քուոդսի
ռեպուդիառե. ծոռպոռա պռոդեսսեթ ռեֆեռռենթուռ եոս եխ.
եու եթիամ ելեիֆենդ մել, սալե սծռիպսեռիթ հիս եու. պոռռո
ադոլեսծենս մեի եա. ին մեա զռիլ պռոբաթուս սալութաթուս. եոս ադ
մինիմ թեմպոռիբուս. սեա նե եթիամ.";
let mut lorem_ipsum_reader = CharReader::new(Cursor::new(lorem_ipsum));
for c in lorem_ipsum.chars() {
assert_eq!(lorem_ipsum_reader.peek_char().unwrap().ok(), Some(c));
assert_eq!(lorem_ipsum_reader.read_char().unwrap().ok(), Some(c));
}
assert!(lorem_ipsum_reader.read_char().is_none());
}
#[test]
fn russian_lorem_ipsum() {
let lorem_ipsum = "Лорем ипсум долор сит амет, атяуи дицам еи
сит, ид сеа фацилис елаборарет. Меа еу яуас алияуид, те яуи
саперет аппеллантур. Ех иус диам дицта волуптариа, еу пер
бруте омиттам аццусата. Хис сапиентем губергрен те, яуидам
луптатум персеяуерис ад ест.
Ан алияуип перицулис нам, нец апериам цотидиеяуе волуптатибус
но. Солум тритани пер ех, меи не одио тритани рецусабо, цу при
веро мелиоре импердиет. Ин граеци индоцтум салутатус нец, диам
сцаевола пертинациа про те. Ут сеа дебитис лаборамус
диссентиас, еи цум яуот лобортис.
Децоре сингулис вим не. Еос не риденс оффициис, еу нонумы
лабитур еррорибус хас, вел омнис цонституто посидониум но. Вел
персиус фастидии репрехендунт ид. Натум иллум ипсум сит ад, еа
еам новум латине. Еос нолуиссе патриояуе елояуентиам те.
Стет малис яуаерендум хас ад, прима цотидиеяуе мел ан,
трацтатос десеруиссе нам ех. Ин малорум сусципиантур вим, ех
меа граецо тритани адолесценс. Промпта цонцлусионемяуе нам еи,
дуо ин лаборе алтерум цотидиеяуе. Но елитр промпта сплендиде
еум, аеяуе ассуеверит цонституам яуи ид. Ад тале еррор
интеллегебат хас, ерудити граецис хас не, пер ут лабитур
еуисмод. Те при суммо путант. Про утинам цоммуне урбанитас еа.
Идяуе репрехендунт еи нам, алии толлит легере нам не, хис еа
виси адверсариум цонцлусионемяуе. Хас ассум омиттам луцилиус
ет, вих цонсул малорум фастидии не, сенсибус ассуеверит дуо
ут. Дуо алиа видит цетеро ат, еа аппареат пертинах вел. Пер
цонституто инцидеринт ин, убияуе риденс сенсерит цум цу. Про
ет цетерос темпорибус, те вел пурто суммо, дуо мунере вертерем
урбанитас ад. Сит оптион елецтрам форенсибус но. Еи татион
сапиентем ест, лаборе сцрипта сингулис но вим, усу еу елигенди
персецути.
Иус ан елецтрам цонтентионес. Меи атяуи нонумес ут, вел амет
репрехендунт ан, вис еу яуаестио патриояуе. Про синт легере
детрацто ад. Постеа долорем евертитур при ет, вим номинави
принципес ирацундиа ех. Доцтус интеллегебат но нам. Фацете
оффициис нецесситатибус цу меа.
Промпта симилияуе вис ин. Пер бонорум перицулис аргументум
ад. Еу дицат фацилис губергрен нам, еффициенди цомпрехенсам
хас еу. Инани нонумы усу но, ад цонцептам репудиандае
про. Тота нуллам делицата еа яуо, усу дуис дебет путент еи.
Вис апериам доценди елояуентиам еа. Ех яуот детрацто
елояуентиам цум, ерос малис дицерет вис ин. Еа цум модус
еяуидем, дебет нуллам ан меи. Алтерум омиттам про ет.
Яуи ех латине алияуам, ан меи одио нуллам. Ид хас омнис ребум
либрис. Ет убияуе путант дебитис про, ех хис медиоцрем
партиендо, но елит елецтрам дуо. Еу меа сонет номинави
цотидиеяуе. Нам фалли новум минимум еу, перфецто ратионибус
цонституто ад меа.
Нобис детрацто еам ид, при еу ассум пертинах, те етиам
проприае салутанди яуо. Легимус сусципиантур ет хас, сед
поссит дефинитионес еа. Ест не патриояуе омиттантур
интеллегебат, еу яуо дебет цонцлудатуряуе. Еум ад мнесарчум
дефинитионем, елитр лаборамус перципитур про не, хас феугаит
фастидии луцилиус ид. Фастидии интеллегат ех.";
let mut lorem_ipsum_reader = CharReader::new(Cursor::new(lorem_ipsum));
for c in lorem_ipsum.chars() {
assert_eq!(lorem_ipsum_reader.peek_char().unwrap().ok(), Some(c));
assert_eq!(lorem_ipsum_reader.read_char().unwrap().ok(), Some(c));
lorem_ipsum_reader.put_back_char(c);
assert_eq!(lorem_ipsum_reader.peek_char().unwrap().ok(), Some(c));
assert_eq!(lorem_ipsum_reader.read_char().unwrap().ok(), Some(c));
}
assert!(lorem_ipsum_reader.read_char().is_none());
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -54,9 +54,9 @@ macro_rules! back_quote_char {
} }
#[macro_export] #[macro_export]
macro_rules! binary_digit_char { macro_rules! octet_char {
($c: expr) => { ($c: expr) => {
$c >= '0' && $c <= '1' ('\u{0000}'..='\u{00FF}').contains(&$c)
}; };
} }
@@ -172,9 +172,9 @@ macro_rules! octal_digit_char {
} }
#[macro_export] #[macro_export]
macro_rules! octet_char { macro_rules! binary_digit_char {
($c: expr) => { ($c: expr) => {
('\u{0000}'..='\u{00FF}').contains(&$c) $c >= '0' && $c <= '1'
}; };
} }

View File

@@ -1,15 +1,17 @@
#[cfg(feature = "num-rug-adapter")] #[cfg(feature = "num-rug-adapter")]
use num_rug_adapter as rug; use num_rug_adapter as rug;
#[cfg(feature = "rug")] #[cfg(feature = "rug")]
use rug; pub use rug;
#[macro_use] // #[macro_use]
pub mod tabled_rc; // extern crate lazy_static;
// #[macro_use]
// extern crate static_assertions;
pub mod char_reader;
#[macro_use] #[macro_use]
pub mod ast; pub mod ast;
#[macro_use] #[macro_use]
pub mod macros; pub mod macros;
pub mod parser;
pub mod put_back_n;
pub mod lexer; pub mod lexer;
pub mod parser;

View File

@@ -1,14 +1,15 @@
use crate::ast::*; use crate::arena::*;
use crate::lexer::*; use crate::atom_table::*;
use crate::tabled_rc::*; use crate::parser::ast::*;
use crate::parser::char_reader::*;
use crate::parser::lexer::*;
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
use crate::rug::ops::NegAssign; use rug::ops::NegAssign;
use std::cell::Cell; use std::cell::Cell;
use std::io::Read; use std::mem;
use std::mem::swap;
use std::rc::Rc; use std::rc::Rc;
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
@@ -50,69 +51,114 @@ struct TokenDesc {
spec: u32, spec: u32,
} }
pub fn get_clause_spec( fn is_partial_string(
name: ClauseName, head: Term,
arity: usize, mut tail: Term,
op_dir: &CompositeOpDir, atom_tbl: &mut AtomTable,
) -> Option<SharedOpDesc> { ) -> Result<(Atom, Option<Box<Term>>), Term> {
match arity { let mut string = match &head {
1 => { Term::Literal(_, Literal::Atom(atom)) => {
/* This is a clause with an operator principal functor. Prefix operators if let Some(c) = atom.as_char() {
are supposed over post. c.to_string()
*/ } else {
if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::Pre) { return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail)));
return Some(cell.clone());
}
if let Some(OpDirValue(cell)) = op_dir.get(name, Fixity::Post) {
return Some(cell.clone());
} }
} }
2 => { Term::Literal(_, Literal::Char(c)) => c.to_string(),
if let Some(OpDirValue(cell)) = op_dir.get(name, Fixity::In) { _ => {
return Some(cell.clone()); return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail)));
} }
}
_ => {}
}; };
None let mut orig_tail = Box::new(tail);
let mut tail_ref = &mut orig_tail;
loop {
match &mut **tail_ref {
Term::Cons(_, prev, succ) => {
match prev.as_ref() {
Term::Literal(_, Literal::Atom(atom)) => {
if let Some(c) = atom.as_char() {
string.push(c);
} else {
return Err(Term::Cons(Cell::default(), Box::new(head), orig_tail));
}
}
Term::Literal(_, Literal::Char(c)) => {
string.push(*c);
}
_ => {
return Err(Term::Cons(Cell::default(), Box::new(head), orig_tail));
}
} }
pub fn get_op_desc(name: ClauseName, op_dir: &CompositeOpDir) -> Option<OpDesc> { tail_ref = succ;
let mut op_desc = OpDesc { }
tail_ref => {
tail = mem::replace(tail_ref, Term::AnonVar);
break;
}
}
}
match &tail {
Term::AnonVar | Term::Var(..) => {
let pstr_atom = atom_tbl.build_with(&string);
Ok((pstr_atom, Some(Box::new(tail))))
}
Term::Literal(_, Literal::Atom(atom!("[]"))) => {
let pstr_atom = atom_tbl.build_with(&string);
Ok((pstr_atom, None))
}
Term::Literal(_, Literal::String(tail)) => {
string += tail.as_str();
let pstr_atom = atom_tbl.build_with(&string);
Ok((pstr_atom, None))
}
_ => {
let pstr_atom = atom_tbl.build_with(&string);
Ok((pstr_atom, Some(Box::new(tail))))
}
}
}
pub fn get_op_desc(
name: Atom,
op_dir: &CompositeOpDir,
) -> Option<CompositeOpDesc> {
let mut op_desc = CompositeOpDesc {
pre: 0, pre: 0,
inf: 0, inf: 0,
post: 0, post: 0,
spec: 0, spec: 0,
}; };
if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::Pre) { if let Some(cell) = op_dir.get(name, Fixity::Pre) {
let (pri, spec) = cell.get(); let (pri, spec) = cell.get();
if pri > 0 { if pri > 0 {
op_desc.pre = pri; op_desc.pre = pri as usize;
op_desc.spec |= spec; op_desc.spec |= spec as u32;
} else if name.as_str() == "-" { } else if name == atom!("-") {
op_desc.spec |= NEGATIVE_SIGN; op_desc.spec |= NEGATIVE_SIGN;
} }
} }
if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::Post) { if let Some(cell) = op_dir.get(name, Fixity::Post) {
let (pri, spec) = cell.get(); let (pri, spec) = cell.get();
if pri > 0 { if pri > 0 {
op_desc.post = pri; op_desc.post = pri as usize;
op_desc.spec |= spec; op_desc.spec |= spec as u32;
} }
} }
if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::In) { if let Some(cell) = op_dir.get(name, Fixity::In) {
let (pri, spec) = cell.get(); let (pri, spec) = cell.get();
if pri > 0 { if pri > 0 {
op_desc.inf = pri; op_desc.inf = pri as usize;
op_desc.spec |= spec; op_desc.spec |= spec as u32;
} }
} }
@@ -123,6 +169,31 @@ pub fn get_op_desc(name: ClauseName, op_dir: &CompositeOpDir) -> Option<OpDesc>
} }
} }
pub fn get_clause_spec(name: Atom, arity: usize, op_dir: &CompositeOpDir) -> Option<OpDesc> {
match arity {
1 => {
/* This is a clause with an operator principal functor. Prefix operators
are supposed over post.
*/
if let Some(cell) = op_dir.get(name, Fixity::Pre) {
return Some(cell);
}
if let Some(cell) = op_dir.get(name, Fixity::Post) {
return Some(cell);
}
}
2 => {
if let Some(cell) = op_dir.get(name, Fixity::In) {
return Some(cell);
}
}
_ => {}
};
None
}
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)
@@ -164,23 +235,8 @@ 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> {
match tt {
TokenType::Open | TokenType::OpenCT => Some(clause_name!("(")),
TokenType::Close => Some(clause_name!(")")),
TokenType::OpenList => Some(clause_name!("[")),
TokenType::CloseList => Some(clause_name!("]")),
TokenType::OpenCurly => Some(clause_name!("{")),
TokenType::CloseCurly => Some(clause_name!("}")),
TokenType::HeadTailSeparator => Some(clause_name!("|")),
TokenType::Comma => Some(clause_name!(",")),
TokenType::End => Some(clause_name!(".")),
_ => None,
}
}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct OpDesc { pub struct CompositeOpDesc {
pub pre: usize, pub pre: usize,
pub inf: usize, pub inf: usize,
pub post: usize, pub post: usize,
@@ -188,14 +244,14 @@ pub struct OpDesc {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Parser<'a, R: Read> { pub struct Parser<'a, R> {
lexer: Lexer<'a, R>, pub lexer: Lexer<'a, R>,
tokens: Vec<Token>, tokens: Vec<Token>,
stack: Vec<TokenDesc>, stack: Vec<TokenDesc>,
terms: Vec<Term>, terms: Vec<Term>,
} }
fn read_tokens<R: Read>(lexer: &mut Lexer<R>) -> Result<Vec<Token>, ParserError> { fn read_tokens<R: CharRead>(lexer: &mut Lexer<R>) -> Result<Vec<Token>, ParserError> {
let mut tokens = vec![]; let mut tokens = vec![];
loop { loop {
@@ -209,7 +265,10 @@ fn read_tokens<R: Read>(lexer: &mut Lexer<R>) -> Result<Vec<Token>, ParserError>
} }
} }
Err(ParserError::UnexpectedEOF) if !tokens.is_empty() => { Err(ParserError::UnexpectedEOF) if !tokens.is_empty() => {
return Err(ParserError::IncompleteReduction(lexer.line_num, lexer.col_num)); return Err(ParserError::IncompleteReduction(
lexer.line_num,
lexer.col_num,
));
} }
Err(e) => { Err(e) => {
return Err(e); return Err(e);
@@ -222,20 +281,46 @@ fn read_tokens<R: Read>(lexer: &mut Lexer<R>) -> Result<Vec<Token>, ParserError>
Ok(tokens) Ok(tokens)
} }
impl<'a, R: Read> Parser<'a, R> { fn atomize_term(atom_tbl: &mut AtomTable, term: &Term) -> Option<Atom> {
pub fn new( match term {
stream: &'a mut ParsingStream<R>, Term::Literal(_, ref c) => atomize_constant(atom_tbl, *c),
atom_tbl: TabledData<Atom>, _ => None,
flags: MachineFlags, }
) -> Self { }
fn atomize_constant(atom_tbl: &mut AtomTable, c: Literal) -> Option<Atom> {
match c {
Literal::Atom(ref name) => Some(*name),
Literal::Char(c) => Some(atom_tbl.build_with(&c.to_string())),
_ => None,
}
}
impl<'a, R: CharRead> Parser<'a, R> {
pub fn new(stream: R, machine_st: &'a mut MachineState) -> Self {
Parser { Parser {
lexer: Lexer::new(atom_tbl, flags, stream), lexer: Lexer::new(stream, machine_st),
tokens: vec![], tokens: vec![],
stack: Vec::new(), stack: Vec::new(),
terms: Vec::new(), terms: Vec::new(),
} }
} }
fn sep_to_atom(&mut self, tt: TokenType) -> Option<Atom> {
match tt {
TokenType::Open | TokenType::OpenCT => Some(atom!("(")),
TokenType::Close => Some(atom!(")")),
TokenType::OpenList => Some(atom!("[")),
TokenType::CloseList => Some(atom!("]")),
TokenType::OpenCurly => Some(atom!("{")),
TokenType::CloseCurly => Some(atom!("}")),
TokenType::HeadTailSeparator => Some(atom!("|")),
TokenType::Comma => Some(atom!(",")),
TokenType::End => Some(atom!(".")),
_ => None,
}
}
#[inline] #[inline]
pub fn line_num(&self) -> usize { pub fn line_num(&self) -> usize {
self.lexer.line_num self.lexer.line_num
@@ -246,25 +331,12 @@ impl<'a, R: Read> Parser<'a, R> {
self.lexer.col_num self.lexer.col_num
} }
#[inline] fn get_term_name(&mut self, td: TokenDesc) -> Option<Atom> {
pub fn get_atom_tbl(&self) -> TabledData<Atom> {
self.lexer.atom_tbl.clone()
}
#[inline]
pub fn set_atom_tbl(&mut self, atom_tbl: TabledData<Atom>) {
self.lexer.atom_tbl = atom_tbl;
}
fn get_term_name(&mut self, td: TokenDesc) -> Option<(ClauseName, Option<SharedOpDesc>)> {
match td.tt { match td.tt {
TokenType::HeadTailSeparator => Some(( TokenType::HeadTailSeparator => Some(atom!("|")),
clause_name!("|"), TokenType::Comma => Some(atom!(",")),
Some(SharedOpDesc::new(td.priority, td.spec)),
)),
TokenType::Comma => Some((clause_name!(","), Some(SharedOpDesc::new(1000, XFY)))),
TokenType::Term => match self.terms.pop() { TokenType::Term => match self.terms.pop() {
Some(Term::Constant(_, Constant::Atom(atom, spec))) => Some((atom, spec)), Some(Term::Literal(_, Literal::Atom(atom))) => Some(atom),
Some(term) => { Some(term) => {
self.terms.push(term); self.terms.push(term);
None None
@@ -277,14 +349,9 @@ impl<'a, R: Read> Parser<'a, R> {
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) = self.get_term_name(td) {
if let Some(arg1) = self.terms.pop() { if let Some(arg1) = self.terms.pop() {
let term = Term::Clause( let term = Term::Clause(Cell::default(), name, vec![arg1, arg2]);
Cell::default(),
name,
vec![Box::new(arg1), Box::new(arg2)],
shared_op_desc,
);
self.terms.push(term); self.terms.push(term);
self.stack.push(TokenDesc { self.stack.push(TokenDesc {
@@ -301,12 +368,11 @@ impl<'a, R: Read> Parser<'a, R> {
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) {
swap(&mut arg1, &mut name); mem::swap(&mut arg1, &mut name);
} }
if let Term::Constant(_, Constant::Atom(name, shared_op_desc)) = name { if let Term::Literal(_, Literal::Atom(name)) = name {
let term = let term = Term::Clause(Cell::default(), name, vec![arg1]);
Term::Clause(Cell::default(), name, vec![Box::new(arg1)], shared_op_desc);
self.terms.push(term); self.terms.push(term);
self.stack.push(TokenDesc { self.stack.push(TokenDesc {
@@ -319,17 +385,8 @@ impl<'a, R: Read> Parser<'a, R> {
} }
} }
fn promote_atom_op( fn promote_atom_op(&mut self, atom: Atom, priority: usize, assoc: u32) {
&mut self, self.terms.push(Term::Literal(Cell::default(), Literal::Atom(atom)));
atom: ClauseName,
priority: usize,
assoc: u32,
op_dir_val: Option<&OpDirValue>,
) {
let spec = op_dir_val.map(|op_dir_val| op_dir_val.shared_op_desc());
self.terms
.push(Term::Constant(Cell::default(), Constant::Atom(atom, spec)));
self.stack.push(TokenDesc { self.stack.push(TokenDesc {
tt: TokenType::Term, tt: TokenType::Term,
priority, priority,
@@ -339,15 +396,15 @@ impl<'a, R: Read> Parser<'a, R> {
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)) if self.lexer.flags.double_quotes.is_codes() => { Token::Literal(Literal::String(s)) if self.lexer.machine_st.flags.double_quotes.is_codes() => {
let mut list = Term::Constant(Cell::default(), Constant::EmptyList); let mut list = Term::Literal(Cell::default(), Literal::Atom(atom!("[]")));
for c in s.chars().rev() { for c in s.as_str().chars().rev() {
list = Term::Cons( list = Term::Cons(
Cell::default(), Cell::default(),
Box::new(Term::Constant( Box::new(Term::Literal(
Cell::default(), Cell::default(),
Constant::Fixnum(c as isize), Literal::Fixnum(Fixnum::build_with(c as i64)),
)), )),
Box::new(list), Box::new(list),
); );
@@ -356,15 +413,19 @@ impl<'a, R: Read> Parser<'a, R> {
self.terms.push(list); self.terms.push(list);
TokenType::Term TokenType::Term
} }
Token::Constant(c) => { Token::Literal(Literal::String(s)) if self.lexer.machine_st.flags.double_quotes.is_chars() => {
self.terms.push(Term::Constant(Cell::default(), c)); self.terms.push(Term::PartialString(Cell::default(), s, None));
TokenType::Term
}
Token::Literal(c) => {
self.terms.push(Term::Literal(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);
} else { } else {
self.terms.push(Term::Var(Cell::default(), v)); self.terms.push(Term::Var(Cell::default(), Rc::new(v)));
} }
TokenType::Term TokenType::Term
@@ -457,7 +518,7 @@ impl<'a, R: Read> Parser<'a, R> {
None None
} }
fn reduce_term(&mut self, op_dir: &CompositeOpDir) -> bool { fn reduce_term(&mut self) -> bool {
if self.stack.is_empty() { if self.stack.is_empty() {
return false; return false;
} }
@@ -489,22 +550,40 @@ impl<'a, R: Read> Parser<'a, R> {
let idx = self.terms.len() - arity; let idx = self.terms.len() - arity;
if TokenType::Term == self.stack[stack_len].tt { if TokenType::Term == self.stack[stack_len].tt {
if self.atomize_term(&self.terms[idx - 1]).is_some() { if atomize_term(&mut self.lexer.machine_st.atom_tbl, &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..).map(Box::new).collect(); let mut subterms: Vec<_> = self.terms.drain(idx..).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| atomize_term(&mut self.lexer.machine_st.atom_tbl, &t))
{
// reduce the '.' functor to a cons cell if it applies. // reduce the '.' functor to a cons cell if it applies.
if name.as_str() == "." && subterms.len() == 2 { if name == atom!(".") && subterms.len() == 2 {
let tail = subterms.pop().unwrap(); let tail = subterms.pop().unwrap();
let head = subterms.pop().unwrap(); let head = subterms.pop().unwrap();
self.terms.push(Term::Cons(Cell::default(), head, tail)); self.terms.push(
match is_partial_string(head, tail, &mut self.lexer.machine_st.atom_tbl) {
Ok((string_buf, tail_opt)) => {
Term::PartialString(Cell::default(), string_buf, tail_opt)
}
Err(term) => term,
},
);
/*
self.terms.push(Term::Cons(
Cell::default(),
Box::new(head),
Box::new(tail),
));
*/
} else { } else {
let spec = get_clause_spec(name.clone(), subterms.len(), op_dir);
self.terms self.terms
.push(Term::Clause(Cell::default(), name, subterms, spec)); .push(Term::Clause(Cell::default(), name, subterms));
} }
if let Some(&mut TokenDesc { if let Some(&mut TokenDesc {
@@ -544,8 +623,8 @@ impl<'a, R: Read> Parser<'a, R> {
* an operator, so expand the * an operator, so expand the
* terms it compacted out again. */ * terms it compacted out again. */
match (term.name(), term.arity()) { match (term.name(), term.arity()) {
(Some(name), 2) if name.as_str() == "," => { (Some(name), 2) if name == atom!(",") => {
let terms = unfold_by_str(term, ","); let terms = unfold_by_str(term, name); // notice: name == "," here.
let arity = terms.len() - 1; let arity = terms.len() - 1;
self.terms.extend(terms.into_iter()); self.terms.extend(terms.into_iter());
@@ -603,8 +682,7 @@ impl<'a, R: Read> Parser<'a, R> {
td.tt = TokenType::Term; td.tt = TokenType::Term;
td.priority = 0; td.priority = 0;
self.terms self.terms.push(Term::Literal(Cell::default(), Literal::Atom(atom!("[]"))));
.push(Term::Constant(Cell::default(), Constant::EmptyList));
return Ok(true); return Ok(true);
} }
} }
@@ -621,7 +699,7 @@ impl<'a, R: Read> Parser<'a, R> {
let list_len = self.stack.len() - 2 * arity; let list_len = self.stack.len() - 2 * arity;
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::Literal(Cell::default(), Literal::Atom(atom!("[]")))
} else { } else {
let term = match self.terms.pop() { let term = match self.terms.pop() {
Some(term) => term, Some(term) => term,
@@ -662,7 +740,18 @@ impl<'a, R: Read> Parser<'a, R> {
priority: 0, priority: 0,
spec: TERM, spec: TERM,
}); });
self.terms.push(list);
self.terms.push(match list {
Term::Cons(_, head, tail) => {
match is_partial_string(*head, *tail, &mut self.lexer.machine_st.atom_tbl) {
Ok((string_buf, tail_opt)) => {
Term::PartialString(Cell::default(), string_buf, tail_opt)
}
Err(term) => term,
}
}
term => term,
});
Ok(true) Ok(true)
} }
@@ -678,7 +767,11 @@ 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(), atom!("{}", self.lexer.atom_tbl)); let term = Term::Literal(
Cell::default(),
Literal::Atom(atom!("{}")),
);
self.terms.push(term); self.terms.push(term);
return Ok(true); return Ok(true);
} }
@@ -710,9 +803,8 @@ impl<'a, R: Read> Parser<'a, R> {
self.terms.push(Term::Clause( self.terms.push(Term::Clause(
Cell::default(), Cell::default(),
clause_name!("{}"), atom!("{}"),
vec![Box::new(term)], vec![term],
None,
)); ));
return Ok(true); return Ok(true);
@@ -744,27 +836,28 @@ impl<'a, R: Read> Parser<'a, R> {
return false; return false;
} }
if let Some(atom) = sep_to_atom(self.stack[idx].tt) { if let Some(atom) = self.sep_to_atom(self.stack[idx].tt) {
self.terms self.terms
.push(Term::Constant(Cell::default(), Constant::Atom(atom, None))); .push(Term::Literal(Cell::default(), Literal::Atom(atom)));
} }
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: &CompositeOpDir) -> Result<bool, ParserError> { fn shift_op(&mut self, name: Atom, op_dir: &CompositeOpDir) -> Result<bool, ParserError> {
if let Some(OpDesc { if let Some(CompositeOpDesc {
pre, pre,
inf, inf,
post, post,
spec, spec,
}) = get_op_desc(name.clone(), op_dir) }) = get_op_desc(name, 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)? {
@@ -775,15 +868,9 @@ impl<'a, R: Read> Parser<'a, R> {
// or post == 0. // or post == 0.
self.reduce_op(inf + post); self.reduce_op(inf + post);
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);
self.promote_atom_op( self.promote_atom_op(name, inf + post, spec & (XFX | XFY | YFX | YF | XF));
name,
inf + post,
spec & (XFX | XFY | YFX | YF | XF),
op_dir_val,
);
} }
_ => { _ => {
self.reduce_op(inf + post); self.reduce_op(inf + post);
@@ -791,49 +878,22 @@ impl<'a, R: Read> Parser<'a, R> {
if let Some(TokenDesc { spec: pspec, .. }) = self.stack.last().cloned() { if let Some(TokenDesc { spec: pspec, .. }) = self.stack.last().cloned() {
// rterm.c: 412 // rterm.c: 412
if is_term!(pspec) { if is_term!(pspec) {
let fixity = if inf > 0 { Fixity::In } else { Fixity::Post };
let op_dir_val = op_dir.get(name.clone(), fixity);
self.promote_atom_op( self.promote_atom_op(
name, name,
inf + post, inf + post,
spec & (XFX | XFY | YFX | XF | YF), spec & (XFX | XFY | YFX | XF | YF),
op_dir_val,
); );
} else { } else {
let op_dir_val = op_dir.get(name.clone(), Fixity::Pre); self.promote_atom_op(name, pre, spec & (FX | FY | NEGATIVE_SIGN));
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); self.promote_atom_op(name, pre, spec & (FX | FY | NEGATIVE_SIGN));
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(),
if pre + inf == 0 {
Fixity::Post
} else if post + pre == 0 {
Fixity::In
} else {
Fixity::Pre
},
);
self.reduce_op(pre + inf + post); // only one non-zero priority among these. self.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);
} }
Ok(true) Ok(true)
@@ -843,38 +903,23 @@ impl<'a, R: Read> Parser<'a, R> {
} }
} }
fn atomize_term(&self, term: &Term) -> Option<ClauseName> { fn negate_number<N, Negator, ToLiteral>(&mut self, n: N, negator: Negator, constr: ToLiteral)
match term {
Term::Constant(_, ref c) => self.atomize_constant(c),
_ => None,
}
}
fn atomize_constant(&self, c: &Constant) -> Option<ClauseName> {
match c {
Constant::Atom(ref name, _) => Some(name.clone()),
Constant::Char(c) => Some(clause_name!(c.to_string(), self.lexer.atom_tbl)),
Constant::EmptyList => Some(clause_name!(c.to_string(), self.lexer.atom_tbl)),
_ => None,
}
}
fn negate_number<N, Negator, ToConstant>(&mut self, n: N, negator: Negator, constr: ToConstant)
where where
Negator: Fn(N) -> N, Negator: Fn(N) -> N,
ToConstant: Fn(N) -> Constant, ToLiteral: Fn(N, &mut Arena) -> Literal,
{ {
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::Literal(_, Literal::Atom(name))
if name.as_str() == "-" if name == atom!("-") && (is_prefix!(desc.spec) || is_negate!(desc.spec)) =>
&& (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); let literal = constr(negator(n), &mut self.lexer.machine_st.arena);
self.shift(Token::Literal(literal), 0, TERM);
return; return;
} }
_ => {} _ => {}
@@ -882,43 +927,45 @@ impl<'a, R: Read> Parser<'a, R> {
} }
} }
self.shift(Token::Constant(constr(n)), 0, TERM); let literal = constr(n, &mut self.lexer.machine_st.arena);
self.shift(Token::Literal(literal), 0, TERM);
} }
fn shift_token(&mut self, token: Token, op_dir: &CompositeOpDir) -> 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: TypedArenaPtr<T>) -> TypedArenaPtr<T> {
if let Some(t) = Rc::get_mut(&mut t) { (&mut t).neg_assign();
t.neg_assign();
};
t t
} }
match token { match token {
Token::Constant(Constant::Fixnum(n)) => self.negate_number(n, |n| -n, Constant::Fixnum), Token::Literal(Literal::Fixnum(n)) => {
Token::Constant(Constant::Integer(n)) => { self.negate_number(n, |n| -n, |n, _| Literal::Fixnum(n))
self.negate_number(n, negate_rc, Constant::Integer)
} }
Token::Constant(Constant::Rational(n)) => { Token::Literal(Literal::Integer(n)) => {
self.negate_number(n, negate_rc, Constant::Rational) self.negate_number(n, negate_rc, |n, _| Literal::Integer(n))
} }
Token::Constant(Constant::Float(n)) => { Token::Literal(Literal::Rational(n)) => {
self.negate_number(n, |n| OrderedFloat(-n.into_inner()), Constant::Float) self.negate_number(n, negate_rc, |r, _| Literal::Rational(r))
} }
Token::Constant(c) => { Token::Literal(Literal::Float(n)) => self.negate_number(
if let Some(name) = self.atomize_constant(&c) { **n,
|n| OrderedFloat(-n.into_inner()),
|n, arena| Literal::Float(arena_alloc!(n, arena)),
),
Token::Literal(c) => {
if let Some(name) = atomize_constant(&mut self.lexer.machine_st.atom_tbl, 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::Literal(c), 0, TERM);
} }
} else { } else {
self.shift(Token::Constant(c), 0, TERM); self.shift(Token::Literal(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() {
if !self.reduce_brackets() { if !self.reduce_brackets() {
return Err(ParserError::IncompleteReduction( return Err(ParserError::IncompleteReduction(
self.lexer.line_num, self.lexer.line_num,
@@ -949,8 +996,10 @@ impl<'a, R: Read> Parser<'a, R> {
/* '|' 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_op_desc(clause_name!("|"), op_dir) let bar_atom = atom!("|");
.map(|OpDesc { inf, spec, .. }| (inf, spec))
let (priority, spec) = get_op_desc(bar_atom, op_dir)
.map(|CompositeOpDesc { inf, spec, .. }| (inf, spec))
.unwrap_or((1000, DELIMITER)); .unwrap_or((1000, DELIMITER));
self.reduce_op(priority); self.reduce_op(priority);
@@ -990,7 +1039,7 @@ impl<'a, R: Read> Parser<'a, R> {
} }
#[inline] #[inline]
pub fn num_lines_read(&self) -> usize { pub fn lines_read(&self) -> usize {
self.lexer.line_num self.lexer.line_num
} }

105
src/raw_block.rs Normal file
View File

@@ -0,0 +1,105 @@
use core::marker::PhantomData;
use std::alloc;
use std::ptr;
pub trait RawBlockTraits {
fn init_size() -> usize;
fn align() -> usize;
}
#[derive(Debug)]
pub struct RawBlock<T: RawBlockTraits> {
pub base: *const u8,
pub top: *const u8,
pub ptr: *mut u8,
_marker: PhantomData<T>,
}
impl<T: RawBlockTraits> RawBlock<T> {
#[inline]
fn empty_block() -> Self {
RawBlock {
base: ptr::null(),
top: ptr::null(),
ptr: ptr::null_mut(),
_marker: PhantomData,
}
}
pub fn new() -> Self {
let mut block = Self::empty_block();
unsafe {
block.grow();
}
block
}
unsafe fn init_at_size(&mut self, cap: usize) {
let layout = alloc::Layout::from_size_align_unchecked(cap, T::align());
self.base = alloc::alloc(layout) as *const _;
self.top = (self.base as usize + cap) as *const _;
self.ptr = self.base as *mut _;
}
pub unsafe fn grow(&mut self) {
if self.base.is_null() {
self.init_at_size(T::init_size());
} else {
let size = self.size();
let layout = alloc::Layout::from_size_align_unchecked(size, T::align());
self.base = alloc::realloc(self.base as *mut _, layout, size * 2) as *const _;
self.top = (self.base as usize + size * 2) as *const _;
self.ptr = (self.base as usize + size) as *mut _;
}
}
/*
#[inline]
pub fn take(&mut self) -> Self {
mem::replace(self, Self::empty_block())
}
*/
#[inline]
pub fn size(&self) -> usize {
self.top as usize - self.base as usize
}
#[inline(always)]
fn free_space(&self) -> usize {
debug_assert!(
self.ptr as *const _ >= self.base,
"self.ptr = {:?} < {:?} = self.base",
self.ptr,
self.base
);
self.top as usize - self.ptr as usize
}
pub unsafe fn alloc(&mut self, size: usize) -> *mut u8 {
if self.free_space() >= size {
let ptr = self.ptr;
self.ptr = (self.ptr as usize + size) as *mut _;
ptr
} else {
ptr::null_mut()
}
}
pub fn deallocate(&mut self) {
unsafe {
let layout = alloc::Layout::from_size_align_unchecked(self.size(), T::align());
alloc::dealloc(self.base as *mut _, layout);
self.top = ptr::null();
self.base = ptr::null();
self.ptr = ptr::null_mut();
}
}
}

View File

@@ -1,24 +1,61 @@
use prolog_parser::ast::*; use crate::parser::ast::*;
use prolog_parser::parser::*; use crate::parser::parser::*;
use prolog_parser::tabled_rc::TabledData;
use crate::arena::*;
use crate::atom_table::*;
use crate::forms::*; use crate::forms::*;
use crate::iterators::*; use crate::iterators::*;
use crate::machine::heap::*;
use crate::machine::machine_indices::*; use crate::machine::machine_indices::*;
use crate::machine::machine_state::MachineState; use crate::machine::machine_state::MachineState;
use crate::machine::streams::Stream; use crate::machine::streams::*;
use crate::parser::char_reader::*;
use crate::types::*;
use fxhash::FxBuildHasher;
use rustyline::error::ReadlineError;
use rustyline::{Cmd, Config, Editor, KeyEvent};
use std::collections::VecDeque; use std::collections::VecDeque;
use std::io::{Cursor, Error, ErrorKind, Read};
type SubtermDeque = VecDeque<(usize, usize)>; type SubtermDeque = VecDeque<(usize, usize)>;
pub(crate) type PrologStream = ParsingStream<Stream>; // pub(crate) type PrologStream = ParsingStream<Stream>;
pub mod readline { impl MachineState {
use crate::machine::streams::Stream; pub(crate) fn devour_whitespace(
use rustyline::error::ReadlineError; &mut self,
use rustyline::{Cmd, Config, Editor, KeyEvent}; mut inner: Stream,
use std::io::{Cursor, Error, ErrorKind, Read}; ) -> Result<bool, ParserError> {
let mut parser = Parser::new(inner, self);
parser.devour_whitespace()?;
inner.add_lines_read(parser.lines_read());
parser.eof()
}
pub(crate) fn read(
&mut self,
mut inner: Stream,
op_dir: &OpDir,
) -> Result<TermWriteResult, ParserError> {
let (term, num_lines_read) = {
let prior_num_lines_read = inner.lines_read();
let mut parser = Parser::new(inner, self);
parser.add_lines_read(prior_num_lines_read);
let term = parser.read_term(&CompositeOpDir::new(op_dir, None))?;
(term, parser.lines_read() - prior_num_lines_read)
};
inner.add_lines_read(num_lines_read);
Ok(write_term_to_heap(&term, &mut self.heap, &mut self.atom_tbl))
}
}
static mut PROMPT: bool = false; static mut PROMPT: bool = false;
@@ -41,6 +78,12 @@ pub mod readline {
} }
} }
#[inline]
pub fn input_stream(arena: &mut Arena) -> Stream {
let input_stream = ReadlineStream::new("");
Stream::from_readline_stream(input_stream, arena)
}
#[derive(Debug)] #[derive(Debug)]
pub struct ReadlineStream { pub struct ReadlineStream {
rl: Editor<()>, rl: Editor<()>,
@@ -49,32 +92,26 @@ pub mod readline {
impl ReadlineStream { impl ReadlineStream {
#[inline] #[inline]
pub(crate) fn new(pending_input: String) -> Self { pub fn new(pending_input: &str) -> Self {
let config = Config::builder().check_cursor_position(true).build(); let config = Config::builder().check_cursor_position(true).build();
let mut rl = Editor::<()>::with_config(config);
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() && rl.load_history(&path).is_err() {
if rl.load_history(&path).is_err() {
println!("Warning: loading history failed"); println!("Warning: loading history failed");
} }
} }
}
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 { ReadlineStream {
rl, rl,
pending_input: Cursor::new(pending_input), pending_input: Cursor::new(pending_input.to_owned()),
} }
} }
#[inline] fn call_readline(&mut self) -> std::io::Result<usize> {
pub(crate) fn input_stream(pending_input: String) -> Stream {
Stream::from(Self::new(pending_input))
}
fn call_readline(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
match self.rl.readline(get_prompt()) { match self.rl.readline(get_prompt()) {
Ok(text) => { Ok(text) => {
*self.pending_input.get_mut() = text; *self.pending_input.get_mut() = text;
@@ -92,7 +129,7 @@ pub mod readline {
*self.pending_input.get_mut() += "\n"; *self.pending_input.get_mut() += "\n";
} }
self.pending_input.read(buf) Ok(self.pending_input.get_ref().len())
} }
Err(ReadlineError::Eof) => Ok(0), Err(ReadlineError::Eof) => Ok(0),
Err(e) => Err(Error::new(ErrorKind::InvalidInput, e)), Err(e) => Err(Error::new(ErrorKind::InvalidInput, e)),
@@ -106,51 +143,32 @@ pub mod readline {
if self.rl.append_history(&path).is_err() { if self.rl.append_history(&path).is_err() {
println!("Warning: couldn't append history (existing file)"); println!("Warning: couldn't append history (existing file)");
} }
} else { } else if self.rl.save_history(&path).is_err() {
if self.rl.save_history(&path).is_err() {
println!("Warning: couldn't save history (new file)"); println!("Warning: couldn't save history (new file)");
} }
} }
} }
}
pub(crate) fn peek_byte(&mut self) -> std::io::Result<u8> { pub(crate) fn peek_byte(&mut self) -> std::io::Result<u8> {
set_prompt(false);
loop { loop {
match self.pending_input.get_ref().bytes().next() { match self.pending_input.get_ref().bytes().next() {
Some(0) => {
return Ok(0);
}
Some(b) => { Some(b) => {
return Ok(b); return Ok(b);
} }
None => match self.call_readline(&mut []) { None => match self.call_readline() {
Err(e) => { Err(e) => {
return Err(e); return Err(e);
} }
Ok(0) => { Ok(0) => {
return Err(Error::new(ErrorKind::UnexpectedEof, "end of file")); self.pending_input.get_mut().push('\u{0}');
return Ok(0);
} }
_ => {} _ => {
},
}
}
}
pub(crate) fn peek_char(&mut self) -> std::io::Result<char> {
set_prompt(false); set_prompt(false);
loop {
match self.pending_input.get_ref().chars().next() {
Some(c) => {
return Ok(c);
} }
None => match self.call_readline(&mut []) {
Err(e) => {
return Err(e);
}
Ok(0) => {
return Err(Error::new(ErrorKind::UnexpectedEof, "end of file"));
}
_ => {}
}, },
} }
} }
@@ -160,104 +178,95 @@ 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) => self.call_readline(buf), Ok(0) => {
result => result, self.call_readline()?;
self.pending_input.read(buf)
}
result => result
} }
} }
} }
#[inline] impl CharRead for ReadlineStream {
pub fn input_stream() -> Stream { fn peek_char(&mut self) -> Option<std::io::Result<char>> {
let input_stream = ReadlineStream::input_stream(String::from("")); loop {
Stream::from(input_stream) let pos = self.pending_input.position() as usize;
match self.pending_input.get_ref()[pos ..].chars().next() {
Some('\u{0}') => {
return Some(Ok('\u{0}'));
}
Some(c) => {
return Some(Ok(c));
}
None => {
match self.call_readline() {
Err(e) => {
return Some(Err(e));
}
Ok(0) => {
self.pending_input.get_mut().push('\u{0}');
return Some(Ok('\u{0}'));
}
_ => {
set_prompt(false);
}
}
}
}
} }
} }
impl MachineState { fn consume(&mut self, nread: usize) {
pub(crate) fn devour_whitespace( let offset = self.pending_input.position() as usize;
&mut self, self.pending_input.set_position((offset + nread) as u64);
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( fn put_back_char(&mut self, c: char) {
&mut self, let offset = self.pending_input.position() as usize;
mut inner: Stream, self.pending_input.set_position((offset - c.len_utf8()) as u64);
atom_tbl: TabledData<Atom>,
op_dir: &OpDir,
) -> Result<TermWriteResult, ParserError> {
let mut stream = parsing_stream(inner.clone())?;
let (term, num_lines_read) = {
let prior_num_lines_read = inner.lines_read();
let mut parser = Parser::new(&mut stream, atom_tbl, self.flags);
parser.add_lines_read(prior_num_lines_read);
let term = parser.read_term(&CompositeOpDir::new(op_dir, None))?;
(term, parser.num_lines_read() - prior_num_lines_read)
};
inner.add_lines_read(num_lines_read);
// 'pausing' the stream saves the pending top buffer
// created by the parsing stream, which was created in this
// scope and is about to be destroyed in it.
let buf = stream.take_buf();
inner.pause_stream(buf)?;
Ok(write_term_to_heap(&term, self))
} }
} }
#[inline] #[inline]
pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult { pub(crate) fn write_term_to_heap(
let term_writer = TermWriter::new(machine_st); term: &Term,
heap: &mut Heap,
atom_tbl: &mut AtomTable,
) -> TermWriteResult {
let term_writer = TermWriter::new(heap, atom_tbl);
term_writer.write_term_to_heap(term) term_writer.write_term_to_heap(term)
} }
#[derive(Debug)] #[derive(Debug)]
struct TermWriter<'a> { struct TermWriter<'a, 'b> {
machine_st: &'a mut MachineState, heap: &'a mut Heap,
atom_tbl: &'b mut AtomTable,
queue: SubtermDeque, queue: SubtermDeque,
var_dict: HeapVarDict, var_dict: HeapVarDict,
} }
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct TermWriteResult { pub struct TermWriteResult {
pub(crate) heap_loc: usize, pub heap_loc: usize,
pub(crate) var_dict: HeapVarDict, pub var_dict: HeapVarDict,
} }
impl<'a> TermWriter<'a> { impl<'a, 'b> TermWriter<'a, 'b> {
#[inline] #[inline]
fn new(machine_st: &'a mut MachineState) -> Self { fn new(heap: &'a mut Heap, atom_tbl: &'b mut AtomTable) -> Self {
TermWriter { TermWriter {
machine_st, heap,
atom_tbl,
queue: SubtermDeque::new(), queue: SubtermDeque::new(),
var_dict: HeapVarDict::new(), var_dict: HeapVarDict::with_hasher(FxBuildHasher::default()),
} }
} }
#[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] = HeapCellValue::Addr(self.term_as_addr(term, h)); self.heap[site_h] = 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));
@@ -267,64 +276,87 @@ 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.heap.len();
self.machine_st self.heap.push(heap_loc_as_cell!(h));
.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) -> HeapCellValue {
match term { match term {
&TermRef::AnonVar(_) | &TermRef::Var(..) => Addr::HeapCell(h), &TermRef::Cons(..) => list_loc_as_cell!(h),
&TermRef::Cons(..) => Addr::HeapCell(h), &TermRef::AnonVar(_) | &TermRef::Var(..) => heap_loc_as_cell!(h),
&TermRef::Constant(_, _, c) => self.machine_st.heap.put_constant(c.clone()), &TermRef::PartialString(_, _, ref src, None) =>
&TermRef::Clause(..) => Addr::Str(h), if src.as_str().is_empty() {
&TermRef::PartialString(..) => Addr::PStrLocation(h, 0), empty_list_as_cell!()
} else if self.heap[h].get_tag() == HeapCellValueTag::CStr {
heap_loc_as_cell!(h)
} else {
pstr_loc_as_cell!(h)
},
&TermRef::PartialString(..) => pstr_loc_as_cell!(h),
&TermRef::Literal(_, _, literal) => HeapCellValue::from(*literal),
&TermRef::Clause(_,_,_,subterms) if subterms.len() == 0 => heap_loc_as_cell!(h),
&TermRef::Clause(..) => str_loc_as_cell!(h),
} }
} }
fn write_term_to_heap(mut self, term: &'a Term) -> TermWriteResult { fn write_term_to_heap(mut self, term: &'a Term) -> TermWriteResult {
let heap_loc = self.machine_st.heap.h(); let heap_loc = self.heap.len();
for term in breadth_first_iter(term, true) { for term in breadth_first_iter(term, true) {
let h = self.machine_st.heap.h(); let h = self.heap.len();
match &term { match &term {
&TermRef::Cons(lvl, ..) => { &TermRef::Cons(Level::Root, ..) => {
self.queue.push_back((2, h + 1)); self.queue.push_back((2, h + 1));
self.machine_st self.heap.push(list_loc_as_cell!(h + 1));
.heap
.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
self.push_stub_addr(); self.push_stub_addr();
self.push_stub_addr(); self.push_stub_addr();
if let Level::Root = lvl {
continue; continue;
} }
} &TermRef::Cons(..) => {
&TermRef::Clause(lvl, _, ref ct, subterms) => { self.queue.push_back((2, h));
self.queue.push_back((subterms.len(), h + 1));
let named = HeapCellValue::NamedStr(subterms.len(), ct.name(), ct.spec());
self.machine_st.heap.push(named); self.push_stub_addr();
self.push_stub_addr();
}
&TermRef::Clause(Level::Root, _, ref ct, subterms) => {
self.heap.push(if subterms.len() == 0 {
heap_loc_as_cell!(heap_loc + 1)
} else {
str_loc_as_cell!(heap_loc + 1)
});
self.queue.push_back((subterms.len(), h + 2));
let named = atom_as_cell!(ct.name(), subterms.len());
self.heap.push(named);
for _ in 0..subterms.len() { for _ in 0..subterms.len() {
self.push_stub_addr(); self.push_stub_addr();
} }
if let Level::Root = lvl {
continue; continue;
} }
&TermRef::Clause(_, _, ref ct, subterms) => {
self.queue.push_back((subterms.len(), h + 1));
let named = atom_as_cell!(ct.name(), subterms.len());
self.heap.push(named);
for _ in 0..subterms.len() {
self.push_stub_addr();
} }
&TermRef::AnonVar(Level::Root) | &TermRef::Constant(Level::Root, ..) => { }
&TermRef::AnonVar(Level::Root) | &TermRef::Literal(Level::Root, ..) => {
let addr = self.term_as_addr(&term, h); let addr = self.term_as_addr(&term, h);
self.machine_st.heap.push(HeapCellValue::Addr(addr)); self.heap.push(addr);
} }
&TermRef::Var(Level::Root, _, ref var) => { &TermRef::Var(Level::Root, _, ref var) => {
let addr = self.term_as_addr(&term, h); let addr = self.term_as_addr(&term, h);
self.var_dict.insert(var.clone(), Addr::HeapCell(h)); self.var_dict.insert(var.clone(), heap_loc_as_cell!(h));
self.machine_st.heap.push(HeapCellValue::Addr(addr)); self.heap.push(addr);
} }
&TermRef::AnonVar(_) => { &TermRef::AnonVar(_) => {
if let Some((arity, site_h)) = self.queue.pop_front() { if let Some((arity, site_h)) = self.queue.pop_front() {
@@ -335,25 +367,28 @@ impl<'a> TermWriter<'a> {
continue; continue;
} }
&TermRef::PartialString(lvl, _, ref pstr, tail) => { &TermRef::PartialString(lvl, _, ref src, tail) => {
if tail.is_some() { if tail.is_some() {
self.machine_st.heap.allocate_pstr(&pstr); allocate_pstr(self.heap, src.as_str(), self.atom_tbl);
} else { } else {
self.machine_st.heap.put_complete_string(&pstr); put_complete_string(self.heap, src.as_str(), self.atom_tbl);
} }
if let Level::Root = lvl { if tail.is_some() {
} else if tail.is_some() { let h = self.heap.len();
let h = self.machine_st.heap.h();
self.queue.push_back((1, h - 1)); self.queue.push_back((1, h - 1));
if let Level::Root = lvl {
continue;
}
} }
} }
&TermRef::Var(_, _, ref var) => { &TermRef::Var(_, _, ref var) => {
if let Some((arity, site_h)) = self.queue.pop_front() { if let Some((arity, site_h)) = self.queue.pop_front() {
if let Some(addr) = self.var_dict.get(var).cloned() { if let Some(addr) = self.var_dict.get(var).cloned() {
self.machine_st.heap[site_h] = HeapCellValue::Addr(addr); self.heap[site_h] = addr;
} else { } else {
self.var_dict.insert(var.clone(), Addr::HeapCell(site_h)); self.var_dict.insert(var.clone(), heap_loc_as_cell!(site_h));
} }
if arity > 1 { if arity > 1 {

View File

@@ -1,37 +1,41 @@
use prolog_parser::ast::*; use crate::parser::ast::*;
use crate::clause_types::*; use crate::atom_table::*;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*; use crate::instructions::*;
use crate::iterators::*; use crate::iterators::*;
use crate::types::*;
pub(crate) struct FactInstruction;
pub(crate) struct QueryInstruction;
pub(crate) 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(term: &'a Term) -> Self::Iterator;
fn to_constant(_: Level, _: Constant, _: RegType) -> Self; fn to_constant(lvl: Level, literal: Literal, r: RegType) -> Instruction;
fn to_list(_: Level, _: RegType) -> Self; fn to_list(lvl: Level, r: RegType) -> Instruction;
fn to_structure(_: ClauseType, _: usize, _: RegType) -> Self; fn to_structure(name: Atom, arity: usize, r: RegType) -> Instruction;
fn to_void(_: usize) -> Self; fn to_void(num_subterms: usize) -> Instruction;
fn is_void_instr(&self) -> bool; fn is_void_instr(instr: &Instruction) -> bool;
fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self; fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction;
fn incr_void_instr(&mut self); fn incr_void_instr(instr: &mut Instruction);
fn constant_subterm(_: Constant) -> Self; fn constant_subterm(literal: Literal) -> Instruction;
fn argument_to_variable(_: RegType, _: usize) -> Self; fn argument_to_variable(r: RegType, r: usize) -> Instruction;
fn argument_to_value(_: RegType, _: usize) -> Self; fn argument_to_value(r: RegType, val: usize) -> Instruction;
fn move_to_register(_: RegType, _: usize) -> Self; fn move_to_register(r: RegType, val: usize) -> Instruction;
fn subterm_to_variable(_: RegType) -> Self; fn subterm_to_variable(r: RegType) -> Instruction;
fn subterm_to_value(_: RegType) -> Self; fn subterm_to_value(r: RegType) -> Instruction;
fn clause_arg_to_instr(_: RegType) -> Self; fn clause_arg_to_instr(r: RegType) -> Instruction;
} }
impl<'a> CompilationTarget<'a> for FactInstruction { impl<'a> CompilationTarget<'a> for FactInstruction {
@@ -41,66 +45,66 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
breadth_first_iter(term, false) // do not iterate over the root clause if one exists. breadth_first_iter(term, false) // do not iterate over the root clause if one exists.
} }
fn to_constant(lvl: Level, constant: Constant, reg: RegType) -> Self { fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
FactInstruction::GetConstant(lvl, constant, reg) Instruction::GetConstant(lvl, HeapCellValue::from(constant), reg)
} }
fn to_structure(ct: ClauseType, arity: usize, reg: RegType) -> Self { fn to_structure(name: Atom, arity: usize, reg: RegType) -> Instruction {
FactInstruction::GetStructure(ct, arity, reg) Instruction::GetStructure(name, arity, reg)
} }
fn to_list(lvl: Level, reg: RegType) -> Self { fn to_list(lvl: Level, reg: RegType) -> Instruction {
FactInstruction::GetList(lvl, reg) Instruction::GetList(lvl, reg)
} }
fn to_void(subterms: usize) -> Self { fn to_void(num_subterms: usize) -> Instruction {
FactInstruction::UnifyVoid(subterms) Instruction::UnifyVoid(num_subterms)
} }
fn is_void_instr(&self) -> bool { fn is_void_instr(instr: &Instruction) -> bool {
match self { match instr {
&FactInstruction::UnifyVoid(_) => true, &Instruction::UnifyVoid(_) => true,
_ => false, _ => false,
} }
} }
fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self { fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction {
FactInstruction::GetPartialString(lvl, string, r, has_tail) Instruction::GetPartialString(lvl, string, r, has_tail)
} }
fn incr_void_instr(&mut self) { fn incr_void_instr(instr: &mut Instruction) {
match self { match instr {
&mut FactInstruction::UnifyVoid(ref mut incr) => *incr += 1, &mut Instruction::UnifyVoid(ref mut incr) => *incr += 1,
_ => {} _ => {}
} }
} }
fn constant_subterm(constant: Constant) -> Self { fn constant_subterm(constant: Literal) -> Instruction {
FactInstruction::UnifyConstant(constant) Instruction::UnifyConstant(HeapCellValue::from(constant))
} }
fn argument_to_variable(arg: RegType, val: usize) -> Self { fn argument_to_variable(arg: RegType, val: usize) -> Instruction {
FactInstruction::GetVariable(arg, val) Instruction::GetVariable(arg, val)
} }
fn move_to_register(arg: RegType, val: usize) -> Self { fn move_to_register(arg: RegType, val: usize) -> Instruction {
FactInstruction::GetVariable(arg, val) Instruction::GetVariable(arg, val)
} }
fn argument_to_value(arg: RegType, val: usize) -> Self { fn argument_to_value(arg: RegType, val: usize) -> Instruction {
FactInstruction::GetValue(arg, val) Instruction::GetValue(arg, val)
} }
fn subterm_to_variable(val: RegType) -> Self { fn subterm_to_variable(val: RegType) -> Instruction {
FactInstruction::UnifyVariable(val) Instruction::UnifyVariable(val)
} }
fn subterm_to_value(val: RegType) -> Self { fn subterm_to_value(val: RegType) -> Instruction {
FactInstruction::UnifyValue(val) Instruction::UnifyValue(val)
} }
fn clause_arg_to_instr(val: RegType) -> Self { fn clause_arg_to_instr(val: RegType) -> Instruction {
FactInstruction::UnifyVariable(val) Instruction::UnifyVariable(val)
} }
} }
@@ -111,65 +115,65 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
post_order_iter(term) post_order_iter(term)
} }
fn to_structure(ct: ClauseType, arity: usize, r: RegType) -> Self { fn to_structure(name: Atom, arity: usize, r: RegType) -> Instruction {
QueryInstruction::PutStructure(ct, arity, r) Instruction::PutStructure(name, arity, r)
} }
fn to_constant(lvl: Level, constant: Constant, reg: RegType) -> Self { fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
QueryInstruction::PutConstant(lvl, constant, reg) Instruction::PutConstant(lvl, HeapCellValue::from(constant), reg)
} }
fn to_list(lvl: Level, reg: RegType) -> Self { fn to_list(lvl: Level, reg: RegType) -> Instruction {
QueryInstruction::PutList(lvl, reg) Instruction::PutList(lvl, reg)
} }
fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self { fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction {
QueryInstruction::PutPartialString(lvl, string, r, has_tail) Instruction::PutPartialString(lvl, string, r, has_tail)
} }
fn to_void(subterms: usize) -> Self { fn to_void(subterms: usize) -> Instruction {
QueryInstruction::SetVoid(subterms) Instruction::SetVoid(subterms)
} }
fn is_void_instr(&self) -> bool { fn is_void_instr(instr: &Instruction) -> bool {
match self { match instr {
&QueryInstruction::SetVoid(_) => true, &Instruction::SetVoid(_) => true,
_ => false, _ => false,
} }
} }
fn incr_void_instr(&mut self) { fn incr_void_instr(instr: &mut Instruction) {
match self { match instr {
&mut QueryInstruction::SetVoid(ref mut incr) => *incr += 1, &mut Instruction::SetVoid(ref mut incr) => *incr += 1,
_ => {} _ => {}
} }
} }
fn constant_subterm(constant: Constant) -> Self { fn constant_subterm(constant: Literal) -> Instruction {
QueryInstruction::SetConstant(constant) Instruction::SetConstant(HeapCellValue::from(constant))
} }
fn argument_to_variable(arg: RegType, val: usize) -> Self { fn argument_to_variable(arg: RegType, val: usize) -> Instruction {
QueryInstruction::PutVariable(arg, val) Instruction::PutVariable(arg, val)
} }
fn move_to_register(arg: RegType, val: usize) -> Self { fn move_to_register(arg: RegType, val: usize) -> Instruction {
QueryInstruction::GetVariable(arg, val) Instruction::GetVariable(arg, val)
} }
fn argument_to_value(arg: RegType, val: usize) -> Self { fn argument_to_value(arg: RegType, val: usize) -> Instruction {
QueryInstruction::PutValue(arg, val) Instruction::PutValue(arg, val)
} }
fn subterm_to_variable(val: RegType) -> Self { fn subterm_to_variable(val: RegType) -> Instruction {
QueryInstruction::SetVariable(val) Instruction::SetVariable(val)
} }
fn subterm_to_value(val: RegType) -> Self { fn subterm_to_value(val: RegType) -> Instruction {
QueryInstruction::SetValue(val) Instruction::SetValue(val)
} }
fn clause_arg_to_instr(val: RegType) -> Self { fn clause_arg_to_instr(val: RegType) -> Instruction {
QueryInstruction::SetValue(val) Instruction::SetValue(val)
} }
} }

View File

@@ -1,8 +1,6 @@
use prolog_parser::ast::*; use crate::atom_table::*;
use prolog_parser::lexer::{Lexer, Token}; use crate::parser::ast::*;
use prolog_parser::tabled_rc::TabledData; use crate::parser::lexer::{Lexer, Token};
use std::rc::Rc;
#[test] #[test]
fn valid_token() { fn valid_token() {
@@ -18,13 +16,12 @@ fn empty_stream() {
#[test] #[test]
fn skip_utf8_bom() { fn skip_utf8_bom() {
let atom_tbl = TabledData::new(Rc::new("my_module".to_string())); let mut machine_st = MachineState::new();
let flags = MachineFlags::default();
let bytes: &[u8] = &[0xEF, 0xBB, 0xBF, '4' as u8, '\n' as u8]; let bytes: &[u8] = &[0xEF, 0xBB, 0xBF, '4' as u8, '\n' as u8];
let mut stream = parsing_stream(bytes).expect("valid stream"); let stream = parsing_stream(bytes).expect("valid stream");
let mut lexer = Lexer::new(atom_tbl, flags, &mut stream); let mut lexer = Lexer::new(stream, &mut machine_st);
match lexer.next_token() { match lexer.next_token() {
Ok(Token::Constant(Constant::Fixnum(4))) => (), Ok(Token::Literal(Literal::Fixnum(Fixnum::build_with(4)))) => (),
_ => assert!(false), _ => assert!(false),
} }
} }

View File

@@ -115,14 +115,6 @@ test_queries_on_builtins :-
1.1 @< 1, 1.1 @< 1,
1.0 @=< 1, 1.0 @=< 1,
\+ 1 @=< 1.0, \+ 1 @=< 1.0,
\+ \+ (variant(X, Y)),
\+ (variant(f(X), f(x))),
\+ \+ (variant(X, X)),
\+ \+ (variant(f(x), f(x))),
\+ (variant([X,Y,Z], [V,W,V])),
\+ \+ (variant([X,Y,Z], [V,W,Z])),
\+ \+ (variant([X,Y,X], [V,W,V])),
\+ \+ (g(B) = B, g(A) = A, variant(A, B)),
keysort([1-1,1-1],[1-1,1-1]), keysort([1-1,1-1],[1-1,1-1]),
\+ \+ findall(Sorted, keysort([2-99,1-a,3-f(_),1-z,1-a,2-44],Sorted), [[1-a,1-z,1-a,2-99,2-44,3-f(_)]]), \+ \+ findall(Sorted, keysort([2-99,1-a,3-f(_),1-z,1-a,2-44],Sorted), [[1-a,1-z,1-a,2-99,2-44,3-f(_)]]),
\+ \+ findall(X, keysort([X-1,1-1],[2-1,1-1]), [2]). \+ \+ findall(X, keysort([X-1,1-1],[2-1,1-1]), [2]).

View File

@@ -16,39 +16,40 @@ test_queries_on_call_with_inference_limit :-
\+ call_with_inference_limit(g(X), 5, R), \+ call_with_inference_limit(g(X), 5, R),
maplist(assertz, [g(1), g(2), g(3), g(4), g(5)]), maplist(assertz, [g(1), g(2), g(3), g(4), g(5)]),
findall([R,X], findall([R,X],
call_with_inference_limit(g(X), 10, R), call_with_inference_limit(g(X), 11, R),
[[true, 1], [[true, 1],
[true, 2], [true, 2],
[true, 3], [true, 3],
[true, 4], [true, 4],
[!, 5]]), [!, 5]]),
findall([R,X], findall([R,X],
(call_with_inference_limit(g(X), 10, R), call(true)), (call_with_inference_limit(g(X), 11, R), call(true)),
[[true, 1], [[true, 1],
[true, 2], [true, 2],
[true, 3], [true, 3],
[true, 4], [true, 4],
[!, 5]]), [!, 5]]),
findall([R,X], findall([R,X],
(call_with_inference_limit(g(X), 4, R), call(true)), (call_with_inference_limit(g(X), 5, R), call(true)),
[[true, 1], [[true, 1],
[true, 2], [true, 2],
[inference_limit_exceeded, _]]), [inference_limit_exceeded, _]]),
findall([X,R1,R2], findall([X,R1,R2],
(call_with_inference_limit(g(X), 4, R1), (call_with_inference_limit(g(X), 5, R1),
call_with_inference_limit(g(X), 5, R2)), call_with_inference_limit(g(X), 6, R2)),
[[1,true,!], [[1,true,!],
[2,true,!], [2,true,!],
[3,true,!], [3,true,!],
[4,true,!], [4,true,!],
[5,!,!]]), [5,!,!]]),
\+ \+ assertz((f(X) :- call_with_inference_limit(g(X), 8, _))), \+ \+ assertz((f(X) :- call_with_inference_limit(tests_on_call_with_inference_limit:g(X), 11, _))),
findall([R,X], findall([R,X],
call_with_inference_limit(f(X), 12, R), call_with_inference_limit(f(X), 14, R),
[[true,1], Solutions),
Solutions == [[true,1],
[true,2], [true,2],
[true,3], [true,3],
[true,4], [true,4],
[!,5]]). [!,5]].
:- initialization(test_queries_on_call_with_inference_limit). :- initialization(test_queries_on_call_with_inference_limit).

View File

@@ -1,14 +1,11 @@
use prolog_parser::ast::*; use crate::atom_table::*;
use prolog_parser::lexer::{Lexer, Token}; use crate::parser::ast::*;
use prolog_parser::tabled_rc::TabledData; use crate::parser::lexer::{Lexer, Token};
use std::rc::Rc;
fn read_all_tokens(text: &str) -> Result<Vec<Token>, ParserError> { fn read_all_tokens(text: &str) -> Result<Vec<Token>, ParserError> {
let atom_tbl = TabledData::new(Rc::new("my_module".to_string())); let mut machine_st = MachineState::new();
let flags = MachineFlags::default(); let stream = parsing_stream(text.as_bytes())?;
let mut stream = parsing_stream(text.as_bytes())?; let mut lexer = Lexer::new(stream, &mut machine_st);
let mut lexer = Lexer::new(atom_tbl, flags, &mut stream);
let mut tokens = Vec::new(); let mut tokens = Vec::new();
while !lexer.eof()? { while !lexer.eof()? {
@@ -21,21 +18,21 @@ fn read_all_tokens(text: &str) -> Result<Vec<Token>, ParserError> {
#[test] #[test]
fn empty_multiline_comment() -> Result<(), ParserError> { fn empty_multiline_comment() -> Result<(), ParserError> {
let tokens = read_all_tokens("/**/ 4\n")?; let tokens = read_all_tokens("/**/ 4\n")?;
assert_eq!(tokens, [Token::Constant(Constant::Fixnum(4))]); assert_eq!(tokens, [Token::Literal(Literal::Fixnum(Fixnum::build_with(4)))]);
Ok(()) Ok(())
} }
#[test] #[test]
fn any_char_multiline_comment() -> Result<(), ParserError> { fn any_char_multiline_comment() -> Result<(), ParserError> {
let tokens = read_all_tokens("/* █╗╚═══╝ © */ 4\n")?; let tokens = read_all_tokens("/* █╗╚═══╝ © */ 4\n")?;
assert_eq!(tokens, [Token::Constant(Constant::Fixnum(4))]); assert_eq!(tokens, [Token::Literal(Literal::Fixnum(4))]);
Ok(()) Ok(())
} }
#[test] #[test]
fn simple_char() -> Result<(), ParserError> { fn simple_char() -> Result<(), ParserError> {
let tokens = read_all_tokens("'a'\n")?; let tokens = read_all_tokens("'a'\n")?;
assert_eq!(tokens, [Token::Constant(Constant::Char('a'))]); assert_eq!(tokens, [Token::Literal(Literal::Char('a'))]);
Ok(()) Ok(())
} }
@@ -45,10 +42,10 @@ fn char_with_meta_seq() -> Result<(), ParserError> {
assert_eq!( assert_eq!(
tokens, tokens,
[ [
Token::Constant(Constant::Char('\\')), Token::Literal(Literal::Char('\\')),
Token::Constant(Constant::Char('\'')), Token::Literal(Literal::Char('\'')),
Token::Constant(Constant::Char('"')), Token::Literal(Literal::Char('"')),
Token::Constant(Constant::Char('`')) Token::Literal(Literal::Char('`'))
] ]
); );
Ok(()) Ok(())
@@ -60,13 +57,13 @@ fn char_with_control_seq() -> Result<(), ParserError> {
assert_eq!( assert_eq!(
tokens, tokens,
[ [
Token::Constant(Constant::Char('\u{07}')), Token::Literal(Literal::Char('\u{07}')),
Token::Constant(Constant::Char('\u{08}')), Token::Literal(Literal::Char('\u{08}')),
Token::Constant(Constant::Char('\r')), Token::Literal(Literal::Char('\r')),
Token::Constant(Constant::Char('\u{0c}')), Token::Literal(Literal::Char('\u{0c}')),
Token::Constant(Constant::Char('\t')), Token::Literal(Literal::Char('\t')),
Token::Constant(Constant::Char('\n')), Token::Literal(Literal::Char('\n')),
Token::Constant(Constant::Char('\u{0b}')), Token::Literal(Literal::Char('\u{0b}')),
] ]
); );
Ok(()) Ok(())
@@ -75,21 +72,21 @@ fn char_with_control_seq() -> Result<(), ParserError> {
#[test] #[test]
fn char_with_octseq() -> Result<(), ParserError> { fn char_with_octseq() -> Result<(), ParserError> {
let tokens = read_all_tokens(r"'\60433\' ")?; let tokens = read_all_tokens(r"'\60433\' ")?;
assert_eq!(tokens, [Token::Constant(Constant::Char('愛'))]); // Japanese character assert_eq!(tokens, [Token::Literal(Literal::Char('愛'))]); // Japanese character
Ok(()) Ok(())
} }
#[test] #[test]
fn char_with_octseq_0() -> Result<(), ParserError> { fn char_with_octseq_0() -> Result<(), ParserError> {
let tokens = read_all_tokens(r"'\0\' ")?; let tokens = read_all_tokens(r"'\0\' ")?;
assert_eq!(tokens, [Token::Constant(Constant::Char('\u{0000}'))]); assert_eq!(tokens, [Token::Literal(Literal::Char('\u{0000}'))]);
Ok(()) Ok(())
} }
#[test] #[test]
fn char_with_hexseq() -> Result<(), ParserError> { fn char_with_hexseq() -> Result<(), ParserError> {
let tokens = read_all_tokens(r"'\x2124\' ")?; let tokens = read_all_tokens(r"'\x2124\' ")?;
assert_eq!(tokens, [Token::Constant(Constant::Char(''))]); // Z math symbol assert_eq!(tokens, [Token::Literal(Literal::Char(''))]); // Z math symbol
Ok(()) Ok(())
} }

View File

@@ -4,6 +4,7 @@
:- use_module(library(charsio)). :- use_module(library(charsio)).
:- use_module(library(files)). :- use_module(library(files)).
:- use_module(library(iso_ext)). :- use_module(library(iso_ext)).
:- use_module(library(lambda)).
:- use_module(library(lists)). :- use_module(library(lists)).
:- use_module(library(si)). :- use_module(library(si)).
@@ -17,7 +18,7 @@ load_scryerrc :-
append(HomeDir, "/.scryerrc", ScryerrcFile), append(HomeDir, "/.scryerrc", ScryerrcFile),
( file_exists(ScryerrcFile) -> ( file_exists(ScryerrcFile) ->
atom_chars(ScryerrcFileAtom, ScryerrcFile), atom_chars(ScryerrcFileAtom, ScryerrcFile),
catch(consult(ScryerrcFileAtom), E, print_exception(E)) catch(use_module(ScryerrcFileAtom), E, print_exception(E))
; true ; true
) )
; true ; true
@@ -184,7 +185,7 @@ submit_query_and_print_results(Term0, VarList) :-
( functor(Term0, call, _) -> ( functor(Term0, call, _) ->
Term = Term0 % prevent pre-mature expansion of incomplete goal Term = Term0 % prevent pre-mature expansion of incomplete goal
% in the first argument, which is done by call/N % in the first argument, which is done by call/N
; expand_goal(call(Term0), user, call(Term)) ; expand_goal(Term0, user, Term)
), ),
setup_call_cleanup(bb_put('$first_answer', true), setup_call_cleanup(bb_put('$first_answer', true),
submit_query_and_print_results_(Term, VarList), submit_query_and_print_results_(Term, VarList),
@@ -272,8 +273,13 @@ trailing_period_is_ambiguous(Value) :-
ValueChars \== ['.'], ValueChars \== ['.'],
graphic_token_char(Char). graphic_token_char(Char).
term_variables_under_max_depth(Term, MaxDepth, Vars) :-
'$term_variables_under_max_depth'(Term, MaxDepth, Vars).
write_eqs_and_read_input(B, VarList) :- write_eqs_and_read_input(B, VarList) :-
term_variables(VarList, Vars0), gather_query_vars(VarList, OrigVars),
% one layer of depth added for (=/2) functor
'$term_variables_under_max_depth'(OrigVars, 22, Vars0),
'$term_attributed_variables'(VarList, AttrVars), '$term_attributed_variables'(VarList, AttrVars),
'$project_atts':project_attributes(Vars0, AttrVars), '$project_atts':project_attributes(Vars0, AttrVars),
copy_term(AttrVars, AttrVars, AttrGoals), copy_term(AttrVars, AttrVars, AttrGoals),
@@ -281,12 +287,13 @@ write_eqs_and_read_input(B, VarList) :-
append([Vars0, AttrGoalVars, AttrVars], Vars), append([Vars0, AttrGoalVars, AttrVars], Vars),
charsio:extend_var_list(Vars, VarList, NewVarList, fabricated), charsio:extend_var_list(Vars, VarList, NewVarList, fabricated),
'$get_b_value'(B0), '$get_b_value'(B0),
gather_query_vars(VarList, OrigVars),
gather_equations(NewVarList, OrigVars, Equations), gather_equations(NewVarList, OrigVars, Equations),
append(Equations, AttrGoals, Goals), append(Equations, AttrGoals, Goals),
term_variables(Equations, EquationVars), % one layer of depth added for (=/2) functor
append([AttrGoalVars, EquationVars], Vars1), maplist(\Term^Vs^term_variables_under_max_depth(Term, 22, Vs), Equations, EquationVars),
charsio:extend_var_list(Vars1, VarList, NewVarList0, fabricated), append([AttrGoalVars | EquationVars], Vars1),
sort(Vars1, Vars2),
charsio:extend_var_list(Vars2, VarList, NewVarList0, fabricated),
( bb_get('$first_answer', true) -> ( bb_get('$first_answer', true) ->
write(' '), write(' '),
bb_put('$first_answer', false) bb_put('$first_answer', false)

758
src/types.rs Normal file
View File

@@ -0,0 +1,758 @@
use crate::arena::*;
use crate::atom_table::*;
use crate::forms::*;
use crate::machine::machine_indices::*;
use crate::machine::partial_string::PartialString;
use crate::parser::ast::Fixnum;
use modular_bitfield::prelude::*;
use std::cmp::Ordering;
use std::convert::TryFrom;
use std::fmt;
use std::mem;
use std::ops::{Add, Sub, SubAssign};
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[bits = 6]
pub enum HeapCellValueTag {
// non-constants / tags with adjoining forwarding bits.
Cons = 0b00,
F64 = 0b01,
Str = 0b000010,
Lis = 0b000011,
Var = 0b000110,
StackVar = 0b000111,
AttrVar = 0b010011,
PStrLoc = 0b111111,
PStrOffset = 0b001110,
// constants.
Fixnum = 0b010010,
Char = 0b011011,
Atom = 0b001010,
PStr = 0b001011,
CStr = 0b010110, // a complete string.
}
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[bits = 6]
pub enum HeapCellValueView {
// non-constants / tags with adjoining forwarding bits.
Cons = 0b00,
F64 = 0b01,
Str = 0b000010,
Lis = 0b000011,
Var = 0b000110,
StackVar = 0b000111,
AttrVar = 0b010011,
PStrLoc = 0b111111,
PStrOffset = 0b001110,
// constants.
Fixnum = 0b010010,
Char = 0b011011,
Atom = 0b001010,
PStr = 0b001011,
CStr = 0b010110,
// trail elements.
TrailedHeapVar = 0b011110,
TrailedStackVar = 0b011111,
TrailedAttrVarHeapLink = 0b101110,
TrailedAttrVarListLink = 0b100010,
TrailedAttachedValue = 0b101010,
TrailedBlackboardEntry = 0b100110,
TrailedBlackboardOffset = 0b100111,
}
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[bits = 2]
pub enum ConsPtrMaskTag {
Cons = 0b00,
F64 = 0b01,
}
#[bitfield]
#[repr(u64)]
#[derive(Copy, Clone, Debug)]
pub struct ConsPtr {
ptr: B61,
m: bool,
tag: ConsPtrMaskTag,
}
impl ConsPtr {
#[inline(always)]
pub fn build_with(ptr: *const ArenaHeader, tag: ConsPtrMaskTag) -> Self {
ConsPtr::new()
.with_ptr(ptr as *const u8 as u64)
.with_m(false)
.with_tag(tag)
}
#[inline]
pub fn as_ptr(self) -> *mut u8 {
self.ptr() as *mut _
}
}
#[derive(BitfieldSpecifier, Copy, Clone, Debug)]
#[bits = 6]
pub(crate) enum RefTag {
HeapCell = 0b0110,
StackCell = 0b111,
AttrVar = 0b10011,
}
#[bitfield]
#[repr(u64)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct Ref {
val: B56,
#[allow(unused)] m: bool,
#[allow(unused)] f: bool,
tag: RefTag,
}
impl Ord for Ref {
fn cmp(&self, rhs: &Ref) -> Ordering {
match self.get_tag() {
RefTag::HeapCell | RefTag::AttrVar => {
match rhs.get_tag() {
RefTag::StackCell => Ordering::Less,
_ => self.get_value().cmp(&rhs.get_value()),
}
}
RefTag::StackCell => {
match rhs.get_tag() {
RefTag::StackCell =>
self.get_value().cmp(&rhs.get_value()),
_ =>
Ordering::Greater,
}
}
}
}
}
impl PartialOrd for Ref {
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
Some(self.cmp(rhs))
}
}
impl Ref {
#[inline(always)]
pub(crate) fn build_with(tag: RefTag, value: u64) -> Self {
Ref::new().with_tag(tag).with_val(value)
}
#[inline(always)]
pub(crate) fn get_tag(self) -> RefTag {
self.tag()
}
#[inline(always)]
pub(crate) fn get_value(self) -> u64 {
self.val()
}
#[inline(always)]
pub(crate) fn as_heap_cell_value(self) -> HeapCellValue {
HeapCellValue::from_bytes(self.into_bytes())
}
#[inline(always)]
pub(crate) fn heap_cell(h: usize) -> Self {
Ref::build_with(RefTag::HeapCell, h as u64)
}
#[inline(always)]
pub(crate) fn stack_cell(h: usize) -> Self {
Ref::build_with(RefTag::StackCell, h as u64)
}
#[inline(always)]
pub(crate) fn attr_var(h: usize) -> Self {
Ref::build_with(RefTag::AttrVar, h as u64)
}
}
#[derive(Debug, Clone, Copy)]
pub enum TrailRef {
Ref(Ref),
AttrVarHeapLink(usize),
AttrVarListLink(usize, usize),
BlackboardEntry(Atom),
BlackboardOffset(Atom, HeapCellValue), // key atom, key value
}
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[bits = 6]
pub(crate) enum TrailEntryTag {
TrailedHeapVar = 0b011110,
TrailedStackVar = 0b011111,
TrailedAttrVar = 0b101110,
TrailedAttrVarHeapLink = 0b100010,
TrailedAttrVarListLink = 0b100011,
TrailedAttachedValue = 0b101010,
TrailedBlackboardEntry = 0b100110,
TrailedBlackboardOffset = 0b100111,
}
#[bitfield]
#[derive(Copy, Clone, Debug)]
#[repr(u64)]
pub(crate) struct TrailEntry {
val: B56,
#[allow(unused)] f: bool,
#[allow(unused)] m: bool,
#[allow(unused)] tag: TrailEntryTag,
}
impl TrailEntry {
#[inline(always)]
pub(crate) fn build_with(tag: TrailEntryTag, value: u64) -> Self {
TrailEntry::new()
.with_tag(tag)
.with_m(false)
.with_f(false)
.with_val(value)
}
#[inline(always)]
pub(crate) fn get_tag(self) -> TrailEntryTag {
match self.tag_or_err() {
Ok(tag) => tag,
Err(_) => TrailEntryTag::TrailedAttachedValue,
}
}
#[inline]
pub(crate) fn get_value(self) -> u64 {
self.val()
}
}
#[repr(u64)]
#[bitfield]
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub struct HeapCellValue {
val: B56,
f: bool,
m: bool,
tag: HeapCellValueTag,
}
impl fmt::Debug for HeapCellValue {
fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
match self.get_tag() {
tag @ (HeapCellValueTag::Cons | HeapCellValueTag::F64) => {
let cons_ptr = ConsPtr::from_bytes(self.into_bytes());
f.debug_struct("HeapCellValue")
.field("tag", &tag)
.field("ptr", &cons_ptr.ptr())
.field("m", &cons_ptr.m())
.finish()
}
HeapCellValueTag::Atom => {
let (name, arity) = cell_as_atom_cell!(self)
.get_name_and_arity();
f.debug_struct("HeapCellValue")
.field("tag", &HeapCellValueTag::Atom)
.field("name", &name.as_str())
.field("arity", &arity)
.field("m", &self.m())
.field("f", &self.f())
.finish()
}
HeapCellValueTag::PStr => {
let (name, _) = cell_as_atom_cell!(self)
.get_name_and_arity();
f.debug_struct("HeapCellValue")
.field("tag", &HeapCellValueTag::PStr)
.field("contents", &name.as_str())
.field("m", &self.m())
.field("f", &self.f())
.finish()
}
tag => {
f.debug_struct("HeapCellValue")
.field("tag", &tag)
.field("value", &self.get_value())
.field("m", &self.get_mark_bit())
.field("f", &self.get_forwarding_bit())
.finish()
}
}
}
}
impl<T> From<TypedArenaPtr<T>> for HeapCellValue {
#[inline]
fn from(arena_ptr: TypedArenaPtr<T>) -> HeapCellValue {
HeapCellValue::from(arena_ptr.header_ptr() as u64)
}
}
impl From<F64Ptr> for HeapCellValue {
#[inline]
fn from(f64_ptr: F64Ptr) -> HeapCellValue {
HeapCellValue::from_bytes(
ConsPtr::from(f64_ptr.as_ptr() as u64)
.with_tag(ConsPtrMaskTag::F64)
.with_m(false)
.into_bytes(),
)
}
}
impl From<ConsPtr> for HeapCellValue {
#[inline(always)]
fn from(cons_ptr: ConsPtr) -> HeapCellValue {
HeapCellValue::from_bytes(
ConsPtr::from(cons_ptr.as_ptr() as u64)
.with_tag(ConsPtrMaskTag::Cons)
.with_m(false)
.into_bytes(),
)
}
}
impl<'a> From<(Number, &mut Arena)> for HeapCellValue {
#[inline(always)]
fn from((n, arena): (Number, &mut Arena)) -> HeapCellValue {
match n {
Number::Float(n) => HeapCellValue::from(arena_alloc!(n, arena)),
Number::Integer(n) => HeapCellValue::from(n),
Number::Rational(n) => HeapCellValue::from(n),
Number::Fixnum(n) => fixnum_as_cell!(n),
}
}
}
impl HeapCellValue {
#[inline(always)]
pub fn build_with(tag: HeapCellValueTag, value: u64) -> Self {
HeapCellValue::new()
.with_tag(tag)
.with_val(value)
.with_m(false)
.with_f(false)
}
#[inline]
pub fn is_string_terminator(mut self, heap: &[HeapCellValue]) -> bool {
use crate::machine::heap::*;
loop {
return read_heap_cell!(self,
(HeapCellValueTag::Atom, (name, arity)) => {
name == atom!("[]") && arity == 0
}
(HeapCellValueTag::CStr) => {
true
}
(HeapCellValueTag::PStrLoc, h) => {
self = heap[h];
continue;
}
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
let cell = heap_bound_store(heap, heap_bound_deref(heap, heap[h]));
if cell.is_var() {
return false;
}
self = cell;
continue;
}
(HeapCellValueTag::PStrOffset, pstr_offset) => {
heap[pstr_offset].get_tag() == HeapCellValueTag::CStr
}
_ => {
false
}
);
}
}
#[inline(always)]
pub fn is_forwarded(self) -> bool {
self.get_forwarding_bit().unwrap_or(false)
}
#[inline]
pub fn is_ref(self) -> bool {
match self.get_tag() {
HeapCellValueTag::Str | HeapCellValueTag::Lis | HeapCellValueTag::Var |
HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar | HeapCellValueTag::PStrLoc |
HeapCellValueTag::PStrOffset => true,
_ => false,
}
}
#[inline]
pub fn as_char(self) -> Option<char> {
read_heap_cell!(self,
(HeapCellValueTag::Char, c) => {
Some(c)
}
(HeapCellValueTag::Atom, (name, arity)) => {
if arity > 0 {
return None;
}
name.as_char()
}
_ => {
None
}
)
}
#[inline]
pub fn is_constant(self) -> bool {
match self.get_tag() {
HeapCellValueTag::Cons | HeapCellValueTag::F64 | HeapCellValueTag::Fixnum |
HeapCellValueTag::Char | HeapCellValueTag::CStr => {
true
}
HeapCellValueTag::Atom => {
cell_as_atom_cell!(self).get_arity() == 0
}
_ => {
false
}
}
}
#[inline(always)]
pub fn is_stack_var(self) -> bool {
self.get_tag() == HeapCellValueTag::StackVar
}
#[inline]
pub fn is_compound(self) -> bool {
match self.get_tag() {
HeapCellValueTag::Str
| HeapCellValueTag::Lis
| HeapCellValueTag::CStr
| HeapCellValueTag::PStr
| HeapCellValueTag::PStrLoc
| HeapCellValueTag::PStrOffset => {
true
}
HeapCellValueTag::Atom => {
cell_as_atom_cell!(self).get_arity() > 0
}
_ => { false }
}
}
#[inline]
pub fn is_var(self) -> bool {
read_heap_cell!(self,
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
true
}
_ => {
false
}
)
}
#[inline]
pub(crate) fn as_var(self) -> Option<Ref> {
read_heap_cell!(self,
(HeapCellValueTag::Var, h) => {
Some(Ref::heap_cell(h))
}
(HeapCellValueTag::AttrVar, h) => {
Some(Ref::attr_var(h))
}
(HeapCellValueTag::StackVar, s) => {
Some(Ref::stack_cell(s))
}
_ => {
None
}
)
}
#[inline]
pub fn get_value(self) -> usize {
self.val() as usize
}
#[inline]
pub fn set_value(&mut self, val: usize) {
self.set_val(val as u64);
}
#[inline]
pub fn get_tag(self) -> HeapCellValueTag {
match self.tag_or_err() {
Ok(tag) => tag,
Err(_) => match ConsPtr::from_bytes(self.into_bytes()).tag() {
ConsPtrMaskTag::Cons => HeapCellValueTag::Cons,
ConsPtrMaskTag::F64 => HeapCellValueTag::F64,
},
}
}
#[inline]
pub fn to_atom(self) -> Option<Atom> {
match self.tag() {
HeapCellValueTag::Atom => Some(Atom::from((self.val() << 3) as usize)),
_ => None,
}
}
#[inline]
pub fn to_pstr(self) -> Option<PartialString> {
match self.tag() {
HeapCellValueTag::PStr => {
Some(PartialString::from(Atom::from((self.val() as usize) << 3)))
}
_ => None,
}
}
#[inline]
pub fn to_fixnum(self) -> Option<Fixnum> {
match self.get_tag() {
HeapCellValueTag::Fixnum => Some(Fixnum::from_bytes(self.into_bytes())),
_ => None,
}
}
#[inline]
pub fn to_untyped_arena_ptr(self) -> Option<UntypedArenaPtr> {
match self.tag() {
HeapCellValueTag::Cons => Some(UntypedArenaPtr::from_bytes(self.into_bytes())),
_ => None,
}
}
#[inline]
pub fn get_forwarding_bit(self) -> Option<bool> {
match self.get_tag() {
HeapCellValueTag::Cons // the list of non-forwardable cell tags.
| HeapCellValueTag::F64
// | HeapCellValueTag::Atom
// | HeapCellValueTag::PStr
| HeapCellValueTag::Fixnum
| HeapCellValueTag::Char => None,
_ => Some(self.f()),
}
}
#[inline]
pub fn set_forwarding_bit(&mut self, f: bool) {
match self.get_tag() {
HeapCellValueTag::Cons // the list of non-forwardable cell tags.
| HeapCellValueTag::F64
// | HeapCellValueTag::Atom
// | HeapCellValueTag::PStr
| HeapCellValueTag::Fixnum
| HeapCellValueTag::Char => {}
_ => self.set_f(f),
}
}
#[inline]
pub fn get_mark_bit(self) -> bool {
match self.get_tag() {
HeapCellValueTag::Cons | HeapCellValueTag::F64 => {
ConsPtr::from_bytes(self.into_bytes()).m()
}
_ => self.m(),
}
}
#[inline]
pub fn set_mark_bit(&mut self, m: bool) {
match self.get_tag() {
HeapCellValueTag::Cons | HeapCellValueTag::F64 => {
let value = ConsPtr::from_bytes(self.into_bytes()).with_m(m);
*self = HeapCellValue::from_bytes(value.into_bytes());
}
_ => self.set_m(m),
}
}
pub fn order_category(self) -> Option<TermOrderCategory> {
match Number::try_from(self).ok() {
Some(Number::Integer(_)) | Some(Number::Fixnum(_)) | Some(Number::Rational(_)) => {
Some(TermOrderCategory::Integer)
}
Some(Number::Float(_)) => Some(TermOrderCategory::FloatingPoint),
None => match self.get_tag() {
HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar => {
Some(TermOrderCategory::Variable)
}
HeapCellValueTag::Char => Some(TermOrderCategory::Atom),
HeapCellValueTag::Atom => {
Some(if cell_as_atom_cell!(self).get_arity() > 0 {
TermOrderCategory::Compound
} else {
TermOrderCategory::Atom
})
}
HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc |
HeapCellValueTag::CStr | HeapCellValueTag::Str => {
Some(TermOrderCategory::Compound)
}
_ => {
None
}
},
}
}
#[inline(always)]
pub fn is_protected(self, e: usize) -> bool {
read_heap_cell!(self,
(HeapCellValueTag::StackVar, s) => {
s < e
}
_ => {
true
}
)
}
}
const_assert!(mem::size_of::<HeapCellValue>() == 8);
#[bitfield]
#[repr(u64)]
#[derive(Copy, Clone, Debug)]
pub struct UntypedArenaPtr {
ptr: B61,
m: bool,
#[allow(unused)] padding: B2,
}
const_assert!(mem::size_of::<UntypedArenaPtr>() == 8);
impl From<*const ArenaHeader> for UntypedArenaPtr {
#[inline]
fn from(ptr: *const ArenaHeader) -> UntypedArenaPtr {
unsafe { mem::transmute(ptr) }
}
}
impl From<UntypedArenaPtr> for *const ArenaHeader {
#[inline]
fn from(ptr: UntypedArenaPtr) -> *const ArenaHeader {
unsafe { mem::transmute(ptr) }
}
}
impl UntypedArenaPtr {
#[inline]
pub fn set_mark_bit(&mut self, m: bool) {
self.set_m(m);
}
#[inline]
pub fn get_ptr(self) -> *const u8 {
self.ptr() as *const u8
}
#[inline]
pub fn get_tag(self) -> ArenaHeaderTag {
unsafe {
let header = *(self.ptr() as *const ArenaHeader);
header.get_tag()
}
}
#[inline]
pub fn payload_offset(self) -> *const u8 {
unsafe {
self.get_ptr()
.offset(mem::size_of::<ArenaHeader>() as isize)
}
}
#[inline]
pub fn get_mark_bit(self) -> bool {
self.m()
}
}
impl Add<usize> for HeapCellValue {
type Output = HeapCellValue;
fn add(self, rhs: usize) -> Self::Output {
match self.get_tag() {
tag @ HeapCellValueTag::Str |
tag @ HeapCellValueTag::Lis |
tag @ HeapCellValueTag::PStrOffset |
tag @ HeapCellValueTag::PStrLoc |
tag @ HeapCellValueTag::Var |
tag @ HeapCellValueTag::AttrVar => {
HeapCellValue::build_with(tag, (self.get_value() + rhs) as u64)
}
_ => {
self
}
}
}
}
impl Sub<usize> for HeapCellValue {
type Output = HeapCellValue;
fn sub(self, rhs: usize) -> Self::Output {
match self.get_tag() {
tag @ HeapCellValueTag::Str |
tag @ HeapCellValueTag::Lis |
tag @ HeapCellValueTag::PStrOffset |
tag @ HeapCellValueTag::PStrLoc |
tag @ HeapCellValueTag::Var |
tag @ HeapCellValueTag::AttrVar => {
HeapCellValue::build_with(tag, (self.get_value() - rhs) as u64)
}
_ => {
self
}
}
}
}
impl SubAssign<usize> for HeapCellValue {
#[inline(always)]
fn sub_assign(&mut self, rhs: usize) {
*self = *self - rhs;
}
}
impl Sub<i64> for HeapCellValue {
type Output = HeapCellValue;
fn sub(self, rhs: i64) -> Self::Output {
if rhs < 0 {
match self.get_tag() {
tag @ HeapCellValueTag::Str |
tag @ HeapCellValueTag::Lis |
tag @ HeapCellValueTag::PStrOffset |
tag @ HeapCellValueTag::PStrLoc |
tag @ HeapCellValueTag::Var |
tag @ HeapCellValueTag::AttrVar => {
HeapCellValue::build_with(tag, (self.get_value() + rhs.abs() as usize) as u64)
}
_ => {
self
}
}
} else {
self.sub(rhs as usize)
}
}
}

View File

@@ -1,97 +1,71 @@
use crate::clause_types::*; use crate::arena::*;
use crate::atom_table::*;
use crate::forms::*; use crate::forms::*;
use crate::indexing::IndexingCodePtr;
use crate::instructions::*; use crate::instructions::*;
use crate::machine::loader::CompilationTarget; 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::*;
use crate::machine::partial_string::*;
use crate::machine::streams::*;
use crate::parser::rug::{Integer, Rational};
use crate::types::*;
use ordered_float::OrderedFloat;
use std::fmt; use std::fmt;
impl fmt::Display for LocalCodePtr { /*
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
LocalCodePtr::DirEntry(p) => write!(f, "LocalCodePtr::DirEntry({})", p),
LocalCodePtr::Halt => write!(f, "LocalCodePtr::Halt"),
LocalCodePtr::IndexingBuf(p, o, i) => write!(f, "LocalCodePtr::IndexingBuf({}, {}, {})", p, o, i),
}
}
}
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::AddDiscontiguousPredicate => REPLCodePtr::AddDiscontiguousPredicate => {
write!(f, "REPLCodePtr::AddDiscontiguousPredicate"), write!(f, "REPLCodePtr::AddDiscontiguousPredicate")
REPLCodePtr::AddDynamicPredicate => }
write!(f, "REPLCodePtr::AddDynamicPredicate"), REPLCodePtr::AddDynamicPredicate => write!(f, "REPLCodePtr::AddDynamicPredicate"),
REPLCodePtr::AddMultifilePredicate => REPLCodePtr::AddMultifilePredicate => write!(f, "REPLCodePtr::AddMultifilePredicate"),
write!(f, "REPLCodePtr::AddMultifilePredicate"), REPLCodePtr::AddGoalExpansionClause => write!(f, "REPLCodePtr::AddGoalExpansionClause"),
REPLCodePtr::AddGoalExpansionClause => REPLCodePtr::AddTermExpansionClause => write!(f, "REPLCodePtr::AddTermExpansionClause"),
write!(f, "REPLCodePtr::AddGoalExpansionClause"), REPLCodePtr::AddInSituFilenameModule => {
REPLCodePtr::AddTermExpansionClause => write!(f, "REPLCodePtr::AddInSituFilenameModule")
write!(f, "REPLCodePtr::AddTermExpansionClause"), }
REPLCodePtr::AddInSituFilenameModule => REPLCodePtr::AbolishClause => write!(f, "REPLCodePtr::AbolishClause"),
write!(f, "REPLCodePtr::AddInSituFilenameModule"), REPLCodePtr::Assertz => write!(f, "REPLCodePtr::Assertz"),
REPLCodePtr::AbolishClause => REPLCodePtr::Asserta => write!(f, "REPLCodePtr::Asserta"),
write!(f, "REPLCodePtr::AbolishClause"), REPLCodePtr::Retract => write!(f, "REPLCodePtr::Retract"),
REPLCodePtr::Assertz => REPLCodePtr::ClauseToEvacuable => write!(f, "REPLCodePtr::ClauseToEvacuable"),
write!(f, "REPLCodePtr::Assertz"), REPLCodePtr::ScopedClauseToEvacuable => {
REPLCodePtr::Asserta => write!(f, "REPLCodePtr::ScopedClauseToEvacuable")
write!(f, "REPLCodePtr::Asserta"), }
REPLCodePtr::Retract => REPLCodePtr::ConcludeLoad => write!(f, "REPLCodePtr::ConcludeLoad"),
write!(f, "REPLCodePtr::Retract"), REPLCodePtr::DeclareModule => write!(f, "REPLCodePtr::DeclareModule"),
REPLCodePtr::ClauseToEvacuable => REPLCodePtr::LoadCompiledLibrary => write!(f, "REPLCodePtr::LoadCompiledLibrary"),
write!(f, "REPLCodePtr::ClauseToEvacuable"), REPLCodePtr::LoadContextSource => write!(f, "REPLCodePtr::LoadContextSource"),
REPLCodePtr::ScopedClauseToEvacuable => REPLCodePtr::LoadContextFile => write!(f, "REPLCodePtr::LoadContextFile"),
write!(f, "REPLCodePtr::ScopedClauseToEvacuable"), REPLCodePtr::LoadContextDirectory => write!(f, "REPLCodePtr::LoadContextDirectory"),
REPLCodePtr::ConcludeLoad => REPLCodePtr::LoadContextModule => write!(f, "REPLCodePtr::LoadContextModule"),
write!(f, "REPLCodePtr::ConcludeLoad"), REPLCodePtr::LoadContextStream => write!(f, "REPLCodePtr::LoadContextStream"),
REPLCodePtr::DeclareModule => REPLCodePtr::PopLoadContext => write!(f, "REPLCodePtr::PopLoadContext"),
write!(f, "REPLCodePtr::DeclareModule"), REPLCodePtr::PopLoadStatePayload => write!(f, "REPLCodePtr::PopLoadStatePayload"),
REPLCodePtr::LoadCompiledLibrary => REPLCodePtr::PushLoadContext => write!(f, "REPLCodePtr::PushLoadContext"),
write!(f, "REPLCodePtr::LoadCompiledLibrary"), REPLCodePtr::PushLoadStatePayload => write!(f, "REPLCodePtr::PushLoadStatePayload"),
REPLCodePtr::LoadContextSource => REPLCodePtr::UseModule => write!(f, "REPLCodePtr::UseModule"),
write!(f, "REPLCodePtr::LoadContextSource"), REPLCodePtr::MetaPredicateProperty => write!(f, "REPLCodePtr::MetaPredicateProperty"),
REPLCodePtr::LoadContextFile => REPLCodePtr::BuiltInProperty => write!(f, "REPLCodePtr::BuiltInProperty"),
write!(f, "REPLCodePtr::LoadContextFile"), REPLCodePtr::DynamicProperty => write!(f, "REPLCodePtr::DynamicProperty"),
REPLCodePtr::LoadContextDirectory => REPLCodePtr::MultifileProperty => write!(f, "REPLCodePtr::MultifileProperty"),
write!(f, "REPLCodePtr::LoadContextDirectory"), REPLCodePtr::DiscontiguousProperty => write!(f, "REPLCodePtr::DiscontiguousProperty"),
REPLCodePtr::LoadContextModule => REPLCodePtr::IsConsistentWithTermQueue => {
write!(f, "REPLCodePtr::LoadContextModule"), write!(f, "REPLCodePtr::IsConsistentWithTermQueue")
REPLCodePtr::LoadContextStream => }
write!(f, "REPLCodePtr::LoadContextStream"), REPLCodePtr::FlushTermQueue => write!(f, "REPLCodePtr::FlushTermQueue"),
REPLCodePtr::PopLoadContext => REPLCodePtr::RemoveModuleExports => write!(f, "REPLCodePtr::RemoveModuleExports"),
write!(f, "REPLCodePtr::PopLoadContext"), REPLCodePtr::AddNonCountedBacktracking => {
REPLCodePtr::PopLoadStatePayload => write!(f, "REPLCodePtr::AddNonCountedBacktracking")
write!(f, "REPLCodePtr::PopLoadStatePayload"),
REPLCodePtr::PushLoadContext =>
write!(f, "REPLCodePtr::PushLoadContext"),
REPLCodePtr::PushLoadStatePayload =>
write!(f, "REPLCodePtr::PushLoadStatePayload"),
REPLCodePtr::UseModule =>
write!(f, "REPLCodePtr::UseModule"),
REPLCodePtr::MetaPredicateProperty =>
write!(f, "REPLCodePtr::MetaPredicateProperty"),
REPLCodePtr::BuiltInProperty =>
write!(f, "REPLCodePtr::BuiltInProperty"),
REPLCodePtr::DynamicProperty =>
write!(f, "REPLCodePtr::DynamicProperty"),
REPLCodePtr::MultifileProperty =>
write!(f, "REPLCodePtr::MultifileProperty"),
REPLCodePtr::DiscontiguousProperty =>
write!(f, "REPLCodePtr::DiscontiguousProperty"),
REPLCodePtr::IsConsistentWithTermQueue =>
write!(f, "REPLCodePtr::IsConsistentWithTermQueue"),
REPLCodePtr::FlushTermQueue =>
write!(f, "REPLCodePtr::FlushTermQueue"),
REPLCodePtr::RemoveModuleExports =>
write!(f, "REPLCodePtr::RemoveModuleExports"),
REPLCodePtr::AddNonCountedBacktracking =>
write!(f, "REPLCodePtr::AddNonCountedBacktracking"),
} }
} }
} }
}
*/
impl fmt::Display for IndexPtr { impl fmt::Display for IndexPtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -107,11 +81,12 @@ impl fmt::Display for CompilationTarget {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
CompilationTarget::User => write!(f, "user"), CompilationTarget::User => write!(f, "user"),
CompilationTarget::Module(ref module_name) => write!(f, "{}", module_name), CompilationTarget::Module(ref module_name) => write!(f, "{}", module_name.as_str()),
} }
} }
} }
/*
impl fmt::Display for FactInstruction { impl fmt::Display for FactInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
@@ -122,11 +97,17 @@ impl fmt::Display for FactInstruction {
write!(f, "get_list {}{}", lvl, r.reg_num()) write!(f, "get_list {}{}", lvl, r.reg_num())
} }
&FactInstruction::GetPartialString(lvl, ref s, r, has_tail) => { &FactInstruction::GetPartialString(lvl, ref s, r, has_tail) => {
write!(f, "get_partial_string({}, {}, {}, {})", write!(
lvl, s, r, has_tail) f,
"get_partial_string({}, {}, {}, {})",
lvl,
s.as_str(),
r,
has_tail
)
} }
&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().as_str(), arity, r)
} }
&FactInstruction::GetValue(ref x, ref a) => { &FactInstruction::GetValue(ref x, ref a) => {
write!(f, "get_value {}, A{}", x, a) write!(f, "get_value {}, A{}", x, a)
@@ -166,11 +147,17 @@ impl fmt::Display for QueryInstruction {
write!(f, "put_list {}{}", lvl, r.reg_num()) write!(f, "put_list {}{}", lvl, r.reg_num())
} }
&QueryInstruction::PutPartialString(lvl, ref s, r, has_tail) => { &QueryInstruction::PutPartialString(lvl, ref s, r, has_tail) => {
write!(f, "put_partial_string({}, {}, {}, {})", write!(
lvl, s, r, has_tail) f,
"put_partial_string({}, {}, {}, {})",
lvl,
s.as_str(),
r,
has_tail
)
} }
&QueryInstruction::PutStructure(ref ct, ref arity, ref r) => { &QueryInstruction::PutStructure(ref ct, ref arity, ref r) => {
write!(f, "put_structure {}/{}, {}", ct.name(), arity, r) write!(f, "put_structure {}/{}, {}", ct.name().as_str(), arity, r)
} }
&QueryInstruction::PutUnsafeValue(y, a) => write!(f, "put_unsafe_value Y{}, A{}", y, a), &QueryInstruction::PutUnsafeValue(y, a) => write!(f, "put_unsafe_value Y{}, A{}", y, a),
&QueryInstruction::PutValue(ref x, ref a) => write!(f, "put_value {}, A{}", x, a), &QueryInstruction::PutValue(ref x, ref a) => write!(f, "put_value {}, A{}", x, a),
@@ -214,89 +201,69 @@ impl fmt::Display for ClauseType {
&ClauseType::System(SystemClauseType::SetCutPoint(r)) => { &ClauseType::System(SystemClauseType::SetCutPoint(r)) => {
write!(f, "$set_cp({})", r) write!(f, "$set_cp({})", r)
} }
&ClauseType::Named(ref name, _, ref idx) | &ClauseType::Op(ref name, _, ref idx) => { &ClauseType::Named(ref name, _, ref idx) => {
let idx = idx.0.get(); let idx = idx.0.get();
write!(f, "{}/{}", name, idx) write!(f, "{}/{}", name.as_str(), idx)
} }
ref ct => { ref ct => {
write!(f, "{}", ct.name()) write!(f, "{}", ct.name().as_str())
} }
} }
} }
} }
*/
impl fmt::Display for HeapCellValue { impl fmt::Display for HeapCellValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { read_heap_cell!(*self,
&HeapCellValue::Addr(ref addr) => write!(f, "{}", addr), (HeapCellValueTag::Atom, (name, arity)) => {
&HeapCellValue::Atom(ref atom, _) => write!(f, "{}", atom.as_str()), if arity == 0 {
&HeapCellValue::DBRef(ref db_ref) => write!(f, "{}", db_ref), write!(f, "{}", name.as_str())
&HeapCellValue::Integer(ref n) => write!(f, "{}", n), } else {
&HeapCellValue::LoadStatePayload(_) => write!(f, "LoadStatePayload"),
&HeapCellValue::Rational(ref n) => write!(f, "{}", n),
&HeapCellValue::NamedStr(arity, ref name, Some(ref cell)) => write!(
f,
"{}/{} (op, priority: {}, spec: {})",
name.as_str(),
arity,
cell.prec(),
cell.assoc()
),
&HeapCellValue::NamedStr(arity, ref name, None) => {
write!(f, "{}/{}", name.as_str(), arity)
}
&HeapCellValue::PartialString(ref pstr, has_tail) => {
write!( write!(
f, f,
"pstr ( buf: \"{}\", has_tail({}) )", "{}/{}",
pstr.as_str_from(0), name.as_str(),
has_tail, arity
) )
} }
&HeapCellValue::Stream(ref stream) => { }
(HeapCellValueTag::PStr, pstr_atom) => {
let pstr = PartialString::from(pstr_atom);
write!(
f,
"pstr ( \"{}\", )",
pstr.as_str_from(0)
)
}
(HeapCellValueTag::Cons, c) => {
match_untyped_arena_ptr!(c,
(ArenaHeaderTag::Integer, n) => {
write!(f, "{}", n)
}
(ArenaHeaderTag::Rational, r) => {
write!(f, "{}", r)
}
(ArenaHeaderTag::F64, fl) => {
write!(f, "{}", fl)
}
(ArenaHeaderTag::Stream, stream) => {
write!(f, "$stream({})", stream.as_ptr() as usize) write!(f, "$stream({})", stream.as_ptr() as usize)
} }
&HeapCellValue::TcpListener(ref tcp_listener) => { _ => {
write!(f, "$tcp_listener({})", tcp_listener.local_addr().unwrap()) write!(f, "")
} }
)
} }
_ => {
unreachable!()
}
)
} }
} }
impl fmt::Display for DBRef { /*
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&DBRef::NamedPred(ref name, arity, _) => write!(f, "db_ref:named:{}/{}", name, arity),
&DBRef::Op(priority, spec, ref name, ..) => {
write!(f, "db_ref:op({}, {}, {})", priority, spec, name)
}
}
}
}
impl fmt::Display for Addr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Addr::Char(c) => write!(f, "Addr::Char({})", c),
&Addr::EmptyList => write!(f, "Addr::EmptyList"),
&Addr::Fixnum(n) => write!(f, "Addr::Fixnum({})", n),
&Addr::Float(fl) => write!(f, "Addr::Float({})", fl),
&Addr::CutPoint(cp) => write!(f, "Addr::CutPoint({})", cp),
&Addr::Con(ref c) => write!(f, "Addr::Con({})", c),
&Addr::Lis(l) => write!(f, "Addr::Lis({})", l),
&Addr::LoadStatePayload(s) => write!(f, "Addr::LoadStatePayload({})", s),
&Addr::AttrVar(h) => write!(f, "Addr::AttrVar({})", h),
&Addr::HeapCell(h) => write!(f, "Addr::HeapCell({})", h),
&Addr::StackCell(fr, sc) => write!(f, "Addr::StackCell({}, {})", fr, sc),
&Addr::Str(s) => write!(f, "Addr::Str({})", s),
&Addr::PStrLocation(h, n) => write!(f, "Addr::PStrLocation({}, {})", h, n),
&Addr::Stream(stream) => write!(f, "Addr::Stream({})", stream),
&Addr::TcpListener(tcp_listener) => write!(f, "Addr::TcpListener({})", tcp_listener),
&Addr::Usize(cp) => write!(f, "Addr::Usize({})", cp),
}
}
}
impl fmt::Display for ControlInstruction { impl fmt::Display for ControlInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
@@ -327,6 +294,7 @@ impl fmt::Display for ControlInstruction {
} }
} }
} }
*/
impl fmt::Display for IndexedChoiceInstruction { impl fmt::Display for IndexedChoiceInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -338,6 +306,7 @@ 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 {
@@ -353,32 +322,49 @@ impl fmt::Display for ChoiceInstruction {
&ChoiceInstruction::DynamicElse(offset, Death::Finite(d), NextOrFail::Fail(i)) => { &ChoiceInstruction::DynamicElse(offset, Death::Finite(d), NextOrFail::Fail(i)) => {
write!(f, "dynamic_else {}, {}, fail({})", offset, d, i) write!(f, "dynamic_else {}, {}, fail({})", offset, d, i)
} }
&ChoiceInstruction::DynamicInternalElse(offset, Death::Infinity, NextOrFail::Next(i)) => { &ChoiceInstruction::DynamicInternalElse(
offset,
Death::Infinity,
NextOrFail::Next(i),
) => {
write!(f, "dynamic_internal_else {}, {}, {}", offset, "inf", i) write!(f, "dynamic_internal_else {}, {}, {}", offset, "inf", i)
} }
&ChoiceInstruction::DynamicInternalElse(offset, Death::Infinity, NextOrFail::Fail(i)) => { &ChoiceInstruction::DynamicInternalElse(
write!(f, "dynamic_internal_else {}, {}, fail({})", offset, "inf", i) offset,
Death::Infinity,
NextOrFail::Fail(i),
) => {
write!(
f,
"dynamic_internal_else {}, {}, fail({})",
offset, "inf", i
)
} }
&ChoiceInstruction::DynamicInternalElse(offset, Death::Finite(d), NextOrFail::Next(i)) => { &ChoiceInstruction::DynamicInternalElse(
offset,
Death::Finite(d),
NextOrFail::Next(i),
) => {
write!(f, "dynamic_internal_else {}, {}, {}", offset, d, i) write!(f, "dynamic_internal_else {}, {}, {}", offset, d, i)
} }
&ChoiceInstruction::DynamicInternalElse(offset, Death::Finite(d), NextOrFail::Fail(i)) => { &ChoiceInstruction::DynamicInternalElse(
offset,
Death::Finite(d),
NextOrFail::Fail(i),
) => {
write!(f, "dynamic_internal_else {}, {}, fail({})", offset, d, i) write!(f, "dynamic_internal_else {}, {}, fail({})", offset, d, i)
} }
&ChoiceInstruction::TryMeElse(offset) => &ChoiceInstruction::TryMeElse(offset) => write!(f, "try_me_else {}", 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) => &ChoiceInstruction::RetryMeElse(offset) => write!(f, "retry_me_else {}", offset),
write!(f, "retry_me_else {}", offset), &ChoiceInstruction::DefaultTrustMe(_) => write!(f, "trust_me_by_default"),
&ChoiceInstruction::DefaultTrustMe(_) => &ChoiceInstruction::TrustMe(_) => write!(f, "trust_me"),
write!(f, "trust_me_by_default"),
&ChoiceInstruction::TrustMe(_) =>
write!(f, "trust_me"),
} }
} }
} }
*/
impl fmt::Display for IndexingCodePtr { impl fmt::Display for IndexingCodePtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -434,8 +420,8 @@ impl fmt::Display for SessionError {
write!( write!(
f, f,
"module {} does not contain claimed export {}/{}", "module {} does not contain claimed export {}/{}",
module, module.as_str(),
key.0, key.0.as_str(),
key.1, key.1,
) )
} }
@@ -452,12 +438,23 @@ impl fmt::Display for SessionError {
write!(f, "queries cannot be defined as facts.") write!(f, "queries cannot be defined as facts.")
} }
&SessionError::ModuleCannotImportSelf(ref module_name) => { &SessionError::ModuleCannotImportSelf(ref module_name) => {
write!(f, "modules ({}, in this case) cannot import themselves.", write!(
module_name) f,
"modules ({}, in this case) cannot import themselves.",
module_name.as_str()
)
} }
&SessionError::PredicateNotMultifileOrDiscontiguous(ref compilation_target, ref key) => { &SessionError::PredicateNotMultifileOrDiscontiguous(
write!(f, "module {} does not define {}/{} as multifile or discontiguous.", ref compilation_target,
compilation_target.module_name(), key.0, key.1) ref key,
) => {
write!(
f,
"module {} does not define {}/{} as multifile or discontiguous.",
compilation_target.module_name().as_str(),
key.0.as_str(),
key.1
)
} }
} }
} }
@@ -466,14 +463,19 @@ impl fmt::Display for SessionError {
impl fmt::Display for ExistenceError { impl fmt::Display for ExistenceError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
&ExistenceError::Module(ref module_name) => { &ExistenceError::Module(module_name) => {
write!(f, "the module {} does not exist", module_name) write!(f, "the module {} does not exist", module_name.as_str())
} }
&ExistenceError::ModuleSource(ref module_source) => { &ExistenceError::ModuleSource(ref module_source) => {
write!(f, "the source/sink {} does not exist", module_source) write!(f, "the source/sink {} does not exist", module_source)
} }
&ExistenceError::Procedure(ref name, arity) => { &ExistenceError::Procedure(name, arity) => {
write!(f, "the procedure {}/{} does not exist", name, arity) write!(
f,
"the procedure {}/{} does not exist",
name.as_str(),
arity
)
} }
&ExistenceError::SourceSink(ref addr) => { &ExistenceError::SourceSink(ref addr) => {
write!(f, "the source/sink {} does not exist", addr) write!(f, "the source/sink {} does not exist", addr)
@@ -489,10 +491,10 @@ impl fmt::Display for ModuleSource {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
&ModuleSource::File(ref file) => { &ModuleSource::File(ref file) => {
write!(f, "at the file {}", file) write!(f, "at the file {}", file.as_str())
} }
&ModuleSource::Library(ref library) => { &ModuleSource::Library(ref library) => {
write!(f, "at library({})", library) write!(f, "at library({})", library.as_str())
} }
} }
} }
@@ -522,6 +524,7 @@ impl fmt::Display for IndexingLine {
} }
} }
/*
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 {
@@ -538,22 +541,15 @@ impl fmt::Display for Line {
Ok(()) 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::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),
} }
} }
} }
*/
impl fmt::Display for Number { /*
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Number::Fixnum(n) => write!(f, "{}", n),
&Number::Float(fl) => write!(f, "{}", fl),
&Number::Integer(ref bi) => write!(f, "{}", bi),
&Number::Rational(ref r) => write!(f, "{}", r),
}
}
}
impl fmt::Display for ArithmeticTerm { impl fmt::Display for ArithmeticTerm {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -663,7 +659,8 @@ impl fmt::Display for CutInstruction {
} }
} }
} }
*/
/*
impl fmt::Display for Level { impl fmt::Display for Level {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
@@ -672,3 +669,4 @@ impl fmt::Display for Level {
} }
} }
} }
*/

View File

@@ -29,23 +29,10 @@ impl Expectable for &[u8] {
/// Tests whether the file can be successfully loaded /// Tests whether the file can be successfully loaded
/// and produces the expected output during it /// and produces the expected output during it
pub(crate) fn load_module_test<T: Expectable>(file: &str, expected: T) { pub(crate) fn load_module_test<T: Expectable>(file: &str, expected: T) {
use scryer_prolog::*; use scryer_prolog::machine::mock_wam::*;
let input = machine::Stream::from(""); let mut wam = Machine::with_test_streams();
let output = machine::Stream::from(String::new()); expected.assert_eq(wam.test_load_file(file).as_slice());
let error = machine::Stream::from(String::new());
let mut wam = machine::Machine::new(input, output.clone(), error);
wam.load_file(
file.into(),
machine::Stream::from(
std::fs::read_to_string(AsRef::<std::path::Path>::as_ref(file)).unwrap(),
),
);
let output = output.bytes().unwrap();
expected.assert_eq(output.as_slice());
} }
pub const SCRYER_PROLOG: &str = "scryer-prolog"; pub const SCRYER_PROLOG: &str = "scryer-prolog";

View File

@@ -8,7 +8,8 @@ fn display_constraints() {
X = 1.\n\ X = 1.\n\
use_module(library(dif)).\n\ use_module(library(dif)).\n\
X = 1.\n\ X = 1.\n\
dif(X,1).\n", dif(X,1).\n
halt.\n",
" \ " \
X = 1.\n \ X = 1.\n \
true.\n \ true.\n \
@@ -25,6 +26,7 @@ fn do_not_duplicate_path_components() {
"\ "\
['tests-pl/issue852-throw_e.pl'].\n\ ['tests-pl/issue852-throw_e.pl'].\n\
['tests-pl/issue852-throw_e.pl'].\n\ ['tests-pl/issue852-throw_e.pl'].\n\
halt.\n\
", ",
"\ "\
caught: e\n\ caught: e\n\
@@ -50,6 +52,7 @@ fn handle_residual_goal() {
set_prolog_flag(occurs_check, true).\n\ set_prolog_flag(occurs_check, true).\n\
-X\\=X.\n\ -X\\=X.\n\
dif(-X,X).\n\ dif(-X,X).\n\
halt.\n\
", ",
" \ " \
true.\n \ true.\n \
@@ -73,6 +76,7 @@ fn occurs_check_flag() {
&["tests-pl/issue841-occurs-check.pl"], &["tests-pl/issue841-occurs-check.pl"],
"\ "\
f(X, X).\n\ f(X, X).\n\
halt.\n\
", ",
"false.\n", "false.\n",
) )
@@ -86,7 +90,8 @@ fn occurs_check_flag2() {
X = -X.\n\ X = -X.\n\
asserta(f(X,g(X))).\n\ asserta(f(X,g(X))).\n\
f(X,X).\n\ f(X,X).\n\
X-X = X-g(X). X-X = X-g(X).\n\
halt.\n\
", ",
" \ " \
true.\n\ true.\n\
@@ -101,7 +106,7 @@ fn occurs_check_flag2() {
// issue #839 // issue #839
#[test] #[test]
fn op3() { fn op3() {
run_top_level_test_with_args(&["tests-pl/issue839-op3.pl"], "", "") run_top_level_test_with_args(&["tests-pl/issue839-op3.pl", "-g", "halt"], "", "")
} }
// issue #820 // issue #820
@@ -127,27 +132,34 @@ fn compound_goal() {
// issue #815 // issue #815
#[test] #[test]
fn no_stutter() { fn no_stutter() {
run_top_level_test_no_args("write(a), write(b), false.\n", "abfalse.\n") run_top_level_test_no_args("write(a), write(b), false.\n\
halt.\n\
",
"abfalse.\n")
} }
/*
// issue #812 // issue #812
#[test] // FIXME: the line number is of by one (should be 4), empty line not accounted for or starting to count at line 0? #[test] // FIXME: the line number is of by one (should be 4), empty line not accounted for or starting to count at line 0?
fn singleton_warning() { fn singleton_warning() {
run_top_level_test_no_args( run_top_level_test_no_args(
"['tests-pl/issue812-singleton-warning.pl'].", "['tests-pl/issue812-singleton-warning.pl'].\n\
halt.\n",
"\ "\
Warning: singleton variables X at line 3 of issue812-singleton-warning.pl\n \ Warning: singleton variables X at line 3 of issue812-singleton-warning.pl\n \
true.\n\ true.\n\
", ",
); );
} }
*/
// issue #807 // issue #807
#[test] #[test]
fn ignored_constraint() { fn ignored_constraint() {
run_top_level_test_no_args( run_top_level_test_no_args(
"use_module(library(freeze)), freeze(X,false), X \\=a.", "use_module(library(freeze)), freeze(X,false), X \\=a.\n\
" freeze:freeze(X,user:false).\n", halt.",
" freeze:freeze(X,false).\n",
); );
} }

View File

@@ -1,4 +1,3 @@
mod helper; mod helper;
mod issues; mod issues;
mod src_tests; mod src_tests;

View File

@@ -1,25 +1,31 @@
use crate::helper::{load_module_test, run_top_level_test_with_args}; use crate::helper::{load_module_test, run_top_level_test_with_args};
use serial_test::serial;
#[serial]
#[test] #[test]
fn builtins() { fn builtins() {
load_module_test("src/tests/builtins.pl", ""); load_module_test("src/tests/builtins.pl", "");
} }
#[serial]
#[test] #[test]
fn call_with_inference_limit() { fn call_with_inference_limit() {
load_module_test("src/tests/call_with_inference_limit.pl", ""); load_module_test("src/tests/call_with_inference_limit.pl", "");
} }
#[serial]
#[test] #[test]
fn facts() { fn facts() {
load_module_test("src/tests/facts.pl", ""); load_module_test("src/tests/facts.pl", "");
} }
#[serial]
#[test] #[test]
fn hello_world() { fn hello_world() {
load_module_test("src/tests/hello_world.pl", "Hello World!\n"); load_module_test("src/tests/hello_world.pl", "Hello World!\n");
} }
#[serial]
#[test] #[test]
fn syntax_error() { fn syntax_error() {
load_module_test( load_module_test(
@@ -28,36 +34,37 @@ fn syntax_error() {
); );
} }
#[serial]
#[test] #[test]
#[ignore] // fails to halt
fn predicates() { fn predicates() {
load_module_test("src/tests/predicates.pl", ""); load_module_test("src/tests/predicates.pl", "");
} }
#[serial]
#[test] #[test]
fn rules() { fn rules() {
load_module_test("src/tests/rules.pl", ""); load_module_test("src/tests/rules.pl", "");
} }
#[serial]
#[test] #[test]
#[ignore]
fn setup_call_cleanup_load() { fn setup_call_cleanup_load() {
load_module_test( load_module_test(
"src/tests/setup_call_cleanup.pl", "src/tests/setup_call_cleanup.pl",
"1+21+31+2>_13165+_131661+_121811+2>41+2>_131661+2>31+2>31+2>4ba", "1+21+31+2>_14304+_143051+_128981+2>41+2>_143051+2>31+2>31+2>4ba",
); );
} }
#[test] #[test]
#[ignore]
fn setup_call_cleanup_process() { fn setup_call_cleanup_process() {
run_top_level_test_with_args( run_top_level_test_with_args(
&["src/tests/setup_call_cleanup.pl"], &["src/tests/setup_call_cleanup.pl", "-f", "-g", "halt"],
"", "",
"1+21+31+2>_14108+_141091+_131241+2>41+2>_141091+2>31+2>31+2>4ba", "1+21+31+2>_15703+_157041+_142971+2>41+2>_157041+2>31+2>31+2>4ba",
); );
} }
#[serial]
#[test] #[test]
fn clpz_load() { fn clpz_load() {
load_module_test("src/tests/clpz/test_clpz.pl", ""); load_module_test("src/tests/clpz/test_clpz.pl", "");