Merge branch 'rebis-dev' into 0.9.0 release

This commit is contained in:
Mark Thom
2022-03-06 09:39:28 -07:00
106 changed files with 38619 additions and 24832 deletions

2
.gitignore vendored
View File

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

800
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -61,10 +61,14 @@ Extend Scryer Prolog to include the following, among other features:
- [x] A simple sockets library representing TCP connections as streams.
- [x] Incremental compilation and loading process, newly written,
primarily in Prolog.
- [ ] Improvements to the WAM compiler and heap representation:
- [ ] Replacing choice points pivoting on inlined semi-deterministic predicates
(`atom`, `var`, etc) with if/else ladders. (_in progress_)
- [ ] 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.
- [ ] A compacting garbage collector satisfying the five properties of
"Precise Garbage Collection in Prolog." (_in progress_, see
the [`rebis-dev` branch](https://github.com/mthom/scryer-prolog/tree/rebis-dev)
and its [announcement](https://github.com/mthom/scryer-prolog/discussions/1167))
"Precise Garbage Collection in Prolog." (_in progress_)
- [ ] Mode declarations.
## Phase 3
@@ -132,6 +136,8 @@ $> cargo run [--release]
The optional `--release` flag will perform various optimizations,
producing a faster executable.
Scryer Prolog must be built with **Rust 1.57 and up**.
### Docker Install (All Platforms)
First, install [Docker](https://docs.docker.com/get-docker/) on Linux,
@@ -205,9 +211,10 @@ predicates it defines. For example, with the program shown above:
; What = pure_world.
```
Press `SPACE` to show further answers, if any exist. Press `RETURN` or
&nbsp;`.` to abort the search and return to the toplevel&nbsp;prompt.
Press&nbsp;`h` to show a help message.
Press `SPACE` to show further answers, if any exist. Press `RETURN`
or&nbsp;`.` to abort the search and return to the
toplevel&nbsp;prompt. Press&nbsp;`f` to see the next 5 answers, and
`a` to see all answers. Press&nbsp;`h` to show a help message.
To quit Scryer Prolog, use the standard predicate `halt/0`:
@@ -554,6 +561,7 @@ The modules that ship with Scryer&nbsp;Prolog are also called
* [`uuid`](src/lib/uuid.pl) UUIDv4 generation and hex representation
* [`tls`](src/lib/tls.pl)
Predicates for negotiating TLS connections explicitly.
* [`ugraphs`](src/lib/ugraphs.pl) Graph manipulation library
To use predicates provided by the `lists` library, write:

View File

@@ -1,8 +1,12 @@
use static_string_indexing::index_static_strings;
use instructions_template::generate_instructions_rs;
use std::env;
use std::fs;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::process::Command;
fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) {
let entries = match current_dir.read_dir() {
@@ -48,6 +52,37 @@ fn main() {
let mut m = IndexMap::new();\n",
)
.unwrap();
find_prolog_files(&mut libraries, "", &lib_path);
libraries.write_all(b"\n m\n };\n}\n").unwrap();
let instructions_path = Path::new(&out_dir).join("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(&out_dir).join("static_atoms.rs");
let mut static_atoms_file = File::create(&static_atoms_path).unwrap();
let quoted_output = index_static_strings(&instructions_path);
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();
println!("cargo:rerun-if-changed=src/");
}

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,177 @@
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(instruction_rs_path: &std::path::Path) -> 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();
fn process_filepath(path: &std::path::Path) -> std::result::Result<syn::File, ()> {
let mut src = String::new();
let mut file = match File::open(path) {
Ok(file) => file,
Err(_) => return Err(()),
};
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, path);
}
};
Ok(syntax)
}
for entry in WalkDir::new("src/")
.into_iter()
.filter_entry(filter_rust_files)
{
let entry = entry.unwrap();
if entry.path().is_dir() {
continue;
}
let syntax = match process_filepath(entry.path()) {
Ok(syntax) => syntax,
Err(_) => continue,
};
visitor.visit_file(&syntax);
}
match process_filepath(instruction_rs_path) {
Ok(syntax) => visitor.visit_file(&syntax),
Err(_) => {}
}
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()
}

View File

@@ -1,53 +1,57 @@
use prolog_parser::ast::*;
use prolog_parser::temp_v;
use crate::parser::ast::*;
use crate::temp_v;
use crate::fixtures::*;
use crate::forms::*;
use crate::instructions::*;
use crate::machine::machine_indices::*;
use crate::targets::*;
use std::cell::Cell;
use std::rc::Rc;
pub(crate) trait Allocator<'a> {
pub(crate) trait Allocator {
fn new() -> Self;
fn mark_anon_var<Target>(&mut self, _: Level, _: GenContext, _: &mut Vec<Target>)
where
Target: CompilationTarget<'a>;
fn mark_non_var<Target>(
fn mark_anon_var<'a, Target: CompilationTarget<'a>>(
&mut self,
_: Level,
_: GenContext,
_: &'a Cell<RegType>,
_: &mut Vec<Target>,
) where
Target: CompilationTarget<'a>;
fn mark_reserved_var<Target>(
lvl: Level,
context: GenContext,
code: &mut Code,
);
fn mark_non_var<'a, Target: CompilationTarget<'a>>(
&mut self,
_: Rc<Var>,
_: Level,
_: &'a Cell<VarReg>,
_: GenContext,
_: &mut Vec<Target>,
_: RegType,
_: bool,
) where
Target: CompilationTarget<'a>;
fn mark_var<Target>(
lvl: Level,
context: GenContext,
cell: &'a Cell<RegType>,
code: &mut Code,
);
fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
&mut self,
_: Rc<Var>,
_: Level,
_: &'a Cell<VarReg>,
_: GenContext,
_: &mut Vec<Target>,
) where
Target: CompilationTarget<'a>;
var_name: Rc<String>,
lvl: Level,
cell: &'a Cell<VarReg>,
term_loc: GenContext,
code: &mut Code,
r: RegType,
is_new_var: bool,
);
fn mark_var<'a, Target: CompilationTarget<'a>>(
&mut self,
var_name: Rc<String>,
lvl: Level,
cell: &'a Cell<VarReg>,
context: GenContext,
code: &mut Code,
);
fn reset(&mut self);
fn reset_contents(&mut self) {}
fn reset_arg(&mut self, _: usize);
fn reset_at_head(&mut self, _: &Vec<Box<Term>>);
fn reset_arg(&mut self, arg_num: usize);
fn reset_at_head(&mut self, args: &Vec<Term>);
fn advance_arg(&mut self);
@@ -56,7 +60,7 @@ pub(crate) trait Allocator<'a> {
fn take_bindings(self) -> AllocVarDict;
fn drain_var_data(
fn drain_var_data<'a>(
&mut self,
vs: VariableFixtures<'a>,
num_of_chunks: usize,
@@ -83,17 +87,17 @@ pub(crate) trait Allocator<'a> {
perm_vs
}
fn get(&self, var: Rc<Var>) -> RegType {
fn get(&self, var: Rc<String>) -> RegType {
self.bindings()
.get(&var)
.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
}
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() {
&mut VarData::Temp(_, ref mut s, _) => *s = r.reg_num(),
&mut VarData::Perm(ref mut s) => *s = r.reg_num(),

801
src/arena.rs Normal file
View File

@@ -0,0 +1,801 @@
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, PartialOrd, Ord)]
pub struct TypedArenaPtr<T: ?Sized>(ptr::NonNull<T>);
impl<T: ?Sized + PartialEq> PartialEq for TypedArenaPtr<T> {
fn eq(&self, other: &TypedArenaPtr<T>) -> bool {
self.0 == other.0 || &**self == &**other
}
}
impl<T: ?Sized + PartialEq> Eq for TypedArenaPtr<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,19 @@
use prolog_parser::ast::*;
use prolog_parser::{atom, clause_name};
use crate::clause_types::*;
use crate::allocator::*;
use crate::arena::*;
use crate::atom_table::*;
use crate::fixtures::*;
use crate::forms::*;
use crate::instructions::*;
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_indices::*;
use crate::rug::ops::PowAssign;
use crate::rug::{Assign, Integer, Rational};
use ordered_float::*;
use std::cell::Cell;
@@ -20,10 +21,33 @@ use std::cmp::{max, min, Ordering};
use std::convert::TryFrom;
use std::f64;
use std::num::FpCategory;
use std::ops::{Add, Div, Mul, Neg, Sub};
use std::ops::Div;
use std::rc::Rc;
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)]
pub(crate) struct ArithInstructionIterator<'a> {
state_stack: Vec<TermIterState<'a>>,
@@ -37,31 +61,30 @@ impl<'a> ArithInstructionIterator<'a> {
.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 {
&Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar),
&Term::Clause(ref cell, ref name, ref terms, ref fixity) => {
match ClauseType::from(name.clone(), terms.len(), fixity.clone()) {
ct @ ClauseType::Named(..) | ct @ ClauseType::Op(..) => {
Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
}
ClauseType::Inlined(InlinedClauseType::IsFloat(_)) => {
let ct = ClauseType::Named(clause_name!("float"), 1, CodeIndex::default());
Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
}
_ => Err(ArithmeticError::NonEvaluableFunctor(
Constant::Atom(name.clone(), fixity.clone()),
terms.len(),
)),
}?
Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar),
Term::Clause(cell, name, terms) => match ClauseType::from(*name, terms.len()) {
ct @ ClauseType::Named(..) => {
Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
}
ClauseType::Inlined(InlinedClauseType::IsFloat(_)) => {
let ct = ClauseType::Named(1, atom!("float"), CodeIndex::default());
Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
}
_ => Err(ArithmeticError::NonEvaluableFunctor(
Literal::Atom(*name),
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) => {
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()),
Term::Var(cell, var) => TermIterState::Var(Level::Shallow, cell, var.clone()),
};
Ok(ArithInstructionIterator {
@@ -72,9 +95,9 @@ impl<'a> ArithInstructionIterator<'a> {
#[derive(Debug)]
pub(crate) enum ArithTermRef<'a> {
Constant(&'a Constant),
Op(ClauseName, usize), // name, arity.
Var(&'a Cell<VarReg>, Rc<Var>),
Literal(&'a Literal),
Op(Atom, usize), // name, arity.
Var(Level, &'a Cell<VarReg>, Rc<String>),
}
impl<'a> Iterator for ArithInstructionIterator<'a> {
@@ -97,14 +120,23 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
ct,
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::Var(_, cell, var) => {
return Some(Ok(ArithTermRef::Var(cell, var.clone())))
TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(c))),
TermIterState::Var(lvl, cell, var) => {
// the expression is the second argument of an
// is/2 but the iterator can't see that, so the
// level needs to be demoted manually.
return Some(Ok(ArithTermRef::Var(lvl.child_level(), cell, var.clone())));
}
_ => {
return Some(Err(ArithmeticError::NonEvaluableFunctor(
Literal::Atom(atom!(".")),
2,
)));
}
_ => return Some(Err(ArithmeticError::NonEvaluableFunctor(atom!("'.'"), 2))),
};
}
@@ -113,8 +145,8 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
}
#[derive(Debug)]
pub(crate) struct ArithmeticEvaluator<'a> {
bindings: &'a AllocVarDict,
pub(crate) struct ArithmeticEvaluator<'a, TermMarker> {
marker: &'a mut TermMarker,
interm: Vec<ArithmeticTerm>,
interm_c: usize,
}
@@ -129,82 +161,99 @@ impl<'a> ArithmeticTermIter<'a> for &'a Term {
type Iter = ArithInstructionIterator<'a>;
fn iter(self) -> Result<Self::Iter, ArithmeticError> {
ArithInstructionIterator::new(self)
ArithInstructionIterator::from(self)
}
}
impl<'a> ArithmeticEvaluator<'a> {
pub(crate) fn new(bindings: &'a AllocVarDict, target_int: usize) -> 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, TermMarker: Allocator> ArithmeticEvaluator<'a, TermMarker> {
pub(crate) fn new(marker: &'a mut TermMarker, target_int: usize) -> Self {
ArithmeticEvaluator {
bindings,
marker,
interm: Vec::new(),
interm_c: target_int,
}
}
fn get_unary_instr(
name: ClauseName,
&self,
name: Atom,
a1: ArithmeticTerm,
t: usize,
) -> Result<ArithmeticInstruction, ArithmeticError> {
match name.as_str() {
"abs" => Ok(ArithmeticInstruction::Abs(a1, t)),
"-" => Ok(ArithmeticInstruction::Neg(a1, t)),
"+" => Ok(ArithmeticInstruction::Plus(a1, t)),
"cos" => Ok(ArithmeticInstruction::Cos(a1, t)),
"sin" => Ok(ArithmeticInstruction::Sin(a1, t)),
"tan" => Ok(ArithmeticInstruction::Tan(a1, t)),
"log" => Ok(ArithmeticInstruction::Log(a1, t)),
"exp" => Ok(ArithmeticInstruction::Exp(a1, t)),
"sqrt" => Ok(ArithmeticInstruction::Sqrt(a1, t)),
"acos" => Ok(ArithmeticInstruction::ACos(a1, t)),
"asin" => Ok(ArithmeticInstruction::ASin(a1, t)),
"atan" => Ok(ArithmeticInstruction::ATan(a1, t)),
"float" => Ok(ArithmeticInstruction::Float(a1, t)),
"truncate" => Ok(ArithmeticInstruction::Truncate(a1, t)),
"round" => Ok(ArithmeticInstruction::Round(a1, t)),
"ceiling" => Ok(ArithmeticInstruction::Ceiling(a1, t)),
"floor" => Ok(ArithmeticInstruction::Floor(a1, t)),
"sign" => Ok(ArithmeticInstruction::Sign(a1, t)),
"\\" => Ok(ArithmeticInstruction::BitwiseComplement(a1, t)),
_ => Err(ArithmeticError::NonEvaluableFunctor(
Constant::Atom(name, None),
1,
)),
) -> Result<Instruction, ArithmeticError> {
match name {
atom!("abs") => Ok(Instruction::Abs(a1, t)),
atom!("-") => Ok(Instruction::Neg(a1, t)),
atom!("+") => Ok(Instruction::Plus(a1, t)),
atom!("cos") => Ok(Instruction::Cos(a1, t)),
atom!("sin") => Ok(Instruction::Sin(a1, t)),
atom!("tan") => Ok(Instruction::Tan(a1, t)),
atom!("log") => Ok(Instruction::Log(a1, t)),
atom!("exp") => Ok(Instruction::Exp(a1, t)),
atom!("sqrt") => Ok(Instruction::Sqrt(a1, t)),
atom!("acos") => Ok(Instruction::ACos(a1, t)),
atom!("asin") => Ok(Instruction::ASin(a1, t)),
atom!("atan") => Ok(Instruction::ATan(a1, t)),
atom!("float") => Ok(Instruction::Float(a1, t)),
atom!("truncate") => Ok(Instruction::Truncate(a1, t)),
atom!("round") => Ok(Instruction::Round(a1, t)),
atom!("ceiling") => Ok(Instruction::Ceiling(a1, t)),
atom!("floor") => Ok(Instruction::Floor(a1, t)),
atom!("sign") => Ok(Instruction::Sign(a1, t)),
atom!("\\") => Ok(Instruction::BitwiseComplement(a1, t)),
_ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 1)),
}
}
fn get_binary_instr(
name: ClauseName,
&self,
name: Atom,
a1: ArithmeticTerm,
a2: ArithmeticTerm,
t: usize,
) -> Result<ArithmeticInstruction, ArithmeticError> {
match name.as_str() {
"+" => Ok(ArithmeticInstruction::Add(a1, a2, t)),
"-" => Ok(ArithmeticInstruction::Sub(a1, a2, t)),
"/" => Ok(ArithmeticInstruction::Div(a1, a2, t)),
"//" => Ok(ArithmeticInstruction::IDiv(a1, a2, t)),
"max" => Ok(ArithmeticInstruction::Max(a1, a2, t)),
"min" => Ok(ArithmeticInstruction::Min(a1, a2, t)),
"div" => Ok(ArithmeticInstruction::IntFloorDiv(a1, a2, t)),
"rdiv" => Ok(ArithmeticInstruction::RDiv(a1, a2, t)),
"*" => Ok(ArithmeticInstruction::Mul(a1, a2, t)),
"**" => Ok(ArithmeticInstruction::Pow(a1, a2, t)),
"^" => Ok(ArithmeticInstruction::IntPow(a1, a2, t)),
">>" => Ok(ArithmeticInstruction::Shr(a1, a2, t)),
"<<" => Ok(ArithmeticInstruction::Shl(a1, a2, t)),
"/\\" => Ok(ArithmeticInstruction::And(a1, a2, t)),
"\\/" => Ok(ArithmeticInstruction::Or(a1, a2, t)),
"xor" => Ok(ArithmeticInstruction::Xor(a1, a2, t)),
"mod" => Ok(ArithmeticInstruction::Mod(a1, a2, t)),
"rem" => Ok(ArithmeticInstruction::Rem(a1, a2, t)),
"gcd" => Ok(ArithmeticInstruction::Gcd(a1, a2, t)),
"atan2" => Ok(ArithmeticInstruction::ATan2(a1, a2, t)),
_ => Err(ArithmeticError::NonEvaluableFunctor(
Constant::Atom(name, None),
2,
)),
) -> Result<Instruction, ArithmeticError> {
match name {
atom!("+") => Ok(Instruction::Add(a1, a2, t)),
atom!("-") => Ok(Instruction::Sub(a1, a2, t)),
atom!("/") => Ok(Instruction::Div(a1, a2, t)),
atom!("//") => Ok(Instruction::IDiv(a1, a2, t)),
atom!("max") => Ok(Instruction::Max(a1, a2, t)),
atom!("min") => Ok(Instruction::Min(a1, a2, t)),
atom!("div") => Ok(Instruction::IntFloorDiv(a1, a2, t)),
atom!("rdiv") => Ok(Instruction::RDiv(a1, a2, t)),
atom!("*") => Ok(Instruction::Mul(a1, a2, t)),
atom!("**") => Ok(Instruction::Pow(a1, a2, t)),
atom!("^") => Ok(Instruction::IntPow(a1, a2, t)),
atom!(">>") => Ok(Instruction::Shr(a1, a2, t)),
atom!("<<") => Ok(Instruction::Shl(a1, a2, t)),
atom!("/\\") => Ok(Instruction::And(a1, a2, t)),
atom!("\\/") => Ok(Instruction::Or(a1, a2, t)),
atom!("xor") => Ok(Instruction::Xor(a1, a2, t)),
atom!("mod") => Ok(Instruction::Mod(a1, a2, t)),
atom!("rem") => Ok(Instruction::Rem(a1, a2, t)),
atom!("gcd") => Ok(Instruction::Gcd(a1, a2, t)),
atom!("atan2") => Ok(Instruction::ATan2(a1, a2, t)),
_ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 2)),
}
}
@@ -219,9 +268,9 @@ impl<'a> ArithmeticEvaluator<'a> {
fn instr_from_clause(
&mut self,
name: ClauseName,
name: Atom,
arity: usize,
) -> Result<ArithmeticInstruction, ArithmeticError> {
) -> Result<Instruction, ArithmeticError> {
match arity {
1 => {
let a1 = self.interm.pop().unwrap();
@@ -233,7 +282,7 @@ impl<'a> ArithmeticEvaluator<'a> {
a1.interm_or(0)
};
Self::get_unary_instr(name, a1, ninterm)
self.get_unary_instr(name, a1, ninterm)
}
2 => {
let a2 = self.interm.pop().unwrap();
@@ -257,67 +306,55 @@ impl<'a> ArithmeticEvaluator<'a> {
min_interm
};
Self::get_binary_instr(name, a1, a2, ninterm)
self.get_binary_instr(name, a1, a2, ninterm)
}
_ => Err(ArithmeticError::NonEvaluableFunctor(
Constant::Atom(name, None),
Literal::Atom(name),
arity,
)),
}
}
fn push_constant(&mut self, c: &Constant) -> Result<(), 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>,
pub(crate) fn eval(
&mut self,
src: &'a Term,
term_loc: GenContext,
) -> Result<ArithCont, ArithmeticError>
{
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? {
ArithTermRef::Constant(c) => self.push_constant(c)?,
ArithTermRef::Var(cell, name) => {
ArithTermRef::Literal(c) => push_literal(&mut self.interm, c)?,
ArithTermRef::Var(lvl, cell, name) => {
let r = if cell.get().norm().reg_num() == 0 {
match self.bindings.get(&name) {
Some(&VarData::Temp(_, t, _)) if t != 0 => RegType::Temp(t),
Some(&VarData::Perm(p)) if p != 0 => RegType::Perm(p),
_ => return Err(ArithmeticError::UninstantiatedVar),
}
let mut getter = || {
use crate::targets::QueryInstruction;
loop {
match self.marker.bindings().get(&name) {
Some(&VarData::Temp(_, t, _)) if t != 0 =>
return RegType::Temp(t),
Some(&VarData::Perm(p)) if p != 0 =>
return RegType::Perm(p),
_ => {
self.marker.mark_var::<QueryInstruction>(
name.clone(),
lvl,
cell,
term_loc,
&mut code,
);
}
}
}
};
getter()
/*
_ => return Err(ArithmeticError::UninstantiatedVar),
*/
} else {
cell.get().norm()
};
@@ -325,7 +362,7 @@ impl<'a> ArithmeticEvaluator<'a> {
self.interm.push(ArithmeticTerm::Reg(r));
}
ArithTermRef::Op(name, arity) => {
code.push(Line::Arithmetic(self.instr_from_clause(name, arity)?));
code.push(self.instr_from_clause(name, arity)?);
}
}
}
@@ -335,27 +372,31 @@ impl<'a> ArithmeticEvaluator<'a> {
}
// 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 {
&Number::Integer(_) => RefOrOwned::Borrowed(n),
&Number::Float(OrderedFloat(f)) => RefOrOwned::Owned(Number::from(
Integer::from_f64(f.floor()).unwrap_or_else(|| Integer::from(0)),
)),
&Number::Fixnum(n) => RefOrOwned::Owned(Number::from(n)),
&Number::Integer(_) | &Number::Fixnum(_) => *n,
&Number::Float(OrderedFloat(f)) => fixnum!(Number, f.floor() as i64, arena),
&Number::Rational(ref r) => {
let r_ref = r.fract_floor_ref();
let (mut fract, mut floor) = (Rational::new(), Integer::new());
(&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.
pub(crate) fn rnd_f(n: &Number) -> f64 {
match n {
&Number::Fixnum(n) => n as f64,
&Number::Fixnum(n) => n.get_num() as f64,
&Number::Integer(ref n) => n.to_f64(),
&Number::Float(OrderedFloat(f)) => f,
&Number::Rational(ref r) => r.to_f64(),
@@ -392,27 +433,27 @@ where
}
#[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)
}
#[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)
}
#[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)
}
#[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)?))
}
#[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)?))
}
@@ -425,161 +466,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 {
type Output = Result<Number, EvalError>;
fn div(self, rhs: Number) -> Self::Output {
match (self, rhs) {
(Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f(
float_fn_to_f(n1)?,
float_fn_to_f(n2)?,
float_fn_to_f(n1.get_num())?,
float_fn_to_f(n2.get_num())?,
)?)),
(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)?,
)?)),
(Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f(
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(
float_fn_to_f(n1)?,
float_fn_to_f(n1.get_num())?,
float_r_to_f(&n2)?,
)?)),
(Number::Rational(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f(
float_r_to_f(&n1)?,
float_fn_to_f(n2)?,
float_fn_to_f(n2.get_num())?,
)?)),
(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)) => {
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(
float_i_to_f(&n1)?,
@@ -620,14 +536,14 @@ impl PartialEq for Number {
fn eq(&self, rhs: &Self) -> bool {
match (self, rhs) {
(&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.eq(&n2),
(&Number::Fixnum(n1), &Number::Integer(ref n2)) => n1.eq(&**n2),
(&Number::Integer(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2),
(&Number::Fixnum(n1), &Number::Rational(ref n2)) => n1.eq(&**n2),
(&Number::Rational(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2),
(&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1 as f64).eq(&n2),
(&Number::Float(n1), &Number::Fixnum(n2)) => n1.eq(&OrderedFloat(n2 as f64)),
(&Number::Fixnum(n1), &Number::Integer(ref n2)) => n1.get_num().eq(&**n2),
(&Number::Integer(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2.get_num()),
(&Number::Fixnum(n1), &Number::Rational(ref n2)) => n1.get_num().eq(&**n2),
(&Number::Rational(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2.get_num()),
(&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1.get_num() as f64).eq(&n2),
(&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::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::Integer(ref n1), &Number::Rational(ref n2)) => {
#[cfg(feature = "num")]
@@ -659,6 +575,46 @@ impl PartialEq 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 {
fn partial_cmp(&self, rhs: &Number) -> Option<Ordering> {
Some(self.cmp(rhs))
@@ -668,92 +624,78 @@ impl PartialOrd for Number {
impl Ord for Number {
fn cmp(&self, rhs: &Number) -> Ordering {
match (self, rhs) {
(&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.cmp(&n2),
(&Number::Fixnum(n1), Number::Integer(n2)) => Integer::from(n1).cmp(&*n2),
(Number::Integer(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Integer::from(n2)),
(&Number::Fixnum(n1), Number::Rational(n2)) => Rational::from(n1).cmp(&*n2),
(Number::Rational(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Rational::from(n2)),
(&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1 as f64).cmp(&n2),
(&Number::Float(n1), &Number::Fixnum(n2)) => n1.cmp(&OrderedFloat(n2 as f64)),
(&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::Fixnum(n1), &Number::Fixnum(n2)) => n1.get_num().cmp(&n2.get_num()),
(&Number::Fixnum(n1), Number::Integer(n2)) => Integer::from(n1.get_num()).cmp(&*n2),
(Number::Integer(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Integer::from(n2.get_num())),
(&Number::Fixnum(n1), Number::Rational(n2)) => Rational::from(n1.get_num()).cmp(&*n2),
(Number::Rational(n1), &Number::Fixnum(n2)) => {
(&**n1).cmp(&Rational::from(n2.get_num()))
}
(&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(n1), &Number::Integer(n2)) => (*n1).cmp(&*n2),
(&Number::Integer(n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(n2),
(&Number::Float(n1), &Number::Integer(ref n2)) => n1.cmp(&OrderedFloat(n2.to_f64())),
(&Number::Integer(ref n1), &Number::Rational(ref n2)) => {
(&Number::Integer(n1), &Number::Rational(n2)) => {
#[cfg(feature = "num")]
{
Rational::from(&**n1).cmp(n2)
}
#[cfg(not(feature = "num"))]
{
(&**n1).partial_cmp(&**n2).unwrap_or(Ordering::Less)
(&*n1).partial_cmp(&*n2).unwrap_or(Ordering::Less)
}
}
(&Number::Rational(ref n1), &Number::Integer(ref n2)) => {
(&Number::Rational(n1), &Number::Integer(n2)) => {
#[cfg(feature = "num")]
{
(&**n1).cmp(&Rational::from(&**n2))
}
#[cfg(not(feature = "num"))]
{
(&**n1).partial_cmp(&**n2).unwrap_or(Ordering::Less)
(&*n1).partial_cmp(&*n2).unwrap_or(Ordering::Less)
}
}
(&Number::Rational(ref n1), &Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(&n2),
(&Number::Float(n1), &Number::Rational(ref n2)) => n1.cmp(&OrderedFloat(n2.to_f64())),
(&Number::Rational(n1), &Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(&n2),
(&Number::Float(n1), &Number::Rational(n2)) => n1.cmp(&OrderedFloat(n2.to_f64())),
(&Number::Float(f1), &Number::Float(f2)) => f1.cmp(&f2),
(&Number::Rational(ref r1), &Number::Rational(ref r2)) => r1.cmp(&r2),
(&Number::Rational(r1), &Number::Rational(r2)) => (*r1).cmp(&*r2),
}
}
}
impl<'a> TryFrom<(Addr, &'a Heap)> for Number {
impl TryFrom<HeapCellValue> for Number {
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]
fn from(src: &'a Integer) -> Self {
Number::Integer(Rc::new(Integer::from(src)))
fn try_from(value: HeapCellValue) -> Result<Number, Self::Error> {
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!(concat!(env!("OUT_DIR"), "/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() {
use nix::sys::signal;
use scryer_prolog::read::readline;
use scryer_prolog::*;
let handler = signal::SigHandler::Handler(handle_sigint);
unsafe { signal::signal(signal::Signal::SIGINT, handler) }.unwrap();
let mut wam = machine::Machine::new(
readline::input_stream(),
machine::Stream::stdout(),
machine::Stream::stderr(),
);
let mut wam = machine::Machine::new();
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 prolog_parser::ast::*;
use prolog_parser::temp_v;
use crate::allocator::*;
use crate::fixtures::*;
use crate::forms::*;
use crate::forms::Level;
use crate::instructions::*;
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::collections::BTreeSet;
@@ -15,23 +18,23 @@ use std::rc::Rc;
#[derive(Debug)]
pub(crate) struct DebrayAllocator {
bindings: IndexMap<Rc<Var>, VarData>,
bindings: IndexMap<Rc<String>, VarData, FxBuildHasher>,
arg_c: usize,
temp_lb: usize,
arity: usize, // 0 if not at head.
contents: IndexMap<usize, Rc<Var>>,
contents: IndexMap<usize, Rc<String>, FxBuildHasher>,
in_use: BTreeSet<usize>,
}
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) {
Some(t_var) if **t_var != *var => true,
_ => 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() {
&VarData::Temp(_, _, ref tvd) => tvd.use_set.contains(&(GenContext::Head, r)),
_ => false,
@@ -44,7 +47,7 @@ impl DebrayAllocator {
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) {
Some(&VarData::Temp(_, _, ref tvd)) => {
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) {
Some(&VarData::Temp(_, _, ref tvd)) => {
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.
// par_k may not be a temporary variable.
let k = self.arg_c;
@@ -123,10 +126,11 @@ impl DebrayAllocator {
}
}
fn evacuate_arg<'a, Target>(&mut self, chunk_num: usize, target: &mut Vec<Target>)
where
Target: CompilationTarget<'a>,
{
fn evacuate_arg<'a, Target: CompilationTarget<'a>>(
&mut self,
chunk_num: usize,
code: &mut Code,
) {
match self.alloc_in_last_goal_hint(chunk_num) {
Some((var, r)) => {
let k = self.arg_c;
@@ -134,7 +138,7 @@ impl DebrayAllocator {
if r != k {
let r = RegType::Temp(r);
target.push(Target::move_to_register(r, k));
code.push(Target::move_to_register(r, k));
self.contents.swap_remove(&k);
self.contents.insert(r.reg_num(), var.clone());
@@ -149,10 +153,10 @@ impl DebrayAllocator {
fn alloc_reg_to_var<'a, Target>(
&mut self,
var: &Var,
var: &String,
lvl: Level,
term_loc: GenContext,
target: &mut Vec<Target>,
target: &mut Vec<Instruction>,
) -> usize
where
Target: CompilationTarget<'a>,
@@ -160,7 +164,7 @@ impl DebrayAllocator {
match term_loc {
GenContext::Head => {
if let Level::Shallow = lvl {
self.evacuate_arg(0, target);
self.evacuate_arg::<Target>(0, target);
self.alloc_with_cr(var)
} else {
self.alloc_with_ca(var)
@@ -169,7 +173,7 @@ impl DebrayAllocator {
GenContext::Mid(_) => self.alloc_with_ca(var),
GenContext::Last(chunk_num) => {
if let Level::Shallow = lvl {
self.evacuate_arg(chunk_num, target);
self.evacuate_arg::<Target>(chunk_num, target);
self.alloc_with_cr(var)
} else {
self.alloc_with_ca(var)
@@ -193,7 +197,7 @@ impl DebrayAllocator {
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 {
GenContext::Head if !r.is_perm() => r.reg_num() == k,
_ => match self.bindings().get(var).unwrap() {
@@ -204,49 +208,49 @@ impl DebrayAllocator {
}
}
impl<'a> Allocator<'a> for DebrayAllocator {
impl Allocator for DebrayAllocator {
fn new() -> DebrayAllocator {
DebrayAllocator {
arity: 0,
arg_c: 1,
temp_lb: 1,
bindings: IndexMap::new(),
contents: IndexMap::new(),
bindings: IndexMap::with_hasher(FxBuildHasher::default()),
contents: IndexMap::with_hasher(FxBuildHasher::default()),
in_use: BTreeSet::new(),
}
}
fn mark_anon_var<Target>(&mut self, lvl: Level, term_loc: GenContext, target: &mut Vec<Target>)
where
Target: CompilationTarget<'a>,
{
fn mark_anon_var<'a, Target: CompilationTarget<'a>>(
&mut self,
lvl: Level,
term_loc: GenContext,
code: &mut Code,
) {
let r = RegType::Temp(self.alloc_reg_to_non_var());
match lvl {
Level::Deep => target.push(Target::subterm_to_variable(r)),
Level::Deep => code.push(Target::subterm_to_variable(r)),
Level::Root | Level::Shallow => {
let k = self.arg_c;
if let GenContext::Last(chunk_num) = term_loc {
self.evacuate_arg(chunk_num, target);
self.evacuate_arg::<Target>(chunk_num, code);
}
self.arg_c += 1;
target.push(Target::argument_to_variable(r, k));
code.push(Target::argument_to_variable(r, k));
}
};
}
fn mark_non_var<Target>(
fn mark_non_var<'a, Target: CompilationTarget<'a>>(
&mut self,
lvl: Level,
term_loc: GenContext,
cell: &Cell<RegType>,
target: &mut Vec<Target>,
) where
Target: CompilationTarget<'a>,
{
cell: &'a Cell<RegType>,
code: &mut Code,
) {
let r = cell.get();
let r = match lvl {
@@ -254,7 +258,7 @@ impl<'a> Allocator<'a> for DebrayAllocator {
let k = self.arg_c;
if let GenContext::Last(chunk_num) = term_loc {
self.evacuate_arg(chunk_num, target);
self.evacuate_arg::<Target>(chunk_num, code);
}
self.arg_c += 1;
@@ -270,20 +274,18 @@ impl<'a> Allocator<'a> for DebrayAllocator {
cell.set(r);
}
fn mark_var<Target>(
fn mark_var<'a, Target: CompilationTarget<'a>>(
&mut self,
var: Rc<Var>,
var: Rc<String>,
lvl: Level,
cell: &'a Cell<VarReg>,
term_loc: GenContext,
target: &mut Vec<Target>,
) where
Target: CompilationTarget<'a>,
{
code: &mut Code,
) {
let (r, is_new_var) = match self.get(var.clone()) {
RegType::Temp(0) => {
// 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, code);
cell.set(VarReg::Norm(RegType::Temp(o)));
(RegType::Temp(o), true)
@@ -297,27 +299,25 @@ impl<'a> Allocator<'a> for DebrayAllocator {
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, code, r, is_new_var);
}
fn mark_reserved_var<Target>(
fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
&mut self,
var: Rc<Var>,
var: Rc<String>,
lvl: Level,
cell: &'a Cell<VarReg>,
term_loc: GenContext,
target: &mut Vec<Target>,
code: &mut Code,
r: RegType,
is_new_var: bool,
) where
Target: CompilationTarget<'a>,
{
) {
match lvl {
Level::Root | Level::Shallow => {
let k = self.arg_c;
if self.is_curr_arg_distinct_from(&var) {
self.evacuate_arg(term_loc.chunk_num(), target);
self.evacuate_arg::<Target>(term_loc.chunk_num(), code);
}
self.arg_c += 1;
@@ -326,24 +326,24 @@ impl<'a> Allocator<'a> for DebrayAllocator {
if !self.in_place(&var, term_loc, r, k) {
if is_new_var {
target.push(Target::argument_to_variable(r, k));
code.push(Target::argument_to_variable(r, k));
} else {
target.push(Target::argument_to_value(r, k));
code.push(Target::argument_to_value(r, k));
}
}
}
Level::Deep if is_new_var => {
if let GenContext::Head = term_loc {
if self.occurs_shallowly_in_head(&var, r.reg_num()) {
target.push(Target::subterm_to_value(r));
code.push(Target::subterm_to_value(r));
} else {
target.push(Target::subterm_to_variable(r));
code.push(Target::subterm_to_variable(r));
}
} else {
target.push(Target::subterm_to_variable(r));
code.push(Target::subterm_to_variable(r));
}
}
Level::Deep => target.push(Target::subterm_to_value(r)),
Level::Deep => code.push(Target::subterm_to_value(r)),
};
if !r.is_perm() {
@@ -382,12 +382,12 @@ impl<'a> Allocator<'a> for DebrayAllocator {
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.arity = args.len();
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());
if !r.is_perm() && r.reg_num() == 0 {

View File

@@ -11,7 +11,7 @@
*/
:- module(least_time, [find_min_time/2,
write_time_nl/1]).
write_time_nl/1]).
:- use_module(library(dcgs)).
@@ -20,12 +20,6 @@
:- use_module(library(reif)).
permutation([], []).
permutation([X|Xs], Ys) :-
permutation(Xs, Yss),
select(X, Ys, Yss).
valid_time([H1,H2,M1,M2], T) :-
memberd_t(H1, [0,1,2], TH1),
memberd_t(H2, [0,1,2,3,4,5,6,7,8,9], TH2),
@@ -33,10 +27,10 @@ valid_time([H1,H2,M1,M2], T) :-
memberd_t(M2, [0,1,2,3,4,5,6,7,8,9], TM2),
( maplist(=(true), [TH1, TH2, TM1, TM2]) ->
( H1 =:= 2 ->
( H2 =< 3 ->
T = true
; T = false
)
( H2 =< 3 ->
T = true
; T = false
)
; T = true
)
; T = false

View File

@@ -1,4 +1,4 @@
use prolog_parser::ast::*;
use crate::parser::ast::*;
use crate::forms::*;
use crate::instructions::*;
@@ -84,8 +84,8 @@ type VariableFixture<'a> = (VarStatus, Vec<&'a Cell<VarReg>>);
#[derive(Debug)]
pub(crate) struct VariableFixtures<'a> {
perm_vars: IndexMap<Rc<Var>, VariableFixture<'a>>,
last_chunk_temp_vars: IndexSet<Rc<Var>>,
perm_vars: IndexMap<Rc<String>, VariableFixture<'a>>,
last_chunk_temp_vars: IndexSet<Rc<String>>,
}
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);
}
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);
}
@@ -115,7 +115,7 @@ impl<'a> VariableFixtures<'a> {
// Compute the conflict set of u.
// 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() {
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)
}
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()
}
@@ -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()
}
fn values(&self) -> indexmap::map::Values<Rc<Var>, VariableFixture<'a>> {
fn values(&self) -> indexmap::map::Values<Rc<String>, VariableFixture<'a>> {
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 {
&QueryInstruction::PutVariable(r @ RegType::Temp(_), _)
| &QueryInstruction::SetVariable(r) => {
&Instruction::PutVariable(r @ RegType::Temp(_), _) |
&Instruction::SetVariable(r) => {
self.safe_vars.insert(r);
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 {
&QueryInstruction::PutValue(r @ RegType::Perm(_), _)
| &QueryInstruction::SetValue(r) => {
&Instruction::PutValue(r @ RegType::Perm(_), _) |
&Instruction::SetValue(r) => {
let p = self.unsafe_vars.entry(r).or_insert(0);
*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 {
&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 p == phase {
*query_instr = QueryInstruction::PutUnsafeValue(i, arg);
*query_instr = Instruction::PutUnsafeValue(i, arg);
self.safe_vars.insert(RegType::Perm(i));
} else {
self.unsafe_vars.insert(RegType::Perm(i), p);
}
}
}
&mut QueryInstruction::SetValue(r) => {
&mut Instruction::SetValue(r) => {
if !self.safe_vars.contains(&r) {
*query_instr = QueryInstruction::SetLocalValue(r);
*query_instr = Instruction::SetLocalValue(r);
self.safe_vars.insert(r);
self.unsafe_vars.remove(&r);

View File

@@ -1,33 +1,41 @@
use prolog_parser::ast::*;
use prolog_parser::parser::OpDesc;
use prolog_parser::{clause_name, is_infix, is_postfix};
use crate::clause_types::*;
use crate::arena::*;
use crate::atom_table::*;
use crate::instructions::*;
use crate::machine::heap::*;
use crate::machine::loader::PredicateQueue;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::rug::{Integer, Rational};
use ordered_float::OrderedFloat;
use crate::parser::ast::*;
use crate::parser::parser::CompositeOpDesc;
use crate::parser::rug::{Integer, Rational};
use crate::types::*;
use fxhash::FxBuildHasher;
use indexmap::{IndexMap, IndexSet};
use ordered_float::OrderedFloat;
use slice_deque::*;
use std::cell::Cell;
use std::convert::TryFrom;
use std::fmt;
use std::ops::AddAssign;
use std::path::PathBuf;
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
// of vars (we get their adjoining cells this way).
pub(crate) type JumpStub = Vec<Term>;
pub type JumpStub = Vec<Term>;
#[derive(Debug, Clone)]
pub(crate) enum TopLevel {
pub enum TopLevel {
Fact(Term), // Term, line_num, col_num
Predicate(Predicate),
Query(Vec<QueryTerm>),
@@ -35,7 +43,7 @@ pub(crate) enum TopLevel {
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum AppendOrPrepend {
pub enum AppendOrPrepend {
Append,
Prepend,
}
@@ -51,7 +59,7 @@ impl AppendOrPrepend {
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum Level {
pub enum Level {
Deep,
Root,
Shallow,
@@ -67,12 +75,12 @@ impl Level {
}
#[derive(Debug, Clone)]
pub(crate) enum QueryTerm {
pub enum QueryTerm {
// 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.
UnblockedCut(Cell<VarReg>),
GetLevelAndUnify(Cell<VarReg>, Rc<Var>),
GetLevelAndUnify(Cell<VarReg>, Rc<String>),
Jump(JumpStub),
}
@@ -95,25 +103,25 @@ impl QueryTerm {
}
#[derive(Debug, Clone)]
pub(crate) struct Rule {
pub(crate) head: (ClauseName, Vec<Box<Term>>, QueryTerm),
pub struct Rule {
pub(crate) head: (Atom, Vec<Term>, QueryTerm),
pub(crate) clauses: Vec<QueryTerm>,
}
#[derive(Clone, Debug, Hash)]
pub(crate) enum ListingSource {
pub enum ListingSource {
DynamicallyGenerated,
File(ClauseName, PathBuf), // filename, path
File(Atom, PathBuf), // filename, path
User,
}
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)
}
}
pub(crate) trait ClauseInfo {
pub trait ClauseInfo {
fn is_consistent(&self, clauses: &PredicateQueue) -> bool {
match clauses.first() {
Some(cl) => {
@@ -123,14 +131,14 @@ pub(crate) trait ClauseInfo {
}
}
fn name(&self) -> Option<ClauseName>;
fn name(&self) -> Option<Atom>;
fn arity(&self) -> usize;
}
impl ClauseInfo for PredicateKey {
#[inline]
fn name(&self) -> Option<ClauseName> {
Some(self.0.clone())
fn name(&self) -> Option<Atom> {
Some(self.0)
}
#[inline]
@@ -140,28 +148,32 @@ impl ClauseInfo for PredicateKey {
}
impl ClauseInfo for Term {
fn name(&self) -> Option<ClauseName> {
fn name(&self) -> Option<Atom> {
//, atom_tbl: &AtomTable) -> Option<StringBuffer> {
match self {
Term::Clause(_, ref name, ref terms, _) => {
Term::Clause(_, name, terms) => {
// let str_buf = StringBuffer::from(*name, atom_tbl);
match name.as_str() {
// str_buf.as_str() {
":-" => {
match terms.len() {
1 => None, // a declaration.
2 => terms[0].name(),
_ => Some(clause_name!(":-")),
1 => None, // a declaration.
2 => terms[0].name(), //.map(|name| StringBuffer::from(name, atom_tbl)),
_ => 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,
}
}
fn arity(&self) -> usize {
match self {
Term::Clause(_, ref name, ref terms, _) => match name.as_str() {
Term::Clause(_, name, terms) => match name.as_str() {
":-" => match terms.len() {
1 => 0,
2 => terms[0].arity(),
@@ -175,8 +187,8 @@ impl ClauseInfo for Term {
}
impl ClauseInfo for Rule {
fn name(&self) -> Option<ClauseName> {
Some(self.head.0.clone())
fn name(&self) -> Option<Atom> {
Some(self.head.0)
}
fn arity(&self) -> usize {
@@ -185,7 +197,7 @@ impl ClauseInfo for Rule {
}
impl ClauseInfo for PredicateClause {
fn name(&self) -> Option<ClauseName> {
fn name(&self) -> Option<Atom> {
match self {
&PredicateClause::Fact(ref term, ..) => term.name(),
&PredicateClause::Rule(ref rule, ..) => rule.name(),
@@ -200,23 +212,20 @@ impl ClauseInfo for PredicateClause {
}
}
// pub(crate) type CompiledResult = (Predicate, VecDeque<TopLevel>);
#[derive(Debug, Clone)]
pub(crate) enum PredicateClause {
pub enum PredicateClause {
Fact(Term),
Rule(Rule),
}
impl PredicateClause {
// TODO: add this to `Term` in `prolog_parser` like `first_arg`.
pub(crate) fn args(&self) -> Option<&[Box<Term>]> {
match *self {
PredicateClause::Fact(ref term, ..) => match term {
Term::Clause(_, _, args, _) => Some(&args),
pub(crate) fn args(&self) -> Option<&[Term]> {
match self {
PredicateClause::Fact(term, ..) => match term {
Term::Clause(_, _, args) => Some(&args),
_ => None,
},
PredicateClause::Rule(ref rule, ..) => {
PredicateClause::Rule(rule, ..) => {
if rule.head.1.is_empty() {
None
} else {
@@ -227,37 +236,34 @@ impl PredicateClause {
}
}
#[derive(Debug)]
pub struct ClauseSpan {
pub left: usize,
pub right: usize,
pub instantiated_arg_index: usize,
}
#[derive(Debug, Clone)]
pub(crate) enum ModuleSource {
Library(ClauseName),
File(ClauseName),
pub enum ModuleSource {
Library(Atom),
File(Atom),
}
impl ModuleSource {
pub(crate) fn as_functor_stub(&self) -> MachineStub {
match self {
ModuleSource::Library(ref name) => {
functor!("library", [clause_name(name.clone())])
ModuleSource::Library(name) => {
functor!(atom!("library"), [atom(name)])
}
ModuleSource::File(ref name) => {
functor!(clause_name(name.clone()))
ModuleSource::File(name) => {
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)]
pub(crate) enum MetaSpec {
pub enum MetaSpec {
Minus,
Plus,
Either,
@@ -265,71 +271,71 @@ pub(crate) enum MetaSpec {
}
#[derive(Debug, Clone)]
pub(crate) enum Declaration {
Dynamic(ClauseName, usize),
MetaPredicate(ClauseName, ClauseName, Vec<MetaSpec>), // module name, name, meta-specs
pub enum Declaration {
Dynamic(Atom, usize),
MetaPredicate(Atom, Atom, Vec<MetaSpec>), // module name, name, meta-specs
Module(ModuleDecl),
NonCountedBacktracking(ClauseName, usize), // name, arity
NonCountedBacktracking(Atom, usize), // name, arity
Op(OpDecl),
UseModule(ModuleSource),
UseQualifiedModule(ModuleSource, IndexSet<ModuleExport>),
}
#[derive(Debug, Clone, Eq, Hash, PartialEq, Ord, PartialOrd)]
pub(crate) struct OpDecl {
pub(crate) prec: usize,
pub(crate) spec: Specifier,
pub(crate) name: ClauseName,
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, Ord, PartialOrd)]
pub struct OpDecl {
pub(crate) op_desc: OpDesc,
pub(crate) name: Atom,
}
#[inline(always)]
pub(crate) fn fixity(spec: u32) -> Fixity {
match spec {
XFY | XFX | YFX => Fixity::In,
XF | YF => Fixity::Post,
FX | FY => Fixity::Pre,
_ => unreachable!(),
}
}
impl OpDecl {
#[inline]
pub(crate) fn new(prec: usize, spec: Specifier, name: ClauseName) -> Self {
Self { prec, spec, name }
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.prec;
self.prec = 0;
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.prec = prec;
self.op_desc.set(prec, self.op_desc.get_spec());
}
#[inline]
pub(crate) fn fixity(&self) -> Fixity {
match self.spec {
XFY | XFX | YFX => Fixity::In,
XF | YF => Fixity::Post,
FX | FY => Fixity::Pre,
_ => unreachable!(),
}
}
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));
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) {
match op_dir.get_mut(&key) {
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 => {}
}
op_dir
.insert(key, OpDirValue::new(self.spec, self.prec))
.map(|op_dir_value| op_dir_value.shared_op_desc().get())
op_dir.insert(key, self.op_desc)
}
pub(crate) fn submit(
&self,
existing_desc: Option<OpDesc>,
existing_desc: Option<CompositeOpDesc>,
op_dir: &mut OpDir,
) -> 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 desc.post > 0 {
return Err(SessionError::OpIsInfixAndPostFix(name));
@@ -337,7 +343,7 @@ impl OpDecl {
}
}
if is_postfix!(spec) {
if is_postfix!(spec as u32) {
if let Some(desc) = existing_desc {
if desc.inf > 0 {
return Err(SessionError::OpIsInfixAndPostFix(name));
@@ -350,22 +356,51 @@ 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) if atom == &atom!("[]") => "",
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(
name: ClauseName,
spec: Option<SharedOpDesc>,
name: Atom,
spec: Option<OpDesc>,
op_dir: &OpDir,
) -> Option<SharedOpDesc> {
fetch_op_spec_from_existing(name.clone(), 1, spec.clone(), op_dir)
.or_else(|| fetch_op_spec_from_existing(name, 2, spec, op_dir))
) -> Option<OpDesc> {
fetch_op_spec_from_existing(name, 2, spec, op_dir)
.or_else(|| fetch_op_spec_from_existing(name, 1, spec, op_dir))
}
pub(crate) fn fetch_op_spec_from_existing(
name: ClauseName,
name: Atom,
arity: usize,
spec: Option<SharedOpDesc>,
op_desc: Option<OpDesc>,
op_dir: &OpDir,
) -> Option<SharedOpDesc> {
if let Some(ref op_desc) = &spec {
) -> Option<OpDesc> {
if let Some(ref op_desc) = &op_desc {
if op_desc.arity() != arity {
/* it's possible to extend operator functors with
* additional terms. When that happens,
@@ -374,61 +409,56 @@ 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(
name: ClauseName,
arity: usize,
op_dir: &OpDir,
) -> Option<SharedOpDesc> {
pub(crate) fn fetch_op_spec(name: Atom, arity: usize, op_dir: &OpDir) -> Option<OpDesc> {
match arity {
2 => op_dir
.get(&(name, Fixity::In))
.and_then(|OpDirValue(spec)| {
if spec.prec() > 0 {
Some(spec.clone())
} else {
None
}
}),
2 => op_dir.get(&(name, Fixity::In)).and_then(|op_desc| {
if op_desc.get_prec() > 0 {
Some(*op_desc)
} else {
None
}
}),
1 => {
if let Some(OpDirValue(spec)) = op_dir.get(&(name.clone(), Fixity::Pre)) {
if spec.prec() > 0 {
return Some(spec.clone());
if let Some(op_desc) = op_dir.get(&(name.clone(), Fixity::Pre)) {
if op_desc.get_prec() > 0 {
return Some(*op_desc);
}
}
op_dir
.get(&(name.clone(), Fixity::Post))
.and_then(|OpDirValue(spec)| {
if spec.prec() > 0 {
Some(spec.clone())
} else {
None
}
})
op_dir.get(&(name, Fixity::Post)).and_then(|op_desc| {
if op_desc.get_prec() > 0 {
Some(*op_desc)
} else {
None
}
})
}
0 => {
fetch_atom_op_spec(name, None, op_dir)
}
_ => None,
}
}
pub(crate) type ModuleDir = IndexMap<ClauseName, Module>;
pub(crate) type ModuleDir = IndexMap<Atom, Module, FxBuildHasher>;
#[derive(Debug, Clone, Eq, Hash, PartialEq)]
pub(crate) enum ModuleExport {
pub enum ModuleExport {
OpDecl(OpDecl),
PredicateKey(PredicateKey),
}
#[derive(Debug, Clone)]
pub(crate) struct ModuleDecl {
pub(crate) name: ClauseName,
pub struct ModuleDecl {
pub(crate) name: Atom,
pub(crate) exports: Vec<ModuleExport>,
}
#[derive(Debug)]
pub(crate) struct Module {
pub struct Module {
pub(crate) module_decl: ModuleDecl,
pub(crate) code_dir: CodeDir,
pub(crate) op_dir: OpDir,
@@ -440,14 +470,19 @@ pub(crate) struct Module {
// Module's and related types are defined in forms.
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_decl,
code_dir: CodeDir::new(),
code_dir: CodeDir::with_hasher(FxBuildHasher::default()),
op_dir: default_op_dir(),
meta_predicates: MetaPredicateDir::new(),
extensible_predicates: ExtensiblePredicates::new(),
local_extensible_predicates: LocalExtensiblePredicates::new(),
meta_predicates: MetaPredicateDir::with_hasher(FxBuildHasher::default()),
extensible_predicates: ExtensiblePredicates::with_hasher(FxBuildHasher::default()),
local_extensible_predicates: LocalExtensiblePredicates::with_hasher(
FxBuildHasher::default(),
),
listing_src,
}
}
@@ -455,71 +490,137 @@ impl Module {
pub(crate) fn new_in_situ(module_decl: ModuleDecl) -> Self {
Module {
module_decl,
code_dir: CodeDir::new(),
op_dir: OpDir::new(),
meta_predicates: MetaPredicateDir::new(),
extensible_predicates: ExtensiblePredicates::new(),
local_extensible_predicates: LocalExtensiblePredicates::new(),
code_dir: CodeDir::with_hasher(FxBuildHasher::default()),
op_dir: OpDir::with_hasher(FxBuildHasher::default()),
meta_predicates: MetaPredicateDir::with_hasher(FxBuildHasher::default()),
extensible_predicates: ExtensiblePredicates::with_hasher(FxBuildHasher::default()),
local_extensible_predicates: LocalExtensiblePredicates::with_hasher(
FxBuildHasher::default()
),
listing_src: ListingSource::DynamicallyGenerated,
}
}
}
#[derive(Debug, Clone)]
pub(crate) enum Number {
#[derive(Debug, Copy, Clone)]
pub enum Number {
Float(OrderedFloat<f64>),
Integer(Rc<Integer>),
Rational(Rc<Rational>),
Fixnum(isize),
}
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)
}
Integer(TypedArenaPtr<Integer>),
Rational(TypedArenaPtr<Rational>),
Fixnum(Fixnum),
}
impl Default for Number {
fn default() -> Self {
Number::Float(OrderedFloat(0f64))
Number::Fixnum(Fixnum::build_with(0))
}
}
impl Into<Constant> for Number {
#[inline]
fn into(self) -> Constant {
impl fmt::Display for Number {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Number::Fixnum(n) => Constant::Fixnum(n),
Number::Integer(n) => Constant::Integer(n),
Number::Float(f) => Constant::Float(f),
Number::Rational(r) => Constant::Rational(r),
Number::Float(fl) => write!(f, "{}", fl),
Number::Integer(n) => write!(f, "{}", n),
Number::Rational(r) => write!(f, "{}", 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]
fn into(self) -> HeapCellValue {
match self {
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),
fn arena_from(value: Integer, arena: &mut Arena) -> Number {
Number::Integer(arena_alloc!(value, arena))
}
}
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 +629,9 @@ impl Number {
#[inline]
pub(crate) fn is_positive(&self) -> bool {
match self {
&Number::Fixnum(n) => n > 0,
&Number::Fixnum(n) => n.get_num() > 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,
}
}
@@ -538,9 +639,9 @@ impl Number {
#[inline]
pub(crate) fn is_negative(&self) -> bool {
match self {
&Number::Fixnum(n) => n < 0,
&Number::Fixnum(n) => n.get_num() < 0,
&Number::Integer(ref n) => &**n < &0,
&Number::Float(OrderedFloat(f)) => f.is_sign_negative(),
&Number::Float(OrderedFloat(f)) => f.is_sign_negative() && OrderedFloat(f) != -0f64,
&Number::Rational(ref r) => &**r < &0,
}
}
@@ -548,36 +649,28 @@ impl Number {
#[inline]
pub(crate) fn is_zero(&self) -> bool {
match self {
&Number::Fixnum(n) => n == 0,
&Number::Fixnum(n) => n.get_num() == 0,
&Number::Integer(ref n) => &**n == &0,
&Number::Float(f) => f == OrderedFloat(0f64),
&Number::Float(f) => f == OrderedFloat(0f64) || f == OrderedFloat(-0f64),
&Number::Rational(ref r) => &**r == &0,
}
}
#[inline]
pub(crate) fn abs(self) -> Self {
pub(crate) fn is_integer(&self) -> bool {
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())),
Number::Fixnum(_) | Number::Integer(_) => true,
_ => false,
}
}
}
#[derive(Debug, Clone)]
pub(crate) enum OptArgIndexKey {
Constant(usize, usize, Constant, Vec<Constant>), // index, IndexingCode location, opt arg, alternatives
List(usize, usize), // index, IndexingCode location
Literal(usize, usize, Literal, Vec<Literal>), // index, IndexingCode location, opt arg, alternatives
List(usize, usize), // index, IndexingCode location
None,
Structure(usize, usize, ClauseName, usize), // index, IndexingCode location, name, arity
Structure(usize, usize, Atom, usize), // index, IndexingCode location, name, arity
}
impl OptArgIndexKey {
@@ -589,7 +682,7 @@ impl OptArgIndexKey {
#[inline]
pub(crate) fn arg_num(&self) -> usize {
match &self {
OptArgIndexKey::Constant(arg_num, ..)
OptArgIndexKey::Literal(arg_num, ..)
| OptArgIndexKey::Structure(arg_num, ..)
| OptArgIndexKey::List(arg_num, _) => {
// these are always at least 1.
@@ -607,7 +700,7 @@ impl OptArgIndexKey {
#[inline]
pub(crate) fn switch_on_term_loc(&self) -> Option<usize> {
match &self {
OptArgIndexKey::Constant(_, loc, ..)
OptArgIndexKey::Literal(_, loc, ..)
| OptArgIndexKey::Structure(_, loc, ..)
| OptArgIndexKey::List(_, loc) => Some(*loc),
OptArgIndexKey::None => None,
@@ -617,7 +710,7 @@ impl OptArgIndexKey {
#[inline]
pub(crate) fn set_switch_on_term_loc(&mut self, value: usize) {
match self {
OptArgIndexKey::Constant(_, ref mut loc, ..)
OptArgIndexKey::Literal(_, ref mut loc, ..)
| OptArgIndexKey::Structure(_, ref mut loc, ..)
| OptArgIndexKey::List(_, ref mut loc) => {
*loc = value;
@@ -631,7 +724,7 @@ impl AddAssign<usize> for OptArgIndexKey {
#[inline]
fn add_assign(&mut self, n: usize) {
match self {
OptArgIndexKey::Constant(_, ref mut o, ..)
OptArgIndexKey::Literal(_, ref mut o, ..)
| OptArgIndexKey::List(_, ref mut o)
| OptArgIndexKey::Structure(_, ref mut o, ..) => {
*o += n;
@@ -700,6 +793,7 @@ pub(crate) struct LocalPredicateSkeleton {
pub(crate) is_multifile: bool,
pub(crate) clause_clause_locs: SliceDeque<usize>,
pub(crate) clause_assert_margin: usize,
pub(crate) retracted_dynamic_clauses: Option<Vec<ClauseIndexInfo>>, // always None if non-dynamic.
}
impl LocalPredicateSkeleton {
@@ -711,6 +805,7 @@ impl LocalPredicateSkeleton {
is_multifile: false,
clause_clause_locs: sdeq![],
clause_assert_margin: 0,
retracted_dynamic_clauses: Some(vec![]),
}
}
@@ -730,6 +825,20 @@ impl LocalPredicateSkeleton {
self.clause_clause_locs.clear();
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)]
@@ -758,13 +867,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(
&self,
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,21 @@
use prolog_parser::ast::*;
use prolog_parser::clause_name;
use prolog_parser::tabled_rc::*;
use crate::atom_table::*;
use crate::parser::ast::*;
use crate::forms::*;
use crate::instructions::*;
use crate::rug::Integer;
use indexmap::IndexMap;
use slice_deque::{sdeq, SliceDeque};
use std::convert::TryFrom;
use std::collections::VecDeque;
use std::hash::Hash;
use std::iter::once;
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)]
enum OptArgIndexKeyType {
Structure,
Constant,
Literal,
// List,
}
@@ -35,7 +23,7 @@ impl OptArgIndexKey {
#[inline]
fn has_key_type(&self, key_type: OptArgIndexKeyType) -> bool {
match (self, key_type) {
(OptArgIndexKey::Constant(..), OptArgIndexKeyType::Constant)
(OptArgIndexKey::Literal(..), OptArgIndexKeyType::Literal)
| (OptArgIndexKey::Structure(..), OptArgIndexKeyType::Structure)
// | (OptArgIndexKey::List(..), OptArgIndexKeyType::List)
=> true,
@@ -45,11 +33,12 @@ impl OptArgIndexKey {
}
#[inline]
fn search_skeleton_for_first_key_type(
skeleton: &[ClauseIndexInfo],
fn search_skeleton_for_first_key_type<'a>(
skeleton: &'a [ClauseIndexInfo],
retracted_dynamic_clauses: &'a Option<Vec<ClauseIndexInfo>>,
key_type: OptArgIndexKeyType,
append_or_prepend: AppendOrPrepend,
) -> Option<&OptArgIndexKey> {
) -> Option<&'a OptArgIndexKey> {
if append_or_prepend.is_append() {
for clause_index_info in skeleton.iter().rev() {
if clause_index_info.opt_arg_index_key.has_key_type(key_type) {
@@ -64,11 +53,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
}
struct IndexingCodeMergingPtr<'a> {
skeleton: &'a mut [ClauseIndexInfo],
retracted_dynamic_clauses: &'a Option<Vec<ClauseIndexInfo>>,
indexing_code: &'a mut Vec<IndexingLine>,
offset: usize,
append_or_prepend: AppendOrPrepend,
@@ -79,22 +77,22 @@ impl<'a> IndexingCodeMergingPtr<'a> {
#[inline]
fn new(
skeleton: &'a mut [ClauseIndexInfo],
retracted_dynamic_clauses: &'a Option<Vec<ClauseIndexInfo>>,
indexing_code: &'a mut Vec<IndexingLine>,
append_or_prepend: AppendOrPrepend,
) -> Self {
let is_dynamic = match &indexing_code[0] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => {
match v {
IndexingCodePtr::External(_) => false,
IndexingCodePtr::DynamicExternal(_) => true,
_ => unreachable!()
}
}
_ => unreachable!()
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => match v {
IndexingCodePtr::External(_) => false,
IndexingCodePtr::DynamicExternal(_) => true,
_ => unreachable!(),
},
_ => unreachable!(),
};
Self {
skeleton,
retracted_dynamic_clauses,
indexing_code,
offset: 0,
append_or_prepend,
@@ -105,15 +103,16 @@ impl<'a> IndexingCodeMergingPtr<'a> {
fn internalize_constant(&mut self, constant_ptr: IndexingCodePtr) {
let constant_key = search_skeleton_for_first_key_type(
self.skeleton,
OptArgIndexKeyType::Constant,
self.retracted_dynamic_clauses,
OptArgIndexKeyType::Literal,
self.append_or_prepend,
);
let mut constants = IndexMap::new();
match constant_key {
Some(OptArgIndexKey::Constant(_, _, ref constant, _)) => {
constants.insert(constant.clone(), constant_ptr);
Some(OptArgIndexKey::Literal(_, _, constant, _)) => {
constants.insert(*constant, constant_ptr);
}
_ => {
if let IndexingCodePtr::DynamicExternal(_) = constant_ptr {
@@ -145,7 +144,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
fn add_static_indexed_choice_for_constant(
&mut self,
external: usize,
constant: Constant,
constant: Literal,
index: usize,
) {
let third_level_index = if self.append_or_prepend.is_append() {
@@ -179,7 +178,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
fn add_dynamic_indexed_choice_for_constant(
&mut self,
external: usize,
constant: Constant,
constant: Literal,
index: usize,
) {
let third_level_index = if self.append_or_prepend.is_append() {
@@ -232,8 +231,8 @@ impl<'a> IndexingCodeMergingPtr<'a> {
fn index_overlapping_constant(
&mut self,
orig_constant: &Constant,
overlapping_constant: Constant,
orig_constant: Literal,
overlapping_constant: Literal,
index: usize,
) {
loop {
@@ -252,7 +251,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
}
IndexingCodePtr::DynamicExternal(_) | IndexingCodePtr::External(_) => {
let mut constants = IndexMap::new();
constants.insert(orig_constant.clone(), *c);
constants.insert(orig_constant, *c);
*c = IndexingCodePtr::Internal(indexing_code_len);
@@ -282,10 +281,18 @@ impl<'a> IndexingCodeMergingPtr<'a> {
);
}
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)) => {
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)) => {
self.offset += o;
@@ -307,7 +314,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
}
}
fn index_constant(&mut self, constant: Constant, index: usize) {
fn index_constant(&mut self, constant: Literal, index: usize) {
loop {
let indexing_code_len = self.indexing_code.len();
@@ -338,10 +345,16 @@ impl<'a> IndexingCodeMergingPtr<'a> {
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(constants)) => {
match constants.get(&constant).cloned() {
None | Some(IndexingCodePtr::Fail) if self.is_dynamic => {
constants.insert(constant, IndexingCodePtr::DynamicExternal(index));
constants.insert(
constant,
IndexingCodePtr::DynamicExternal(index),
);
}
None | Some(IndexingCodePtr::Fail) => {
constants.insert(constant, IndexingCodePtr::External(index));
constants.insert(
constant,
IndexingCodePtr::External(index),
);
}
Some(IndexingCodePtr::DynamicExternal(o)) => {
self.add_dynamic_indexed_choice_for_constant(o, constant, index);
@@ -372,6 +385,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
fn internalize_structure(&mut self, structure_ptr: IndexingCodePtr) {
let structure_key = search_skeleton_for_first_key_type(
self.skeleton,
self.retracted_dynamic_clauses,
OptArgIndexKeyType::Structure,
self.append_or_prepend,
);
@@ -379,8 +393,8 @@ impl<'a> IndexingCodeMergingPtr<'a> {
let mut structures = IndexMap::new();
match structure_key {
Some(OptArgIndexKey::Structure(_, _, ref name, ref arity)) => {
structures.insert((name.clone(), *arity), structure_ptr);
Some(OptArgIndexKey::Structure(_, _, name, arity)) => {
structures.insert((*name, *arity), structure_ptr);
}
_ => {
if let IndexingCodePtr::DynamicExternal(_) = structure_ptr {
@@ -428,8 +442,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
};
let indexing_code_len = self.indexing_code.len();
self.indexing_code
.push(IndexingLine::IndexedChoice(third_level_index));
self.indexing_code.push(IndexingLine::IndexedChoice(third_level_index));
match &mut self.indexing_code[self.offset] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref mut structures)) => {
@@ -599,6 +612,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
pub(crate) fn merge_clause_index(
target_indexing_code: &mut Vec<IndexingLine>,
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.
append_or_prepend: AppendOrPrepend,
) {
@@ -609,27 +623,28 @@ pub(crate) fn merge_clause_index(
let mut merging_ptr = IndexingCodeMergingPtr::new(
skeleton,
retracted_clauses,
target_indexing_code,
append_or_prepend,
);
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;
merging_ptr.index_constant(constant.clone(), offset);
merging_ptr.index_constant(*constant, offset);
for overlapping_constant in overlapping_constants {
merging_ptr.offset = 0;
merging_ptr.index_overlapping_constant(
constant,
overlapping_constant.clone(),
*constant,
*overlapping_constant,
offset,
);
}
}
OptArgIndexKey::Structure(_, index_loc, ref name, ref arity) => {
merging_ptr.index_structure((name.clone(), *arity), new_clause_loc - index_loc + 1);
OptArgIndexKey::Structure(_, index_loc, name, arity) => {
merging_ptr.index_structure((*name, *arity), new_clause_loc - index_loc + 1);
}
OptArgIndexKey::List(_, index_loc) => {
merging_ptr.index_list(new_clause_loc - index_loc + 1);
@@ -650,13 +665,13 @@ pub(crate) fn merge_clause_index(
}
pub(crate) fn remove_constant_indices(
constant: &Constant,
overlapping_constants: &[Constant],
constant: Literal,
overlapping_constants: &[Literal],
indexing_code: &mut Vec<IndexingLine>,
offset: usize,
) {
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] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..)) => {
@@ -688,11 +703,13 @@ pub(crate) fn remove_constant_indices(
)) => {
constants_index = index;
match constants.get(constant).cloned() {
Some(IndexingCodePtr::DynamicExternal(_)) |
Some(IndexingCodePtr::External(_)) |
Some(IndexingCodePtr::Fail) => {
constants.remove(constant);
let constant = *constant;
match constants.get(&constant).cloned() {
Some(IndexingCodePtr::DynamicExternal(_))
| Some(IndexingCodePtr::External(_))
| Some(IndexingCodePtr::Fail) => {
constants.remove(&constant);
break;
}
Some(IndexingCodePtr::Internal(o)) => {
@@ -704,13 +721,14 @@ pub(crate) fn remove_constant_indices(
}
}
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 let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() {
let ext = IndexingCodePtr::External(
indexed_choice_instr.offset()
);
let ext = IndexingCodePtr::External(indexed_choice_instr.offset());
match &mut indexing_code[constants_index] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(
@@ -724,7 +742,7 @@ pub(crate) fn remove_constant_indices(
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
ref mut constants,
)) => {
constants.insert(constant.clone(), ext);
constants.insert(*constant, ext);
}
_ => {
unreachable!()
@@ -736,7 +754,10 @@ pub(crate) fn remove_constant_indices(
break;
}
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 let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() {
@@ -754,7 +775,7 @@ pub(crate) fn remove_constant_indices(
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
ref mut constants,
)) => {
constants.insert(constant.clone(), ext);
constants.insert(*constant, ext);
}
_ => {
unreachable!()
@@ -790,7 +811,7 @@ pub(crate) fn remove_constant_indices(
}
pub(crate) fn remove_structure_index(
name: &ClauseName,
name: Atom,
arity: usize,
indexing_code: &mut Vec<IndexingLine>,
offset: usize,
@@ -825,7 +846,8 @@ pub(crate) fn remove_structure_index(
structures_index = index;
match structures.get(&(name.clone(), arity)).cloned() {
Some(IndexingCodePtr::DynamicExternal(_)) | Some(IndexingCodePtr::External(_)) => {
Some(IndexingCodePtr::DynamicExternal(_))
| Some(IndexingCodePtr::External(_)) => {
structures.remove(&(name.clone(), arity));
break;
}
@@ -1012,27 +1034,14 @@ pub(crate) fn remove_index(
clause_loc: usize,
) {
match opt_arg_index_key {
OptArgIndexKey::Constant(_, _, ref constant, ref overlapping_constants) => {
remove_constant_indices(
constant,
overlapping_constants,
indexing_code,
clause_loc,
);
OptArgIndexKey::Literal(_, _, constant, ref overlapping_constants) => {
remove_constant_indices(*constant, overlapping_constants, indexing_code, clause_loc);
}
OptArgIndexKey::Structure(_, _, ref name, ref arity) => {
remove_structure_index(
name,
*arity,
indexing_code,
clause_loc,
);
OptArgIndexKey::Structure(_, _, name, arity) => {
remove_structure_index(*name, *arity, indexing_code, clause_loc);
}
OptArgIndexKey::List(..) => {
remove_list_index(
indexing_code,
clause_loc,
);
remove_list_index(indexing_code, clause_loc);
}
OptArgIndexKey::None => {
unreachable!()
@@ -1076,49 +1085,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![];
match constant {
Constant::Atom(ref name, ref op) => {
if name.is_char() {
let c = name.as_str().chars().next().unwrap();
constants.push(Constant::Char(c));
}
if op.is_some() {
constants.push(Constant::Atom(name.clone(), None));
Literal::Atom(ref name) => {
if let Some(c) = name.as_char() {
constants.push(Literal::Char(c));
}
}
Constant::Char(c) => {
let atom = clause_name!(c.to_string(), atom_tbl);
constants.push(Constant::Atom(atom, None));
Literal::Char(c) => {
let atom = atom_tbl.build_with(&c.to_string());
constants.push(Literal::Atom(atom));
}
Constant::Fixnum(ref n) => {
constants.push(Constant::Integer(Rc::new(Integer::from(*n))));
/*
Literal::Fixnum(ref n) => {
constants.push(Literal::Integer(arena_alloc!(n, arena))); //Rc::new(Integer::from(*n))));
/*
if *n >= 0 {
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() {
constants.push(Constant::Fixnum(n));
}
if let Some(n) = n.to_usize() {
constants.push(Constant::Usize(n));
Fixnum::build_with_checked(n as i64).map(|n| {
constants.push(Literal::Fixnum(n));
}).unwrap();
}
}
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) {
constants.push(Constant::Fixnum(n));
constants.push(Literal::Fixnum(n));
}
}
*/
_ => {}
}
@@ -1127,16 +1139,16 @@ pub(crate) fn constant_key_alternatives(constant: &Constant, atom_tbl: TabledDat
#[derive(Debug)]
pub(crate) struct StaticCodeIndices {
constants: IndexMap<Constant, SliceDeque<IndexedChoiceInstruction>>,
lists: SliceDeque<IndexedChoiceInstruction>,
structures: IndexMap<(ClauseName, usize), SliceDeque<IndexedChoiceInstruction>>,
constants: IndexMap<Literal, VecDeque<IndexedChoiceInstruction>>,
lists: VecDeque<IndexedChoiceInstruction>,
structures: IndexMap<(Atom, usize), VecDeque<IndexedChoiceInstruction>>,
}
#[derive(Debug)]
pub(crate) struct DynamicCodeIndices {
constants: IndexMap<Constant, SliceDeque<usize>>,
lists: SliceDeque<usize>,
structures: IndexMap<(ClauseName, usize), SliceDeque<usize>>,
constants: IndexMap<Literal, VecDeque<usize>>,
lists: VecDeque<usize>,
structures: IndexMap<(Atom, usize), VecDeque<usize>>,
}
pub(crate) trait Indexer {
@@ -1144,32 +1156,29 @@ pub(crate) trait Indexer {
fn new() -> Self;
fn constants(&mut self) -> &mut IndexMap<Constant, SliceDeque<Self::ThirdLevelIndex>>;
fn lists(&mut self) -> &mut SliceDeque<Self::ThirdLevelIndex>;
fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque<Self::ThirdLevelIndex>>;
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<Self::ThirdLevelIndex>>;
fn lists(&mut self) -> &mut VecDeque<Self::ThirdLevelIndex>;
fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque<Self::ThirdLevelIndex>>;
fn compute_index(is_initial_index: bool, index: usize) -> Self::ThirdLevelIndex;
fn second_level_index<IndexKey: Eq + Hash>(
indices: IndexMap<IndexKey, SliceDeque<Self::ThirdLevelIndex>>,
prelude: &mut SliceDeque<IndexingLine>,
indices: IndexMap<IndexKey, VecDeque<Self::ThirdLevelIndex>>,
prelude: &mut VecDeque<IndexingLine>,
) -> IndexMap<IndexKey, IndexingCodePtr>;
fn switch_on<IndexKey: Eq + Hash>(
instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction,
index: &mut IndexMap<IndexKey, SliceDeque<Self::ThirdLevelIndex>>,
prelude: &mut SliceDeque<IndexingLine>,
index: &mut IndexMap<IndexKey, VecDeque<Self::ThirdLevelIndex>>,
prelude: &mut VecDeque<IndexingLine>,
) -> IndexingCodePtr;
fn switch_on_list(
lists: &mut SliceDeque<Self::ThirdLevelIndex>,
prelude: &mut SliceDeque<IndexingLine>,
lists: &mut VecDeque<Self::ThirdLevelIndex>,
prelude: &mut VecDeque<IndexingLine>,
) -> IndexingCodePtr;
fn remove_instruction_with_offset(
code: &mut SliceDeque<Self::ThirdLevelIndex>,
offset: usize,
);
fn remove_instruction_with_offset(code: &mut SliceDeque<Self::ThirdLevelIndex>, offset: usize);
fn var_offset_wrapper(var_offset: usize) -> IndexingCodePtr;
}
@@ -1181,23 +1190,23 @@ impl Indexer for StaticCodeIndices {
fn new() -> Self {
Self {
constants: IndexMap::new(),
lists: sdeq![],
lists: VecDeque::new(),
structures: IndexMap::new(),
}
}
#[inline]
fn constants(&mut self) -> &mut IndexMap<Constant, SliceDeque<IndexedChoiceInstruction>> {
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<IndexedChoiceInstruction>> {
&mut self.constants
}
#[inline]
fn lists(&mut self) -> &mut SliceDeque<IndexedChoiceInstruction> {
fn lists(&mut self) -> &mut VecDeque<IndexedChoiceInstruction> {
&mut self.lists
}
#[inline]
fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque<IndexedChoiceInstruction>> {
fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque<IndexedChoiceInstruction>> {
&mut self.structures
}
@@ -1210,18 +1219,18 @@ impl Indexer for StaticCodeIndices {
}
fn second_level_index<IndexKey: Eq + Hash>(
indices: IndexMap<IndexKey, SliceDeque<IndexedChoiceInstruction>>,
prelude: &mut SliceDeque<IndexingLine>,
indices: IndexMap<IndexKey, VecDeque<IndexedChoiceInstruction>>,
prelude: &mut VecDeque<IndexingLine>,
) -> IndexMap<IndexKey, IndexingCodePtr> {
let mut index_locs = IndexMap::new();
for (key, mut code) in indices.into_iter() {
if code.len() > 1 {
index_locs.insert(key, IndexingCodePtr::Internal(prelude.len() + 1));
cap_choice_seq_with_trust(&mut code);
cap_choice_seq_with_trust(code.make_contiguous());
prelude.push_back(IndexingLine::from(code));
} else {
code.first().map(|i| {
code.front().map(|i| {
index_locs.insert(key, IndexingCodePtr::External(i.offset()));
});
}
@@ -1232,8 +1241,8 @@ impl Indexer for StaticCodeIndices {
fn switch_on<IndexKey: Eq + Hash>(
mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction,
index: &mut IndexMap<IndexKey, SliceDeque<IndexedChoiceInstruction>>,
prelude: &mut SliceDeque<IndexingLine>,
index: &mut IndexMap<IndexKey, VecDeque<IndexedChoiceInstruction>>,
prelude: &mut VecDeque<IndexingLine>,
) -> IndexingCodePtr {
let index = mem::replace(index, IndexMap::new());
let index = Self::second_level_index(index, prelude);
@@ -1253,25 +1262,28 @@ impl Indexer for StaticCodeIndices {
}
fn switch_on_list(
lists: &mut SliceDeque<IndexedChoiceInstruction>,
prelude: &mut SliceDeque<IndexingLine>,
lists: &mut VecDeque<IndexedChoiceInstruction>,
prelude: &mut VecDeque<IndexingLine>,
) -> IndexingCodePtr {
if lists.len() > 1 {
cap_choice_seq_with_trust(lists);
let lists = mem::replace(lists, sdeq![]);
cap_choice_seq_with_trust(lists.make_contiguous());
let lists = mem::replace(lists, VecDeque::new());
prelude.push_back(IndexingLine::from(lists));
IndexingCodePtr::Internal(1)
} else {
lists
.first()
.front()
.map(|i| IndexingCodePtr::External(i.offset()))
.unwrap_or(IndexingCodePtr::Fail)
}
}
#[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() {
if offset == line.offset() {
code.remove(index);
@@ -1294,23 +1306,23 @@ impl Indexer for DynamicCodeIndices {
fn new() -> Self {
Self {
constants: IndexMap::new(),
lists: sdeq![],
lists: VecDeque::new(),
structures: IndexMap::new(),
}
}
#[inline]
fn constants(&mut self) -> &mut IndexMap<Constant, SliceDeque<usize>> {
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<usize>> {
&mut self.constants
}
#[inline]
fn lists(&mut self) -> &mut SliceDeque<usize> {
fn lists(&mut self) -> &mut VecDeque<usize> {
&mut self.lists
}
#[inline]
fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque<usize>> {
fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque<usize>> {
&mut self.structures
}
@@ -1320,17 +1332,17 @@ impl Indexer for DynamicCodeIndices {
}
fn second_level_index<IndexKey: Eq + Hash>(
indices: IndexMap<IndexKey, SliceDeque<usize>>,
prelude: &mut SliceDeque<IndexingLine>,
indices: IndexMap<IndexKey, VecDeque<usize>>,
prelude: &mut VecDeque<IndexingLine>,
) -> IndexMap<IndexKey, IndexingCodePtr> {
let mut index_locs = IndexMap::new();
for (key, code) in indices.into_iter() {
if code.len() > 1 {
index_locs.insert(key, IndexingCodePtr::Internal(prelude.len() + 1));
prelude.push_back(IndexingLine::DynamicIndexedChoice(code));
prelude.push_back(IndexingLine::DynamicIndexedChoice(code.into_iter().collect()));
} else {
code.first().map(|i| {
code.front().map(|i| {
index_locs.insert(key, IndexingCodePtr::DynamicExternal(*i));
});
}
@@ -1341,8 +1353,8 @@ impl Indexer for DynamicCodeIndices {
fn switch_on<IndexKey: Eq + Hash>(
mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction,
index: &mut IndexMap<IndexKey, SliceDeque<usize>>,
prelude: &mut SliceDeque<IndexingLine>,
index: &mut IndexMap<IndexKey, VecDeque<usize>>,
prelude: &mut VecDeque<IndexingLine>,
) -> IndexingCodePtr {
let index = mem::replace(index, IndexMap::new());
let index = Self::second_level_index(index, prelude);
@@ -1362,16 +1374,16 @@ impl Indexer for DynamicCodeIndices {
}
fn switch_on_list(
lists: &mut SliceDeque<usize>,
prelude: &mut SliceDeque<IndexingLine>,
lists: &mut VecDeque<usize>,
prelude: &mut VecDeque<IndexingLine>,
) -> IndexingCodePtr {
if lists.len() > 1 {
let lists = mem::replace(lists, sdeq![]);
prelude.push_back(IndexingLine::DynamicIndexedChoice(lists));
let lists = mem::replace(lists, VecDeque::new());
prelude.push_back(IndexingLine::DynamicIndexedChoice(lists.into_iter().collect()));
IndexingCodePtr::Internal(1)
} else {
lists
.first()
.front()
.map(|i| IndexingCodePtr::DynamicExternal(*i))
.unwrap_or(IndexingCodePtr::Fail)
}
@@ -1395,19 +1407,13 @@ impl Indexer for DynamicCodeIndices {
#[derive(Debug)]
pub(crate) struct CodeOffsets<I: Indexer> {
atom_tbl: TabledData<Atom>,
indices: I,
optimal_index: usize,
}
impl<I: Indexer> CodeOffsets<I> {
pub(crate) fn new(
atom_tbl: TabledData<Atom>,
indices: I,
optimal_index: usize,
) -> Self {
pub(crate) fn new(indices: I, optimal_index: usize) -> Self {
CodeOffsets {
atom_tbl,
indices,
optimal_index,
}
@@ -1419,15 +1425,24 @@ impl<I: Indexer> CodeOffsets<I> {
self.indices.lists().push_back(index);
}
fn index_constant(&mut self, constant: &Constant, index: usize) -> Vec<Constant> {
let overlapping_constants = constant_key_alternatives(constant, self.atom_tbl.clone());
let code = self.indices.constants().entry(constant.clone()).or_insert(sdeq![]);
fn index_constant(
&mut self,
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(VecDeque::new());
let is_initial_index = code.is_empty();
code.push_back(I::compute_index(is_initial_index, index));
for constant in &overlapping_constants {
let code = self.indices.constants().entry(constant.clone()).or_insert(sdeq![]);
let code = self
.indices
.constants()
.entry(*constant)
.or_insert(VecDeque::new());
let is_initial_index = code.is_empty();
let index = I::compute_index(is_initial_index, index);
@@ -1438,11 +1453,12 @@ impl<I: Indexer> CodeOffsets<I> {
overlapping_constants
}
fn index_structure(&mut self, name: &ClauseName, arity: usize, index: usize) -> usize {
let code = self.indices
fn index_structure(&mut self, name: Atom, arity: usize, index: usize) -> usize {
let code = self
.indices
.structures()
.entry((name.clone(), arity))
.or_insert(sdeq![]);
.or_insert(VecDeque::new());
let code_len = code.len();
let is_initial_index = code.is_empty();
@@ -1456,28 +1472,25 @@ impl<I: Indexer> CodeOffsets<I> {
optimal_arg: &Term,
index: usize,
clause_index_info: &mut ClauseIndexInfo,
atom_tbl: &mut AtomTable,
) {
match optimal_arg {
&Term::Clause(_, ref name, ref terms, _) => {
&Term::Clause(_, name, ref terms) => {
clause_index_info.opt_arg_index_key =
OptArgIndexKey::Structure(self.optimal_index, 0, name.clone(), terms.len());
self.index_structure(name, terms.len(), index);
}
&Term::Cons(..) | &Term::Constant(_, Constant::String(_)) => {
&Term::Cons(..) | &Term::Literal(_, Literal::String(_)) | &Term::PartialString(..) => {
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
self.index_list(index);
}
&Term::Constant(_, ref constant) => {
let overlapping_constants = self.index_constant(constant, index);
&Term::Literal(_, constant) => {
let overlapping_constants = self.index_constant(atom_tbl, constant, index);
clause_index_info.opt_arg_index_key = OptArgIndexKey::Constant(
self.optimal_index,
0,
constant.clone(),
overlapping_constants,
);
clause_index_info.opt_arg_index_key =
OptArgIndexKey::Literal(self.optimal_index, 0, constant, overlapping_constants);
}
_ => {}
}
@@ -1496,7 +1509,7 @@ impl<I: Indexer> CodeOffsets<I> {
return vec![];
}
let mut prelude = sdeq![];
let mut prelude = VecDeque::new();
let mut emitted_switch_on_structure = false;
let mut emitted_switch_on_constant = false;

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

View File

@@ -1,25 +1,34 @@
#[cfg(feature = "num-rug-adapter")]
use num_rug_adapter as rug;
#[cfg(feature = "rug")]
use rug;
#![recursion_limit = "4112"]
#[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 arithmetic;
mod clause_types;
mod codegen;
pub mod codegen;
mod debray_allocator;
mod fixtures;
mod forms;
mod heap_iter;
mod heap_print;
pub mod heap_print;
mod indexing;
mod instructions;
#[macro_use]
pub mod instructions {
include!(concat!(env!("OUT_DIR"), "/instructions.rs"));
}
mod iterators;
pub mod machine;
mod raw_block;
pub mod read;
mod targets;
mod write;
pub mod types;
use machine::*;
use instructions::instr;

View File

@@ -94,12 +94,6 @@ number_to_rational(Eps0, Real0, Fraction) :-
),
!.
number(X) :-
( integer(X)
; float(X)
; rational(X)
).
stern_brocot_(Qnn/Qnd, Qpn/Qpd, A/B, C/D, Fraction) :-
Fn1 is A + C,
Fd1 is B + D,

View File

@@ -24,30 +24,42 @@
'$absent_from_list'(Ls, Attr).
'$absent_from_list'(X, Attr) :-
( var(X) -> true
; X = [L|Ls], L \= Attr -> '$absent_from_list'(Ls, Attr)
( var(X) ->
true
; X = [L|Ls],
L \= Attr ->
'$absent_from_list'(Ls, 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) :-
nonvar(L),
( L \= Attr -> nonvar(Ls), '$get_from_list'(Ls, V, Attr)
; L = Attr, '$enqueue_attr_var'(V)
( L \= Attr ->
nonvar(Ls),
'$get_from_list'(Ls, V, Attr)
; L = Attr,
'$enqueue_attr_var'(V)
).
'$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) :-
( var(Ls) ->
Ls = [Attr | _], '$enqueue_attr_var'(V)
; Ls = [_ | Ls0], '$add_to_list'(Ls0, V, Attr)
( var(Ls) ->
Ls = [Attr | _],
'$enqueue_attr_var'(V)
; Ls = [_ | Ls0],
'$add_to_list'(Ls0, V, Attr)
).
'$del_attr'(Ls0, _, _) :-
var(Ls0), !.
var(Ls0),
!.
'$del_attr'(Ls0, V, Attr) :-
Ls0 = [Att | Ls1],
nonvar(Att),
@@ -134,22 +146,22 @@ put_attr(Name, Arity, Module) -->
[(put_atts(V, +Attr) :-
!,
functor(Attr, Head, Arity),
functor(AttrForm, Head, Arity),
'$get_attr_list'(V, Ls),
atts:'$del_attr'(Ls, V, Module:AttrForm),
atts:'$put_attr'(V, Module:Attr)),
functor(AttrForm, Head, Arity),
'$get_attr_list'(V, Ls),
atts:'$del_attr'(Ls, V, Module:AttrForm),
atts:'$put_attr'(V, Module:Attr)),
(put_atts(V, Attr) :-
!,
functor(Attr, Head, Arity),
functor(AttrForm, Head, Arity),
'$get_attr_list'(V, Ls),
atts:'$del_attr'(Ls, V, Module:AttrForm),
atts:'$put_attr'(V, Module:Attr)),
functor(AttrForm, Head, Arity),
'$get_attr_list'(V, Ls),
atts:'$del_attr'(Ls, V, Module:AttrForm),
atts:'$put_attr'(V, Module:Attr)),
(put_atts(V, -Attr) :-
!,
functor(Attr, _, _),
'$get_attr_list'(V, Ls),
atts:'$del_attr'(Ls, V, Module:Attr))].
'$get_attr_list'(V, Ls),
atts:'$del_attr'(Ls, V, Module:Attr))].
get_attr(Name, Arity, Module) -->
{ functor(Attr, Name, Arity) },

View File

@@ -12,17 +12,18 @@ between(Lower, Upper, X) :-
( nonvar(X) ->
Lower =< X,
X =< Upper
; compare(Ord, Lower, Upper),
between_(Ord, Lower, Upper, X)
; Lower =< Upper,
between_(Lower, Upper, X)
).
between_(<, Lower0, Upper, X) :-
( X = Lower0
; Lower1 is Lower0 + 1,
compare(Ord, Lower1, Upper),
between_(Ord, Lower1, Upper, X)
).
between_(=, Upper, Upper, Upper).
between_(Lower, Upper, Lower1) :-
Lower < Upper,
!,
( Lower1 = Lower
; Lower0 is Lower + 1,
between_(Lower0, Upper, Lower1)
).
between_(Lower, Lower, Lower).
enumerate_nats(I, I).
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,
(:)/7, (:)/8, (:)/9, (:)/10, (:)/11, (:)/12,
abolish/1, asserta/1, assertz/1,
@@ -59,65 +59,62 @@ call(G, A, B, C, D, E, F, G) :- '$call'(G, A, B, C, D, E, F, G).
call(G, A, B, C, D, E, F, G, H) :- '$call'(G, A, B, C, D, E, F, G, H).
Module : Predicate :-
( atom(Module) ->
'$module_call'(Module, Predicate)
;
throw(error(type_error(atom, Module), (:)/2))
).
% dynamic module resolution.
Module : Predicate :-
( atom(Module) -> '$module_call'(Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1) :-
( atom(Module) -> '$module_call'(A1, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
( atom(Module) ->
'$module_call'(A1, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2) :-
( atom(Module) -> '$module_call'(A1, A2, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
( atom(Module) -> '$module_call'(A1, A2, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3) :-
( atom(Module) -> '$module_call'(A1, A2, A3, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
( atom(Module) -> '$module_call'(A1, A2, A3, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3, A4) :-
( atom(Module) -> '$module_call'(A1, A2, A3, A4, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
( atom(Module) -> '$module_call'(A1, A2, A3, A4, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3, A4, A5) :-
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3, A4, A5, A6) :-
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7) :-
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7, A8) :-
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7, A8, A9) :-
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) :-
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
% flags.
@@ -205,153 +202,184 @@ repeat.
repeat :- repeat.
:- meta_predicate ','(0,0).
:- 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).
','(G1, G2) :-
'$get_b_value'(B),
( '$call_with_default_policy'(var(G1)) ->
throw(error(instantiation_error, (',')/2))
; '$call_with_default_policy'(','(G1, G2, B))
).
G1 -> G2 :- control_entry_point((G1 -> G2)).
';'(G1, G2) :-
'$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 staggered_if_then/2.
staggered_if_then(G1, G2) :-
'$get_staggered_cp'(B),
call('$call'(G1)),
'$set_cp'(B),
call('$call'(G2)).
G1 ; G2 :- control_entry_point((G1 ; G2)).
G1 -> G2 :-
'$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 staggered_sc/2.
staggered_sc(G, _) :- call('$call'(G)).
staggered_sc(_, G) :- call('$call'(G)).
:-non_counted_backtracking call_or_cut/3.
!.
call_or_cut(G, B, ErrorPI) :-
( '$call_with_default_policy'(var(G)) ->
throw(error(instantiation_error, ErrorPI))
; '$call_with_default_policy'(call_or_cut(G, B))
).
:- non_counted_backtracking set_cp/1.
set_cp(B) :- '$set_cp'(B).
','(G1, G2) :- control_entry_point((G1, G2)).
:- non_counted_backtracking control_entry_point/1.
control_entry_point(G) :-
functor(G, Name, Arity),
catch(builtins:control_entry_point_(G),
dispatch_prep_error,
builtins:throw(error(type_error(callable, G), Name/Arity))).
:- non_counted_backtracking control_functor/1.
:- non_counted_backtracking control_entry_point_/1.
control_functor(_:G) :- nonvar(G), control_functor(G).
control_functor(call(_:C)) :- C == !.
control_functor(!).
control_functor((_,_)).
control_functor((_;_)).
control_functor((_->_)).
control_entry_point_(G) :-
'$get_cp'(B),
dispatch_prep(G,B,Conts),
dispatch_call_list(Conts).
:- non_counted_backtracking call_or_cut/2.
:- non_counted_backtracking cont_list_to_goal/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)
).
cont_list_goal([Cont], Cont) :- !.
cont_list_goal(Conts, builtins:dispatch_call_list(Conts)).
:- non_counted_backtracking call_or_cut_interp/2.
:- non_counted_backtracking module_qualified_cut/1.
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)).
module_qualified_cut(Gs) :-
( functor(Gs, call, 1) ->
arg(1, Gs, G1)
; Gs = G1
),
functor(G1, (:), 2),
arg(2, G1, G2),
G2 == !.
:- non_counted_backtracking (',')/3.
:- non_counted_backtracking dispatch_prep/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))
dispatch_prep(Gs, B, [Cont|Conts]) :-
( callable(Gs) ->
( functor(Gs, ',', 2) ->
arg(1, Gs, G1),
arg(2, Gs, G2),
dispatch_prep(G1, B, IConts1),
cont_list_goal(IConts1, Cont),
dispatch_prep(G2, B, Conts)
; functor(Gs, ';', 2) ->
arg(1, Gs, G1),
arg(2, Gs, G2),
dispatch_prep(G1, B, IConts0),
dispatch_prep(G2, B, IConts1),
cont_list_goal(IConts0, Cont0),
cont_list_goal(IConts1, Cont1),
Cont = builtins:staggered_sc(Cont0, Cont1),
Conts = []
; functor(Gs, ->, 2) ->
arg(1, Gs, G1),
arg(2, Gs, G2),
dispatch_prep(G1, B, IConts1),
dispatch_prep(G2, B, IConts2),
cont_list_goal(IConts1, Cont1),
cont_list_goal(IConts2, Cont2),
Cont = builtins:staggered_if_then(Cont1, Cont2),
Conts = []
; ( Gs == ! ; module_qualified_cut(Gs) ) ->
Cont = builtins:set_cp(B),
Conts = []
; Cont = Gs,
Conts = []
)
; call(G1) ->
'$call_with_default_policy'(call_or_cut(G2, B, (->)/2))
; var(Gs) ->
Cont = Gs,
Conts = []
; throw(dispatch_prep_error)
).
:- non_counted_backtracking dispatch_call_list/1.
dispatch_call_list([]).
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'(dispatch_call_list(Gs)).
dispatch_call_list([G1,G2,G3,G4,G5,G6,G7]) :-
!,
'$call'(G1),
'$call'(G2),
'$call'(G3),
'$call'(G4),
'$call'(G5),
'$call'(G6),
'$call'(G7).
dispatch_call_list([G1,G2,G3,G4,G5,G6]) :-
!,
'$call'(G1),
'$call'(G2),
'$call'(G3),
'$call'(G4),
'$call'(G5),
'$call'(G6).
dispatch_call_list([G1,G2,G3,G4,G5]) :-
!,
'$call'(G1),
'$call'(G2),
'$call'(G3),
'$call'(G4),
'$call'(G5).
dispatch_call_list([G1,G2,G3,G4]) :-
!,
'$call'(G1),
'$call'(G2),
'$call'(G3),
'$call'(G4).
dispatch_call_list([G1,G2,G3]) :-
!,
'$call'(G1),
'$call'(G2),
'$call'(G3).
dispatch_call_list([G1,G2]) :-
!,
'$call'(G1),
'$call'(G2).
dispatch_call_list([G1]) :-
'$call'(G1).
% univ.
:- non_counted_backtracking univ_errors/3.
univ_errors(Term, List, N) :-
'$skip_max_list'(N, -1, List, R),
( var(R) ->
( var(Term),
throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 a)
; true
)
'$skip_max_list'(N, _, List, R),
( var(R) ->
( var(Term),
throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 a)
; true
)
; R \== [] ->
throw(error(type_error(list, List), (=..)/2)) % 8.5.3.3 b)
; List = [H|T] ->
@@ -388,9 +416,10 @@ univ_worker(Term, List, _) :-
!,
'$call_with_default_policy'(List = [Term]).
univ_worker(Term, [Name|Args], N) :-
var(Term), !,
var(Term),
!,
'$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)).
univ_worker(Term, List, _) :-
'$call_with_default_policy'(functor(Term, Name, Arity)),
@@ -415,7 +444,7 @@ get_args([Arg|Args], Func, I0, N) :-
:- meta_predicate parse_options_list(?, 0, ?, ?, ?).
parse_options_list(Options, Selector, DefaultPairs, OptionValues, Stub) :-
'$skip_max_list'(_, -1, Options, Tail),
'$skip_max_list'(_, _, Options, Tail),
( Tail == [] ->
true
; var(Tail) ->
@@ -468,7 +497,7 @@ parse_write_options_(max_depth(MaxDepth), max_depth-MaxDepth) :-
).
must_be_var_names_list(VarNames) :-
'$skip_max_list'(_, -1, VarNames, Tail),
'$skip_max_list'(_, _, VarNames, Tail),
( Tail == [] ->
must_be_var_names_list_(VarNames, VarNames)
; var(Tail) ->
@@ -565,7 +594,7 @@ can_be_list(List, _) :-
var(List),
!.
can_be_list(List, _) :-
'$skip_max_list'(_, -1, List, Tail),
'$skip_max_list'(_, _, List, Tail),
( var(Tail) ->
true
; Tail == []
@@ -620,9 +649,11 @@ throw(Ball) :-
),
'$unwind_stack'.
:- non_counted_backtracking '$iterate_find_all'/4.
'$iterate_find_all'(Template, Goal, _, LhOffset) :-
call(Goal),
'$call'(Goal),
'$copy_to_lh'(LhOffset, Template),
'$fail'.
'$iterate_find_all'(_, _, Solutions, LhOffset) :-
@@ -636,7 +667,7 @@ truncate_lh_to(LhLength) :- '$truncate_lh_to'(LhLength).
:- meta_predicate findall(?, 0, ?).
findall(Template, Goal, Solutions) :-
error:can_be(list, Solutions),
'$call_with_default_policy'(error:can_be(list, Solutions)),
'$lh_length'(LhLength),
'$call_with_default_policy'(
catch(builtins:'$iterate_find_all'(Template, Goal, Solutions, LhLength),
@@ -644,7 +675,6 @@ findall(Template, Goal, Solutions) :-
( builtins:truncate_lh_to(LhLength), builtins:throw(Error) ))
).
:- non_counted_backtracking '$iterate_find_all_diff'/5.
'$iterate_find_all_diff'(Template, Goal, _, _, LhOffset) :-
@@ -659,8 +689,8 @@ findall(Template, Goal, Solutions) :-
:- meta_predicate findall(?, 0, ?, ?).
findall(Template, Goal, Solutions0, Solutions1) :-
error:can_be(list, Solutions0),
error:can_be(list, Solutions1),
'$call_with_default_policy'(error:can_be(list, Solutions0)),
'$call_with_default_policy'(error:can_be(list, Solutions1)),
'$lh_length'(LhLength),
'$call_with_default_policy'(
catch(builtins:'$iterate_find_all_diff'(Template, Goal, Solutions0,
@@ -679,9 +709,9 @@ set_difference([], _, []) :- !.
set_difference(Xs, [], Xs).
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, _, [], Pairs).
@@ -713,15 +743,15 @@ rightmost_power(Term, FinalTerm, Xs) :-
findall_with_existential(Template, Goal, PairedSolutions, Witnesses0, Witnesses) :-
( nonvar(Goal),
( Goal = _ ^ _
; Goal = _ : (_ ^ _)
) ->
rightmost_power(Goal, Goal1, ExistentialVars0),
loader:strip_module(Goal, M, Goal1),
( Goal1 = _ ^ _ ) ->
rightmost_power(Goal1, Goal2, ExistentialVars0),
term_variables(ExistentialVars0, ExistentialVars),
sort(Witnesses0, Witnesses1),
sort(ExistentialVars, ExistentialVars1),
set_difference(Witnesses1, ExistentialVars1, Witnesses),
findall(Witnesses-Template, Goal1, PairedSolutions)
expand_goal(M:Goal2, M, Goal3),
findall(Witnesses-Template, Goal3, PairedSolutions)
; Witnesses = Witnesses0,
findall(Witnesses-Template, Goal, PairedSolutions)
).
@@ -779,11 +809,11 @@ setof(Template, Goal, Solution) :-
( var(H) ->
throw(error(instantiation_error, clause/2))
; 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),
Module:'$clause'(H, B)
; '$no_such_predicate'(Module, H) ->
'$fail'
; throw(error(permission_error(access, private_procedure, Name/Arity),
clause/2))
)
@@ -800,12 +830,11 @@ clause(H, B) :-
arg(1, H, Module),
arg(2, H, F),
'$module_clause'(F, B, Module)
; '$no_such_predicate'(user, H) ->
'$fail'
; '$head_is_dynamic'(user, H) ->
'$clause_body_is_valid'(B),
'$clause'(H, B)
; '$no_such_predicate'(user, H) -> %% '$no_such_predicate' fails if
%% H is not callable.
'$fail'
; throw(error(permission_error(access, private_procedure, Name/Arity),
clause/2))
)
@@ -854,13 +883,14 @@ asserta_clause(Head, Body) :-
:- meta_predicate asserta(0).
asserta(Clause) :-
asserta(Clause0) :-
loader:strip_module(Clause0, Module, Clause),
( Clause \= (_ :- _) ->
Head = Clause,
Body = true,
asserta_clause(Head, Body)
module_asserta_clause(Head, Body, Module)
; Clause = (Head :- Body) ->
asserta_clause(Head, Body)
module_asserta_clause(Head, Body, Module)
).
module_assertz_clause(Head, Body, Module) :-
@@ -909,13 +939,14 @@ assertz_clause(Head, Body) :-
:- meta_predicate assertz(0).
assertz(Clause) :-
assertz(Clause0) :-
loader:strip_module(Clause0, Module, Clause),
( Clause \= (_ :- _) ->
Head = Clause,
Body = true,
assertz_clause(Head, Body)
module_assertz_clause(Head, Body, Module)
; Clause = (Head :- Body) ->
assertz_clause(Head, Body)
module_assertz_clause(Head, Body, Module)
).
@@ -999,13 +1030,14 @@ retract_clause(Head, Body) :-
:- meta_predicate retract(0).
retract(Clause0) :-
strip_module(Clause0, Module, Clause),
( Clause = (Head :- Body) ->
true
; Head = Clause,
Body = true
),
retract_clause(Module:Head, Body).
loader:strip_module(Clause0, Module, Clause),
( Clause \= (_ :- _) ->
Head = Clause,
Body = true,
retract_module_clause(Head, Body, Module)
; Clause = (Head :- Body) ->
retract_module_clause(Head, Body, Module)
).
:- meta_predicate retractall(0).
@@ -1022,8 +1054,10 @@ module_abolish(Pred, Module) :-
; Pred = Name/Arity ->
( var(Name) ->
throw(error(instantiation_error, abolish/1))
; var(Arity) ->
throw(error(instantiation_error, abolish/1))
; integer(Arity) ->
( \+ atom(Name) ->
(\+ atom(Name) ->
throw(error(type_error(atom, Name), abolish/1))
; Arity < 0 ->
throw(error(domain_error(not_less_than_zero, Arity), abolish/1))
@@ -1075,17 +1109,16 @@ abolish(Pred) :-
; throw(error(type_error(predicate_indicator, Pred), abolish/1))
).
'$iterate_db_refs'(Ref, Name/Arity) :-
'$lookup_db_ref'(Ref, Name, Arity).
'$iterate_db_refs'(Ref, Name/Arity) :-
'$get_next_db_ref'(Ref, NextRef),
'$iterate_db_refs'(NextRef, Name/Arity).
'$iterate_db_refs'(Name, Arity, Name/Arity). % :-
% '$lookup_db_ref'(Ref, Name, Arity).
'$iterate_db_refs'(RName, RArity, Name/Arity) :-
'$get_next_db_ref'(RName, RArity, RRName, RRArity),
'$iterate_db_refs'(RRName, RRArity, Name/Arity).
current_predicate(Pred) :-
( var(Pred) ->
'$get_next_db_ref'(Ref, _),
'$iterate_db_refs'(Ref, Pred)
'$get_next_db_ref'(RN, RA, _, _),
'$iterate_db_refs'(RN, RA, Pred)
; Pred \= _/_ ->
throw(error(type_error(predicate_indicator, Pred), current_predicate/1))
; Pred = Name/Arity,
@@ -1094,15 +1127,14 @@ current_predicate(Pred) :-
; integer(Arity), Arity < 0
) ->
throw(error(type_error(predicate_indicator, Pred), current_predicate/1))
; '$get_next_db_ref'(Ref, _),
'$iterate_db_refs'(Ref, Pred)
; '$get_next_db_ref'(RN, RA, _, _),
'$iterate_db_refs'(RN, RA, Pred)
).
'$iterate_op_db_refs'(Ref, Priority, Spec, Op) :-
'$lookup_op_db_ref'(Ref, Priority, Spec, Op).
'$iterate_op_db_refs'(Ref, Priority, Spec, Op) :-
'$get_next_op_db_ref'(Ref, NextRef),
'$iterate_op_db_refs'(NextRef, Priority, Spec, Op).
'$iterate_op_db_refs'(RPriority, RSpec, ROp, _, RPriority, RSpec, ROp).
'$iterate_op_db_refs'(RPriority, RSpec, ROp, OssifiedOpDir, Priority, Spec, Op) :-
'$get_next_op_db_ref'(RPriority, RSpec, ROp, OssifiedOpDir, RRPriority, RRSpec, RROp),
'$iterate_op_db_refs'(RRPriority, RRSpec, RROp, OssifiedOpDir, Priority, Spec, Op).
can_be_op_priority(Priority) :- var(Priority).
can_be_op_priority(Priority) :- op_priority(Priority).
@@ -1114,8 +1146,8 @@ current_op(Priority, Spec, Op) :-
( can_be_op_priority(Priority),
can_be_op_specifier(Spec),
error:can_be(atom, Op) ->
'$get_next_op_db_ref'(Ref, _),
'$iterate_op_db_refs'(Ref, Priority, Spec, Op)
'$get_next_op_db_ref'(RPriority, RSpec, ROp, OssifiedOpDir, _, _, Op),
'$iterate_op_db_refs'(RPriority, RSpec, ROp, OssifiedOpDir, Priority, Spec, Op)
).
list_of_op_atoms(Var) :-
@@ -1209,7 +1241,7 @@ atom_length(Atom, Length) :-
).
atom_chars(Atom, List) :-
'$skip_max_list'(_, -1, List, Tail),
'$skip_max_list'(_, _, List, Tail),
( ( Tail == [] ; var(Tail) ) ->
true
; throw(error(type_error(list, List), atom_chars/2))
@@ -1227,7 +1259,7 @@ atom_chars(Atom, List) :-
).
atom_codes(Atom, List) :-
'$skip_max_list'(_, -1, List, Tail),
'$skip_max_list'(_, _, List, Tail),
( ( Tail == [] ; var(Tail) ) ->
true
; throw(error(type_error(list, List), atom_codes/2))
@@ -1284,9 +1316,9 @@ sub_atom(Atom, Before, Length, After, Sub_atom) :-
; atom_chars(Atom, AtomChars),
lists:append(BeforeChars, LengthAndAfterChars, AtomChars),
lists:append(LengthChars, AfterChars, LengthAndAfterChars),
'$skip_max_list'(Before, -1, BeforeChars, []),
'$skip_max_list'(Length, -1, LengthChars, []),
'$skip_max_list'(After, -1, AfterChars, []),
'$skip_max_list'(Before, _, BeforeChars, []),
'$skip_max_list'(Length, _, LengthChars, []),
'$skip_max_list'(After, _, AfterChars, []),
atom_chars(Sub_atom, LengthChars)
).
@@ -1481,7 +1513,8 @@ open(SourceSink, Mode, Stream, StreamOptions) :-
atom(SourceSink) ->
atom_chars(SourceSink, SourceSinkString)
; SourceSink = SourceSinkString
), '$open'(SourceSinkString, Mode, Stream, Alias, EOFAction, Reposition, Type)
),
'$open'(SourceSinkString, Mode, Stream, Alias, EOFAction, Reposition, Type)
)
).

View File

@@ -1,9 +1,9 @@
:- module(charsio, [char_type/2,
chars_utf8bytes/2,
get_single_char/1,
read_n_chars/3,
get_n_chars/3,
read_line_to_chars/3,
read_term_from_chars/2,
read_from_chars/2,
write_term_to_chars/3,
chars_base64/3]).
@@ -113,18 +113,8 @@ get_single_char(C) :-
).
read_term_from_chars(Chars, Term) :-
( var(Chars) ->
instantiation_error(read_term_from_chars/2)
; nonvar(Term) ->
throw(error(uninstantiation_error(Term), read_term_from_chars/2))
; '$skip_max_list'(_, -1, Chars, Chars0),
Chars0 == [],
partial_string(Chars) ->
true
;
type_error(complete_string, Chars, read_term_from_chars/2)
),
read_from_chars(Chars, Term) :-
must_be(chars, Chars),
'$read_term_from_chars'(Chars, Term).
@@ -205,7 +195,7 @@ read_line_to_chars(Stream, Cs0, Cs) :-
characters read.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
read_n_chars(Stream, N, Cs) :-
get_n_chars(Stream, N, Cs) :-
can_be(integer, N),
( var(N) ->
read_to_eof(Stream, Cs),

View File

@@ -6169,7 +6169,7 @@ distinct_goals_([flow_to(F,To)|Es], V) -->
get_attr(To, lowlink, L2),
L1 =\= L2 } ->
{ get_attr(To, value, N) },
[neq_num(V, N)]
[clpz:neq_num(V, N)]
; []
),
distinct_goals_(Es, V).
@@ -6690,7 +6690,7 @@ gcc_edge_goal(arc_to(_,_,V,F), Val) -->
get_attr(Val, lowlink, L2),
L1 =\= L2,
get_attr(Val, value, Value) } ->
[neq_num(V, Value)]
[clpz:neq_num(V, Value)]
; []
).

View File

@@ -1,5 +1,5 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Written 2020, 2021 by Markus Triska (triska@metalevel.at)
Written 2020, 2021, 2022 by Markus Triska (triska@metalevel.at)
Part of Scryer Prolog.
Predicates for cryptographic applications.
@@ -46,6 +46,7 @@
:- use_module(library(format)).
:- use_module(library(charsio)).
:- use_module(library(si)).
:- use_module(library(iso_ext), [partial_string/3]).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
hex_bytes(?Hex, ?Bytes) is det.
@@ -594,7 +595,9 @@ crypto_data_decrypt(CipherText0, Algorithm, Key, IV, PlainText, Options) :-
member(Encoding, [utf8,octet]),
encoding_chars(octet, CipherText0, CipherText1),
maplist(char_code, TagChars, Tag),
append(CipherText1, TagChars, CipherText),
% we append the tag very efficiently, retaining a compact
% internal string representation of the ciphertext
partial_string(CipherText1, CipherText, TagChars),
( Algorithm = 'chacha20-poly1305' -> true
; domain_error('chacha20-poly1305', Algorithm, crypto_data_decrypt/6)
),

View File

@@ -1,16 +1,26 @@
:- module(dcgs,
[op(1105, xfy, '|'),
phrase/2,
phrase/3,
seq//1,
seqq//1,
... //0
]).
phrase/2,
phrase/3,
seq//1,
seqq//1,
... //0
]).
:- 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]).
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, ?, ?).
@@ -18,100 +28,44 @@
phrase(GRBody, S0) :-
phrase(GRBody, S0, []).
phrase(GRBody, S0, S) :-
( var(GRBody) ->
throw(error(instantiation_error, phrase/3))
; strip_module(GRBody, Module, GRBody0),
dcg_constr(GRBody0) ->
( var(Module) ->
phrase_(GRBody0, S0, S)
; phrase_(Module:GRBody0, S0, S)
)
; functor(GRBody, _, _) ->
call(GRBody, S0, S)
; throw(error(type_error(callable, GRBody), phrase/3))
load_context(GRBody, Module, GRBody0),
( var(GRBody0) ->
instantiation_error(phrase/3)
; dcg_body(GRBody0, S0, S, GRBody1, Module) ->
call(GRBody1)
; type_error(callable, GRBody0, phrase/3)
).
phrase_([], S, S).
phrase_(!, S, S).
phrase_(_:[], S, S) :- !.
phrase_(_:!, S, S) :- !.
phrase_((A, B), S0, S) :-
phrase(A, S0, S1), phrase(B, S1, S).
phrase_(M:(A, B), S0, S) :-
!,
phrase(M:A, S0, S1), phrase(M:B, S1, S).
phrase_((A -> B ; C), S0, S) :-
!,
( phrase(A, S0, S1) ->
phrase(B, S1, S)
; phrase(C, S0, S)
module_call_qualified(M, Call, Call1) :-
( nonvar(M) -> Call1 = M:Call
; Call = Call1
).
phrase_(M:(A -> B ; C), S0, S) :-
!,
( phrase(M:A, S0, S1) ->
phrase(M:B, S1, S)
; phrase(M:C, S0, S)
).
phrase_((A ; B), S0, S) :-
( phrase(A, S0, S) ; phrase(B, S0, S) ).
phrase_(M:(A ; B), S0, S) :-
!,
( phrase(M:A, S0, S) ; phrase(M:B, S0, S) ).
phrase_((A | B), S0, S) :-
( phrase(A, S0, S) ; phrase(B, S0, S) ).
phrase_(M:(A | B), S0, S) :-
!,
( phrase(M:A, S0, S) ; phrase(M:B, S0, S) ).
phrase_({G}, S0, S) :-
( call(G), S0 = S ).
phrase_(M:{G}, S0, S) :-
!,
( call(M:G), S0 = S ).
phrase_(call(G), S0, S) :-
call(G, S0, S).
phrase_(M:call(G), S0, S) :-
!,
call(M:G, S0, S).
phrase_((A -> B), S0, S) :-
phrase((A -> B ; fail), S0, S).
phrase_(M:(A -> B), S0, S) :-
!,
phrase((M:A -> M:B ; fail), S0, S).
phrase_(phrase(NonTerminal), S0, S) :-
phrase(NonTerminal, S0, S).
phrase_(M:phrase(NonTerminal), S0, S) :-
!,
phrase(M:NonTerminal, S0, S).
phrase_([T|Ts], S0, S) :-
append([T|Ts], S, S0).
phrase_(_:[T|Ts], S0, S) :-
append([T|Ts], S, S0).
% The same version of the below two dcg_rule clauses, but with module scoping.
dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :-
dcg_non_terminal(NonTerminal, S0, S, Head),
dcg_body(GRBody, S0, S1, Goal1),
dcg_body(GRBody, S0, S1, Goal1, _),
dcg_terminals(Terminals, S, S1, Goal2),
Body = ( Goal1, Goal2 ).
dcg_rule(( M:NonTerminal --> GRBody ), ( M:Head :- Body )) :-
NonTerminal \= ( _, _ ),
dcg_non_terminal(NonTerminal, S0, S, Head),
dcg_body(GRBody, S0, S, Body).
dcg_body(GRBody, S0, S, Body, _).
% This program uses append/3 as defined in the Prolog prologue.
% Expands a DCG rule into a Prolog rule, when no error condition applies.
dcg_rule(( NonTerminal, Terminals --> GRBody ), ( Head :- Body )) :-
dcg_non_terminal(NonTerminal, S0, S, Head),
dcg_body(GRBody, S0, S1, Goal1),
dcg_body(GRBody, S0, S1, Goal1, _),
dcg_terminals(Terminals, S, S1, Goal2),
Body = ( Goal1, Goal2 ).
dcg_rule(( NonTerminal --> GRBody ), ( Head :- Body )) :-
NonTerminal \= ( _, _ ),
dcg_non_terminal(NonTerminal, S0, S, Head),
dcg_body(GRBody, S0, S, Body).
dcg_body(GRBody, S0, S, Body, _).
dcg_non_terminal(NonTerminal, S0, S, Goal) :-
NonTerminal =.. NonTerminalUniv,
@@ -121,18 +75,20 @@ dcg_non_terminal(NonTerminal, S0, S, Goal) :-
dcg_terminals(Terminals, S0, S, S0 = List) :-
append(Terminals, S, List).
dcg_body(Var, S0, S, Body) :-
dcg_body(Var, S0, S, Body, M) :-
var(Var),
Body = phrase(Var, S0, S).
dcg_body(GRBody, S0, S, Body) :-
module_call_qualified(M, Var, Var1),
Body = phrase(Var1, S0, S).
dcg_body(GRBody, S0, S, Body, M) :-
nonvar(GRBody),
dcg_constr(GRBody),
dcg_cbody(GRBody, S0, S, Body).
dcg_body(NonTerminal, S0, S, Goal) :-
dcg_cbody(GRBody, S0, S, Body, M).
dcg_body(NonTerminal, S0, S, Goal1, M) :-
nonvar(NonTerminal),
\+ dcg_constr(NonTerminal),
NonTerminal \= ( _ -> _ ),
NonTerminal \= ( \+ _ ),
module_call_qualified(M, Goal, Goal1),
dcg_non_terminal(NonTerminal, S0, S, Goal).
% The following constructs in a grammar rule body
@@ -151,37 +107,40 @@ dcg_constr((_->_)). % 7.14.12 - if-then (existence implementation dep.)
% The principal functor of the first argument indicates
% the construct to be expanded.
dcg_cbody([], S0, S, S0 = S).
dcg_cbody([T|Ts], S0, S, Goal) :-
dcg_cbody([], S0, S, S0 = S, _M).
dcg_cbody([T|Ts], S0, S, Goal, _M) :-
must_be(list, [T|Ts]),
dcg_terminals([T|Ts], S0, S, Goal).
dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second )) :-
dcg_body(GRFirst, S0, S1, First),
dcg_body(GRSecond, S1, S, Second).
dcg_cbody(( GREither ; GROr ), S0, S, ( Either ; Or )) :-
dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second ), M) :-
dcg_body(GRFirst, S0, S1, First, M),
dcg_body(GRSecond, S1, S, Second, M).
dcg_cbody(( GREither ; GROr ), S0, S, ( Either ; Or ), M) :-
\+ subsumes_term(( _ -> _ ), GREither),
dcg_body(GREither, S0, S, Either),
dcg_body(GROr, S0, S, Or).
dcg_cbody(( GRCond ; GRElse ), S0, S, ( Cond ; Else )) :-
dcg_body(GREither, S0, S, Either, M),
dcg_body(GROr, S0, S, Or, M).
dcg_cbody(( GRCond ; GRElse ), S0, S, ( Cond ; Else ), M) :-
subsumes_term(( _GRIf -> _GRThen ), GRCond),
dcg_cbody(GRCond, S0, S, Cond),
dcg_body(GRElse, S0, S, Else).
dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or )) :-
dcg_body(GREither, S0, S, Either),
dcg_body(GROr, S0, S, Or).
dcg_cbody({Goal}, S0, S, ( Goal, S0 = S )).
dcg_cbody(call(Cont), S0, S, call(Cont, S0, S)).
dcg_cbody(phrase(Body), S0, S, phrase(Body, S0, S)).
dcg_cbody(!, S0, S, ( !, S0 = S )).
dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody,S0,_), S0 = S )).
dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then )) :-
dcg_body(GRIf, S0, S1, If),
dcg_body(GRThen, S1, S, Then).
dcg_cbody(GRCond, S0, S, Cond, M),
dcg_body(GRElse, S0, S, Else, M).
dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or ), M) :-
dcg_body(GREither, S0, S, Either, M),
dcg_body(GROr, S0, S, Or, M).
dcg_cbody({Goal}, S0, S, ( Goal1, S0 = S ), M) :-
module_call_qualified(M, Goal, Goal1).
dcg_cbody(call(Cont), S0, S, call(Cont1, S0, S), M) :-
module_call_qualified(M, Cont, Cont1).
dcg_cbody(phrase(Body), S0, S, phrase(Body1, S0, S), M) :-
module_call_qualified(M, Body, Body1).
dcg_cbody(!, S0, S, ( !, S0 = S ), _M).
dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody1,S0,_), S0 = S ), M) :-
module_call_qualified(M, GRBody, GRBody1).
dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then ), M) :-
dcg_body(GRIf, S0, S1, If, M),
dcg_body(GRThen, S1, S, Then, M).
user:term_expansion(Term0, Term) :-
nonvar(Term0),
dcg_rule(Term0, (Head :- Body)),
Term = (Head :- Body).
dcg_rule(Term0, Term).
% Describes a sequence
seq([]) --> [].
@@ -193,3 +152,13 @@ seqq([Es|Ess]) --> seq(Es), seqq(Ess).
% Describes an arbitrary number of elements
... --> [] | [_], ... .
user:goal_expansion(phrase(GRBody, S, S0), GRBody1) :-
load_context(GRBody, M, GRBody0),
nonvar(GRBody0),
catch(dcgs:dcg_body(GRBody0, S, S0, GRBody1, M),
error(E, must_be/2),
( GRBody1 = throw(error(E, must_be/2)) )
).
user:goal_expansion(phrase(GRBody, S), phrase(GRBody, S, [])).

View File

@@ -80,7 +80,7 @@ character(C) :-
atom_length(C, 1).
ilist(Ls) :-
'$skip_max_list'(_, -1, Ls, Rs),
'$skip_max_list'(_, _, Ls, Rs),
( var(Rs) ->
instantiation_error(must_be/2)
; Rs == []
@@ -124,7 +124,7 @@ can_(list, Term) :- list_or_partial_list(Term).
can_(boolean, Term) :- boolean(Term).
list_or_partial_list(Ls) :-
'$skip_max_list'(_, -1, Ls, Rs),
'$skip_max_list'(_, _, Ls, Rs),
( var(Rs) -> true
; Rs == []
).

View File

@@ -174,7 +174,7 @@ file_creation_time(File, T) :-
file_time_(File, Which, T) :-
file_must_exist(File, file_time_/3),
'$file_time'(File, Which, T0),
read_term_from_chars(T0, T).
read_from_chars(T0, T).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@@ -1,5 +1,5 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Written 2020, 2021 by Markus Triska (triska@metalevel.at)
Written 2020, 2021, 2022 by Markus Triska (triska@metalevel.at)
Part of Scryer Prolog.
This library provides the nonterminal format_//2 to describe
@@ -28,6 +28,9 @@
if N is 0 or omitted, no decimal point is used.
~ND like ~Nd, separating digits to the left of the decimal point
in groups of three, using the character "," (comma)
~NU like ~ND, using "_" (underscore) to separate groups of digits
~NL format an integer so that at most N digits appear on a line.
If N is 0 or omitted, it defaults to 72.
~Nr where N is an integer between 2 and 36: format the
next argument, which must be an integer, in radix N.
The characters "a" to "z" are used for radices 10 to 36.
@@ -200,14 +203,22 @@ cells([~|Fs0], Args0, Tab, Es, VNs) -->
cells([~|Fs0], Args0, Tab, Es, VNs) -->
{ numeric_argument(Fs0, Num, ['D'|Fs], Args0, [Arg|Args]) },
!,
{ number_chars(Num, NCs),
phrase(("~",seq(NCs),"d"), FStr),
phrase(format_(FStr, [Arg]), Cs0),
phrase(upto_what(Bs0, .), Cs0, Ds),
reverse(Bs0, Bs1),
phrase(groups_of_three(Bs1), Bs2),
reverse(Bs2, Bs),
append(Bs, Ds, Cs) },
{ separate_digits_fractional(Arg, ',', Num, Cs) },
cells(Fs, Args, Tab, [chars(Cs)|Es], VNs).
cells([~|Fs0], Args0, Tab, Es, VNs) -->
{ numeric_argument(Fs0, Num, ['U'|Fs], Args0, [Arg|Args]) },
!,
{ separate_digits_fractional(Arg, '_', Num, Cs) },
cells(Fs, Args, Tab, [chars(Cs)|Es], VNs).
cells([~|Fs0], Args0, Tab, Es, VNs) -->
{ numeric_argument(Fs0, Num0, ['L'|Fs], Args0, [Arg|Args]) },
!,
{ ( Num0 =:= 0 ->
Num = 72
; Num = Num0
),
phrase(format_("~d", [Arg]), Cs0),
phrase(split_lines_width(Cs0, Num), Cs) },
cells(Fs, Args, Tab, [chars(Cs)|Es], VNs).
cells([~,i|Fs], [_|Args], Tab, Es, VNs) --> !,
cells(Fs, Args, Tab, Es, VNs).
@@ -312,12 +323,30 @@ Cs = [a,b,c], Rest = [~,t,e,s,t].
Cs = [a,b,c], Rest = [].
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
separate_digits_fractional(Arg, Sep, Num, Cs) :-
number_chars(Num, NCs),
phrase(("~",seq(NCs),"d"), FStr),
phrase(format_(FStr, [Arg]), Cs0),
phrase(upto_what(Bs0, .), Cs0, Ds),
reverse(Bs0, Bs1),
phrase(groups_of_three(Bs1,Sep), Bs2),
reverse(Bs2, Bs),
append(Bs, Ds, Cs).
upto_what([], W), [W] --> [W], !.
upto_what([C|Cs], W) --> [C], !, upto_what(Cs, W).
upto_what([], _) --> [].
groups_of_three([A,B,C,D|Rs]) --> !, [A,B,C], ",", groups_of_three([D|Rs]).
groups_of_three(Ls) --> seq(Ls).
groups_of_three([A,B,C,D|Rs], Sep) --> !, [A,B,C,Sep], groups_of_three([D|Rs], Sep).
groups_of_three(Ls, _) --> seq(Ls).
split_lines_width(Cs, Num) -->
( { length(Prefix, Num),
append(Prefix, [R|Rs], Cs) } ->
seq(Prefix), "_\n",
split_lines_width([R|Rs], Num)
; seq(Cs)
).
cell(From, To, Es0) -->
( { Es0 == [] } -> []

View File

@@ -14,7 +14,7 @@
partial_string_tail/2,
setup_call_cleanup/3,
call_nth/2,
variant/2,
% variant/2,
copy_term_nat/2]).
:- use_module(library(error), [can_be/2,
@@ -22,10 +22,7 @@
instantiation_error/1,
type_error/3]).
:- meta_predicate(call_cleanup(0, 0)).
:- meta_predicate(setup_call_cleanup(0, 0, 0)).
:- use_module(library(lists), [maplist/3]).
:- 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).
% setup_call_cleanup.
:- meta_predicate(setup_call_cleanup(0, 0, 0)).
setup_call_cleanup(S, G, C) :-
'$get_b_value'(B),
call(S),
'$call'(S),
'$set_cp_by_default'(B),
'$get_current_block'(Bb),
( C = _:CC,
@@ -71,6 +71,8 @@ setup_call_cleanup(S, G, C) :-
; '$call_with_default_policy'(scc_helper(C, G, Bb))
).
:- meta_predicate(scc_helper(?,0,?)).
:- non_counted_backtracking scc_helper/3.
scc_helper(C, G, Bb) :-
'$get_cp'(Cp),
@@ -96,7 +98,8 @@ scc_helper(_, _, _) :-
:- non_counted_backtracking run_cleaners_with_handling/0.
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)),
'$set_cp_by_default'(B),
'$call_with_default_policy'(run_cleaners_with_handling).
@@ -134,16 +137,31 @@ handle_ile(B, E, _) :-
:- meta_predicate(call_with_inference_limit(0, ?, ?)).
call_with_inference_limit(G, L, R) :-
( integer(L) ->
( L < 0 ->
domain_error(not_less_than_zero, L, call_with_inference_limit/3)
; true
)
; var(L) ->
instantiation_error(call_with_inference_limit/3)
; type_error(integer, L, call_with_inference_limit/3)
),
'$get_current_block'(Bb),
'$get_b_value'(B),
'$call_with_default_policy'(call_with_inference_limit(G, L, R, Bb, 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.
call_with_inference_limit(G, L, R, Bb, B) :-
'$install_new_block'(NBb),
'$install_inference_counter'(B, L, Count0),
call(G),
'$call'(G),
'$inference_level'(R, B),
'$remove_inference_counter'(B, Count1),
'$call_with_default_policy'(is(Diff, L - (Count1 - Count0))),
@@ -160,14 +178,12 @@ call_with_inference_limit(_, _, R, Bb, B) :-
'$erase_ball',
'$call_with_default_policy'(handle_ile(B, Ball, R)).
variant(X, Y) :- '$variant'(X, Y).
partial_string(String, L, L0) :-
( String == [] ->
L = L0
; catch(atom_chars(Atom, String),
error(E, _),
throw(error(E, partial_string/3))),
error(E, _),
throw(error(E, partial_string/3))),
'$create_partial_string'(Atom, L, L0)
).

View File

@@ -3,7 +3,7 @@
maplist/3, maplist/4, maplist/5, maplist/6,
maplist/7, maplist/8, maplist/9, same_length/2, nth0/3,
sum_list/2, transpose/2, list_to_set/2, list_max/2,
list_min/2, permutation/2]).
list_min/2, permutation/2]).
/* Author: Mark Thom, Jan Wielemaker, and Richard O'Keefe
Copyright (c) 2018-2021, Mark Thom
@@ -50,24 +50,20 @@
:- meta_predicate foldl(3, ?, ?, ?).
:- meta_predicate foldl(4, ?, ?, ?, ?).
length(Xs, N) :-
var(N),
!,
'$skip_max_list'(M, -1, Xs, Xs0),
( Xs0 == [] -> N = M
; var(Xs0) -> length_addendum(Xs0, N, M)).
length(Xs, N) :-
integer(N),
N >= 0, !,
'$skip_max_list'(M, N, Xs, Xs0),
( Xs0 == [] -> N = M
; var(Xs0) -> R is N-M, length_rundown(Xs0, R)).
length(Xs0, N) :-
'$skip_max_list'(M, N, Xs0,Xs),
!,
( Xs == [] -> N = M
; nonvar(Xs) -> var(N), Xs = [_|_], throw(error(resource_error(finite_memory),length/2))
; nonvar(N) -> R is N-M, length_rundown(Xs, R)
; N == Xs -> throw(error(resource_error(finite_memory),length/2))
; length_addendum(Xs, N, M)
).
length(_, N) :-
integer(N), !,
domain_error(not_less_than_zero, N, length/2).
integer(N), !,
domain_error(not_less_than_zero, N, length/2).
length(_, N) :-
type_error(integer, N, length/2).
type_error(integer, N, length/2).
length_addendum([], N, N).
length_addendum([_|Xs], N, M) :-
@@ -285,8 +281,8 @@ list_min_(N, Min0, Min) :-
% or partial list.
permutation(Xs, Ys) :-
'$skip_max_list'(Xlen, -1, Xs, XTail),
'$skip_max_list'(Ylen, -1, Ys, YTail),
'$skip_max_list'(Xlen, _, Xs, XTail),
'$skip_max_list'(Ylen, _, Ys, YTail),
( XTail == [], YTail == [] % both proper lists
-> Xlen == Ylen
; var(XTail), YTail == [] % partial, proper

View File

@@ -89,7 +89,7 @@ because the order it relies on may have been changed.
% setof/3.
is_ordset(Term) :-
'$skip_max_list'(_, -1, Term, Tail), Tail == [], %% is_list(Term),
'$skip_max_list'(_, _, Term, Tail), Tail == [], %% is_list(Term),
is_ordset2(Term).
is_ordset2([]).

View File

@@ -21,7 +21,7 @@
:- use_module(library(freeze)).
:- use_module(library(iso_ext), [setup_call_cleanup/3, partial_string/3]).
:- use_module(library(lists), [member/2, maplist/2]).
:- use_module(library(charsio), [read_n_chars/3]).
:- use_module(library(charsio), [get_n_chars/3]).
:- meta_predicate(phrase_from_file(2, ?)).
:- meta_predicate(phrase_from_file(2, ?, ?)).
@@ -62,7 +62,7 @@ reader_step(Stream, Pos, Xs0) :-
set_stream_position(Stream, Pos),
( at_end_of_stream(Stream)
-> Xs0 = []
; read_n_chars(Stream, 4096, Cs),
; get_n_chars(Stream, 4096, Cs),
partial_string(Cs, Xs0, Xs),
stream_to_lazy_list(Stream, Xs)
).

View File

@@ -22,11 +22,11 @@ random(R) :-
random_integer(Lower, Upper, R) :-
var(R),
( (var(Lower) ; var(Upper)) ->
instantiation_error(random_integer/3)
instantiation_error(random_integer/3)
; \+ integer(Lower) ->
domain_error(integer, Lower, random_integer/3)
type_error(integer, Lower, random_integer/3)
; \+ integer(Upper) ->
domain_error(integer, Upper, random_integer/3)
type_error(integer, Upper, random_integer/3)
; Upper > Lower,
random(R0),
R is floor((Upper - Lower) * R0 + Lower)

View File

@@ -79,5 +79,6 @@ tmember(P_2, [X|Xs]) :-
:- meta_predicate(tmember_t(2, ?, ?)).
tmember_t(_P_2, [], false).
tmember_t(P_2, [X|Xs], T) :-
if_( call(P_2, X), T = true, tmember_t(P_2, Xs, T) ).

View File

@@ -9,26 +9,26 @@
syntaxes. The DCGs are presented in the order they appear in the RFC.
While some DCGs below use `char_type/2`, the most common ones are defined
manually in order to take advantage of Prolog's first-argument indexing.
BSD 3-Clause License
Copyright (c) 2021, Aram Panasenco
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE

View File

@@ -1,29 +1,29 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Written Apr 2021 by Aram Panasenco (panasenco@ucla.edu)
Part of Scryer Prolog.
`json_chars//1` can be used with [`phrase_from_file/2`](src/lib/pio.pl)
or [`phrase/2`](src/lib/dcgs.pl) to parse and generate [JSON](https://www.json.org/json-en.html).
BSD 3-Clause License
Copyright (c) 2021, Aram Panasenco
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -44,7 +44,7 @@
:- use_module(library(dif)).
:- use_module(library(lists)).
/* The DCGs are written to match the McKeeman form presented on the right side of https://www.json.org/json-en.html
/* The DCGs are written to match the McKeeman form presented on the right side of https://www.json.org/json-en.html
as closely as possible. Note that the names in the McKeeman form conflict with the pictures on the site. */
json_chars(Internal) --> json_element(Internal).

View File

@@ -58,6 +58,7 @@
:- use_module(library(error)).
:- use_module(library(dcgs)).
:- use_module(library(pio)).
:- use_module(library(charsio)).
load_html(Source, Es, Options) :-
load_structure_(Source, Es, Options, html).
@@ -75,15 +76,8 @@ load_structure_(file(Fs), [E], Options, What) :-
load_(What, Cs, E, Options).
load_structure_(stream(Stream), [E], Options, What) :-
must_be(list, Options),
read_to_end(Stream, Cs),
get_n_chars(Stream, _, Cs),
load_(What, Cs, E, Options).
load_(html, Cs, E, Options) :- '$load_html'(Cs, E, Options).
load_(xml, Cs, E, Options) :- '$load_xml'(Cs, E, Options).
read_to_end(Stream, Cs) :-
'$get_n_chars'(Stream, 4096, Cs0),
( Cs0 = [] -> Cs = []
; partial_string(Cs0, Cs, Rest),
read_to_end(Stream, Rest)
).

View File

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

View File

@@ -49,11 +49,11 @@
:- use_module(library(error)).
:- use_module(library(dcgs)).
:- use_module(library(lists)).
:- use_module(library(charsio), [read_term_from_chars/2]).
:- use_module(library(charsio), [read_from_chars/2]).
current_time(T) :-
'$current_time'(T0),
read_term_from_chars(T0, T).
read_from_chars(T0, T).
format_time([], _) --> [].
format_time(['%','%'|Fs], T) --> !, "%", format_time(Fs, T).

630
src/lib/ugraphs.pl Normal file
View File

@@ -0,0 +1,630 @@
/* Author: R.A.O'Keefe, Vitor Santos Costa, Jan Wielemaker
E-mail: J.Wielemaker@vu.nl
WWW: http://www.swi-prolog.org
Copyright (c) 1984-2021, VU University Amsterdam
CWI, Amsterdam
SWI-Prolog Solutions .b.v
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
:- module(ugraphs,
[ add_edges/3, % +Graph, +Edges, -NewGraph
add_vertices/3, % +Graph, +Vertices, -NewGraph
complement/2, % +Graph, -NewGraph
compose/3, % +LeftGraph, +RightGraph, -NewGraph
del_edges/3, % +Graph, +Edges, -NewGraph
del_vertices/3, % +Graph, +Vertices, -NewGraph
edges/2, % +Graph, -Edges
neighbors/3, % +Vertex, +Graph, -Vertices
neighbours/3, % +Vertex, +Graph, -Vertices
reachable/3, % +Vertex, +Graph, -Vertices
top_sort/2, % +Graph, -Sort
top_sort/3, % +Graph, -Sort0, -Sort
transitive_closure/2, % +Graph, -Closure
transpose_ugraph/2, % +Graph, -NewGraph
vertices/2, % +Graph, -Vertices
vertices_edges_to_ugraph/3, % +Vertices, +Edges, -Graph
ugraph_union/3, % +Graph1, +Graph2, -Graph
connect_ugraph/3 % +Graph1, -Start, -Graph
]).
/** <module> Graph manipulation library
The S-representation of a graph is a list of (vertex-neighbours) pairs,
where the pairs are in standard order (as produced by keysort) and the
neighbours of each vertex are also in standard order (as produced by
sort). This form is convenient for many calculations.
A new UGraph from raw data can be created using
vertices_edges_to_ugraph/3.
Adapted to support some of the functionality of the SICStus ugraphs
library by Vitor Santos Costa.
Ported from YAP 5.0.1 to SWI-Prolog by Jan Wielemaker.
@author R.A.O'Keefe
@author Vitor Santos Costa
@author Jan Wielemaker
@license BSD-2 or Artistic 2.0
*/
:- use_module(library(lists)).
:- use_module(library(pairs)).
:- use_module(library(ordsets)).
%! vertices(+Graph, -Vertices)
%
% Unify Vertices with all vertices appearing in Graph. Example:
%
% ?- vertices([1-[3,5],2-[4],3-[],4-[5],5-[]], L).
% L = [1, 2, 3, 4, 5]
vertices([], []) :- !.
vertices([Vertex-_|Graph], [Vertex|Vertices]) :-
vertices(Graph, Vertices).
%! vertices_edges_to_ugraph(+Vertices, +Edges, -UGraph) is det.
%
% Create a UGraph from Vertices and edges. Given a graph with a
% set of Vertices and a set of Edges, Graph must unify with the
% corresponding S-representation. Note that the vertices without
% edges will appear in Vertices but not in Edges. Moreover, it is
% sufficient for a vertice to appear in Edges.
%
% ==
% ?- vertices_edges_to_ugraph([],[1-3,2-4,4-5,1-5], L).
% L = [1-[3,5], 2-[4], 3-[], 4-[5], 5-[]]
% ==
%
% In this case all vertices are defined implicitly. The next
% example shows three unconnected vertices:
%
% ==
% ?- vertices_edges_to_ugraph([6,7,8],[1-3,2-4,4-5,1-5], L).
% L = [1-[3,5], 2-[4], 3-[], 4-[5], 5-[], 6-[], 7-[], 8-[]]
% ==
vertices_edges_to_ugraph(Vertices, Edges, Graph) :-
sort(Edges, EdgeSet),
p_to_s_vertices(EdgeSet, IVertexBag),
append(Vertices, IVertexBag, VertexBag),
sort(VertexBag, VertexSet),
p_to_s_group(VertexSet, EdgeSet, Graph).
%! add_vertices(+Graph, +Vertices, -NewGraph)
%
% Unify NewGraph with a new graph obtained by adding the list of
% Vertices to Graph. Example:
%
% ```
% ?- add_vertices([1-[3,5],2-[]], [0,1,2,9], NG).
% NG = [0-[], 1-[3,5], 2-[], 9-[]]
% ```
% replace with real msort/2 when available
msort_(List, Sorted) :-
pairs_keys(Pairs, List),
keysort(Pairs, SortedPairs),
pairs_keys(SortedPairs, Sorted).
add_vertices(Graph, Vertices, NewGraph) :-
% msort/2 not available in Scryer Prolog yet: msort(Vertices, V1),
msort_(Vertices, V1),
add_vertices_to_s_graph(V1, Graph, NewGraph).
add_vertices_to_s_graph(L, [], NL) :-
!,
add_empty_vertices(L, NL).
add_vertices_to_s_graph([], L, L) :- !.
add_vertices_to_s_graph([V1|VL], [V-Edges|G], NGL) :-
compare(Res, V1, V),
add_vertices_to_s_graph(Res, V1, VL, V, Edges, G, NGL).
add_vertices_to_s_graph(=, _, VL, V, Edges, G, [V-Edges|NGL]) :-
add_vertices_to_s_graph(VL, G, NGL).
add_vertices_to_s_graph(<, V1, VL, V, Edges, G, [V1-[]|NGL]) :-
add_vertices_to_s_graph(VL, [V-Edges|G], NGL).
add_vertices_to_s_graph(>, V1, VL, V, Edges, G, [V-Edges|NGL]) :-
add_vertices_to_s_graph([V1|VL], G, NGL).
add_empty_vertices([], []).
add_empty_vertices([V|G], [V-[]|NG]) :-
add_empty_vertices(G, NG).
%! del_vertices(+Graph, +Vertices, -NewGraph) is det.
%
% Unify NewGraph with a new graph obtained by deleting the list of
% Vertices and all the edges that start from or go to a vertex in
% Vertices to the Graph. Example:
%
% ==
% ?- del_vertices([1-[3,5],2-[4],3-[],4-[5],5-[],6-[],7-[2,6],8-[]],
% [2,1],
% NL).
% NL = [3-[],4-[5],5-[],6-[],7-[6],8-[]]
% ==
%
% @compat Upto 5.6.48 the argument order was (+Vertices, +Graph,
% -NewGraph). Both YAP and SWI-Prolog have changed the argument
% order for compatibility with recent SICStus as well as
% consistency with del_edges/3.
del_vertices(Graph, Vertices, NewGraph) :-
sort(Vertices, V1), % JW: was msort
( V1 = []
-> Graph = NewGraph
; del_vertices(Graph, V1, V1, NewGraph)
).
del_vertices(G, [], V1, NG) :-
!,
del_remaining_edges_for_vertices(G, V1, NG).
del_vertices([], _, _, []).
del_vertices([V-Edges|G], [V0|Vs], V1, NG) :-
compare(Res, V, V0),
split_on_del_vertices(Res, V,Edges, [V0|Vs], NVs, V1, NG, NGr),
del_vertices(G, NVs, V1, NGr).
del_remaining_edges_for_vertices([], _, []).
del_remaining_edges_for_vertices([V0-Edges|G], V1, [V0-NEdges|NG]) :-
ord_subtract(Edges, V1, NEdges),
del_remaining_edges_for_vertices(G, V1, NG).
split_on_del_vertices(<, V, Edges, Vs, Vs, V1, [V-NEdges|NG], NG) :-
ord_subtract(Edges, V1, NEdges).
split_on_del_vertices(>, V, Edges, [_|Vs], Vs, V1, [V-NEdges|NG], NG) :-
ord_subtract(Edges, V1, NEdges).
split_on_del_vertices(=, _, _, [_|Vs], Vs, _, NG, NG).
%! add_edges(+Graph, +Edges, -NewGraph)
%
% Unify NewGraph with a new graph obtained by adding the list of Edges
% to Graph. Example:
%
% ```
% ?- add_edges([1-[3,5],2-[4],3-[],4-[5],
% 5-[],6-[],7-[],8-[]],
% [1-6,2-3,3-2,5-7,3-2,4-5],
% NL).
% NL = [1-[3,5,6], 2-[3,4], 3-[2], 4-[5],
% 5-[7], 6-[], 7-[], 8-[]]
% ```
add_edges(Graph, Edges, NewGraph) :-
p_to_s_graph(Edges, G1),
ugraph_union(Graph, G1, NewGraph).
%! ugraph_union(+Graph1, +Graph2, -NewGraph)
%
% NewGraph is the union of Graph1 and Graph2. Example:
%
% ```
% ?- ugraph_union([1-[2],2-[3]],[2-[4],3-[1,2,4]],L).
% L = [1-[2], 2-[3,4], 3-[1,2,4]]
% ```
ugraph_union(Set1, [], Set1) :- !.
ugraph_union([], Set2, Set2) :- !.
ugraph_union([Head1-E1|Tail1], [Head2-E2|Tail2], Union) :-
compare(Order, Head1, Head2),
ugraph_union(Order, Head1-E1, Tail1, Head2-E2, Tail2, Union).
ugraph_union(=, Head-E1, Tail1, _-E2, Tail2, [Head-Es|Union]) :-
ord_union(E1, E2, Es),
ugraph_union(Tail1, Tail2, Union).
ugraph_union(<, Head1, Tail1, Head2, Tail2, [Head1|Union]) :-
ugraph_union(Tail1, [Head2|Tail2], Union).
ugraph_union(>, Head1, Tail1, Head2, Tail2, [Head2|Union]) :-
ugraph_union([Head1|Tail1], Tail2, Union).
%! del_edges(+Graph, +Edges, -NewGraph)
%
% Unify NewGraph with a new graph obtained by removing the list of
% Edges from Graph. Notice that no vertices are deleted. Example:
%
% ```
% ?- del_edges([1-[3,5],2-[4],3-[],4-[5],5-[],6-[],7-[],8-[]],
% [1-6,2-3,3-2,5-7,3-2,4-5,1-3],
% NL).
% NL = [1-[5],2-[4],3-[],4-[],5-[],6-[],7-[],8-[]]
% ```
del_edges(Graph, Edges, NewGraph) :-
p_to_s_graph(Edges, G1),
graph_subtract(Graph, G1, NewGraph).
%! graph_subtract(+Set1, +Set2, ?Difference)
%
% Is based on ord_subtract
graph_subtract(Set1, [], Set1) :- !.
graph_subtract([], _, []).
graph_subtract([Head1-E1|Tail1], [Head2-E2|Tail2], Difference) :-
compare(Order, Head1, Head2),
graph_subtract(Order, Head1-E1, Tail1, Head2-E2, Tail2, Difference).
graph_subtract(=, H-E1, Tail1, _-E2, Tail2, [H-E|Difference]) :-
ord_subtract(E1,E2,E),
graph_subtract(Tail1, Tail2, Difference).
graph_subtract(<, Head1, Tail1, Head2, Tail2, [Head1|Difference]) :-
graph_subtract(Tail1, [Head2|Tail2], Difference).
graph_subtract(>, Head1, Tail1, _, Tail2, Difference) :-
graph_subtract([Head1|Tail1], Tail2, Difference).
%! edges(+Graph, -Edges)
%
% Unify Edges with all edges appearing in Graph. Example:
%
% ?- edges([1-[3,5],2-[4],3-[],4-[5],5-[]], L).
% L = [1-3, 1-5, 2-4, 4-5]
edges(Graph, Edges) :-
s_to_p_graph(Graph, Edges).
p_to_s_graph(P_Graph, S_Graph) :-
sort(P_Graph, EdgeSet),
p_to_s_vertices(EdgeSet, VertexBag),
sort(VertexBag, VertexSet),
p_to_s_group(VertexSet, EdgeSet, S_Graph).
p_to_s_vertices([], []).
p_to_s_vertices([A-Z|Edges], [A,Z|Vertices]) :-
p_to_s_vertices(Edges, Vertices).
p_to_s_group([], _, []).
p_to_s_group([Vertex|Vertices], EdgeSet, [Vertex-Neibs|G]) :-
p_to_s_group(EdgeSet, Vertex, Neibs, RestEdges),
p_to_s_group(Vertices, RestEdges, G).
p_to_s_group([V1-X|Edges], V2, [X|Neibs], RestEdges) :- V1 == V2,
!,
p_to_s_group(Edges, V2, Neibs, RestEdges).
p_to_s_group(Edges, _, [], Edges).
s_to_p_graph([], []) :- !.
s_to_p_graph([Vertex-Neibs|G], P_Graph) :-
s_to_p_graph(Neibs, Vertex, P_Graph, Rest_P_Graph),
s_to_p_graph(G, Rest_P_Graph).
s_to_p_graph([], _, P_Graph, P_Graph) :- !.
s_to_p_graph([Neib|Neibs], Vertex, [Vertex-Neib|P], Rest_P) :-
s_to_p_graph(Neibs, Vertex, P, Rest_P).
%! transitive_closure(+Graph, -Closure)
%
% Generate the graph Closure as the transitive closure of Graph.
% Example:
%
% ```
% ?- transitive_closure([1-[2,3],2-[4,5],4-[6]],L).
% L = [1-[2,3,4,5,6], 2-[4,5,6], 4-[6]]
% ```
transitive_closure(Graph, Closure) :-
warshall(Graph, Graph, Closure).
warshall([], Closure, Closure) :- !.
warshall([V-_|G], E, Closure) :-
memberchk(V-Y, E), % Y := E(v)
warshall(E, V, Y, NewE),
warshall(G, NewE, Closure).
warshall([X-Neibs|G], V, Y, [X-NewNeibs|NewG]) :-
memberchk(V, Neibs),
!,
ord_union(Neibs, Y, NewNeibs),
warshall(G, V, Y, NewG).
warshall([X-Neibs|G], V, Y, [X-Neibs|NewG]) :-
!,
warshall(G, V, Y, NewG).
warshall([], _, _, []).
%! transpose_ugraph(Graph, NewGraph) is det.
%
% Unify NewGraph with a new graph obtained from Graph by replacing
% all edges of the form V1-V2 by edges of the form V2-V1. The cost
% is O(|V|*log(|V|)). Notice that an undirected graph is its own
% transpose. Example:
%
% ==
% ?- transpose([1-[3,5],2-[4],3-[],4-[5],
% 5-[],6-[],7-[],8-[]], NL).
% NL = [1-[],2-[],3-[1],4-[2],5-[1,4],6-[],7-[],8-[]]
% ==
%
% @compat This predicate used to be known as transpose/2.
% Following SICStus 4, we reserve transpose/2 for matrix
% transposition and renamed ugraph transposition to
% transpose_ugraph/2.
transpose_ugraph(Graph, NewGraph) :-
edges(Graph, Edges),
vertices(Graph, Vertices),
flip_edges(Edges, TransposedEdges),
vertices_edges_to_ugraph(Vertices, TransposedEdges, NewGraph).
flip_edges([], []).
flip_edges([Key-Val|Pairs], [Val-Key|Flipped]) :-
flip_edges(Pairs, Flipped).
%! compose(+LeftGraph, +RightGraph, -NewGraph)
%
% Compose NewGraph by connecting the _drains_ of LeftGraph to the
% _sources_ of RightGraph. Example:
%
% ?- compose([1-[2],2-[3]],[2-[4],3-[1,2,4]],L).
% L = [1-[4], 2-[1,2,4], 3-[]]
compose(G1, G2, Composition) :-
vertices(G1, V1),
vertices(G2, V2),
ord_union(V1, V2, V),
compose(V, G1, G2, Composition).
compose([], _, _, []) :- !.
compose([Vertex|Vertices], [Vertex-Neibs|G1], G2,
[Vertex-Comp|Composition]) :-
!,
compose1(Neibs, G2, [], Comp),
compose(Vertices, G1, G2, Composition).
compose([Vertex|Vertices], G1, G2, [Vertex-[]|Composition]) :-
compose(Vertices, G1, G2, Composition).
compose1([V1|Vs1], [V2-N2|G2], SoFar, Comp) :-
compare(Rel, V1, V2),
!,
compose1(Rel, V1, Vs1, V2, N2, G2, SoFar, Comp).
compose1(_, _, Comp, Comp).
compose1(<, _, Vs1, V2, N2, G2, SoFar, Comp) :-
!,
compose1(Vs1, [V2-N2|G2], SoFar, Comp).
compose1(>, V1, Vs1, _, _, G2, SoFar, Comp) :-
!,
compose1([V1|Vs1], G2, SoFar, Comp).
compose1(=, V1, Vs1, V1, N2, G2, SoFar, Comp) :-
ord_union(N2, SoFar, Next),
compose1(Vs1, G2, Next, Comp).
%! top_sort(+Graph, -Sorted) is semidet.
%! top_sort(+Graph, -Sorted, ?Tail) is semidet.
%
% Sorted is a topological sorted list of nodes in Graph. A
% toplogical sort is possible if the graph is connected and
% acyclic. In the example we show how topological sorting works
% for a linear graph:
%
% ==
% ?- top_sort([1-[2], 2-[3], 3-[]], L).
% L = [1, 2, 3]
% ==
%
% The predicate top_sort/3 is a difference list version of
% top_sort/2.
top_sort(Graph, Sorted) :-
vertices_and_zeros(Graph, Vertices, Counts0),
count_edges(Graph, Vertices, Counts0, Counts1),
select_zeros(Counts1, Vertices, Zeros),
top_sort(Zeros, Sorted, Graph, Vertices, Counts1).
top_sort(Graph, Sorted0, Sorted) :-
vertices_and_zeros(Graph, Vertices, Counts0),
count_edges(Graph, Vertices, Counts0, Counts1),
select_zeros(Counts1, Vertices, Zeros),
top_sort(Zeros, Sorted, Sorted0, Graph, Vertices, Counts1).
vertices_and_zeros([], [], []) :- !.
vertices_and_zeros([Vertex-_|Graph], [Vertex|Vertices], [0|Zeros]) :-
vertices_and_zeros(Graph, Vertices, Zeros).
count_edges([], _, Counts, Counts) :- !.
count_edges([_-Neibs|Graph], Vertices, Counts0, Counts2) :-
incr_list(Neibs, Vertices, Counts0, Counts1),
count_edges(Graph, Vertices, Counts1, Counts2).
incr_list([], _, Counts, Counts) :- !.
incr_list([V1|Neibs], [V2|Vertices], [M|Counts0], [N|Counts1]) :-
V1 == V2,
!,
N is M+1,
incr_list(Neibs, Vertices, Counts0, Counts1).
incr_list(Neibs, [_|Vertices], [N|Counts0], [N|Counts1]) :-
incr_list(Neibs, Vertices, Counts0, Counts1).
select_zeros([], [], []) :- !.
select_zeros([0|Counts], [Vertex|Vertices], [Vertex|Zeros]) :-
!,
select_zeros(Counts, Vertices, Zeros).
select_zeros([_|Counts], [_|Vertices], Zeros) :-
select_zeros(Counts, Vertices, Zeros).
top_sort([], [], Graph, _, Counts) :-
!,
vertices_and_zeros(Graph, _, Counts).
top_sort([Zero|Zeros], [Zero|Sorted], Graph, Vertices, Counts1) :-
graph_memberchk(Zero-Neibs, Graph),
decr_list(Neibs, Vertices, Counts1, Counts2, Zeros, NewZeros),
top_sort(NewZeros, Sorted, Graph, Vertices, Counts2).
top_sort([], Sorted0, Sorted0, Graph, _, Counts) :-
!,
vertices_and_zeros(Graph, _, Counts).
top_sort([Zero|Zeros], [Zero|Sorted], Sorted0, Graph, Vertices, Counts1) :-
graph_memberchk(Zero-Neibs, Graph),
decr_list(Neibs, Vertices, Counts1, Counts2, Zeros, NewZeros),
top_sort(NewZeros, Sorted, Sorted0, Graph, Vertices, Counts2).
graph_memberchk(Element1-Edges, [Element2-Edges2|_]) :-
Element1 == Element2,
!,
Edges = Edges2.
graph_memberchk(Element, [_|Rest]) :-
graph_memberchk(Element, Rest).
decr_list([], _, Counts, Counts, Zeros, Zeros) :- !.
decr_list([V1|Neibs], [V2|Vertices], [1|Counts1], [0|Counts2], Zi, Zo) :-
V1 == V2,
!,
decr_list(Neibs, Vertices, Counts1, Counts2, [V2|Zi], Zo).
decr_list([V1|Neibs], [V2|Vertices], [N|Counts1], [M|Counts2], Zi, Zo) :-
V1 == V2,
!,
M is N-1,
decr_list(Neibs, Vertices, Counts1, Counts2, Zi, Zo).
decr_list(Neibs, [_|Vertices], [N|Counts1], [N|Counts2], Zi, Zo) :-
decr_list(Neibs, Vertices, Counts1, Counts2, Zi, Zo).
%! neighbors(+Vertex, +Graph, -Neigbours) is det.
%! neighbours(+Vertex, +Graph, -Neigbours) is det.
%
% Neigbours is a sorted list of the neighbours of Vertex in Graph.
% Example:
%
% ```
% ?- neighbours(4,[1-[3,5],2-[4],3-[],
% 4-[1,2,7,5],5-[],6-[],7-[],8-[]], NL).
% NL = [1,2,7,5]
% ```
neighbors(Vertex, Graph, Neig) :-
neighbours(Vertex, Graph, Neig).
neighbours(V,[V0-Neig|_],Neig) :-
V == V0,
!.
neighbours(V,[_|G],Neig) :-
neighbours(V,G,Neig).
%! connect_ugraph(+UGraphIn, -Start, -UGraphOut) is det.
%
% Adds Start as an additional vertex that is connected to all vertices
% in UGraphIn. This can be used to create an topological sort for a
% not connected graph. Start is before any vertex in UGraphIn in the
% standard order of terms. No vertex in UGraphIn can be a variable.
%
% Can be used to order a not-connected graph as follows:
%
% ```
% top_sort_unconnected(Graph, Vertices) :-
% ( top_sort(Graph, Vertices)
% -> true
% ; connect_ugraph(Graph, Start, Connected),
% top_sort(Connected, Ordered0),
% Ordered0 = [Start|Vertices]
% ).
% ```
connect_ugraph([], 0, []) :- !.
connect_ugraph(Graph, Start, [Start-Vertices|Graph]) :-
vertices(Graph, Vertices),
Vertices = [First|_],
before(First, Start).
%! before(+Term, -Before) is det.
%
% Unify Before to a term that comes before Term in the standard
% order of terms.
%
% @error instantiation_error if Term is unbound.
before(X, _) :-
var(X),
!,
instantiation_error(X).
before(Number, Start) :-
number(Number),
!,
Start is Number - 1.
before(_, 0).
%! complement(+UGraphIn, -UGraphOut)
%
% UGraphOut is a ugraph with an edge between all vertices that are
% _not_ connected in UGraphIn and all edges from UGraphIn removed.
% Example:
%
% ```
% ?- complement([1-[3,5],2-[4],3-[],
% 4-[1,2,7,5],5-[],6-[],7-[],8-[]], NL).
% NL = [1-[2,4,6,7,8],2-[1,3,5,6,7,8],3-[1,2,4,5,6,7,8],
% 4-[3,5,6,8],5-[1,2,3,4,6,7,8],6-[1,2,3,4,5,7,8],
% 7-[1,2,3,4,5,6,8],8-[1,2,3,4,5,6,7]]
% ```
%
% @tbd Simple two-step algorithm. You could be smarter, I suppose.
complement(G, NG) :-
vertices(G,Vs),
complement(G,Vs,NG).
complement([], _, []).
complement([V-Ns|G], Vs, [V-INs|NG]) :-
ord_add_element(Ns,V,Ns1),
ord_subtract(Vs,Ns1,INs),
complement(G, Vs, NG).
%! reachable(+Vertex, +UGraph, -Vertices)
%
% True when Vertices is an ordered set of vertices reachable in
% UGraph, including Vertex. Example:
%
% ?- reachable(1,[1-[3,5],2-[4],3-[],4-[5],5-[]],V).
% V = [1, 3, 5]
reachable(N, G, Rs) :-
reachable([N], G, [N], Rs).
reachable([], _, Rs, Rs).
reachable([N|Ns], G, Rs0, RsF) :-
neighbours(N, G, Nei),
ord_union(Rs0, Nei, Rs1, D),
append(Ns, D, Nsi),
reachable(Nsi, G, Rs1, RsF).

View File

@@ -4,9 +4,9 @@
This library provides reasoning about UUID (only version 4 right now).
There are three predicates:
* uuidv4/1, to generate a new UUIDv4
* uuidv4_string/1, to generate a new UUIDv4 in string hex representation
* uuidv4_string/1, to generate a new UUIDv4 in string hex representation
* uuid_string/2, to converte between UUID list of bytes and UUID hex representation
Examples:
?- uuidv4(X).
X = [42,147,248,242,117,196,79,2,129,159|...].
@@ -30,7 +30,7 @@
:- use_module(library(dcgs)).
:- use_module(library(lists)).
/*
/*
An UUID is made of 16 bytes, composed of 5 sections:
time_low - 4
time_mid - 2

View File

@@ -1,4 +1,3 @@
:- module(loader, [consult/1,
expand_goal/3,
expand_term/2,
@@ -90,18 +89,22 @@ unload_evacuable(Evacuable) :-
run_initialization_goals(Module) :-
( predicate_property(Module:'$initialization_goals'(_), dynamic) ->
% FIXME: failing here. also, see add_module.
findall(Module:Goal, '$call'(builtins:retract(Module:'$initialization_goals'(Goal))), Goals),
abolish(Module:'$initialization_goals'/1),
( maplist(Module:call, Goals) ->
true
; %% initialization goals can fail without thwarting the load.
write('Warning: initialization/1 failed for: '),
writeq(maplist(Module:call, Goals)),
nl
)
maplist(loader:success_or_warning, Goals)
; true
).
success_or_warning(Goal) :-
( call(Goal) ->
true
; %% initialization goals can fail without thwarting the load.
write('Warning: initialization/1 failed for: '),
writeq(Goal),
nl
).
run_initialization_goals :-
prolog_load_context(module, Module),
run_initialization_goals(user),
@@ -258,8 +261,8 @@ expand_term_goals(Terms0, Terms) :-
Terms = (Module:Head2 :- Body1)
; 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),
Terms = (Head1 :- Body1)
)
@@ -316,6 +319,7 @@ compile_dispatch(user:goal_expansion(Term, Terms), Evacuable) :-
compile_dispatch((user:goal_expansion(Term, Terms) :- Body), Evacuable) :-
'$add_goal_expansion_clause'(user, (goal_expansion(Term, Terms) :- Body), Evacuable).
remove_module(Module, Evacuable) :-
( nonvar(Module),
Module = library(ModuleName),
@@ -508,7 +512,8 @@ open_file(Path, Stream) :-
; catch(open(Path, read, Stream),
error(existence_error(source_sink, _), _),
( atom_concat(Path, '.pl', ExtendedPath),
open(ExtendedPath, read, Stream) )
open(ExtendedPath, read, Stream)
)
)
).
@@ -540,15 +545,15 @@ use_module(Module, Exports, Evacuable) :-
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) :-
'$cpp_built_in_property'(Name, Arity).
'$built_in_property'(Name, Arity).
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) :-
'$cpp_multifile_property'(Module, Name, Arity).
'$multifile_property'(Module, Name, Arity).
check_predicate_property(discontiguous, Module, Name, Arity, discontiguous) :-
'$cpp_discontiguous_property'(Module, Name, Arity).
'$discontiguous_property'(Module, Name, Arity).
@@ -573,15 +578,13 @@ predicate_property(Callable, Property) :-
atom(Module),
nonvar(Callable0) ->
functor(Callable0, Name, Arity),
( atom(Name),
Name \== [] ->
( atom(Name) ->
extract_predicate_property(Property, PropertyType),
check_predicate_property(PropertyType, Module, Name, Arity, Property)
; type_error(callable, Callable0, predicate_property/2)
)
; functor(Callable, Name, Arity),
( atom(Name),
Name \== [] ->
( atom(Name) ->
extract_predicate_property(Property, PropertyType),
load_context(Module),
check_predicate_property(PropertyType, Module, Name, Arity, Property)
@@ -624,11 +627,16 @@ expand_subgoal(UnexpandedGoals, MS, Module, ExpandedGoals, HeadVars) :-
).
expand_module_name(ESG0, M, ESG) :-
expand_module_name(ESG0, MS, M, ESG) :-
( var(ESG0) ->
ESG = M:ESG0
; ESG0 = _:_ ->
ESG = ESG0
; functor(ESG0, F, A0),
A is A0 + MS,
functor(EESG0, F, A),
predicate_property(EESG0, built_in) ->
ESG = ESG0
; ESG = M:ESG0
).
@@ -641,7 +649,7 @@ expand_meta_predicate_subgoals([SG | SGs], [MS | MSs], M, [ESG | ESGs], HeadVars
pairs:same_key(SG, HeadVars, [_|_], _) ->
expand_subgoal(SG, MS, M, ESG, HeadVars)
; expand_subgoal(SG, MS, M, ESG0, HeadVars),
expand_module_name(ESG0, M, ESG)
expand_module_name(ESG0, MS, M, ESG)
),
expand_meta_predicate_subgoals(SGs, MSs, M, ESGs, HeadVars)
; ESG = SG,
@@ -656,14 +664,17 @@ expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars) :-
( GoalFunctor == (:),
SubGoals = [M, SubGoal] ->
expand_module_names(SubGoal, MetaSpecs, M, ExpandedSubGoal, HeadVars),
ExpandedGoals = M:ExpandedSubGoal
expand_module_name(ExpandedSubGoal, 0, M, ExpandedGoals)
; expand_meta_predicate_subgoals(SubGoals, MetaSpecs, Module, ExpandedGoalList, HeadVars),
ExpandedGoals =.. [GoalFunctor | ExpandedGoalList]
).
expand_goal(UnexpandedGoals, Module, ExpandedGoals) :-
expand_goal(UnexpandedGoals, Module, ExpandedGoals, []),
% if a goal isn't callable, defer to call/N to report the error.
catch('$call'(loader:expand_goal(UnexpandedGoals, Module, ExpandedGoals, [])),
error(type_error(callable, _), _),
'$call'(UnexpandedGoals = ExpandedGoals)),
!.
expand_goal_cases((Goal0, Goals0), Module, ExpandedGoals, HeadVars) :-
@@ -705,32 +716,29 @@ 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) :-
( var(Goals0) ->
Goals1 =.. [Functor, Goals0, Hole]
; ( Goals0 = [G | Gs] ->
( Gs == [] ->
Goals1 =.. [Functor, G, Hole]
; Goals1 =.. [Functor, G, Goals2],
thread_goals(Gs, Goals2, Hole, Functor)
)
; Goals1 =.. [Functor, Goals0, Hole]
; Goals0 = [G | Gs] ->
( Gs == [] ->
Goals1 =.. [Functor, G, Hole]
; Goals1 =.. [Functor, G, Goals2],
thread_goals(Gs, Goals2, Hole, Functor)
)
; Goals1 =.. [Functor, Goals0, Hole]
).
thread_goals(Goals0, Goals1, Functor) :-
( var(Goals0) ->
Goals0 = Goals1
; Goals0 = [G | Gs] ->
( Gs = [] ->
Goals1 = G
; Goals1 =.. [Functor, G, Goals2],
thread_goals(Gs, Goals2, Functor)
)
; Goals1 = Goals0
).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
@@ -773,12 +781,14 @@ call_clause('$call'(G), G0) :-
instantiation_error(call/1)
; G = M:G1,
!,
callable(G1),
functor(G1, F, _),
atom(F),
atom(M),
F \== [],
G0 = M:G1
; !,
callable(G),
functor(G, F, _),
atom(F),
F \== [],
@@ -788,6 +798,7 @@ call_clause('$call'(G), G0) :-
call_clause(G, G0) :-
strip_module(G, M, G1),
callable(G1),
functor(G1, F, _),
atom(F),
F \== [],
@@ -818,6 +829,7 @@ call_clause('$call'(G1), Args, N, G0) :-
F \== [],
append(As, Args, As1),
G3 =.. [F | As1],
callable(G3),
G0 = M:G3
; !,
G1 =.. [F | As],
@@ -826,6 +838,7 @@ call_clause('$call'(G1), Args, N, G0) :-
load_context(M),
append(As, Args, As1),
G2 =.. [F | As1],
callable(G2),
G0 = M:G2
).
@@ -840,6 +853,7 @@ call_clause(G, Args, _, G0) :-
),
append(As, Args, As1),
G2 =.. [F | As1],
callable(G2),
expand_goal(call(M:G2), M, call(G0)).

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +1,23 @@
use crate::heap_iter::*;
use crate::machine::*;
use prolog_parser::temp_v;
use crate::parser::ast::*;
use crate::temp_v;
use crate::types::*;
use indexmap::IndexSet;
use std::cmp::Ordering;
use std::vec::IntoIter;
pub(super) type Bindings = Vec<(usize, Addr)>;
pub(super) type Bindings = Vec<(usize, HeapCellValue)>;
#[derive(Debug)]
pub(super) struct AttrVarInitializer {
pub(super) attr_var_queue: Vec<usize>,
pub(super) bindings: Bindings,
pub(super) cp: LocalCodePtr,
pub(super) instigating_p: LocalCodePtr,
pub(super) p: usize,
pub(super) cp: usize,
// pub(super) instigating_p: usize,
pub(super) verify_attrs_loc: usize,
}
@@ -23,8 +26,8 @@ impl AttrVarInitializer {
AttrVarInitializer {
attr_var_queue: vec![],
bindings: vec![],
instigating_p: LocalCodePtr::default(),
cp: LocalCodePtr::default(),
p: 0,
cp: 0,
verify_attrs_loc,
}
}
@@ -37,44 +40,39 @@ impl AttrVarInitializer {
}
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() {
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.cp = self.cp;
} else {
self.attr_var_init.cp = self.p.local() + 1;
}
self.attr_var_init.p = self.p;
self.attr_var_init.cp = self.cp;
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));
}
fn populate_var_and_value_lists(&mut self) -> (Addr, Addr) {
fn populate_var_and_value_lists(&mut self) -> (HeapCellValue, HeapCellValue) {
let iter = self
.attr_var_init
.bindings
.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
.attr_var_init
.bindings
.drain(0..)
.map(|(_, addr)| HeapCellValue::Addr(addr));
let iter = self.attr_var_init.bindings.drain(0..).map(|(_, ref v)| *v);
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)
}
fn verify_attributes(&mut self) {
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();
@@ -83,69 +81,104 @@ impl MachineState {
self[temp_v!(2)] = value_list_addr;
}
pub(super) fn gather_attr_vars_created_since(&self, b: usize) -> IntoIter<Addr> {
let mut attr_vars: Vec<_> = self.attr_var_init.attr_var_queue[b..]
.iter()
.filter_map(|h| match self.store(self.deref(Addr::HeapCell(*h))) {
Addr::AttrVar(h) => Some(Addr::AttrVar(h)),
_ => None,
})
.collect();
pub(super) fn gather_attr_vars_created_since(&mut self, b: usize) -> IntoIter<HeapCellValue> {
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()
.filter_map(|h| {
read_heap_cell!(self.store(self.deref(heap_loc_as_cell!(*h))),
(HeapCellValueTag::AttrVar, h) => {
Some(attr_var_as_cell!(h))
}
_ => {
None
}
)
})
.collect()
};
attr_vars
.sort_unstable_by(|a1, a2| self.compare_term_test(a1, a2).unwrap_or(Ordering::Less));
attr_vars.sort_unstable_by(|a1, a2| {
compare_term_test!(self, *a1, *a2).unwrap_or(Ordering::Less)
});
self.term_dedup(&mut attr_vars);
attr_vars.dedup();
attr_vars.into_iter()
}
pub(super) fn verify_attr_interrupt(&mut self, p: usize) {
self.allocate(self.num_of_args + 2);
pub(super) fn verify_attr_interrupt(&mut self, p: usize, arity: usize) {
self.allocate(arity + 3);
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 {
self.stack.index_and_frame_mut(e)[i] = self[RegType::Temp(i)];
for i in 1..arity + 1 {
and_frame[i] = self.registers[i];
}
self.stack.index_and_frame_mut(e)[self.num_of_args + 1] = Addr::CutPoint(self.b0);
self.stack.index_and_frame_mut(e)[self.num_of_args + 2] = Addr::Usize(self.num_of_args);
and_frame[arity + 1] =
fixnum_as_cell!(Fixnum::build_with(self.b0 as i64));
and_frame[arity + 2] =
fixnum_as_cell!(Fixnum::build_with(self.num_of_args as i64));
and_frame[arity + 3] =
fixnum_as_cell!(Fixnum::build_with(self.attr_var_init.cp as i64));
self.verify_attributes();
self.num_of_args = 2;
self.num_of_args = 3;
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_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() {
if let HeapCellValue::Addr(Addr::AttrVar(h)) = self.heap.index_addr(&addr).as_ref() {
if seen_set.contains(h) {
continue;
while let Some(value) = iter.next() {
read_heap_cell!(value,
(HeapCellValueTag::AttrVar, h) => {
if seen_set.contains(&h) {
continue;
}
let value = unmark_cell_bits!(value);
seen_vars.push(value);
seen_set.insert(h);
let mut l = h + 1;
// let mut list_elements = vec![];
// let iter_stack_len = iter.stack_len();
loop {
read_heap_cell!(iter.heap[l],
(HeapCellValueTag::Lis) => {
iter.push_stack(l);
// l = elem + 1;
break;
}
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
if h == l {
break;
} else {
l = h;
}
}
_ => {
break;
}
)
}
// iter.stack_slice_from(iter_stack_len ..).reverse();
}
seen_vars.push(addr);
seen_set.insert(*h);
let mut l = h + 1;
let mut list_elements = vec![];
while let Addr::Lis(elem) = self.store(self.deref(Addr::HeapCell(l))) {
list_elements.push(self.heap[elem].as_addr(elem));
l = elem + 1;
_ => {
}
for element in list_elements.into_iter().rev() {
iter.stack().push(element);
}
}
);
}
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;
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 {
&Line::Choice(ChoiceInstruction::TryMeElse(offset)) if offset > 0 => {
&Instruction::TryMeElse(offset) if offset > 0 => {
stack.push(index + offset);
}
&Line::Choice(ChoiceInstruction::DefaultRetryMeElse(offset))
| &Line::Choice(ChoiceInstruction::RetryMeElse(offset))
&Instruction::DefaultRetryMeElse(offset) |
&Instruction::RetryMeElse(offset)
if offset > 0 =>
{
stack.push(index + offset);
}
&Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(offset)))
&Instruction::DynamicElse(_, _, NextOrFail::Next(offset))
if offset > 0 =>
{
stack.push(index + offset);
}
&Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(offset)))
&Instruction::DynamicInternalElse(_, _, NextOrFail::Next(offset))
if offset > 0 =>
{
stack.push(index + offset);
}
&Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => {
&Instruction::JmpByCall(_, offset, _) => {
stack.push(index + offset);
}
&Line::Control(ControlInstruction::JmpBy(_, offset, _, true)) => {
&Instruction::JmpByExecute(_, offset, _) => {
stack.push(index + offset);
return true;
}
&Line::Control(ControlInstruction::Proceed)
| &Line::Control(ControlInstruction::CallClause(_, _, _, true, _)) => {
&Instruction::Proceed => {
return true;
}
&Line::Control(ControlInstruction::RevJmpBy(offset)) => {
&Instruction::RevJmpBy(offset) => {
if offset > 0 {
stack.push(index - offset);
} else {
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
* 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 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::types::*;
use std::mem;
use std::ops::IndexMut;
@@ -7,20 +8,24 @@ use std::ops::IndexMut;
type Trail = Vec<(Ref, HeapCellValue)>;
#[derive(Debug, Clone, Copy)]
pub(crate) enum AttrVarPolicy {
pub enum AttrVarPolicy {
DeepCopy,
StripAttributes,
}
pub(crate) trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
fn deref(&self, val: Addr) -> Addr;
fn push(&mut self, val: HeapCellValue);
pub trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
fn store(&self, value: HeapCellValue) -> HeapCellValue;
fn deref(&self, value: HeapCellValue) -> HeapCellValue;
fn push(&mut self, value: HeapCellValue);
fn stack(&mut self) -> &mut Stack;
fn store(&self, val: Addr) -> Addr;
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);
copy_term_state.copy_term_impl(addr);
}
@@ -47,50 +52,51 @@ impl<T: CopierTarget> CopyTermState<T> {
#[inline]
fn value_at_scan(&mut self) -> &mut HeapCellValue {
let scan = self.scan;
&mut self.target[scan]
&mut self.target[self.scan]
}
fn trail_list_cell(&mut self, addr: usize, threshold: usize) {
let trail_item = mem::replace(
&mut self.target[addr],
HeapCellValue::Addr(Addr::Lis(threshold)),
);
self.trail.push((Ref::HeapCell(addr), trail_item));
let trail_item = mem::replace(&mut self.target[addr], list_loc_as_cell!(threshold));
self.trail.push((Ref::heap_cell(addr), trail_item));
}
fn copy_list(&mut self, addr: usize) {
for offset in 0..2 {
if let Addr::Lis(h) = self.target[addr + offset].as_addr(addr + offset) {
if h >= self.old_h {
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(h));
self.scan += 1;
read_heap_cell!(self.target[addr + offset],
(HeapCellValueTag::Lis, h) => {
if h >= self.old_h {
*self.value_at_scan() = list_loc_as_cell!(h);
self.scan += 1;
return;
return;
}
}
}
_ => {
}
)
}
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 {
let hcv = self.target[addr + i].context_free_clone();
let hcv = self.target[addr + i];
self.target.push(hcv);
}
let cdr = self
.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);
} 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);
}
}
@@ -98,187 +104,190 @@ impl<T: CopierTarget> CopyTermState<T> {
self.scan += 1;
}
fn copy_partial_string(&mut self, addr: usize, n: usize) {
if let &HeapCellValue::Addr(Addr::PStrLocation(h, _)) = &self.target[addr] {
if h >= self.old_h {
*self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(h, n));
fn copy_partial_string(&mut self, scan_tag: HeapCellValueTag, pstr_loc: usize) {
read_heap_cell!(self.target[pstr_loc],
(HeapCellValueTag::PStrLoc, h) => {
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;
return;
}
}
_ => {}
);
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;
let (pstr, has_tail) = match &self.target[addr] {
&HeapCellValue::PartialString(ref pstr, has_tail) => {
(pstr.clone_from_offset(0), has_tail)
}
_ => {
unreachable!()
}
};
self.target
.push(HeapCellValue::PartialString(pstr, has_tail));
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));
}
let trail_item = mem::replace(&mut self.target[pstr_loc], replacement);
self.trail.push((Ref::heap_cell(pstr_loc), trail_item));
}
fn reinstantiate_var(&mut self, addr: Addr, frontier: usize) {
match addr {
Addr::HeapCell(h) => {
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier));
self.target[h] = HeapCellValue::Addr(Addr::HeapCell(frontier));
fn reinstantiate_var(&mut self, addr: HeapCellValue, frontier: usize) {
read_heap_cell!(addr,
(HeapCellValueTag::Var, h) => {
self.target[frontier] = heap_loc_as_cell!(frontier);
self.target[h] = heap_loc_as_cell!(frontier);
self.trail
.push((Ref::HeapCell(h), HeapCellValue::Addr(Addr::HeapCell(h))));
self.trail.push((Ref::heap_cell(h), heap_loc_as_cell!(h)));
}
Addr::StackCell(fr, sc) => {
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier));
self.target.stack().index_and_frame_mut(fr)[sc] = Addr::HeapCell(frontier);
(HeapCellValueTag::StackVar, s) => {
self.target[frontier] = heap_loc_as_cell!(frontier);
self.target.stack()[s] = heap_loc_as_cell!(frontier);
self.trail.push((
Ref::StackCell(fr, sc),
HeapCellValue::Addr(Addr::StackCell(fr, sc)),
));
self.trail.push((Ref::stack_cell(s), stack_loc_as_cell!(s)));
}
Addr::AttrVar(h) => {
(HeapCellValueTag::AttrVar, h) => {
let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
self.target.threshold()
} else {
frontier
};
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(threshold));
self.target[h] = HeapCellValue::Addr(Addr::HeapCell(threshold));
self.target[frontier] = heap_loc_as_cell!(threshold);
self.target[h] = heap_loc_as_cell!(threshold);
self.trail
.push((Ref::AttrVar(h), HeapCellValue::Addr(Addr::AttrVar(h))));
self.trail.push((Ref::attr_var(h), attr_var_as_cell!(h)));
if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
self.target
.push(HeapCellValue::Addr(Addr::AttrVar(threshold)));
self.target.push(attr_var_as_cell!(threshold));
let list_val = self.target[h + 1].context_free_clone();
let list_val = self.target[h + 1];
self.target.push(list_val);
}
}
_ => {
unreachable!()
}
}
);
}
fn copy_var(&mut self, addr: Addr) {
let rd = self.target.store(self.target.deref(addr));
fn copy_var(&mut self, addr: HeapCellValue) {
let rd = self.target.deref(addr);
let ra = self.target.store(rd);
match rd {
Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => {
*self.value_at_scan() = HeapCellValue::Addr(rd);
self.scan += 1;
}
_ if addr == rd => {
self.reinstantiate_var(addr, self.scan);
self.scan += 1;
}
_ => {
*self.value_at_scan() = HeapCellValue::Addr(rd);
read_heap_cell!(ra,
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
if h >= self.old_h {
*self.value_at_scan() = ra;
self.scan += 1;
return;
}
}
_ => {}
);
if rd == ra {
self.reinstantiate_var(ra, self.scan);
self.scan += 1;
} else {
*self.value_at_scan() = ra;
}
}
fn copy_structure(&mut self, addr: usize) {
match self.target[addr].context_free_clone() {
HeapCellValue::NamedStr(arity, name, fixity) => {
read_heap_cell!(self.target[addr],
(HeapCellValueTag::Atom, (name, arity)) => {
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(
&mut self.target[addr],
HeapCellValue::Addr(Addr::Str(threshold)),
str_loc_as_cell!(threshold),
);
self.trail.push((Ref::HeapCell(addr), trail_item));
self.target
.push(HeapCellValue::NamedStr(arity, name, fixity));
self.trail.push((Ref::heap_cell(addr), trail_item));
self.target.push(atom_as_cell!(name, 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);
}
}
HeapCellValue::Addr(Addr::Str(addr)) => {
*self.value_at_scan() = HeapCellValue::Addr(Addr::Str(addr))
(HeapCellValueTag::Str, h) => {
*self.value_at_scan() = str_loc_as_cell!(h);
}
_ => {
unreachable!()
}
}
);
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.target.push(HeapCellValue::Addr(addr));
self.target.push(addr);
while self.scan < self.target.threshold() {
match self.value_at_scan() {
&mut HeapCellValue::Addr(addr) => match addr {
Addr::Con(h) => {
let addr = self.target[h].as_addr(h);
let addr = *self.value_at_scan();
if addr == Addr::Con(h) {
*self.value_at_scan() = self.target[h].context_free_clone();
} else {
*self.value_at_scan() = HeapCellValue::Addr(addr);
}
}
Addr::Lis(h) => {
if h >= self.old_h {
self.scan += 1;
} else {
self.copy_list(h);
}
}
addr @ Addr::AttrVar(_)
| addr @ Addr::HeapCell(_)
| addr @ Addr::StackCell(..) => {
self.copy_var(addr);
}
Addr::Str(addr) => {
self.copy_structure(addr);
}
Addr::PStrLocation(addr, n) => {
self.copy_partial_string(addr, n);
}
Addr::Stream(h) => {
*self.value_at_scan() = self.target[h].context_free_clone();
}
_ => {
read_heap_cell!(addr,
(HeapCellValueTag::Lis, h) => {
if h >= self.old_h {
self.scan += 1;
} else {
self.copy_list(h);
}
},
}
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var) => {
self.copy_var(addr);
}
(HeapCellValueTag::Str, h) => {
self.copy_structure(h);
}
(HeapCellValueTag::PStrLoc | HeapCellValueTag::PStrOffset, pstr_loc) => {
self.copy_partial_string(addr.get_tag(), pstr_loc);
}
_ => {
self.scan += 1;
}
}
);
}
self.unwind_trail();
@@ -286,12 +295,117 @@ impl<T: CopierTarget> CopyTermState<T> {
fn unwind_trail(&mut self) {
for (r, value) in self.trail.drain(0..) {
match r {
Ref::AttrVar(h) | Ref::HeapCell(h) => self.target[h] = value,
Ref::StackCell(fr, sc) => {
self.target.stack().index_and_frame_mut(fr)[sc] = value.as_addr(0)
}
let index = r.get_value() as usize;
match r.get_tag() {
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));
}
}

4886
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,462 +1,282 @@
use core::marker::PhantomData;
use prolog_parser::ast::Constant;
use crate::machine::machine_indices::*;
use crate::arena::*;
use crate::atom_table::*;
use crate::forms::*;
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::mem;
use std::ops::{Index, IndexMut};
use std::ptr;
#[derive(Debug)]
pub(crate) struct StandardHeapTraits {}
pub(crate) type Heap = Vec<HeapCellValue>;
impl RawBlockTraits for StandardHeapTraits {
impl From<Literal> for HeapCellValue {
#[inline]
fn init_size() -> usize {
256 * mem::size_of::<HeapCellValue>()
}
#[inline]
fn align() -> usize {
mem::align_of::<HeapCellValue>()
}
}
#[derive(Debug)]
pub(crate) struct HeapTemplate<T: RawBlockTraits> {
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 {
None
fn from(literal: Literal) -> Self {
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) => {
typed_arena_ptr_as_cell!(bigint_ptr)
}
Literal::Float(f) => HeapCellValue::from(f),
Literal::String(s) => {
if s == atom!("") {
empty_list_as_cell!()
} else {
string_as_cstr_cell!(s)
}
}
}
}
}
#[derive(Debug)]
pub(crate) struct HeapIter<'a, T: RawBlockTraits> {
offset: usize,
buf: &'a RawBlock<T>,
}
impl TryFrom<HeapCellValue> for Literal {
type Error = ();
impl<'a, T: RawBlockTraits> HeapIter<'a, T> {
pub(crate) fn new(buf: &'a RawBlock<T>, offset: usize) -> Self {
HeapIter { buf, offset }
fn try_from(value: HeapCellValue) -> Result<Literal, ()> {
read_heap_cell!(value,
(HeapCellValueTag::Atom, (name, arity)) => {
if arity == 0 {
Ok(Literal::Atom(name))
} else {
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(())
}
)
}
}
impl<'a, T: RawBlockTraits> Iterator for HeapIter<'a, T> {
type Item = &'a HeapCellValue;
// 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
}
);
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 as *const _)) }
} else {
None
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)]
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() {
println!("{} : {}", h + index, term);
println!("{} : {:?}", h + index, term);
}
}
#[derive(Debug)]
pub(crate) struct HeapIterMut<'a, T: RawBlockTraits> {
offset: usize,
buf: &'a mut RawBlock<T>,
}
#[inline]
pub(crate) fn put_complete_string(
heap: &mut Heap,
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> {
pub(crate) fn new(buf: &'a mut RawBlock<T>, offset: usize) -> Self {
HeapIterMut { buf, offset }
}
}
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 {
None
}
}
}
impl<T: RawBlockTraits> HeapTemplate<T> {
#[inline]
pub(crate) fn new() -> Self {
HeapTemplate {
buf: RawBlock::new(),
_marker: PhantomData,
}
}
#[inline]
pub(crate) fn clone(&self, h: usize) -> HeapCellValue {
match &self[h] {
&HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr),
&HeapCellValue::Atom(ref name, ref op) => HeapCellValue::Atom(name.clone(), op.clone()),
&HeapCellValue::DBRef(ref db_ref) => HeapCellValue::DBRef(db_ref.clone()),
&HeapCellValue::Integer(ref n) => HeapCellValue::Integer(n.clone()),
&HeapCellValue::LoadStatePayload(_) => HeapCellValue::Addr(Addr::LoadStatePayload(h)),
&HeapCellValue::NamedStr(arity, ref name, ref op) => {
HeapCellValue::NamedStr(arity, name.clone(), op.clone())
}
&HeapCellValue::PartialString(..) => HeapCellValue::Addr(Addr::PStrLocation(h, 0)),
&HeapCellValue::Rational(ref r) => HeapCellValue::Rational(r.clone()),
&HeapCellValue::Stream(_) => HeapCellValue::Addr(Addr::Stream(h)),
&HeapCellValue::TcpListener(_) => HeapCellValue::Addr(Addr::TcpListener(h)),
}
}
#[inline]
pub(crate) fn put_complete_string(&mut self, s: &str) -> Addr {
if s.is_empty() {
return Addr::EmptyList;
}
let addr = self.allocate_pstr(s);
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 {
if src == "" {
return if orig_h == self.h() {
None
} else {
let tail_h = self.h() - 1;
self[tail_h] = HeapCellValue::Addr(Addr::HeapCell(tail_h));
Some(Addr::PStrLocation(orig_h, 0))
};
}
let h = self.h();
let (pstr, rest_src) = match PartialString::new(src) {
Some(tuple) => tuple,
None => {
if src.len() > '\u{0}'.len_utf8() {
src = &src['\u{0}'.len_utf8()..];
continue;
} else if orig_h == h {
return None;
} else {
self[h - 1] = HeapCellValue::Addr(Addr::HeapCell(h - 1));
return Some(Addr::PStrLocation(orig_h, 0));
}
}
};
self.push(HeapCellValue::PartialString(pstr, true));
if rest_src != "" {
self.push(HeapCellValue::Addr(Addr::PStrLocation(h + 2, 0)));
src = rest_src;
if heap.len() == h + 1 {
let pstr_atom = cell_as_atom!(heap[h]);
heap[h] = atom_as_cstr_cell!(pstr_atom);
heap_loc_as_cell!(h)
} else {
self.push(HeapCellValue::Addr(Addr::HeapCell(h + 1)));
return Some(Addr::PStrLocation(orig_h, 0));
heap.push(empty_list_as_cell!());
pstr_loc_as_cell!(h)
}
}
}
#[inline]
pub(crate) fn truncate(&mut self, h: usize) {
let new_top = h * mem::size_of::<HeapCellValue>() + self.buf.base as usize;
let mut h = new_top;
unsafe {
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);
None => {
let h = heap.len();
heap.push(empty_list_as_cell!());
heap_loc_as_cell!(h)
}
}
}
pub(crate) fn clear(&mut self) {
if !self.buf.base.is_null() {
self.truncate(0);
self.buf.top = self.buf.base;
#[inline]
pub(crate) fn put_partial_string(
heap: &mut Heap,
s: &str,
atom_tbl: &mut AtomTable,
) -> HeapCellValue {
match allocate_pstr(heap, s, atom_tbl) {
Some(h) => {
pstr_loc_as_cell!(h)
}
None => {
empty_list_as_cell!()
}
}
}
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;
#[inline]
pub(crate) fn allocate_pstr(
heap: &mut Heap,
mut src: &str,
atom_tbl: &mut AtomTable,
) -> Option<usize> {
let orig_h = heap.len();
for value in values.map(|v| v.into()) {
self.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
self.push(value);
loop {
if src == "" {
return if orig_h == heap.len() {
None
} else {
let tail_h = heap.len() - 1;
heap[tail_h] = heap_loc_as_cell!(tail_h);
h += 2;
Some(orig_h)
};
}
self.push(HeapCellValue::Addr(Addr::EmptyList));
let h = heap.len();
head_addr
}
/* Create an iterator starting from the passed offset. */
pub(crate) fn iter_from<'a>(&'a self, offset: usize) -> HeapIter<'a, T> {
HeapIter::new(&self.buf, offset * mem::size_of::<HeapCellValue>())
}
pub(crate) fn iter_mut_from<'a>(&'a mut self, offset: usize) -> HeapIterMut<'a, T> {
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> {
match &self[s] {
&HeapCellValue::Addr(Addr::Fixnum(n)) => usize::try_from(n).ok(),
&HeapCellValue::Integer(ref n) => n.to_usize(),
_ => None,
let (pstr, rest_src) = match PartialString::new(src, atom_tbl) {
Some(tuple) => tuple,
None => {
if src.len() > '\u{0}'.len_utf8() {
src = &src['\u{0}'.len_utf8()..];
continue;
} else if orig_h == h {
return None;
} else {
heap[h - 1] = heap_loc_as_cell!(h - 1);
return Some(orig_h);
}
}
};
match addr {
Addr::Str(s) => {
match &self[*s] {
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));
}
}
heap.push(string_as_pstr_cell!(pstr));
None
}
*/
_ => None,
}
}
_ => unreachable!(),
}
}
if rest_src != "" {
heap.push(pstr_loc_as_cell!(h + 2));
src = rest_src;
} else {
heap.push(heap_loc_as_cell!(h + 1));
return Some(orig_h);
}
}
}
pub fn filtered_iter_to_heap_list<SrcT: Into<HeapCellValue>>(
heap: &mut Heap,
values: impl Iterator<Item = SrcT>,
filter_fn: impl Fn(&Heap, HeapCellValue) -> bool,
) -> usize {
let head_addr = heap.len();
let mut h = head_addr;
for value in values {
let value = value.into();
if filter_fn(heap, value) {
heap.push(list_loc_as_cell!(h + 1));
heap.push(value);
h += 2;
}
}
heap.push(empty_list_as_cell!());
head_addr
}
#[inline(always)]
pub fn iter_to_heap_list<Iter, SrcT>(heap: &mut Heap, values: Iter) -> usize
where
Iter: Iterator<Item = SrcT>,
SrcT: Into<HeapCellValue>,
{
filtered_iter_to_heap_list(heap, values, |_, _| true)
}
pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option<usize> {
let extract_integer = |s: usize| -> Option<usize> {
match Number::try_from(heap[s]) {
Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
Ok(Number::Integer(n)) => n.to_usize(),
_ => 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])
read_heap_cell!(addr,
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();
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,
);
}
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)
_ => {
None
}
}
}
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 prolog_parser::clause_name;
use crate::parser::ast::*;
use crate::clause_types::*;
use crate::arena::*;
use crate::atom_table::*;
use crate::fixtures::*;
use crate::forms::*;
use crate::instructions::*;
use crate::machine::code_repo::CodeRepo;
use crate::machine::heap::*;
use crate::machine::loader::*;
use crate::machine::machine_state::*;
use crate::machine::partial_string::*;
use crate::machine::raw_block::RawBlockTraits;
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 std::cell::Cell;
use std::cmp::Ordering;
use std::collections::{BTreeMap, BTreeSet};
use std::convert::TryFrom;
use std::fmt;
// use std::mem;
use std::net::TcpListener;
use std::ops::{Add, AddAssign, Deref, Sub, SubAssign};
use std::collections::BTreeSet;
use std::ops::Deref;
use std::rc::Rc;
use crate::types::*;
#[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)]
pub(crate) enum DBRef {
NamedPred(ClauseName, usize, Option<SharedOpDesc>),
Op(
usize,
Specifier,
ClauseName,
Rc<OssifiedOpDir>,
SharedOpDesc,
),
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DBRef {
NamedPred(Atom, usize),
Op(Atom, Fixity, TypedArenaPtr<OssifiedOpDir>),
}
// 7.2
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) enum TermOrderCategory {
pub enum TermOrderCategory {
Variable,
FloatingPoint,
Integer,
@@ -55,322 +40,45 @@ pub(crate) enum TermOrderCategory {
Compound,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
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 {
impl PartialEq<Ref> for HeapCellValue {
fn eq(&self, r: &Ref) -> bool {
self.as_var() == Some(*r)
}
}
// for use crate::in MachineState::bind.
impl PartialOrd<Ref> for Addr {
impl PartialOrd<Ref> for HeapCellValue {
fn partial_cmp(&self, r: &Ref) -> Option<Ordering> {
match self {
&Addr::StackCell(fr, sc) => match *r {
Ref::AttrVar(_) | Ref::HeapCell(_) => Some(Ordering::Greater),
Ref::StackCell(fr1, sc1) => {
if fr1 < fr || (fr1 == fr && sc1 < sc) {
Some(Ordering::Greater)
} else if fr1 == fr && sc1 == sc {
Some(Ordering::Equal)
} else {
Some(Ordering::Less)
read_heap_cell!(*self,
(HeapCellValueTag::StackVar, s1) => {
match r.get_tag() {
RefTag::StackCell => {
let s2 = r.get_value() as usize;
s1.partial_cmp(&s2)
}
_ => Some(Ordering::Greater),
}
},
&Addr::HeapCell(h) | &Addr::AttrVar(h) => match r {
Ref::StackCell(..) => Some(Ordering::Less),
Ref::AttrVar(h1) | Ref::HeapCell(h1) => h.partial_cmp(h1),
},
_ => None,
}
}
}
impl Addr {
#[inline]
pub(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,
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h1) => {
// _ if self.is_ref() => {
// let h1 = self.get_value();
match r.get_tag() {
RefTag::StackCell => Some(Ordering::Less),
_ => {
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 {
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)
_ => {
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)]
pub(crate) enum IndexPtr {
pub enum IndexPtr {
DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined.
DynamicIndex(usize),
Index(usize),
@@ -378,7 +86,7 @@ pub(crate) enum IndexPtr {
}
#[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 {
type Target = Cell<IndexPtr>;
@@ -418,265 +126,25 @@ impl Default for CodeIndex {
}
}
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
pub(crate) enum REPLCodePtr {
AddDiscontiguousPredicate,
AddDynamicPredicate,
AddMultifilePredicate,
AddGoalExpansionClause,
AddTermExpansionClause,
AddInSituFilenameModule,
ClauseToEvacuable,
ScopedClauseToEvacuable,
ConcludeLoad,
DeclareModule,
LoadCompiledLibrary,
LoadContextSource,
LoadContextFile,
LoadContextDirectory,
LoadContextModule,
LoadContextStream,
PopLoadContext,
PopLoadStatePayload,
PushLoadContext,
PushLoadStatePayload,
UseModule,
BuiltInProperty,
MetaPredicateProperty,
MultifileProperty,
DiscontiguousProperty,
DynamicProperty,
AbolishClause,
Asserta,
Assertz,
Retract,
IsConsistentWithTermQueue,
FlushTermQueue,
RemoveModuleExports,
AddNonCountedBacktracking,
}
pub(crate) type HeapVarDict = IndexMap<Rc<String>, HeapCellValue, FxBuildHasher>;
pub(crate) type AllocVarDict = IndexMap<Rc<String>, VarData, FxBuildHasher>;
#[derive(Debug, Clone, PartialEq)]
pub(crate) enum CodePtr {
BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call.
CallN(usize, LocalCodePtr, bool), // arity, local, last call.
Local(LocalCodePtr),
// DynamicTransaction(DynamicTransactionType, LocalCodePtr), // the type of transaction, the return pointer.
REPL(REPLCodePtr, LocalCodePtr), // the REPL code, the return pointer.
VerifyAttrInterrupt(usize), // location of the verify attribute interrupt code in the CodeDir.
}
pub(crate) type GlobalVarDir = IndexMap<Atom, (Ball, Option<HeapCellValue>), FxBuildHasher>;
impl CodePtr {
pub(crate) fn local(&self) -> LocalCodePtr {
match self {
&CodePtr::BuiltInClause(_, ref local)
| &CodePtr::CallN(_, ref local, _)
| &CodePtr::Local(ref local) => local.clone(),
&CodePtr::VerifyAttrInterrupt(p) => LocalCodePtr::DirEntry(p),
&CodePtr::REPL(_, p) => p, // | &CodePtr::DynamicTransaction(_, p) => p,
}
}
#[inline]
pub(crate) fn is_halt(&self) -> bool {
if let CodePtr::Local(LocalCodePtr::Halt) = self {
true
} else {
false
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub(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 {
type Output = CodePtr;
fn add(self, rhs: usize) -> Self::Output {
match self {
p @ CodePtr::REPL(..) | p @ CodePtr::VerifyAttrInterrupt(_) => {
// |
// p @ CodePtr::DynamicTransaction(..) => {
p
}
CodePtr::Local(local) => CodePtr::Local(local + rhs),
CodePtr::BuiltInClause(_, local) | CodePtr::CallN(_, local, _) => {
CodePtr::Local(local + rhs)
}
}
}
}
impl AddAssign<usize> for CodePtr {
fn add_assign(&mut self, rhs: usize) {
match self {
&mut CodePtr::VerifyAttrInterrupt(_) => {}
&mut CodePtr::Local(ref mut local) => *local += rhs,
_ => *self = CodePtr::Local(self.local() + rhs),
}
}
}
impl SubAssign<usize> for CodePtr {
#[inline]
fn sub_assign(&mut self, rhs: usize) {
match self {
CodePtr::Local(ref mut local) => *local -= rhs,
_ => unreachable!(),
}
}
}
pub(crate) type HeapVarDict = IndexMap<Rc<Var>, Addr>;
pub(crate) type AllocVarDict = IndexMap<Rc<Var>, VarData>;
pub(crate) type GlobalVarDir = IndexMap<ClauseName, (Ball, Option<Addr>)>;
pub(crate) type StreamAliasDir = IndexMap<ClauseName, Stream>;
pub(crate) type StreamAliasDir = IndexMap<Atom, Stream, FxBuildHasher>;
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 =
IndexMap<(CompilationTarget, PredicateKey), LocalPredicateSkeleton>;
IndexMap<(CompilationTarget, PredicateKey), LocalPredicateSkeleton, FxBuildHasher>;
pub(crate) type CodeDir = IndexMap<PredicateKey, CodeIndex, FxBuildHasher>;
#[derive(Debug)]
pub(crate) struct IndexStore {
pub struct IndexStore {
pub(super) code_dir: CodeDir,
pub(super) extensible_predicates: ExtensiblePredicates,
pub(super) local_extensible_predicates: LocalExtensiblePredicates,
@@ -688,31 +156,21 @@ pub(crate) struct IndexStore {
pub(super) stream_aliases: StreamAliasDir,
}
impl Default for IndexStore {
#[inline]
fn default() -> Self {
index_store!(CodeDir::new(), default_op_dir(), ModuleDir::new())
}
}
impl IndexStore {
pub(crate) fn get_predicate_skeleton_mut(
&mut self,
compilation_target: &CompilationTarget,
key: &PredicateKey,
) -> Option<&mut PredicateSkeleton> {
match (key.0.as_str(), key.1) {
// ("term_expansion", 2) => self.extensible_predicates.get_mut(key),
_ => match compilation_target {
CompilationTarget::User => self.extensible_predicates.get_mut(key),
CompilationTarget::Module(ref module_name) => {
if let Some(module) = self.modules.get_mut(module_name) {
module.extensible_predicates.get_mut(key)
} else {
None
}
match compilation_target {
CompilationTarget::User => self.extensible_predicates.get_mut(key),
CompilationTarget::Module(ref module_name) => {
if let Some(module) = self.modules.get_mut(module_name) {
module.extensible_predicates.get_mut(key)
} else {
None
}
},
}
}
}
@@ -737,7 +195,7 @@ impl IndexStore {
&mut self,
mut src_compilation_target: CompilationTarget,
local_compilation_target: CompilationTarget,
listing_src_file_name: Option<ClauseName>,
listing_src_file_name: Option<Atom>,
key: PredicateKey,
) -> Option<&mut LocalPredicateSkeleton> {
if let Some(filename) = listing_src_file_name {
@@ -748,8 +206,8 @@ impl IndexStore {
CompilationTarget::User => self
.local_extensible_predicates
.get_mut(&(local_compilation_target, key)),
CompilationTarget::Module(ref module_name) => {
if let Some(module) = self.modules.get_mut(module_name) {
CompilationTarget::Module(module_name) => {
if let Some(module) = self.modules.get_mut(&module_name) {
module
.local_extensible_predicates
.get_mut(&(local_compilation_target, key))
@@ -764,7 +222,7 @@ impl IndexStore {
&self,
mut src_compilation_target: CompilationTarget,
local_compilation_target: CompilationTarget,
listing_src_file_name: Option<ClauseName>,
listing_src_file_name: Option<Atom>,
key: PredicateKey,
) -> Option<&LocalPredicateSkeleton> {
if let Some(filename) = listing_src_file_name {
@@ -775,8 +233,8 @@ impl IndexStore {
CompilationTarget::User => self
.local_extensible_predicates
.get(&(local_compilation_target, key)),
CompilationTarget::Module(ref module_name) => {
if let Some(module) = self.modules.get(module_name) {
CompilationTarget::Module(module_name) => {
if let Some(module) = self.modules.get(&module_name) {
module
.local_extensible_predicates
.get(&(local_compilation_target, key))
@@ -806,35 +264,30 @@ impl IndexStore {
pub(crate) fn get_predicate_code_index(
&self,
name: ClauseName,
name: Atom,
arity: usize,
module: ClauseName,
op_spec: Option<SharedOpDesc>,
module: Atom,
) -> Option<CodeIndex> {
if module.as_str() == "user" {
match ClauseType::from(name, arity, op_spec) {
ClauseType::Named(name, arity, _) => self.code_dir.get(&(name, arity)).cloned(),
ClauseType::Op(name, spec, ..) => self.code_dir.get(&(name, spec.arity())).cloned(),
if module == atom!("user") {
match ClauseType::from(name, arity) {
ClauseType::Named(arity, name, _) => self.code_dir.get(&(name, arity)).cloned(),
_ => None,
}
} else {
self.modules.get(&module).and_then(|module| {
match ClauseType::from(name, arity, op_spec) {
ClauseType::Named(name, arity, _) => {
self.modules
.get(&module)
.and_then(|module| match ClauseType::from(name, arity) {
ClauseType::Named(arity, name, _) => {
module.code_dir.get(&(name, arity)).cloned()
}
ClauseType::Op(name, spec, ..) => {
module.code_dir.get(&(name, spec.arity())).cloned()
}
_ => None,
}
})
})
}
}
pub(crate) fn get_meta_predicate_spec(
&self,
name: ClauseName,
name: Atom,
arity: usize,
compilation_target: &CompilationTarget,
) -> Option<&Vec<MetaSpec>> {
@@ -850,9 +303,13 @@ impl IndexStore {
}
}
pub(crate) fn is_dynamic_predicate(&self, module_name: ClauseName, key: PredicateKey) -> bool {
match module_name.as_str() {
"user" => self
pub(crate) fn is_dynamic_predicate(
&self,
module_name: Atom,
key: PredicateKey,
) -> bool {
match module_name {
atom!("user") => self
.extensible_predicates
.get(&key)
.map(|skeleton| skeleton.core.is_dynamic)
@@ -870,62 +327,10 @@ impl IndexStore {
#[inline]
pub(super) fn new() -> Self {
IndexStore::default()
}
pub(super) fn get_cleaner_sites(&self) -> (usize, usize) {
let r_w_h = clause_name!("run_cleaners_with_handling");
let r_wo_h = clause_name!("run_cleaners_without_handling");
let iso_ext = clause_name!("iso_ext");
let r_w_h = self
.get_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,
}
index_store!(
CodeDir::with_hasher(FxBuildHasher::default()),
default_op_dir(),
ModuleDir::with_hasher(FxBuildHasher::default())
)
}
}

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

View File

@@ -1,16 +1,13 @@
use core::marker::PhantomData;
use crate::machine::machine_indices::*;
use crate::machine::raw_block::*;
use crate::raw_block::*;
use crate::types::*;
use std::mem;
use std::ops::{Index, IndexMut};
use std::ptr;
#[derive(Debug)]
struct StackTraits {}
impl RawBlockTraits for StackTraits {
impl RawBlockTraits for Stack {
#[inline]
fn init_size() -> usize {
10 * 1024 * 1024
@@ -18,31 +15,23 @@ impl RawBlockTraits for StackTraits {
#[inline]
fn align() -> usize {
mem::align_of::<Addr>()
}
#[inline]
fn base_offset(base: *const u8) -> *const u8 {
unsafe { base.offset(Self::align() as isize) }
mem::align_of::<HeapCellValue>()
}
}
const fn prelude_size<Prelude>() -> usize {
let size = mem::size_of::<Prelude>();
let align = mem::align_of::<Addr>();
(size & !(align - 1)) + align
#[inline(always)]
pub const fn prelude_size<Prelude>() -> usize {
mem::size_of::<Prelude>()
}
#[derive(Debug)]
pub(crate) struct Stack {
buf: RawBlock<StackTraits>,
_marker: PhantomData<Addr>,
pub struct Stack {
buf: RawBlock<Stack>,
_marker: PhantomData<HeapCellValue>,
}
impl Drop for Stack {
fn drop(&mut self) {
self.drop_in_place();
self.buf.deallocate();
}
}
@@ -56,8 +45,7 @@ pub(crate) struct FramePrelude {
pub(crate) struct AndFramePrelude {
pub(crate) univ_prelude: FramePrelude,
pub(crate) e: usize,
pub(crate) cp: LocalCodePtr,
pub(crate) interrupt_cp: LocalCodePtr,
pub(crate) cp: usize,
}
#[derive(Debug)]
@@ -67,22 +55,22 @@ pub(crate) struct AndFrame {
impl AndFrame {
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 {
type Output = Addr;
type Output = HeapCellValue;
fn index(&self, index: usize) -> &Self::Output {
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 {
let ptr = mem::transmute::<&AndFrame, *const u8>(self);
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 {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
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 {
let ptr = mem::transmute::<&mut AndFrame, *const u8>(self);
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) univ_prelude: FramePrelude,
pub(crate) e: usize,
pub(crate) cp: LocalCodePtr,
pub(crate) cp: 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) h: usize,
pub(crate) b0: usize,
@@ -119,18 +131,18 @@ pub(crate) struct OrFrame {
}
impl Index<usize> for OrFrame {
type Output = Addr;
type Output = HeapCellValue;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
let prelude_offset = prelude_size::<OrFramePrelude>();
let index_offset = index * mem::size_of::<Addr>();
let index_offset = index * mem::size_of::<HeapCellValue>();
unsafe {
let ptr = mem::transmute::<&OrFrame, *const u8>(self);
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]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
let prelude_offset = prelude_size::<OrFramePrelude>();
let index_offset = index * mem::size_of::<Addr>();
let index_offset = index * mem::size_of::<HeapCellValue>();
unsafe {
let ptr = mem::transmute::<&mut OrFrame, *const u8>(self);
let ptr = ptr as usize + prelude_offset + index_offset;
&mut *(ptr as *mut Addr)
&mut *(ptr as *mut HeapCellValue)
}
}
}
impl OrFrame {
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 {
let frame_size = AndFrame::size_of(num_cells);
unsafe {
let new_top = self.buf.new_block(frame_size);
let e = self.buf.top as usize - self.buf.base as usize;
let e = self.buf.ptr 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 {
let offset = prelude_size::<AndFramePrelude>() + idx * mem::size_of::<Addr>();
ptr::write(
(self.buf.top as usize + offset) as *mut Addr,
Addr::StackCell(e, idx + 1),
(new_ptr as usize + offset) as *mut HeapCellValue,
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;
self.buf.top = new_top;
e
}
}
@@ -192,27 +217,27 @@ impl Stack {
let frame_size = OrFrame::size_of(num_cells);
unsafe {
let new_top = self.buf.new_block(frame_size);
let b = self.buf.top as usize - self.buf.base as usize;
let b = self.buf.ptr 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 {
let offset = prelude_size::<OrFramePrelude>() + idx * mem::size_of::<Addr>();
ptr::write(
(self.buf.top as usize + offset) as *mut Addr,
Addr::StackCell(b, idx),
(new_ptr as usize + offset) as *mut HeapCellValue,
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;
self.buf.top = new_top;
b
}
}
#[inline]
#[inline(always)]
pub(crate) fn index_and_frame(&self, e: usize) -> &AndFrame {
unsafe {
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 {
unsafe {
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 {
unsafe {
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 {
unsafe {
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) {
if b == 0 {
self.inner_truncate(mem::align_of::<Addr>());
} else {
self.inner_truncate(b);
let base = self.buf.base as usize + b;
if base < self.buf.ptr as usize {
self.buf.ptr = base as *mut _;
}
}
#[inline]
fn inner_truncate(&mut self, b: usize) {
let base = b + self.buf.base as usize;
if base < self.buf.top as usize {
self.buf.top = base as *const _;
}
}
pub(crate) fn drop_in_place(&mut self) {
self.truncate(mem::align_of::<Addr>());
debug_assert!(if self.buf.top.is_null() {
self.buf.top == self.buf.base
} else {
self.buf.top as usize == self.buf.base as usize + mem::align_of::<Addr>()
});
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::machine::mock_wam::*;
#[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));
}
and_frame[5] = empty_list_as_cell!();
assert_eq!(and_frame[5], empty_list_as_cell!());
let b = wam.machine_st.stack.allocate_or_frame(5);
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 prolog_parser::parser::*;
use crate::machine::machine_errors::CompilationError;
use crate::forms::*;
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 std::collections::VecDeque;
use std::fmt;
pub(crate) trait TermStream: Sized {
type Evacuable;
pub struct LoadStatePayload<TS> {
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 eof(&mut self) -> Result<bool, CompilationError>;
fn listing_src(&self) -> &ListingSource;
fn evacuate<'a>(loader: Loader<'a, Self>) -> Result<Self::Evacuable, SessionError>;
}
#[derive(Debug)]
pub(super) struct BootstrappingTermStream<'a> {
pub struct BootstrappingTermStream<'a> {
listing_src: ListingSource,
parser: Parser<'a, Stream>,
pub(super) parser: Parser<'a, Stream>,
}
impl<'a> BootstrappingTermStream<'a> {
#[inline]
pub(super) fn from_prolog_stream(
stream: &'a mut PrologStream,
atom_tbl: TabledData<Atom>,
flags: MachineFlags,
pub(super) fn from_char_reader(
stream: Stream,
machine_st: &'a mut MachineState,
listing_src: ListingSource,
) -> Self {
let parser = Parser::new(stream, atom_tbl, flags);
Self {
parser,
listing_src,
}
let parser = Parser::new(stream, machine_st);
Self { parser, listing_src }
}
}
impl<'a> TermStream for BootstrappingTermStream<'a> {
type Evacuable = CompilationTarget;
#[inline]
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError> {
self.parser.reset();
@@ -61,24 +66,9 @@ impl<'a> TermStream for BootstrappingTermStream<'a> {
fn listing_src(&self) -> &ListingSource {
&self.listing_src
}
fn evacuate(mut loader: Loader<Self>) -> Result<Self::Evacuable, SessionError> {
if !loader.predicates.is_empty() {
loader.compile_and_submit()?;
}
loader
.load_state
.retraction_info
.reset(loader.load_state.wam.code_repo.code.len());
loader.load_state.remove_module_op_exports();
Ok(loader.load_state.compilation_target.take())
}
}
pub(crate) struct LiveTermStream {
pub struct LiveTermStream {
pub(super) term_queue: VecDeque<Term>,
pub(super) listing_src: ListingSource,
}
@@ -93,28 +83,18 @@ impl LiveTermStream {
}
}
pub(crate) struct LoadStatePayload {
pub(super) term_stream: LiveTermStream,
pub(super) compilation_target: CompilationTarget,
pub(super) retraction_info: RetractionInfo,
pub(super) module_op_exports: Vec<(OpDecl, Option<(usize, Specifier)>)>,
pub(super) non_counted_bt_preds: IndexSet<PredicateKey>,
pub(super) predicates: PredicateQueue,
pub(super) clause_clauses: Vec<(Term, Term)>,
}
impl fmt::Debug for LoadStatePayload {
impl<TS> fmt::Debug for LoadStatePayload<TS> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "LoadStatePayload")
}
}
impl LoadStatePayload {
pub(super) fn new(wam: &Machine) -> Self {
impl<TS> LoadStatePayload<TS> {
pub(super) fn new(code_repo_len: usize, term_stream: TS) -> Self {
Self {
term_stream: LiveTermStream::new(ListingSource::User),
term_stream,
compilation_target: CompilationTarget::default(),
retraction_info: RetractionInfo::new(wam.code_repo.code.len()),
retraction_info: RetractionInfo::new(code_repo_len),
module_op_exports: vec![],
non_counted_bt_preds: IndexSet::new(),
predicates: predicate_queue![],
@@ -124,8 +104,6 @@ impl LoadStatePayload {
}
impl TermStream for LiveTermStream {
type Evacuable = LoadStatePayload;
#[inline]
fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
Ok(self.term_queue.pop_front().unwrap())
@@ -140,9 +118,4 @@ impl TermStream for LiveTermStream {
fn listing_src(&self) -> &ListingSource {
&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
* of token trees.
*/
@@ -13,53 +7,420 @@ macro_rules! count_tt {
($($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 {
($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),*]) => ({
{
#[allow(unused_variables, unused_mut)]
let mut addendum = Heap::new();
let arity = count_tt!($($dt) +);
let aux_lens = [$($aux.len()),*];
let arity: usize = count_tt!($($dt) +);
#[allow(unused_variables)]
let aux_lens: [usize; count_tt!($($aux) *)] = [$($aux.len()),*];
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 ),)+ ];
$(
result.extend($aux.into_iter());
result.extend($aux.iter());
)*
result.extend(addendum.into_iter());
@@ -68,383 +429,183 @@ macro_rules! functor {
});
($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)]
let mut addendum = Heap::new();
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 ),)+ ];
result.extend(addendum.into_iter());
result
}
});
($name:expr, $fixity:expr) => (
vec![ HeapCellValue::Atom(clause_name!($name), Some($fixity)) ]
);
(clause_name($name:expr)) => (
vec![ HeapCellValue::Atom($name, None) ]
);
($name:expr) => (
vec![ HeapCellValue::Atom(clause_name!($name), None) ]
);
($name:expr) => ({
vec![ atom_as_cell!($name) ]
});
}
macro_rules! functor_term {
(aux(0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
HeapCellValue::Addr(Addr::HeapCell($arity + 1))
(str(0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
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();
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) => ({
HeapCellValue::Addr(Addr::HeapCell($arity + $h + 1))
(str($h:expr, 0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
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();
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) => (
HeapCellValue::Addr($e)
(literal($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
HeapCellValue::from($e)
);
(constant($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
from_constant!($e, $h, $arity, $aux_lens, $addendum)
(integer($e:expr, $arena:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
HeapCellValue::arena_from(Number::arena_from($e, $arena), $arena)
);
(constant($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
from_constant!($e, 0, $arity, $aux_lens, $addendum)
);
(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)))
(fixnum($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
fixnum_as_cell!(Fixnum::build_with($e as i64))
);
(indexing_code_ptr($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
let stub =
match $e {
IndexingCodePtr::DynamicExternal(o) => functor!("dynamic_external", [integer(o)]),
IndexingCodePtr::External(o) => functor!("external", [integer(o)]),
IndexingCodePtr::Internal(o) => functor!("internal", [integer(o)]),
IndexingCodePtr::Fail => vec![HeapCellValue::Atom(clause_name!("fail"), None)],
IndexingCodePtr::DynamicExternal(o) => functor!(atom!("dynamic_external"), [fixnum(o)]),
IndexingCodePtr::External(o) => functor!(atom!("external"), [fixnum(o)]),
IndexingCodePtr::Internal(o) => functor!(atom!("internal"), [fixnum(o)]),
IndexingCodePtr::Fail => {
vec![atom_as_cell!(atom!("fail"))]
},
};
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());
HeapCellValue::Addr(Addr::HeapCell(h))
str_loc_as_cell!(h)
});
(clause_name($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
HeapCellValue::Atom($e, None)
(number($arena:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
HeapCellValue::from(($e, $arena))
);
(atom($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
HeapCellValue::Atom(clause_name!($e), None)
);
(value($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
$e
atom_as_cell!($e)
);
(string($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({
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) => ({
if $e {
functor_term!(atom("true"), $arity, $aux_lens, $addendum)
functor_term!(atom(atom!("true")), $arity, $aux_lens, $addendum)
} 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
);
}
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 {
($cmp: expr, $at_1: expr, $at_2: expr) => {{
let ct = ClauseType::Inlined(InlinedClauseType::CompareNumber($cmp, $at_1, $at_2));
call_clause!(ct, 2, 0)
$cmp.set_terms($at_1, $at_2);
call_clause!(ClauseType::Inlined(InlinedClauseType::CompareNumber($cmp)), 0)
}};
}
macro_rules! jmp_call {
($arity:expr, $offset:expr, $pvs:expr) => {
Line::Control(ControlInstruction::JmpBy($arity, $offset, $pvs, false))
};
}
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! call_clause {
($clause_type:expr, $pvs:expr) => {{
let mut instr = $clause_type.to_instr();
instr.perm_vars_mut().map(|pvs| *pvs = $pvs);
instr
}};
}
macro_rules! dir_entry {
($idx:expr) => {
LocalCodePtr::DirEntry($idx)
macro_rules! call_clause_by_default {
($clause_type:expr, $pvs:expr) => {{
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 {
($r: expr) => {
ArithmeticTerm::Reg($r)
};
}
macro_rules! atom_from {
($self:expr, $e:expr) => {
match $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! unmark_cell_bits {
($e:expr) => {{
let mut result = $e;
macro_rules! try_or_fail {
($s:expr, $e:expr) => {{
match $e {
Ok(val) => val,
Err(msg) => {
$s.throw_exception(msg);
return;
}
}
result.set_mark_bit(false);
result.set_forwarding_bit(false);
result
}};
}
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_rules! binary_digit_char {
macro_rules! octet_char {
($c: expr) => {
$c >= '0' && $c <= '1'
('\u{0000}'..='\u{00FF}').contains(&$c)
};
}
@@ -172,9 +172,9 @@ macro_rules! octal_digit_char {
}
#[macro_export]
macro_rules! octet_char {
macro_rules! binary_digit_char {
($c: expr) => {
('\u{0000}'..='\u{00FF}').contains(&$c)
$c >= '0' && $c <= '1'
};
}

View File

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

View File

@@ -1,14 +1,15 @@
use crate::ast::*;
use crate::lexer::*;
use crate::tabled_rc::*;
use crate::arena::*;
use crate::atom_table::*;
use crate::parser::ast::*;
use crate::parser::char_reader::*;
use crate::parser::lexer::*;
use ordered_float::OrderedFloat;
use crate::rug::ops::NegAssign;
use rug::ops::NegAssign;
use std::cell::Cell;
use std::io::Read;
use std::mem::swap;
use std::mem;
use std::rc::Rc;
#[derive(Debug, Clone, Copy, PartialEq)]
@@ -50,69 +51,114 @@ struct TokenDesc {
spec: u32,
}
pub fn get_clause_spec(
name: ClauseName,
arity: usize,
op_dir: &CompositeOpDir,
) -> Option<SharedOpDesc> {
match arity {
1 => {
/* This is a clause with an operator principal functor. Prefix operators
are supposed over post.
*/
if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::Pre) {
return Some(cell.clone());
}
if let Some(OpDirValue(cell)) = op_dir.get(name, Fixity::Post) {
return Some(cell.clone());
fn is_partial_string(
head: Term,
mut tail: Term,
atom_tbl: &mut AtomTable,
) -> Result<(Atom, Option<Box<Term>>), Term> {
let mut string = match &head {
Term::Literal(_, Literal::Atom(atom)) => {
if let Some(c) = atom.as_char() {
c.to_string()
} else {
return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail)));
}
}
2 => {
if let Some(OpDirValue(cell)) = op_dir.get(name, Fixity::In) {
return Some(cell.clone());
}
Term::Literal(_, Literal::Char(c)) => c.to_string(),
_ => {
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));
}
}
tail_ref = succ;
}
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: ClauseName, op_dir: &CompositeOpDir) -> Option<OpDesc> {
let mut op_desc = OpDesc {
pub fn get_op_desc(
name: Atom,
op_dir: &CompositeOpDir,
) -> Option<CompositeOpDesc> {
let mut op_desc = CompositeOpDesc {
pre: 0,
inf: 0,
post: 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();
if pri > 0 {
op_desc.pre = pri;
op_desc.spec |= spec;
} else if name.as_str() == "-" {
op_desc.pre = pri as usize;
op_desc.spec |= spec as u32;
} else if name == atom!("-") {
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();
if pri > 0 {
op_desc.post = pri;
op_desc.spec |= spec;
op_desc.post = pri as usize;
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();
if pri > 0 {
op_desc.inf = pri;
op_desc.spec |= spec;
op_desc.inf = pri as usize;
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 {
d2.priority <= priority
&& 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
}
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)]
pub struct OpDesc {
pub struct CompositeOpDesc {
pub pre: usize,
pub inf: usize,
pub post: usize,
@@ -188,14 +244,14 @@ pub struct OpDesc {
}
#[derive(Debug)]
pub struct Parser<'a, R: Read> {
lexer: Lexer<'a, R>,
pub struct Parser<'a, R> {
pub lexer: Lexer<'a, R>,
tokens: Vec<Token>,
stack: Vec<TokenDesc>,
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![];
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() => {
return Err(ParserError::IncompleteReduction(lexer.line_num, lexer.col_num));
return Err(ParserError::IncompleteReduction(
lexer.line_num,
lexer.col_num,
));
}
Err(e) => {
return Err(e);
@@ -222,20 +281,46 @@ fn read_tokens<R: Read>(lexer: &mut Lexer<R>) -> Result<Vec<Token>, ParserError>
Ok(tokens)
}
impl<'a, R: Read> Parser<'a, R> {
pub fn new(
stream: &'a mut ParsingStream<R>,
atom_tbl: TabledData<Atom>,
flags: MachineFlags,
) -> Self {
fn atomize_term(atom_tbl: &mut AtomTable, term: &Term) -> Option<Atom> {
match term {
Term::Literal(_, ref c) => atomize_constant(atom_tbl, *c),
_ => None,
}
}
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 {
lexer: Lexer::new(atom_tbl, flags, stream),
lexer: Lexer::new(stream, machine_st),
tokens: vec![],
stack: 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]
pub fn line_num(&self) -> usize {
self.lexer.line_num
@@ -246,25 +331,12 @@ impl<'a, R: Read> Parser<'a, R> {
self.lexer.col_num
}
#[inline]
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>)> {
fn get_term_name(&mut self, td: TokenDesc) -> Option<Atom> {
match td.tt {
TokenType::HeadTailSeparator => Some((
clause_name!("|"),
Some(SharedOpDesc::new(td.priority, td.spec)),
)),
TokenType::Comma => Some((clause_name!(","), Some(SharedOpDesc::new(1000, XFY)))),
TokenType::HeadTailSeparator => Some(atom!("|")),
TokenType::Comma => Some(atom!(",")),
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) => {
self.terms.push(term);
None
@@ -277,14 +349,9 @@ impl<'a, R: Read> Parser<'a, R> {
fn push_binary_op(&mut self, td: TokenDesc, spec: Specifier) {
if let Some(arg2) = self.terms.pop() {
if let Some((name, shared_op_desc)) = self.get_term_name(td) {
if let Some(name) = self.get_term_name(td) {
if let Some(arg1) = self.terms.pop() {
let term = Term::Clause(
Cell::default(),
name,
vec![Box::new(arg1), Box::new(arg2)],
shared_op_desc,
);
let term = Term::Clause(Cell::default(), name, vec![arg1, arg2]);
self.terms.push(term);
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 name) = self.terms.pop() {
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 {
let term =
Term::Clause(Cell::default(), name, vec![Box::new(arg1)], shared_op_desc);
if let Term::Literal(_, Literal::Atom(name)) = name {
let term = Term::Clause(Cell::default(), name, vec![arg1]);
self.terms.push(term);
self.stack.push(TokenDesc {
@@ -319,17 +385,8 @@ impl<'a, R: Read> Parser<'a, R> {
}
}
fn promote_atom_op(
&mut self,
atom: ClauseName,
priority: usize,
assoc: u32,
op_dir_val: Option<&OpDirValue>,
) {
let spec = op_dir_val.map(|op_dir_val| op_dir_val.shared_op_desc());
self.terms
.push(Term::Constant(Cell::default(), Constant::Atom(atom, spec)));
fn promote_atom_op(&mut self, atom: Atom, priority: usize, assoc: u32) {
self.terms.push(Term::Literal(Cell::default(), Literal::Atom(atom)));
self.stack.push(TokenDesc {
tt: TokenType::Term,
priority,
@@ -339,15 +396,15 @@ impl<'a, R: Read> Parser<'a, R> {
fn shift(&mut self, token: Token, priority: usize, spec: Specifier) {
let tt = match token {
Token::Constant(Constant::String(s)) if self.lexer.flags.double_quotes.is_codes() => {
let mut list = Term::Constant(Cell::default(), Constant::EmptyList);
Token::Literal(Literal::String(s)) if self.lexer.machine_st.flags.double_quotes.is_codes() => {
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(
Cell::default(),
Box::new(Term::Constant(
Box::new(Term::Literal(
Cell::default(),
Constant::Fixnum(c as isize),
Literal::Fixnum(Fixnum::build_with(c as i64)),
)),
Box::new(list),
);
@@ -356,15 +413,19 @@ impl<'a, R: Read> Parser<'a, R> {
self.terms.push(list);
TokenType::Term
}
Token::Constant(c) => {
self.terms.push(Term::Constant(Cell::default(), c));
Token::Literal(Literal::String(s)) if self.lexer.machine_st.flags.double_quotes.is_chars() => {
self.terms.push(Term::PartialString(Cell::default(), s, None));
TokenType::Term
}
Token::Literal(c) => {
self.terms.push(Term::Literal(Cell::default(), c));
TokenType::Term
}
Token::Var(v) => {
if v.trim() == "_" {
self.terms.push(Term::AnonVar);
} else {
self.terms.push(Term::Var(Cell::default(), v));
self.terms.push(Term::Var(Cell::default(), Rc::new(v)));
}
TokenType::Term
@@ -457,7 +518,7 @@ impl<'a, R: Read> Parser<'a, R> {
None
}
fn reduce_term(&mut self, op_dir: &CompositeOpDir) -> bool {
fn reduce_term(&mut self) -> bool {
if self.stack.is_empty() {
return false;
}
@@ -489,22 +550,40 @@ impl<'a, R: Read> Parser<'a, R> {
let idx = self.terms.len() - arity;
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);
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.
if name.as_str() == "." && subterms.len() == 2 {
if name == atom!(".") && subterms.len() == 2 {
let tail = 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 {
let spec = get_clause_spec(name.clone(), subterms.len(), op_dir);
self.terms
.push(Term::Clause(Cell::default(), name, subterms, spec));
.push(Term::Clause(Cell::default(), name, subterms));
}
if let Some(&mut TokenDesc {
@@ -544,8 +623,8 @@ impl<'a, R: Read> Parser<'a, R> {
* an operator, so expand the
* terms it compacted out again. */
match (term.name(), term.arity()) {
(Some(name), 2) if name.as_str() == "," => {
let terms = unfold_by_str(term, ",");
(Some(name), 2) if name == atom!(",") => {
let terms = unfold_by_str(term, name); // notice: name == "," here.
let arity = terms.len() - 1;
self.terms.extend(terms.into_iter());
@@ -603,8 +682,7 @@ impl<'a, R: Read> Parser<'a, R> {
td.tt = TokenType::Term;
td.priority = 0;
self.terms
.push(Term::Constant(Cell::default(), Constant::EmptyList));
self.terms.push(Term::Literal(Cell::default(), Literal::Atom(atom!("[]"))));
return Ok(true);
}
}
@@ -621,7 +699,7 @@ impl<'a, R: Read> Parser<'a, R> {
let list_len = self.stack.len() - 2 * arity;
let end_term = if self.stack[idx].tt != TokenType::HeadTailSeparator {
Term::Constant(Cell::default(), Constant::EmptyList)
Term::Literal(Cell::default(), Literal::Atom(atom!("[]")))
} else {
let term = match self.terms.pop() {
Some(term) => term,
@@ -662,7 +740,18 @@ impl<'a, R: Read> Parser<'a, R> {
priority: 0,
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)
}
@@ -678,7 +767,11 @@ impl<'a, R: Read> Parser<'a, R> {
td.priority = 0;
td.spec = TERM;
let term = Term::Constant(Cell::default(), atom!("{}", self.lexer.atom_tbl));
let term = Term::Literal(
Cell::default(),
Literal::Atom(atom!("{}")),
);
self.terms.push(term);
return Ok(true);
}
@@ -710,9 +803,8 @@ impl<'a, R: Read> Parser<'a, R> {
self.terms.push(Term::Clause(
Cell::default(),
clause_name!("{}"),
vec![Box::new(term)],
None,
atom!("{}"),
vec![term],
));
return Ok(true);
@@ -744,27 +836,28 @@ impl<'a, R: Read> Parser<'a, R> {
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
.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].tt = TokenType::Term;
self.stack[idx].priority = 0;
true
}
_ => false,
}
}
fn shift_op(&mut self, name: ClauseName, op_dir: &CompositeOpDir) -> Result<bool, ParserError> {
if let Some(OpDesc {
fn shift_op(&mut self, name: Atom, op_dir: &CompositeOpDir) -> Result<bool, ParserError> {
if let Some(CompositeOpDesc {
pre,
inf,
post,
spec,
}) = get_op_desc(name.clone(), op_dir)
}) = get_op_desc(name, op_dir)
{
if (pre > 0 && inf + post > 0) || is_negate!(spec) {
match self.tokens.last().ok_or(ParserError::UnexpectedEOF)? {
@@ -775,15 +868,9 @@ impl<'a, R: Read> Parser<'a, R> {
// or post == 0.
self.reduce_op(inf + post);
let fixity = if inf > 0 { Fixity::In } else { Fixity::Post };
let op_dir_val = op_dir.get(name.clone(), fixity);
// let fixity = if inf > 0 { Fixity::In } else { Fixity::Post };
self.promote_atom_op(
name,
inf + post,
spec & (XFX | XFY | YFX | YF | XF),
op_dir_val,
);
self.promote_atom_op(name, inf + post, spec & (XFX | XFY | YFX | YF | XF));
}
_ => {
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() {
// rterm.c: 412
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(
name,
inf + post,
spec & (XFX | XFY | YFX | XF | YF),
op_dir_val,
);
} else {
let op_dir_val = op_dir.get(name.clone(), Fixity::Pre);
self.promote_atom_op(
name,
pre,
spec & (FX | FY | NEGATIVE_SIGN),
op_dir_val,
);
self.promote_atom_op(name, pre, spec & (FX | FY | NEGATIVE_SIGN));
}
} else {
let op_dir_val = op_dir.get(name.clone(), Fixity::Pre);
self.promote_atom_op(
name,
pre,
spec & (FX | FY | NEGATIVE_SIGN),
op_dir_val,
);
self.promote_atom_op(name, pre, spec & (FX | FY | NEGATIVE_SIGN));
}
}
}
} 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.promote_atom_op(name, pre + inf + post, spec, op_dir_val);
self.promote_atom_op(name, pre + inf + post, spec);
}
Ok(true)
@@ -843,38 +903,23 @@ impl<'a, R: Read> Parser<'a, R> {
}
}
fn atomize_term(&self, term: &Term) -> Option<ClauseName> {
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)
fn negate_number<N, Negator, ToLiteral>(&mut self, n: N, negator: Negator, constr: ToLiteral)
where
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(term) = self.terms.last().cloned() {
match term {
Term::Constant(_, Constant::Atom(ref name, _))
if name.as_str() == "-"
&& (is_prefix!(desc.spec) || is_negate!(desc.spec)) =>
Term::Literal(_, Literal::Atom(name))
if name == atom!("-") && (is_prefix!(desc.spec) || is_negate!(desc.spec)) =>
{
self.stack.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;
}
_ => {}
@@ -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 negate_rc<T: NegAssign>(mut t: Rc<T>) -> Rc<T> {
if let Some(t) = Rc::get_mut(&mut t) {
t.neg_assign();
};
fn negate_rc<T: NegAssign>(mut t: TypedArenaPtr<T>) -> TypedArenaPtr<T> {
(&mut t).neg_assign();
t
}
match token {
Token::Constant(Constant::Fixnum(n)) => self.negate_number(n, |n| -n, Constant::Fixnum),
Token::Constant(Constant::Integer(n)) => {
self.negate_number(n, negate_rc, Constant::Integer)
Token::Literal(Literal::Fixnum(n)) => {
self.negate_number(n, |n| -n, |n, _| Literal::Fixnum(n))
}
Token::Constant(Constant::Rational(n)) => {
self.negate_number(n, negate_rc, Constant::Rational)
Token::Literal(Literal::Integer(n)) => {
self.negate_number(n, negate_rc, |n, _| Literal::Integer(n))
}
Token::Constant(Constant::Float(n)) => {
self.negate_number(n, |n| OrderedFloat(-n.into_inner()), Constant::Float)
Token::Literal(Literal::Rational(n)) => {
self.negate_number(n, negate_rc, |r, _| Literal::Rational(r))
}
Token::Constant(c) => {
if let Some(name) = self.atomize_constant(&c) {
Token::Literal(Literal::Float(n)) => self.negate_number(
**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)? {
self.shift(Token::Constant(c), 0, TERM);
self.shift(Token::Literal(c), 0, TERM);
}
} 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::Open => self.shift(Token::Open, 1300, DELIMITER),
Token::OpenCT => self.shift(Token::OpenCT, 1300, DELIMITER),
Token::Close => {
if !self.reduce_term(op_dir) {
if !self.reduce_term() {
if !self.reduce_brackets() {
return Err(ParserError::IncompleteReduction(
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.
* See: http://www.complang.tuwien.ac.at/ulrich/iso-prolog/dtc2#Res_A78
*/
let (priority, spec) = get_op_desc(clause_name!("|"), op_dir)
.map(|OpDesc { inf, spec, .. }| (inf, spec))
let bar_atom = atom!("|");
let (priority, spec) = get_op_desc(bar_atom, op_dir)
.map(|CompositeOpDesc { inf, spec, .. }| (inf, spec))
.unwrap_or((1000, DELIMITER));
self.reduce_op(priority);
@@ -990,7 +1039,7 @@ impl<'a, R: Read> Parser<'a, R> {
}
#[inline]
pub fn num_lines_read(&self) -> usize {
pub fn lines_read(&self) -> usize {
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,263 +1,278 @@
use prolog_parser::ast::*;
use prolog_parser::parser::*;
use prolog_parser::tabled_rc::TabledData;
use crate::parser::ast::*;
use crate::parser::parser::*;
use crate::arena::*;
use crate::atom_table::*;
use crate::forms::*;
use crate::iterators::*;
use crate::machine::heap::*;
use crate::machine::machine_indices::*;
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::io::{Cursor, Error, ErrorKind, Read};
type SubtermDeque = VecDeque<(usize, usize)>;
pub(crate) type PrologStream = ParsingStream<Stream>;
pub mod readline {
use crate::machine::streams::Stream;
use rustyline::error::ReadlineError;
use rustyline::{Cmd, Config, Editor, KeyEvent};
use std::io::{Cursor, Error, ErrorKind, Read};
static mut PROMPT: bool = false;
const HISTORY_FILE: &'static str = ".scryer_history";
pub(crate) fn set_prompt(value: bool) {
unsafe {
PROMPT = value;
}
}
#[inline]
fn get_prompt() -> &'static str {
unsafe {
if PROMPT {
"?- "
} else {
""
}
}
}
#[derive(Debug)]
pub struct ReadlineStream {
rl: Editor<()>,
pending_input: Cursor<String>,
}
impl ReadlineStream {
#[inline]
pub(crate) fn new(pending_input: String) -> Self {
let config = Config::builder().check_cursor_position(true).build();
let mut rl = Editor::<()>::with_config(config); //Editor::<()>::new();
if let Some(mut path) = dirs_next::home_dir() {
path.push(HISTORY_FILE);
if path.exists() {
if rl.load_history(&path).is_err() {
println!("Warning: loading history failed");
}
}
}
rl.bind_sequence(KeyEvent::from('\t'), Cmd::Insert(1, "\t".to_string()));
ReadlineStream {
rl,
pending_input: Cursor::new(pending_input),
}
}
#[inline]
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()) {
Ok(text) => {
*self.pending_input.get_mut() = text;
self.pending_input.set_position(0);
unsafe {
if PROMPT {
self.rl.history_mut().add(self.pending_input.get_ref());
self.save_history();
PROMPT = false;
}
}
if self.pending_input.get_ref().chars().last() != Some('\n') {
*self.pending_input.get_mut() += "\n";
}
self.pending_input.read(buf)
}
Err(ReadlineError::Eof) => Ok(0),
Err(e) => Err(Error::new(ErrorKind::InvalidInput, e)),
}
}
fn save_history(&mut self) {
if let Some(mut path) = dirs_next::home_dir() {
path.push(HISTORY_FILE);
if path.exists() {
if self.rl.append_history(&path).is_err() {
println!("Warning: couldn't append history (existing file)");
}
} else {
if self.rl.save_history(&path).is_err() {
println!("Warning: couldn't save history (new file)");
}
}
}
}
pub(crate) fn peek_byte(&mut self) -> std::io::Result<u8> {
set_prompt(false);
loop {
match self.pending_input.get_ref().bytes().next() {
Some(b) => {
return Ok(b);
}
None => match self.call_readline(&mut []) {
Err(e) => {
return Err(e);
}
Ok(0) => {
return Err(Error::new(ErrorKind::UnexpectedEof, "end of file"));
}
_ => {}
},
}
}
}
pub(crate) fn peek_char(&mut self) -> std::io::Result<char> {
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"));
}
_ => {}
},
}
}
}
}
impl Read for ReadlineStream {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
match self.pending_input.read(buf) {
Ok(0) => self.call_readline(buf),
result => result,
}
}
}
#[inline]
pub fn input_stream() -> Stream {
let input_stream = ReadlineStream::input_stream(String::from(""));
Stream::from(input_stream)
}
}
// pub(crate) type PrologStream = ParsingStream<Stream>;
impl MachineState {
pub(crate) fn devour_whitespace(
&mut self,
mut inner: Stream,
atom_tbl: TabledData<Atom>,
) -> Result<bool, ParserError> {
let mut stream = parsing_stream(inner.clone())?;
let mut parser = Parser::new(&mut stream, atom_tbl, self.flags);
let mut parser = Parser::new(inner, self);
parser.devour_whitespace()?;
inner.add_lines_read(parser.lines_read());
inner.add_lines_read(parser.num_lines_read());
let result = parser.eof();
let buf = stream.take_buf();
inner.pause_stream(buf)?;
result
parser.eof()
}
pub(crate) fn read(
&mut self,
mut inner: Stream,
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);
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.num_lines_read() - prior_num_lines_read)
(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))
}
}
// '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.
static mut PROMPT: bool = false;
let buf = stream.take_buf();
inner.pause_stream(buf)?;
const HISTORY_FILE: &'static str = ".scryer_history";
Ok(write_term_to_heap(&term, self))
pub(crate) fn set_prompt(value: bool) {
unsafe {
PROMPT = value;
}
}
#[inline]
pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult {
let term_writer = TermWriter::new(machine_st);
fn get_prompt() -> &'static str {
unsafe {
if PROMPT {
"?- "
} else {
""
}
}
}
#[inline]
pub fn input_stream(arena: &mut Arena) -> Stream {
let input_stream = ReadlineStream::new("");
Stream::from_readline_stream(input_stream, arena)
}
#[derive(Debug)]
pub struct ReadlineStream {
rl: Editor<()>,
pending_input: Cursor<String>,
}
impl ReadlineStream {
#[inline]
pub fn new(pending_input: &str) -> Self {
let config = Config::builder().check_cursor_position(true).build();
let mut rl = Editor::<()>::with_config(config);
if let Some(mut path) = dirs_next::home_dir() {
path.push(HISTORY_FILE);
if path.exists() && rl.load_history(&path).is_err() {
println!("Warning: loading history failed");
}
}
rl.bind_sequence(KeyEvent::from('\t'), Cmd::Insert(1, "\t".to_string()));
ReadlineStream {
rl,
pending_input: Cursor::new(pending_input.to_owned()),
}
}
#[inline]
pub fn reset(&mut self) {
self.pending_input.get_mut().clear();
self.pending_input.set_position(0);
}
fn call_readline(&mut self) -> std::io::Result<usize> {
match self.rl.readline(get_prompt()) {
Ok(text) => {
*self.pending_input.get_mut() = text;
self.pending_input.set_position(0);
unsafe {
if PROMPT {
self.rl.history_mut().add(self.pending_input.get_ref());
self.save_history();
PROMPT = false;
}
}
if self.pending_input.get_ref().chars().last() != Some('\n') {
*self.pending_input.get_mut() += "\n";
}
Ok(self.pending_input.get_ref().len())
}
Err(ReadlineError::Eof) => Ok(0),
Err(e) => Err(Error::new(ErrorKind::InvalidInput, e)),
}
}
fn save_history(&mut self) {
if let Some(mut path) = dirs_next::home_dir() {
path.push(HISTORY_FILE);
if path.exists() {
if self.rl.append_history(&path).is_err() {
println!("Warning: couldn't append history (existing file)");
}
} else if self.rl.save_history(&path).is_err() {
println!("Warning: couldn't save history (new file)");
}
}
}
pub(crate) fn peek_byte(&mut self) -> std::io::Result<u8> {
loop {
match self.pending_input.get_ref().bytes().next() {
Some(0) => {
return Ok(0);
}
Some(b) => {
return Ok(b);
}
None => match self.call_readline() {
Err(e) => {
return Err(e);
}
Ok(0) => {
self.pending_input.get_mut().push('\u{0}');
return Ok(0);
}
_ => {
set_prompt(false);
}
},
}
}
}
}
impl Read for ReadlineStream {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
match self.pending_input.read(buf) {
Ok(0) => {
self.call_readline()?;
self.pending_input.read(buf)
}
result => result
}
}
}
impl CharRead for ReadlineStream {
fn peek_char(&mut self) -> Option<std::io::Result<char>> {
loop {
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);
}
}
}
}
}
}
fn consume(&mut self, nread: usize) {
let offset = self.pending_input.position() as usize;
self.pending_input.set_position((offset + nread) as u64);
}
fn put_back_char(&mut self, c: char) {
let offset = self.pending_input.position() as usize;
self.pending_input.set_position((offset - c.len_utf8()) as u64);
}
}
#[inline]
pub(crate) fn write_term_to_heap(
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)
}
#[derive(Debug)]
struct TermWriter<'a> {
machine_st: &'a mut MachineState,
struct TermWriter<'a, 'b> {
heap: &'a mut Heap,
atom_tbl: &'b mut AtomTable,
queue: SubtermDeque,
var_dict: HeapVarDict,
}
#[derive(Debug)]
pub(crate) struct TermWriteResult {
pub(crate) heap_loc: usize,
pub(crate) var_dict: HeapVarDict,
pub struct TermWriteResult {
pub heap_loc: usize,
pub var_dict: HeapVarDict,
}
impl<'a> TermWriter<'a> {
impl<'a, 'b> TermWriter<'a, 'b> {
#[inline]
fn new(machine_st: &'a mut MachineState) -> Self {
fn new(heap: &'a mut Heap, atom_tbl: &'b mut AtomTable) -> Self {
TermWriter {
machine_st,
heap,
atom_tbl,
queue: SubtermDeque::new(),
var_dict: HeapVarDict::new(),
var_dict: HeapVarDict::with_hasher(FxBuildHasher::default()),
}
}
#[inline]
fn modify_head_of_queue(&mut self, term: &TermRef<'a>, h: usize) {
if let Some((arity, site_h)) = self.queue.pop_front() {
self.machine_st.heap[site_h] = HeapCellValue::Addr(self.term_as_addr(term, h));
self.heap[site_h] = self.term_as_addr(term, h);
if arity > 1 {
self.queue.push_front((arity - 1, site_h + 1));
@@ -267,64 +282,87 @@ impl<'a> TermWriter<'a> {
#[inline]
fn push_stub_addr(&mut self) {
let h = self.machine_st.heap.h();
self.machine_st
.heap
.push(HeapCellValue::Addr(Addr::HeapCell(h)));
let h = self.heap.len();
self.heap.push(heap_loc_as_cell!(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 {
&TermRef::AnonVar(_) | &TermRef::Var(..) => Addr::HeapCell(h),
&TermRef::Cons(..) => Addr::HeapCell(h),
&TermRef::Constant(_, _, c) => self.machine_st.heap.put_constant(c.clone()),
&TermRef::Clause(..) => Addr::Str(h),
&TermRef::PartialString(..) => Addr::PStrLocation(h, 0),
&TermRef::Cons(..) => list_loc_as_cell!(h),
&TermRef::AnonVar(_) | &TermRef::Var(..) => heap_loc_as_cell!(h),
&TermRef::PartialString(_, _, ref src, None) =>
if src.as_str().is_empty() {
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 {
let heap_loc = self.machine_st.heap.h();
let heap_loc = self.heap.len();
for term in breadth_first_iter(term, true) {
let h = self.machine_st.heap.h();
let h = self.heap.len();
match &term {
&TermRef::Cons(lvl, ..) => {
&TermRef::Cons(Level::Root, ..) => {
self.queue.push_back((2, h + 1));
self.machine_st
.heap
.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
self.heap.push(list_loc_as_cell!(h + 1));
self.push_stub_addr();
self.push_stub_addr();
if let Level::Root = lvl {
continue;
}
continue;
}
&TermRef::Clause(lvl, _, ref ct, subterms) => {
self.queue.push_back((subterms.len(), h + 1));
let named = HeapCellValue::NamedStr(subterms.len(), ct.name(), ct.spec());
&TermRef::Cons(..) => {
self.queue.push_back((2, h));
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() {
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);
self.machine_st.heap.push(HeapCellValue::Addr(addr));
self.heap.push(addr);
}
&TermRef::Var(Level::Root, _, ref var) => {
let addr = self.term_as_addr(&term, h);
self.var_dict.insert(var.clone(), Addr::HeapCell(h));
self.machine_st.heap.push(HeapCellValue::Addr(addr));
self.var_dict.insert(var.clone(), heap_loc_as_cell!(h));
self.heap.push(addr);
}
&TermRef::AnonVar(_) => {
if let Some((arity, site_h)) = self.queue.pop_front() {
@@ -335,25 +373,28 @@ impl<'a> TermWriter<'a> {
continue;
}
&TermRef::PartialString(lvl, _, ref pstr, tail) => {
&TermRef::PartialString(lvl, _, ref src, tail) => {
if tail.is_some() {
self.machine_st.heap.allocate_pstr(&pstr);
allocate_pstr(self.heap, src.as_str(), self.atom_tbl);
} 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 {
} else if tail.is_some() {
let h = self.machine_st.heap.h();
if tail.is_some() {
let h = self.heap.len();
self.queue.push_back((1, h - 1));
if let Level::Root = lvl {
continue;
}
}
}
&TermRef::Var(_, _, ref var) => {
if let Some((arity, site_h)) = self.queue.pop_front() {
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 {
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 {

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

View File

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

View File

@@ -115,14 +115,6 @@ test_queries_on_builtins :-
1.1 @< 1,
1.0 @=< 1,
\+ 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]),
\+ \+ 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]).

View File

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

View File

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

View File

@@ -2,8 +2,10 @@
copy_term/3]).
:- use_module(library(charsio)).
:- use_module(library(error)).
:- use_module(library(files)).
:- use_module(library(iso_ext)).
:- use_module(library(lambda)).
:- use_module(library(lists)).
:- use_module(library(si)).
@@ -17,7 +19,7 @@ load_scryerrc :-
append(HomeDir, "/.scryerrc", ScryerrcFile),
( file_exists(ScryerrcFile) ->
atom_chars(ScryerrcFileAtom, ScryerrcFile),
catch(consult(ScryerrcFileAtom), E, print_exception(E))
catch(use_module(ScryerrcFileAtom), E, print_exception(E))
; true
)
; true
@@ -111,7 +113,7 @@ run_goals([g(Gs0)|Goals]) :-
( ends_with_dot(Gs0) -> Gs1 = Gs0
; append(Gs0, ".", Gs1)
),
read_term_from_chars(Gs1, Goal),
read_from_chars(Gs1, Goal),
( catch(
user:Goal,
Exception,
@@ -152,26 +154,27 @@ instruction_match(Term, VarList) :-
( var(Term) ->
throw(error(instantiation_error, repl/0))
; Term = [Item] ->
!,
( atom(Item) ->
( Item == user ->
catch(load(user_input), E, print_exception_with_check(E))
;
( Item == user ->
catch(load(user_input), E, print_exception_with_check(E))
;
submit_query_and_print_results(consult(Item), [])
)
)
; catch(type_error(atom, Item, repl/0),
E,
print_exception_with_check(E))
E,
print_exception_with_check(E))
)
; Term = end_of_file ->
halt
;
submit_query_and_print_results(Term, VarList)
submit_query_and_print_results(Term, VarList)
).
submit_query_and_print_results_(Term, VarList) :-
'$get_b_value'(B),
bb_put('$report_all', false),
bb_put('$report_n_more', 0),
'$call'(Term),
write_eqs_and_read_input(B, VarList),
!.
@@ -184,7 +187,7 @@ submit_query_and_print_results(Term0, VarList) :-
( functor(Term0, call, _) ->
Term = Term0 % prevent pre-mature expansion of incomplete goal
% 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),
submit_query_and_print_results_(Term, VarList),
@@ -193,10 +196,10 @@ submit_query_and_print_results(Term0, VarList) :-
needs_bracketing(Value, Op) :-
catch((functor(Value, F, _),
current_op(EqPrec, EqSpec, Op),
current_op(FPrec, _, F)),
_,
false),
current_op(EqPrec, EqSpec, Op),
current_op(FPrec, _, F)),
_,
false),
( EqPrec < FPrec ->
true
; FPrec > 0, F == Value, graphic_token_char(F) ->
@@ -210,15 +213,15 @@ needs_bracketing(Value, Op) :-
write_goal(G, VarList, MaxDepth) :-
( G = (Var = Value) ->
( var(Value) ->
select((Var = _), VarList, NewVarList)
select((Var = _), VarList, NewVarList)
; VarList = NewVarList
),
write(Var),
write(' = '),
( needs_bracketing(Value, (=)) ->
write('('),
write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]),
write(')')
write('('),
write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]),
write(')')
; write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)])
)
; G == [] ->
@@ -229,20 +232,20 @@ write_goal(G, VarList, MaxDepth) :-
write_last_goal(G, VarList, MaxDepth) :-
( G = (Var = Value) ->
( var(Value) ->
select((Var = _), VarList, NewVarList)
select((Var = _), VarList, NewVarList)
; VarList = NewVarList
),
write(Var),
write(' = '),
( needs_bracketing(Value, (=)) ->
write('('),
write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]),
write(')')
write('('),
write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]),
write(')')
; write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]),
( trailing_period_is_ambiguous(Value) ->
write(' ')
; true
)
( trailing_period_is_ambiguous(Value) ->
write(' ')
; true
)
)
; G == [] ->
write('true')
@@ -272,8 +275,13 @@ trailing_period_is_ambiguous(Value) :-
ValueChars \== ['.'],
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) :-
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),
'$project_atts':project_attributes(Vars0, AttrVars),
copy_term(AttrVars, AttrVars, AttrGoals),
@@ -281,12 +289,13 @@ write_eqs_and_read_input(B, VarList) :-
append([Vars0, AttrGoalVars, AttrVars], Vars),
charsio:extend_var_list(Vars, VarList, NewVarList, fabricated),
'$get_b_value'(B0),
gather_query_vars(VarList, OrigVars),
gather_equations(NewVarList, OrigVars, Equations),
append(Equations, AttrGoals, Goals),
term_variables(Equations, EquationVars),
append([AttrGoalVars, EquationVars], Vars1),
charsio:extend_var_list(Vars1, VarList, NewVarList0, fabricated),
% one layer of depth added for (=/2) functor
maplist(\Term^Vs^term_variables_under_max_depth(Term, 22, Vs), Equations, EquationVars),
append([AttrGoalVars | EquationVars], Vars1),
term_variables(Vars1, Vars2), % deduplicate vars of Vars1 but preserve their order.
charsio:extend_var_list(Vars2, VarList, NewVarList0, fabricated),
( bb_get('$first_answer', true) ->
write(' '),
bb_put('$first_answer', false)
@@ -294,11 +303,11 @@ write_eqs_and_read_input(B, VarList) :-
),
( B0 == B ->
( Goals == [] ->
write('true.'), nl
write('true.'), nl
; loader:thread_goals(Goals, ThreadedGoals, (',')),
write_eq(ThreadedGoals, NewVarList0, 20),
write('.'),
nl
write_eq(ThreadedGoals, NewVarList0, 20),
write('.'),
nl
)
; loader:thread_goals(Goals, ThreadedGoals, (',')),
write_eq(ThreadedGoals, NewVarList0, 20),
@@ -306,7 +315,14 @@ write_eqs_and_read_input(B, VarList) :-
).
read_input(ThreadedGoals, NewVarList) :-
get_single_char(C),
( bb_get('$report_all', true) ->
C = n
; bb_get('$report_n_more', N), N > 1 ->
N1 is N - 1,
bb_put('$report_n_more', N1),
C = n
; get_single_char(C)
),
( C = w ->
nl,
write(' '),
@@ -323,7 +339,13 @@ read_input(ThreadedGoals, NewVarList) :-
help_message,
read_input(ThreadedGoals, NewVarList)
; member(C, ['\n', .]) ->
nl, write('; ...'), nl
nl, write('; ... .'), nl
; C = a ->
bb_put('$report_all', true),
nl, write('; '), false
; C = f ->
bb_put('$report_n_more', 5),
nl, write('; '), false
; read_input(ThreadedGoals, NewVarList)
).
@@ -331,6 +353,8 @@ help_message :-
nl, nl,
write('SPACE, "n" or ";": next solution, if any\n'),
write('RETURN or ".": stop enumeration\n'),
write('"a": enumerate all solutions\n'),
write('"f": enumerate the next 5 solutions\n'),
write('"h": display this help message\n'),
write('"w": write terms without depth limit\n'),
write('"p": print terms with depth limit\n\n').
@@ -340,7 +364,7 @@ gather_query_vars([_ = Var | Vars], QueryVars) :-
QueryVars = [Var | QueryVars0],
gather_query_vars(Vars, QueryVars0)
;
gather_query_vars(Vars, QueryVars)
gather_query_vars(Vars, QueryVars)
).
gather_query_vars([], []).
@@ -358,8 +382,8 @@ select_all([OtherVar = OtherValue | Pairs], Var, Value, Vars, NewPairs) :-
Vars = [OtherVar = OtherValue | Vars0],
select_all(Pairs, Var, Value, Vars0, NewPairs)
;
NewPairs = [OtherVar = OtherValue | NewPairs0],
select_all(Pairs, Var, Value, Vars, NewPairs0)
NewPairs = [OtherVar = OtherValue | NewPairs0],
select_all(Pairs, Var, Value, Vars, NewPairs0)
).
gather_equations([], _, []).
@@ -370,11 +394,11 @@ gather_equations([Var = Value | Pairs], OrigVarList, Goals) :-
append([Var = Value | VarEqs], Goals0, Goals),
gather_equations(NewPairs, OrigVarList, Goals0)
;
gather_equations(Pairs, OrigVarList, Goals)
gather_equations(Pairs, OrigVarList, Goals)
)
;
Goals = [Var = Value | Goals0],
gather_equations(Pairs, OrigVarList, Goals0)
Goals = [Var = Value | Goals0],
gather_equations(Pairs, OrigVarList, Goals0)
).
print_exception(E) :-

810
src/types.rs Normal file
View File

@@ -0,0 +1,810 @@
use crate::arena::*;
use crate::atom_table::*;
use crate::forms::*;
use crate::machine::machine_indices::*;
use crate::machine::partial_string::PartialString;
use crate::machine::streams::*;
use crate::parser::ast::Fixnum;
use crate::parser::rug::{Integer, Rational};
use ordered_float::OrderedFloat;
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::Display for HeapCellValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
read_heap_cell!(*self,
(HeapCellValueTag::Atom, (name, arity)) => {
if arity == 0 {
write!(f, "{}", name.as_str())
} else {
write!(
f,
"{}/{}",
name.as_str(),
arity
)
}
}
(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, "")
}
)
}
_ => {
unreachable!()
}
)
}
}
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)
}
}
}

Some files were not shown because too many files have changed in this diff Show More