use new heap term representation
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
||||
src/static_atoms.rs
|
||||
target/
|
||||
|
||||
|
||||
|
||||
|
||||
565
Cargo.lock
generated
565
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
29
Cargo.toml
29
Cargo.toml
@@ -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,14 +12,19 @@ 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"]
|
||||
|
||||
[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" }
|
||||
proc-macro2 = "*"
|
||||
|
||||
[dependencies]
|
||||
cpu-time = "1.0.0"
|
||||
@@ -31,15 +36,17 @@ 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"
|
||||
# temporary to remove unnecessary braces warnings.
|
||||
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 }
|
||||
rug = { version = "1.12.0", optional = true }
|
||||
rustyline = "7.0.0"
|
||||
unicode_reader = "1.0.0"
|
||||
ring = "0.16.13"
|
||||
ripemd160 = "0.8.0"
|
||||
sha3 = "0.8.2"
|
||||
@@ -50,7 +57,9 @@ 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]
|
||||
|
||||
18
build.rs
18
build.rs
@@ -1,8 +1,11 @@
|
||||
use static_string_indexing::index_static_strings;
|
||||
|
||||
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 +51,21 @@ 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 static_atoms_path = Path::new("src/static_atoms.rs");
|
||||
let mut static_atoms_file = File::create(&static_atoms_path).unwrap();
|
||||
|
||||
let quoted_output = index_static_strings();
|
||||
|
||||
static_atoms_file
|
||||
.write_all(quoted_output.to_string().as_bytes())
|
||||
.unwrap();
|
||||
|
||||
Command::new("rustfmt")
|
||||
.arg(static_atoms_path.as_os_str())
|
||||
.spawn().unwrap()
|
||||
.wait().unwrap();
|
||||
}
|
||||
|
||||
265
crates/prolog_parser/Cargo.lock
generated
265
crates/prolog_parser/Cargo.lock
generated
@@ -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"
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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())
|
||||
};
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::lexer::{Lexer, Token};
|
||||
use prolog_parser::tabled_rc::TabledData;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
#[test]
|
||||
fn valid_token() {
|
||||
let stream = parsing_stream("valid text".as_bytes());
|
||||
assert!(stream.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_stream() {
|
||||
let bytes: &[u8] = &[];
|
||||
assert!(parsing_stream(bytes).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn skip_utf8_bom() {
|
||||
let atom_tbl = TabledData::new(Rc::new("my_module".to_string()));
|
||||
let flags = MachineFlags::default();
|
||||
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);
|
||||
match lexer.next_token() {
|
||||
Ok(Token::Constant(Constant::Fixnum(4))) => (),
|
||||
_ => assert!(false),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_utf16_bom() {
|
||||
let bytes: &[u8] = &[0xFF, 0xFE, 'a' as u8, '\n' as u8];
|
||||
let stream = parsing_stream(bytes);
|
||||
match stream {
|
||||
Err(ParserError::Utf8Error(0, 0)) => (),
|
||||
_ => assert!(false),
|
||||
}
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::lexer::{Lexer, Token};
|
||||
use prolog_parser::tabled_rc::TabledData;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
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 tokens = Vec::new();
|
||||
while !lexer.eof()? {
|
||||
let token = lexer.next_token()?;
|
||||
tokens.push(token);
|
||||
}
|
||||
Ok(tokens)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_multiline_comment() -> Result<(), ParserError> {
|
||||
let tokens = read_all_tokens("/**/ 4\n")?;
|
||||
assert_eq!(tokens, [Token::Constant(Constant::Fixnum(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))]);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_char() -> Result<(), ParserError> {
|
||||
let tokens = read_all_tokens("'a'\n")?;
|
||||
assert_eq!(tokens, [Token::Constant(Constant::Char('a'))]);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn char_with_meta_seq() -> Result<(), ParserError> {
|
||||
let tokens = read_all_tokens(r#"'\\' '\'' '\"' '\`' "#)?; // use literal string so \ are escaped
|
||||
assert_eq!(
|
||||
tokens,
|
||||
[
|
||||
Token::Constant(Constant::Char('\\')),
|
||||
Token::Constant(Constant::Char('\'')),
|
||||
Token::Constant(Constant::Char('"')),
|
||||
Token::Constant(Constant::Char('`'))
|
||||
]
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn char_with_control_seq() -> Result<(), ParserError> {
|
||||
let tokens = read_all_tokens(r"'\a' '\b' '\r' '\f' '\t' '\n' '\v' ")?;
|
||||
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}')),
|
||||
]
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn char_with_octseq() -> Result<(), ParserError> {
|
||||
let tokens = read_all_tokens(r"'\60433\' ")?;
|
||||
assert_eq!(tokens, [Token::Constant(Constant::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}'))]);
|
||||
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
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn char_with_hexseq_invalid() {
|
||||
assert!(read_all_tokens(r"'\x\' ").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty() -> Result<(), ParserError> {
|
||||
let tokens = read_all_tokens("")?;
|
||||
assert!(tokens.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn comment_then_eof() -> Result<(), ParserError> {
|
||||
assert!(read_all_tokens("% only a comment").is_err());
|
||||
Ok(())
|
||||
}
|
||||
11
crates/static-string-indexing/Cargo.toml
Normal file
11
crates/static-string-indexing/Cargo.toml
Normal file
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "static-string-indexing"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "*"
|
||||
syn = { version = "*", features = ['full', 'visit', 'extra-traits'] }
|
||||
indexmap = "*"
|
||||
walkdir = "2"
|
||||
quote = "*"
|
||||
161
crates/static-string-indexing/src/lib.rs
Normal file
161
crates/static-string-indexing/src/lib.rs
Normal file
@@ -0,0 +1,161 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use syn::*;
|
||||
use syn::parse::*;
|
||||
use syn::visit::*;
|
||||
|
||||
use indexmap::IndexSet;
|
||||
|
||||
struct StaticStrVisitor {
|
||||
static_strs: IndexSet<String>,
|
||||
}
|
||||
|
||||
impl StaticStrVisitor {
|
||||
fn new() -> Self {
|
||||
Self { static_strs: IndexSet::new() }
|
||||
}
|
||||
}
|
||||
|
||||
struct MacroFnArgs {
|
||||
args: Vec<Expr>,
|
||||
}
|
||||
|
||||
struct ReadHeapCellExprAndArms {
|
||||
expr: Expr,
|
||||
arms: Vec<Arm>,
|
||||
}
|
||||
|
||||
impl Parse for ReadHeapCellExprAndArms {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let mut arms = vec![];
|
||||
let expr = input.parse()?;
|
||||
|
||||
input.parse::<Token![,]>()?;
|
||||
arms.push(input.parse()?);
|
||||
|
||||
while !input.is_empty() {
|
||||
if let Ok(_) = input.parse::<Token![,]>() {}
|
||||
arms.push(input.parse()?);
|
||||
}
|
||||
|
||||
Ok(ReadHeapCellExprAndArms { expr, arms })
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for MacroFnArgs {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let mut args = vec![];
|
||||
|
||||
if !input.is_empty() {
|
||||
args.push(input.parse()?);
|
||||
}
|
||||
|
||||
while !input.is_empty() {
|
||||
if let Ok(_) = input.parse::<Token![,]>() {}
|
||||
args.push(input.parse()?);
|
||||
}
|
||||
|
||||
Ok(MacroFnArgs { args })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> Visit<'ast> for StaticStrVisitor {
|
||||
fn visit_macro(&mut self, m: &'ast Macro) {
|
||||
let Macro { path, .. } = m;
|
||||
|
||||
if path.is_ident("atom") {
|
||||
if let Some(Lit::Str(string)) = m.parse_body::<Lit>().ok() {
|
||||
self.static_strs.insert(string.value());
|
||||
}
|
||||
} else if path.is_ident("read_heap_cell") {
|
||||
if let Some(m) = m.parse_body::<ReadHeapCellExprAndArms>().ok() {
|
||||
self.visit_expr(&m.expr);
|
||||
|
||||
for e in m.arms {
|
||||
self.visit_arm(&e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let Some(m) = m.parse_body::<MacroFnArgs>().ok() {
|
||||
for e in m.args {
|
||||
self.visit_expr(&e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn index_static_strings() -> TokenStream {
|
||||
use quote::*;
|
||||
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
|
||||
use walkdir::WalkDir;
|
||||
|
||||
fn filter_rust_files(e: &walkdir::DirEntry) -> bool {
|
||||
if e.path().is_dir() {
|
||||
return true;
|
||||
}
|
||||
|
||||
e.path().extension().and_then(OsStr::to_str) == Some("rs")
|
||||
}
|
||||
|
||||
let mut visitor = StaticStrVisitor::new();
|
||||
|
||||
for entry in WalkDir::new("src/").into_iter().filter_entry(filter_rust_files) {
|
||||
let entry = entry.unwrap();
|
||||
|
||||
if entry.path().is_dir() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut file = match File::open(entry.path()) {
|
||||
Ok(file) => file,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let mut src = String::new();
|
||||
|
||||
match file.read_to_string(&mut src) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
panic!("error reading file: {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
let syntax = match syn::parse_file(&src) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
panic!("parse error: {} in file {:?}", e, entry.path());
|
||||
}
|
||||
};
|
||||
|
||||
visitor.visit_file(&syntax);
|
||||
}
|
||||
|
||||
let indices = (0 .. visitor.static_strs.len()).map(|i| i << 3);
|
||||
let indices_iter = indices.clone();
|
||||
|
||||
let static_strs_len = visitor.static_strs.len();
|
||||
let static_strs: &Vec<_> = &visitor.static_strs.into_iter().collect();
|
||||
|
||||
quote! {
|
||||
use phf;
|
||||
|
||||
static STRINGS: [&'static str; #static_strs_len] = [
|
||||
#(
|
||||
#static_strs,
|
||||
)*
|
||||
];
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! atom {
|
||||
#((#static_strs) => { Atom { index: #indices_iter } };)*
|
||||
}
|
||||
|
||||
static STATIC_ATOMS_MAP: phf::Map<&'static str, Atom> = phf::phf_map! {
|
||||
#(#static_strs => { Atom { index: #indices } },)*
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
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::machine::machine_indices::*;
|
||||
use crate::targets::*;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
@@ -14,7 +13,7 @@ pub(crate) trait Allocator<'a> {
|
||||
|
||||
fn mark_anon_var<Target>(&mut self, _: Level, _: GenContext, _: &mut Vec<Target>)
|
||||
where
|
||||
Target: CompilationTarget<'a>;
|
||||
Target: crate::targets::CompilationTarget<'a>;
|
||||
fn mark_non_var<Target>(
|
||||
&mut self,
|
||||
_: Level,
|
||||
@@ -22,10 +21,10 @@ pub(crate) trait Allocator<'a> {
|
||||
_: &'a Cell<RegType>,
|
||||
_: &mut Vec<Target>,
|
||||
) where
|
||||
Target: CompilationTarget<'a>;
|
||||
Target: crate::targets::CompilationTarget<'a>;
|
||||
fn mark_reserved_var<Target>(
|
||||
&mut self,
|
||||
_: Rc<Var>,
|
||||
_: Rc<String>,
|
||||
_: Level,
|
||||
_: &'a Cell<VarReg>,
|
||||
_: GenContext,
|
||||
@@ -33,21 +32,21 @@ pub(crate) trait Allocator<'a> {
|
||||
_: RegType,
|
||||
_: bool,
|
||||
) where
|
||||
Target: CompilationTarget<'a>;
|
||||
Target: crate::targets::CompilationTarget<'a>;
|
||||
fn mark_var<Target>(
|
||||
&mut self,
|
||||
_: Rc<Var>,
|
||||
_: Rc<String>,
|
||||
_: Level,
|
||||
_: &'a Cell<VarReg>,
|
||||
_: GenContext,
|
||||
_: &mut Vec<Target>,
|
||||
) where
|
||||
Target: CompilationTarget<'a>;
|
||||
Target: crate::targets::CompilationTarget<'a>;
|
||||
|
||||
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_at_head(&mut self, args: &Vec<Term>);
|
||||
|
||||
fn advance_arg(&mut self);
|
||||
|
||||
@@ -83,17 +82,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(),
|
||||
|
||||
797
src/arena.rs
Normal file
797
src/arena.rs
Normal file
@@ -0,0 +1,797 @@
|
||||
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,
|
||||
// PausedPrologStream = 0b101100,
|
||||
ReadlineStream = 0b110000,
|
||||
StaticStringStream = 0b110100,
|
||||
ByteStream = 0b111000,
|
||||
// StandardInputStream = 0b100,
|
||||
StandardOutputStream = 0b1100,
|
||||
StandardErrorStream = 0b11000,
|
||||
NullStream = 0b111100,
|
||||
TcpListener = 0b1000000,
|
||||
Dropped = 0b1000100,
|
||||
}
|
||||
|
||||
#[bitfield]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ArenaHeader {
|
||||
size: B56,
|
||||
m: bool,
|
||||
tag: ArenaHeaderTag,
|
||||
}
|
||||
|
||||
const_assert!(mem::size_of::<ArenaHeader>() == 8);
|
||||
|
||||
impl ArenaHeader {
|
||||
#[inline]
|
||||
pub fn build_with(size: u64, tag: ArenaHeaderTag) -> Self {
|
||||
ArenaHeader::new()
|
||||
.with_size(size)
|
||||
.with_tag(tag)
|
||||
.with_m(false)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_tag(self) -> ArenaHeaderTag {
|
||||
self.tag()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, PartialOrd, Eq, Ord)]
|
||||
pub struct TypedArenaPtr<T: ?Sized>(ptr::NonNull<T>);
|
||||
|
||||
impl<T: ?Sized + Hash> Hash for TypedArenaPtr<T> {
|
||||
#[inline(always)]
|
||||
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
||||
(&*self as &T).hash(hasher)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Clone for TypedArenaPtr<T> {
|
||||
fn clone(&self) -> Self {
|
||||
TypedArenaPtr(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Copy for TypedArenaPtr<T> {}
|
||||
|
||||
impl<T: ?Sized> Deref for TypedArenaPtr<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { self.0.as_ref() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> DerefMut for TypedArenaPtr<T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
unsafe { self.0.as_mut() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Display> fmt::Display for TypedArenaPtr<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", **self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> TypedArenaPtr<T> {
|
||||
#[inline]
|
||||
pub const fn new(data: *mut T) -> Self {
|
||||
unsafe { TypedArenaPtr(ptr::NonNull::new_unchecked(data)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_ptr(&self) -> *mut T {
|
||||
self.0.as_ptr()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn header_ptr(&self) -> *const ArenaHeader {
|
||||
let mut ptr = self.as_ptr() as *const u8 as usize;
|
||||
ptr -= mem::size_of::<*const ArenaHeader>();
|
||||
ptr as *const ArenaHeader
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn header_ptr_mut(&mut self) -> *mut ArenaHeader {
|
||||
let mut ptr = self.as_ptr() as *const u8 as usize;
|
||||
ptr -= mem::size_of::<*const ArenaHeader>();
|
||||
ptr as *mut ArenaHeader
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_mark_bit(&self) -> bool {
|
||||
unsafe { (*self.header_ptr()).m() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_tag(&mut self, tag: ArenaHeaderTag) {
|
||||
unsafe { (*self.header_ptr_mut()).set_tag(tag); }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_tag(&self) -> ArenaHeaderTag {
|
||||
unsafe { (*self.header_ptr()).get_tag() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn mark(&mut self) {
|
||||
unsafe {
|
||||
(*self.header_ptr_mut()).set_m(true);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn unmark(&mut self) {
|
||||
unsafe {
|
||||
(*self.header_ptr_mut()).set_m(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ArenaAllocated {
|
||||
type PtrToAllocated;
|
||||
|
||||
fn tag() -> ArenaHeaderTag;
|
||||
fn size(&self) -> usize;
|
||||
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct F64Ptr(pub TypedArenaPtr<OrderedFloat<f64>>);
|
||||
|
||||
impl fmt::Display for F64Ptr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", *self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for F64Ptr {
|
||||
type Target = TypedArenaPtr<OrderedFloat<f64>>;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for F64Ptr {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaAllocated for OrderedFloat<f64> {
|
||||
type PtrToAllocated = F64Ptr;
|
||||
|
||||
#[inline]
|
||||
fn tag() -> ArenaHeaderTag {
|
||||
ArenaHeaderTag::F64
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size(&self) -> usize {
|
||||
mem::size_of::<Self>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
|
||||
unsafe {
|
||||
ptr::write(dst, self);
|
||||
F64Ptr(TypedArenaPtr::new(dst as *mut Self))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaAllocated for Integer {
|
||||
type PtrToAllocated = TypedArenaPtr<Integer>;
|
||||
|
||||
#[inline]
|
||||
fn tag() -> ArenaHeaderTag {
|
||||
ArenaHeaderTag::Integer
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size(&self) -> usize {
|
||||
mem::size_of::<Self>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
|
||||
unsafe {
|
||||
ptr::write(dst, self);
|
||||
TypedArenaPtr::new(dst as *mut Self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaAllocated for Rational {
|
||||
type PtrToAllocated = TypedArenaPtr<Rational>;
|
||||
|
||||
#[inline]
|
||||
fn tag() -> ArenaHeaderTag {
|
||||
ArenaHeaderTag::Rational
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size(&self) -> usize {
|
||||
mem::size_of::<Self>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
|
||||
unsafe {
|
||||
ptr::write(dst, self);
|
||||
TypedArenaPtr::new(dst as *mut Self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaAllocated for OssifiedOpDir {
|
||||
type PtrToAllocated = TypedArenaPtr<OssifiedOpDir>;
|
||||
|
||||
#[inline]
|
||||
fn tag() -> ArenaHeaderTag {
|
||||
ArenaHeaderTag::OssifiedOpDir
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size(&self) -> usize {
|
||||
mem::size_of::<Self>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
|
||||
unsafe {
|
||||
ptr::write(dst, self);
|
||||
TypedArenaPtr::new(dst as *mut Self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaAllocated for LiveLoadState {
|
||||
type PtrToAllocated = TypedArenaPtr<LiveLoadState>;
|
||||
|
||||
#[inline]
|
||||
fn tag() -> ArenaHeaderTag {
|
||||
ArenaHeaderTag::LiveLoadState
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size(&self) -> usize {
|
||||
mem::size_of::<Self>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
|
||||
unsafe {
|
||||
ptr::write(dst, self);
|
||||
TypedArenaPtr::new(dst as *mut Self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaAllocated for TcpListener {
|
||||
type PtrToAllocated = TypedArenaPtr<TcpListener>;
|
||||
|
||||
#[inline]
|
||||
fn tag() -> ArenaHeaderTag {
|
||||
ArenaHeaderTag::TcpListener
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size(&self) -> usize {
|
||||
mem::size_of::<Self>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
|
||||
unsafe {
|
||||
ptr::write(dst, self);
|
||||
TypedArenaPtr::new(dst as *mut Self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct AllocSlab {
|
||||
next: *mut AllocSlab,
|
||||
header: ArenaHeader,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Arena(*mut AllocSlab);
|
||||
|
||||
unsafe impl Send for Arena {}
|
||||
unsafe impl Sync for Arena {}
|
||||
|
||||
impl Arena {
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
Arena(ptr::null_mut())
|
||||
}
|
||||
|
||||
pub unsafe fn alloc<T: ArenaAllocated>(&mut self, value: T) -> T::PtrToAllocated {
|
||||
let size = value.size() + mem::size_of::<AllocSlab>();
|
||||
|
||||
let align = mem::align_of::<AllocSlab>();
|
||||
let layout = alloc::Layout::from_size_align_unchecked(size, align);
|
||||
|
||||
let slab = alloc::alloc(layout) as *mut AllocSlab;
|
||||
|
||||
(*slab).next = self.0;
|
||||
(*slab).header = ArenaHeader::build_with(value.size() as u64, T::tag());
|
||||
|
||||
let offset = (*slab).payload_offset();
|
||||
let result = value.copy_to_arena(offset as *mut T);
|
||||
|
||||
self.0 = slab;
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn drop_slab_in_place(value: &mut AllocSlab) {
|
||||
match value.header.tag() {
|
||||
ArenaHeaderTag::Integer => {
|
||||
ptr::drop_in_place(value.payload_offset() as *mut Integer);
|
||||
}
|
||||
ArenaHeaderTag::Rational => {
|
||||
ptr::drop_in_place(value.payload_offset() as *mut Rational);
|
||||
}
|
||||
ArenaHeaderTag::InputFileStream => {
|
||||
ptr::drop_in_place(value.payload_offset() as *mut InputFileStream);
|
||||
}
|
||||
ArenaHeaderTag::OutputFileStream => {
|
||||
ptr::drop_in_place(value.payload_offset() as *mut OutputFileStream);
|
||||
}
|
||||
ArenaHeaderTag::NamedTcpStream => {
|
||||
ptr::drop_in_place(value.payload_offset() as *mut NamedTcpStream);
|
||||
}
|
||||
ArenaHeaderTag::NamedTlsStream => {
|
||||
ptr::drop_in_place(value.payload_offset() as *mut NamedTlsStream);
|
||||
}
|
||||
// ArenaHeaderTag::PausedPrologStream => {
|
||||
// // idea: PausedPrologStream with only the buffer of unread characters.
|
||||
// // no stream to be wrapped, no nuttin'.
|
||||
// ptr::drop_in_place(value.payload_offset() as *mut PausedPrologStream);
|
||||
// }
|
||||
ArenaHeaderTag::ReadlineStream => {
|
||||
ptr::drop_in_place(value.payload_offset() as *mut ReadlineStream);
|
||||
}
|
||||
ArenaHeaderTag::StaticStringStream => {
|
||||
ptr::drop_in_place(value.payload_offset() as *mut StaticStringStream);
|
||||
}
|
||||
ArenaHeaderTag::ByteStream => {
|
||||
ptr::drop_in_place(value.payload_offset() as *mut ByteStream);
|
||||
}
|
||||
ArenaHeaderTag::OssifiedOpDir => {
|
||||
ptr::drop_in_place(
|
||||
mem::transmute::<_, *mut OssifiedOpDir>(value.payload_offset())
|
||||
);
|
||||
}
|
||||
ArenaHeaderTag::LiveLoadState | ArenaHeaderTag::InactiveLoadState => {
|
||||
ptr::drop_in_place(
|
||||
mem::transmute::<_, *mut LiveLoadState>(value.payload_offset())
|
||||
);
|
||||
}
|
||||
ArenaHeaderTag::Dropped => {
|
||||
}
|
||||
ArenaHeaderTag::TcpListener => {
|
||||
ptr::drop_in_place(value.payload_offset() as *mut TcpListener);
|
||||
}
|
||||
ArenaHeaderTag::F64 | ArenaHeaderTag::StandardOutputStream |
|
||||
ArenaHeaderTag::StandardErrorStream | 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(&self) -> *const u8 {
|
||||
let mut ptr = (self as *const AllocSlab) as usize;
|
||||
ptr += mem::size_of::<AllocSlab>();
|
||||
ptr as *const u8
|
||||
}
|
||||
}
|
||||
|
||||
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!() }
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,19 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::{atom, clause_name};
|
||||
|
||||
use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::clause_types::*;
|
||||
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,7 +21,7 @@ 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;
|
||||
|
||||
@@ -37,31 +38,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(..) => {
|
||||
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(clause_name!("float"), 1, CodeIndex::default());
|
||||
let ct = ClauseType::Named(atom!("float"), 1, CodeIndex::default());
|
||||
Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
|
||||
}
|
||||
_ => Err(ArithmeticError::NonEvaluableFunctor(
|
||||
Constant::Atom(name.clone(), fixity.clone()),
|
||||
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 +72,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(&'a Cell<VarReg>, Rc<String>),
|
||||
}
|
||||
|
||||
impl<'a> Iterator for ArithInstructionIterator<'a> {
|
||||
@@ -97,14 +97,20 @@ 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::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(c))),
|
||||
TermIterState::Var(_, cell, var) => {
|
||||
return Some(Ok(ArithTermRef::Var(cell, var.clone())))
|
||||
return Some(Ok(ArithTermRef::Var(cell, var.clone())));
|
||||
}
|
||||
_ => {
|
||||
return Some(Err(ArithmeticError::NonEvaluableFunctor(
|
||||
Literal::Atom(atom!(".")),
|
||||
2,
|
||||
)));
|
||||
}
|
||||
_ => return Some(Err(ArithmeticError::NonEvaluableFunctor(atom!("'.'"), 2))),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -129,10 +135,31 @@ impl<'a> ArithmeticTermIter<'a> for &'a Term {
|
||||
type Iter = ArithInstructionIterator<'a>;
|
||||
|
||||
fn iter(self) -> Result<Self::Iter, ArithmeticError> {
|
||||
ArithInstructionIterator::new(self)
|
||||
ArithInstructionIterator::from(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: &Literal) -> Result<(), ArithmeticError> {
|
||||
match c {
|
||||
Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(*n))),
|
||||
Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(*n))),
|
||||
Literal::Float(n) => interm.push(ArithmeticTerm::Number(Number::Float(***n))),
|
||||
Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(*n))),
|
||||
Literal::Atom(name) if name == &atom!("e") => interm.push(ArithmeticTerm::Number(
|
||||
Number::Float(OrderedFloat(f64::consts::E)),
|
||||
)),
|
||||
Literal::Atom(name) if name == &atom!("pi") => interm.push(ArithmeticTerm::Number(
|
||||
Number::Float(OrderedFloat(f64::consts::PI)),
|
||||
)),
|
||||
Literal::Atom(name) if name == &atom!("epsilon") => interm.push(ArithmeticTerm::Number(
|
||||
Number::Float(OrderedFloat(f64::EPSILON)),
|
||||
)),
|
||||
_ => return Err(ArithmeticError::NonEvaluableFunctor(*c, 0)),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl<'a> ArithmeticEvaluator<'a> {
|
||||
pub(crate) fn new(bindings: &'a AllocVarDict, target_int: usize) -> Self {
|
||||
ArithmeticEvaluator {
|
||||
@@ -143,68 +170,64 @@ impl<'a> ArithmeticEvaluator<'a> {
|
||||
}
|
||||
|
||||
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,
|
||||
)),
|
||||
match name {
|
||||
atom!("abs") => Ok(ArithmeticInstruction::Abs(a1, t)),
|
||||
atom!("-") => Ok(ArithmeticInstruction::Neg(a1, t)),
|
||||
atom!("+") => Ok(ArithmeticInstruction::Plus(a1, t)),
|
||||
atom!("cos") => Ok(ArithmeticInstruction::Cos(a1, t)),
|
||||
atom!("sin") => Ok(ArithmeticInstruction::Sin(a1, t)),
|
||||
atom!("tan") => Ok(ArithmeticInstruction::Tan(a1, t)),
|
||||
atom!("log") => Ok(ArithmeticInstruction::Log(a1, t)),
|
||||
atom!("exp") => Ok(ArithmeticInstruction::Exp(a1, t)),
|
||||
atom!("sqrt") => Ok(ArithmeticInstruction::Sqrt(a1, t)),
|
||||
atom!("acos") => Ok(ArithmeticInstruction::ACos(a1, t)),
|
||||
atom!("asin") => Ok(ArithmeticInstruction::ASin(a1, t)),
|
||||
atom!("atan") => Ok(ArithmeticInstruction::ATan(a1, t)),
|
||||
atom!("float") => Ok(ArithmeticInstruction::Float(a1, t)),
|
||||
atom!("truncate") => Ok(ArithmeticInstruction::Truncate(a1, t)),
|
||||
atom!("round") => Ok(ArithmeticInstruction::Round(a1, t)),
|
||||
atom!("ceiling") => Ok(ArithmeticInstruction::Ceiling(a1, t)),
|
||||
atom!("floor") => Ok(ArithmeticInstruction::Floor(a1, t)),
|
||||
atom!("sign") => Ok(ArithmeticInstruction::Sign(a1, t)),
|
||||
atom!("\\") => Ok(ArithmeticInstruction::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,
|
||||
)),
|
||||
match name {
|
||||
atom!("+") => Ok(ArithmeticInstruction::Add(a1, a2, t)),
|
||||
atom!("-") => Ok(ArithmeticInstruction::Sub(a1, a2, t)),
|
||||
atom!("/") => Ok(ArithmeticInstruction::Div(a1, a2, t)),
|
||||
atom!("//") => Ok(ArithmeticInstruction::IDiv(a1, a2, t)),
|
||||
atom!("max") => Ok(ArithmeticInstruction::Max(a1, a2, t)),
|
||||
atom!("min") => Ok(ArithmeticInstruction::Min(a1, a2, t)),
|
||||
atom!("div") => Ok(ArithmeticInstruction::IntFloorDiv(a1, a2, t)),
|
||||
atom!("rdiv") => Ok(ArithmeticInstruction::RDiv(a1, a2, t)),
|
||||
atom!("*") => Ok(ArithmeticInstruction::Mul(a1, a2, t)),
|
||||
atom!("**") => Ok(ArithmeticInstruction::Pow(a1, a2, t)),
|
||||
atom!("^") => Ok(ArithmeticInstruction::IntPow(a1, a2, t)),
|
||||
atom!(">>") => Ok(ArithmeticInstruction::Shr(a1, a2, t)),
|
||||
atom!("<<") => Ok(ArithmeticInstruction::Shl(a1, a2, t)),
|
||||
atom!("/\\") => Ok(ArithmeticInstruction::And(a1, a2, t)),
|
||||
atom!("\\/") => Ok(ArithmeticInstruction::Or(a1, a2, t)),
|
||||
atom!("xor") => Ok(ArithmeticInstruction::Xor(a1, a2, t)),
|
||||
atom!("mod") => Ok(ArithmeticInstruction::Mod(a1, a2, t)),
|
||||
atom!("rem") => Ok(ArithmeticInstruction::Rem(a1, a2, t)),
|
||||
atom!("gcd") => Ok(ArithmeticInstruction::Gcd(a1, a2, t)),
|
||||
atom!("atan2") => Ok(ArithmeticInstruction::ATan2(a1, a2, t)),
|
||||
_ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 2)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,7 +242,7 @@ impl<'a> ArithmeticEvaluator<'a> {
|
||||
|
||||
fn instr_from_clause(
|
||||
&mut self,
|
||||
name: ClauseName,
|
||||
name: Atom,
|
||||
arity: usize,
|
||||
) -> Result<ArithmeticInstruction, ArithmeticError> {
|
||||
match arity {
|
||||
@@ -233,7 +256,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,60 +280,22 @@ 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) -> 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::Literal(c) => push_literal(&mut self.interm, c)?,
|
||||
ArithTermRef::Var(cell, name) => {
|
||||
let r = if cell.get().norm().reg_num() == 0 {
|
||||
match self.bindings.get(&name) {
|
||||
@@ -335,27 +320,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.round() 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 +381,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 +414,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 +484,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 +523,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,15 +572,17 @@ 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::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(ref n1), &Number::Integer(ref n2)) => n1.cmp(n2),
|
||||
(&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(&n2),
|
||||
(&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(n2),
|
||||
(&Number::Float(n1), &Number::Integer(ref n2)) => n1.cmp(&OrderedFloat(n2.to_f64())),
|
||||
(&Number::Integer(ref n1), &Number::Rational(ref n2)) => {
|
||||
#[cfg(feature = "num")]
|
||||
@@ -706,54 +612,38 @@ impl Ord for Number {
|
||||
}
|
||||
}
|
||||
|
||||
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
366
src/atom_table.rs
Normal file
@@ -0,0 +1,366 @@
|
||||
use crate::parser::ast::MAX_ARITY;
|
||||
use crate::raw_block::*;
|
||||
use crate::types::*;
|
||||
|
||||
use std::borrow::Borrow;
|
||||
use std::cmp::Ordering;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
use std::str;
|
||||
|
||||
use indexmap::IndexSet;
|
||||
|
||||
use modular_bitfield::prelude::*;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Atom {
|
||||
pub index: usize,
|
||||
}
|
||||
|
||||
const_assert!(mem::size_of::<Atom>() == 8);
|
||||
|
||||
include!("./static_atoms.rs");
|
||||
|
||||
impl<'a> From<&'a Atom> for Atom {
|
||||
#[inline]
|
||||
fn from(atom: &'a Atom) -> Self {
|
||||
*atom
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for Atom {
|
||||
#[inline]
|
||||
fn from(value: bool) -> Self {
|
||||
if value { atom!("true") } else { atom!("false") }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
use std::cell::RefCell;
|
||||
|
||||
const ATOM_TABLE_INIT_SIZE: usize = 1 << 16;
|
||||
const ATOM_TABLE_ALIGN: usize = 8;
|
||||
|
||||
#[cfg(test)]
|
||||
thread_local! {
|
||||
static ATOM_TABLE_BUF_BASE: RefCell<*const u8> = RefCell::new(ptr::null_mut());
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
static mut ATOM_TABLE_BUF_BASE: *const u8 = ptr::null_mut();
|
||||
|
||||
#[cfg(test)]
|
||||
fn set_atom_tbl_buf_base(ptr: *const u8) {
|
||||
ATOM_TABLE_BUF_BASE.with(|atom_table_buf_base| {
|
||||
*atom_table_buf_base.borrow_mut() = ptr;
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn get_atom_tbl_buf_base() -> *const u8 {
|
||||
ATOM_TABLE_BUF_BASE.with(|atom_table_buf_base| *atom_table_buf_base.borrow())
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
fn set_atom_tbl_buf_base(ptr: *const u8) {
|
||||
unsafe {
|
||||
ATOM_TABLE_BUF_BASE = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
pub(crate) fn get_atom_tbl_buf_base() -> *const u8 {
|
||||
unsafe { ATOM_TABLE_BUF_BASE }
|
||||
}
|
||||
|
||||
impl RawBlockTraits for AtomTable {
|
||||
#[inline]
|
||||
fn init_size() -> usize {
|
||||
ATOM_TABLE_INIT_SIZE
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn align() -> usize {
|
||||
ATOM_TABLE_ALIGN
|
||||
}
|
||||
}
|
||||
|
||||
#[bitfield]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct AtomHeader {
|
||||
#[allow(unused)] m: bool,
|
||||
len: B50,
|
||||
#[allow(unused)] padding: B13,
|
||||
}
|
||||
|
||||
impl AtomHeader {
|
||||
fn build_with(len: u64) -> Self {
|
||||
AtomHeader::new().with_len(len).with_m(false)
|
||||
}
|
||||
}
|
||||
|
||||
impl Borrow<str> for Atom {
|
||||
#[inline]
|
||||
fn borrow(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Atom {
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
||||
self.as_str().hash(hasher)
|
||||
// hasher.write_usize(self.index)
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! is_char {
|
||||
($s:expr) => {
|
||||
!$s.is_empty() && $s.chars().nth(1).is_none()
|
||||
};
|
||||
}
|
||||
|
||||
impl Atom {
|
||||
#[inline]
|
||||
pub fn buf(self) -> *const u8 {
|
||||
let ptr = self.as_ptr();
|
||||
|
||||
if ptr.is_null() {
|
||||
return ptr::null();
|
||||
}
|
||||
|
||||
(ptr as usize + mem::size_of::<AtomHeader>()) as *const u8
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_static(self) -> bool {
|
||||
self.index < STRINGS.len() << 3
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn as_ptr(self) -> *const u8 {
|
||||
if self.is_static() {
|
||||
ptr::null()
|
||||
} else {
|
||||
(get_atom_tbl_buf_base() as usize + self.index - (STRINGS.len() << 3)) as *const u8
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn from(index: usize) -> Self {
|
||||
Self { index }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn len(self) -> usize {
|
||||
if self.is_static() {
|
||||
STRINGS[self.index >> 3].len()
|
||||
} else {
|
||||
unsafe { ptr::read(self.as_ptr() as *const AtomHeader).len() as _ }
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn flat_index(self) -> u64 {
|
||||
(self.index >> 3) as u64
|
||||
}
|
||||
|
||||
pub fn as_char(self) -> Option<char> {
|
||||
let s = self.as_str();
|
||||
let mut it = s.chars();
|
||||
|
||||
let c1 = it.next();
|
||||
let c2 = it.next();
|
||||
|
||||
if c2.is_none() { c1 } else { None }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn chars(&self) -> str::Chars {
|
||||
self.as_str().chars()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_str(&self) -> &str {
|
||||
unsafe {
|
||||
let ptr = self.as_ptr();
|
||||
|
||||
if ptr.is_null() {
|
||||
return STRINGS[self.index >> 3];
|
||||
}
|
||||
|
||||
let header = ptr::read::<AtomHeader>(ptr as *const _);
|
||||
let len = header.len() as usize;
|
||||
let buf = (ptr as usize + mem::size_of::<AtomHeader>()) as *mut u8;
|
||||
|
||||
str::from_utf8_unchecked(slice::from_raw_parts(buf, len))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn defrock_brackets(&self, atom_tbl: &mut AtomTable) -> Self {
|
||||
let s = self.as_str();
|
||||
|
||||
let s = if s.starts_with('(') && s.ends_with(')') {
|
||||
&s['('.len_utf8()..s.len() - ')'.len_utf8()]
|
||||
} else {
|
||||
return *self;
|
||||
};
|
||||
|
||||
atom_tbl.build_with(s)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn write_to_ptr(string: &str, ptr: *mut u8) {
|
||||
ptr::write(ptr as *mut _, AtomHeader::build_with(string.len() as u64));
|
||||
let str_ptr = (ptr as usize + mem::size_of::<AtomHeader>()) as *mut u8;
|
||||
ptr::copy_nonoverlapping(string.as_ptr(), str_ptr as *mut u8, string.len());
|
||||
}
|
||||
|
||||
impl PartialOrd for Atom {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &Atom) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Atom {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &Atom) -> Ordering {
|
||||
self.as_str().cmp(other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AtomTable {
|
||||
block: RawBlock<AtomTable>,
|
||||
pub table: IndexSet<Atom>,
|
||||
}
|
||||
|
||||
impl Drop for AtomTable {
|
||||
fn drop(&mut self) {
|
||||
self.block.deallocate();
|
||||
}
|
||||
}
|
||||
|
||||
impl AtomTable {
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
let table = Self {
|
||||
block: RawBlock::new(),
|
||||
table: IndexSet::new(),
|
||||
};
|
||||
|
||||
set_atom_tbl_buf_base(table.block.base);
|
||||
table
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn buf(&self) -> *const u8 {
|
||||
self.block.base as *const u8
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn top(&self) -> *const u8 {
|
||||
self.block.top
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn lookup_str(&self, string: &str) -> Option<Atom> {
|
||||
STATIC_ATOMS_MAP.get(string).or_else(|| self.table.get(string)).cloned()
|
||||
}
|
||||
|
||||
pub fn build_with(&mut self, string: &str) -> Atom {
|
||||
if let Some(atom) = self.lookup_str(string) {
|
||||
return atom;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let size = mem::size_of::<AtomHeader>() + string.len();
|
||||
let align_offset = 8 * mem::align_of::<AtomHeader>();
|
||||
let size = (size & !(align_offset - 1)) + align_offset;
|
||||
|
||||
let len_ptr = {
|
||||
let mut ptr;
|
||||
|
||||
loop {
|
||||
ptr = self.block.alloc(size);
|
||||
|
||||
if ptr.is_null() {
|
||||
self.block.grow();
|
||||
set_atom_tbl_buf_base(self.block.base);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ptr
|
||||
};
|
||||
|
||||
let ptr_base = self.block.base as usize;
|
||||
|
||||
write_to_ptr(string, len_ptr);
|
||||
|
||||
let atom = Atom {
|
||||
index: (STRINGS.len() << 3) + len_ptr as usize - ptr_base,
|
||||
};
|
||||
|
||||
self.table.insert(atom);
|
||||
|
||||
atom
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[bitfield]
|
||||
#[repr(u64)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct AtomCell {
|
||||
name: B46,
|
||||
arity: B10,
|
||||
#[allow(unused)] f: bool,
|
||||
#[allow(unused)] m: bool,
|
||||
#[allow(unused)] tag: B6,
|
||||
}
|
||||
|
||||
impl AtomCell {
|
||||
#[inline]
|
||||
pub fn build_with(name: u64, arity: u16, tag: HeapCellValueTag) -> Self {
|
||||
if arity > 0 {
|
||||
debug_assert!(arity as usize <= MAX_ARITY);
|
||||
|
||||
AtomCell::new()
|
||||
.with_name(name)
|
||||
.with_arity(arity)
|
||||
.with_f(false)
|
||||
.with_tag(tag as u8)
|
||||
} else {
|
||||
AtomCell::new()
|
||||
.with_name(name)
|
||||
.with_f(false)
|
||||
.with_tag(tag as u8)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_index(self) -> usize {
|
||||
self.name() as usize
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_name(self) -> Atom {
|
||||
Atom::from(self.get_index() << 3)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_arity(self) -> usize {
|
||||
self.arity() as usize
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_name_and_arity(self) -> (Atom, usize) {
|
||||
(Atom::from(self.get_index() << 3), self.get_arity())
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
1115
src/clause_types.rs
1115
src/clause_types.rs
File diff suppressed because it is too large
Load Diff
213
src/codegen.rs
213
src/codegen.rs
@@ -1,7 +1,6 @@
|
||||
/// Code generation to WAM-like instructions.
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::tabled_rc::TabledData;
|
||||
use prolog_parser::{perm_v, temp_v};
|
||||
use crate::atom_table::*;
|
||||
use crate::parser::ast::*;
|
||||
use crate::{perm_v, temp_v};
|
||||
|
||||
use crate::allocator::*;
|
||||
use crate::arithmetic::*;
|
||||
@@ -12,6 +11,7 @@ use crate::indexing::*;
|
||||
use crate::instructions::*;
|
||||
use crate::iterators::*;
|
||||
use crate::targets::*;
|
||||
use crate::types::*;
|
||||
|
||||
use crate::machine::machine_errors::*;
|
||||
|
||||
@@ -108,7 +108,11 @@ impl CodeGenSettings {
|
||||
ChoiceInstruction::DynamicInternalElse(
|
||||
global_clock_time,
|
||||
Death::Infinity,
|
||||
if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) },
|
||||
if offset == 0 {
|
||||
NextOrFail::Next(0)
|
||||
} else {
|
||||
NextOrFail::Next(offset)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
ChoiceInstruction::TryMeElse(offset)
|
||||
@@ -120,7 +124,11 @@ impl CodeGenSettings {
|
||||
ChoiceInstruction::DynamicElse(
|
||||
global_clock_tick,
|
||||
Death::Infinity,
|
||||
if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) },
|
||||
if offset == 0 {
|
||||
NextOrFail::Next(0)
|
||||
} else {
|
||||
NextOrFail::Next(offset)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
ChoiceInstruction::TryMeElse(offset)
|
||||
@@ -132,7 +140,11 @@ impl CodeGenSettings {
|
||||
ChoiceInstruction::DynamicInternalElse(
|
||||
global_clock_tick,
|
||||
Death::Infinity,
|
||||
if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) },
|
||||
if offset == 0 {
|
||||
NextOrFail::Next(0)
|
||||
} else {
|
||||
NextOrFail::Next(offset)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
ChoiceInstruction::RetryMeElse(offset)
|
||||
@@ -144,7 +156,11 @@ impl CodeGenSettings {
|
||||
ChoiceInstruction::DynamicElse(
|
||||
global_clock_tick,
|
||||
Death::Infinity,
|
||||
if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) },
|
||||
if offset == 0 {
|
||||
NextOrFail::Next(0)
|
||||
} else {
|
||||
NextOrFail::Next(offset)
|
||||
},
|
||||
)
|
||||
} else if self.non_counted_bt {
|
||||
ChoiceInstruction::DefaultRetryMeElse(offset)
|
||||
@@ -169,11 +185,7 @@ impl CodeGenSettings {
|
||||
|
||||
pub(crate) fn trust_me(&self) -> ChoiceInstruction {
|
||||
if let Some(global_clock_tick) = self.global_clock_tick {
|
||||
ChoiceInstruction::DynamicElse(
|
||||
global_clock_tick,
|
||||
Death::Infinity,
|
||||
NextOrFail::Fail(0),
|
||||
)
|
||||
ChoiceInstruction::DynamicElse(global_clock_tick, Death::Infinity, NextOrFail::Fail(0))
|
||||
} else if self.non_counted_bt {
|
||||
ChoiceInstruction::DefaultTrustMe(0)
|
||||
} else {
|
||||
@@ -183,18 +195,18 @@ impl CodeGenSettings {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct CodeGenerator<TermMarker> {
|
||||
atom_tbl: TabledData<Atom>,
|
||||
pub(crate) struct CodeGenerator<'a, TermMarker> {
|
||||
pub(crate) atom_tbl: &'a mut AtomTable,
|
||||
marker: TermMarker,
|
||||
pub(crate) var_count: IndexMap<Rc<Var>, usize>,
|
||||
pub(crate) var_count: IndexMap<Rc<String>, usize>,
|
||||
settings: CodeGenSettings,
|
||||
pub(crate) skeleton: PredicateSkeleton,
|
||||
pub(crate) jmp_by_locs: Vec<usize>,
|
||||
global_jmp_by_locs_offset: usize,
|
||||
}
|
||||
|
||||
impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
pub(crate) fn new(atom_tbl: TabledData<Atom>, settings: CodeGenSettings) -> Self {
|
||||
impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
|
||||
pub(crate) fn new(atom_tbl: &'b mut AtomTable, settings: CodeGenSettings) -> Self {
|
||||
CodeGenerator {
|
||||
atom_tbl,
|
||||
marker: Allocator::new(),
|
||||
@@ -215,13 +227,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_var_count(&self, var: &'a Var) -> usize {
|
||||
fn get_var_count(&self, var: &'a String) -> usize {
|
||||
*self.var_count.get(var).unwrap()
|
||||
}
|
||||
|
||||
fn mark_var_in_non_callable(
|
||||
&mut self,
|
||||
name: Rc<Var>,
|
||||
name: Rc<String>,
|
||||
term_loc: GenContext,
|
||||
vr: &'a Cell<VarReg>,
|
||||
code: &mut Code,
|
||||
@@ -239,7 +251,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
|
||||
fn mark_non_callable(
|
||||
&mut self,
|
||||
name: Rc<Var>,
|
||||
name: Rc<String>,
|
||||
arg: usize,
|
||||
term_loc: GenContext,
|
||||
vr: &'a Cell<VarReg>,
|
||||
@@ -261,7 +273,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
|
||||
fn add_or_increment_void_instr<Target>(target: &mut Vec<Target>)
|
||||
where
|
||||
Target: CompilationTarget<'a>,
|
||||
Target: crate::targets::CompilationTarget<'a>,
|
||||
{
|
||||
if let Some(ref mut instr) = target.last_mut() {
|
||||
if Target::is_void_instr(&*instr) {
|
||||
@@ -273,10 +285,10 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
target.push(Target::to_void(1));
|
||||
}
|
||||
|
||||
fn deep_var_instr<Target: CompilationTarget<'a>>(
|
||||
fn deep_var_instr<Target: crate::targets::CompilationTarget<'a>>(
|
||||
&mut self,
|
||||
cell: &'a Cell<VarReg>,
|
||||
var: &'a Rc<Var>,
|
||||
var: &'a Rc<String>,
|
||||
term_loc: GenContext,
|
||||
is_exposed: bool,
|
||||
target: &mut Vec<Target>,
|
||||
@@ -289,7 +301,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
}
|
||||
}
|
||||
|
||||
fn subterm_to_instr<Target: CompilationTarget<'a>>(
|
||||
fn subterm_to_instr<Target: crate::targets::CompilationTarget<'a>>(
|
||||
&mut self,
|
||||
subterm: &'a Term,
|
||||
term_loc: GenContext,
|
||||
@@ -303,12 +315,14 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
&Term::AnonVar => {
|
||||
Self::add_or_increment_void_instr(target);
|
||||
}
|
||||
&Term::Cons(ref cell, _, _) | &Term::Clause(ref cell, _, _, _) => {
|
||||
&Term::Cons(ref cell, ..)
|
||||
| &Term::Clause(ref cell, ..)
|
||||
| Term::PartialString(ref cell, ..) => {
|
||||
self.marker
|
||||
.mark_non_var(Level::Deep, term_loc, cell, target);
|
||||
target.push(Target::clause_arg_to_instr(cell.get()));
|
||||
}
|
||||
&Term::Constant(_, ref constant) => {
|
||||
&Term::Literal(_, ref constant) => {
|
||||
target.push(Target::constant_subterm(constant.clone()));
|
||||
}
|
||||
&Term::Var(ref cell, ref var) => {
|
||||
@@ -324,7 +338,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
is_exposed: bool,
|
||||
) -> Vec<Target>
|
||||
where
|
||||
Target: CompilationTarget<'a>,
|
||||
Target: crate::targets::CompilationTarget<'a>,
|
||||
Iter: Iterator<Item = TermRef<'a>>,
|
||||
{
|
||||
let mut target = Vec::new();
|
||||
@@ -343,7 +357,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
target.push(Target::to_structure(ct, terms.len(), cell.get()));
|
||||
|
||||
for subterm in terms {
|
||||
self.subterm_to_instr(subterm.as_ref(), term_loc, is_exposed, &mut target);
|
||||
self.subterm_to_instr(subterm, term_loc, is_exposed, &mut target);
|
||||
}
|
||||
}
|
||||
TermRef::Cons(lvl, cell, head, tail) => {
|
||||
@@ -353,13 +367,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
self.subterm_to_instr(head, term_loc, is_exposed, &mut target);
|
||||
self.subterm_to_instr(tail, term_loc, is_exposed, &mut target);
|
||||
}
|
||||
TermRef::Constant(lvl @ Level::Shallow, cell, Constant::String(ref string)) => {
|
||||
TermRef::Literal(lvl @ Level::Shallow, cell, Literal::String(ref string)) => {
|
||||
self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
|
||||
target.push(Target::to_pstr(lvl, string.to_string(), cell.get(), false));
|
||||
target.push(Target::to_pstr(lvl, *string, cell.get(), false));
|
||||
}
|
||||
TermRef::Constant(lvl @ Level::Shallow, cell, constant) => {
|
||||
TermRef::Literal(lvl @ Level::Shallow, cell, constant) => {
|
||||
self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
|
||||
target.push(Target::to_constant(lvl, constant.clone(), cell.get()));
|
||||
target.push(Target::to_constant(lvl, *constant, cell.get()));
|
||||
}
|
||||
TermRef::PartialString(lvl, cell, string, tail) => {
|
||||
self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
|
||||
@@ -418,6 +432,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
};
|
||||
|
||||
self.update_var_count(chunked_term.post_order_iter());
|
||||
|
||||
vs.mark_vars_in_chunk(chunked_term.post_order_iter(), lt_arity, term_loc);
|
||||
}
|
||||
}
|
||||
@@ -476,7 +491,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
fn compile_inlined(
|
||||
&mut self,
|
||||
ct: &InlinedClauseType,
|
||||
terms: &'a Vec<Box<Term>>,
|
||||
terms: &'a Vec<Term>,
|
||||
term_loc: GenContext,
|
||||
code: &mut Code,
|
||||
) -> Result<(), CompilationError> {
|
||||
@@ -484,16 +499,16 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
&InlinedClauseType::CompareNumber(cmp, ..) => {
|
||||
self.marker.reset_arg(2);
|
||||
|
||||
let (mut lcode, at_1) = self.call_arith_eval(terms[0].as_ref(), 1)?;
|
||||
let (mut rcode, at_2) = self.call_arith_eval(terms[1].as_ref(), 2)?;
|
||||
let (mut lcode, at_1) = self.call_arith_eval(&terms[0], 1)?;
|
||||
let (mut rcode, at_2) = self.call_arith_eval(&terms[1], 2)?;
|
||||
|
||||
let at_1 = if let &Term::Var(ref vr, ref name) = terms[0].as_ref() {
|
||||
let at_1 = if let &Term::Var(ref vr, ref name) = &terms[0] {
|
||||
ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 1, term_loc, vr, code))
|
||||
} else {
|
||||
at_1.unwrap_or(interm!(1))
|
||||
};
|
||||
|
||||
let at_2 = if let &Term::Var(ref vr, ref name) = terms[1].as_ref() {
|
||||
let at_2 = if let &Term::Var(ref vr, ref name) = &terms[1] {
|
||||
ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 2, term_loc, vr, code))
|
||||
} else {
|
||||
at_2.unwrap_or(interm!(2))
|
||||
@@ -504,10 +519,10 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
|
||||
code.push(compare_number_instr!(cmp, at_1, at_2));
|
||||
}
|
||||
&InlinedClauseType::IsAtom(..) => match terms[0].as_ref() {
|
||||
&Term::Constant(_, Constant::Char(_))
|
||||
| &Term::Constant(_, Constant::EmptyList)
|
||||
| &Term::Constant(_, Constant::Atom(..)) => {
|
||||
&InlinedClauseType::IsAtom(..) => match &terms[0] {
|
||||
&Term::Literal(_, Literal::Char(_))
|
||||
| &Term::Literal(_, Literal::Atom(atom!("[]")))
|
||||
| &Term::Literal(_, Literal::Atom(..)) => {
|
||||
code.push(succeed!());
|
||||
}
|
||||
&Term::Var(ref vr, ref name) => {
|
||||
@@ -519,11 +534,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
code.push(fail!());
|
||||
}
|
||||
},
|
||||
&InlinedClauseType::IsAtomic(..) => match terms[0].as_ref() {
|
||||
&Term::AnonVar | &Term::Clause(..) | &Term::Cons(..) => {
|
||||
&InlinedClauseType::IsAtomic(..) => match &terms[0] {
|
||||
&Term::AnonVar | &Term::Clause(..) | &Term::Cons(..) | &Term::PartialString(..) => {
|
||||
code.push(fail!());
|
||||
}
|
||||
&Term::Constant(..) => {
|
||||
&Term::Literal(..) => {
|
||||
code.push(succeed!());
|
||||
}
|
||||
&Term::Var(ref vr, ref name) => {
|
||||
@@ -532,7 +547,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
code.push(is_atomic!(r));
|
||||
}
|
||||
},
|
||||
&InlinedClauseType::IsCompound(..) => match terms[0].as_ref() {
|
||||
&InlinedClauseType::IsCompound(..) => match &terms[0] {
|
||||
&Term::Clause(..) | &Term::Cons(..) => {
|
||||
code.push(succeed!());
|
||||
}
|
||||
@@ -545,8 +560,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
code.push(fail!());
|
||||
}
|
||||
},
|
||||
&InlinedClauseType::IsRational(..) => match terms[0].as_ref() {
|
||||
&Term::Constant(_, Constant::Rational(_)) => {
|
||||
&InlinedClauseType::IsRational(..) => match &terms[0] {
|
||||
&Term::Literal(_, Literal::Rational(_)) => {
|
||||
code.push(succeed!());
|
||||
}
|
||||
&Term::Var(ref vr, ref name) => {
|
||||
@@ -558,8 +573,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
code.push(fail!());
|
||||
}
|
||||
},
|
||||
&InlinedClauseType::IsFloat(..) => match terms[0].as_ref() {
|
||||
&Term::Constant(_, Constant::Float(_)) => {
|
||||
&InlinedClauseType::IsFloat(..) => match &terms[0] {
|
||||
&Term::Literal(_, Literal::Float(_)) => {
|
||||
code.push(succeed!());
|
||||
}
|
||||
&Term::Var(ref vr, ref name) => {
|
||||
@@ -571,12 +586,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
code.push(fail!());
|
||||
}
|
||||
},
|
||||
&InlinedClauseType::IsNumber(..) => match terms[0].as_ref() {
|
||||
&Term::Constant(_, Constant::Float(_))
|
||||
| &Term::Constant(_, Constant::Rational(_))
|
||||
| &Term::Constant(_, Constant::Integer(_))
|
||||
| &Term::Constant(_, Constant::Fixnum(_))
|
||||
| &Term::Constant(_, Constant::Usize(_)) => {
|
||||
&InlinedClauseType::IsNumber(..) => match &terms[0] {
|
||||
&Term::Literal(_, Literal::Float(_))
|
||||
| &Term::Literal(_, Literal::Rational(_))
|
||||
| &Term::Literal(_, Literal::Integer(_))
|
||||
| &Term::Literal(_, Literal::Fixnum(_)) => {
|
||||
// | &Term::Literal(_, Literal::Usize(_)) => {
|
||||
code.push(succeed!());
|
||||
}
|
||||
&Term::Var(ref vr, ref name) => {
|
||||
@@ -588,7 +603,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
code.push(fail!());
|
||||
}
|
||||
},
|
||||
&InlinedClauseType::IsNonVar(..) => match terms[0].as_ref() {
|
||||
&InlinedClauseType::IsNonVar(..) => match &terms[0] {
|
||||
&Term::AnonVar => {
|
||||
code.push(fail!());
|
||||
}
|
||||
@@ -601,10 +616,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
code.push(succeed!());
|
||||
}
|
||||
},
|
||||
&InlinedClauseType::IsInteger(..) => match terms[0].as_ref() {
|
||||
&Term::Constant(_, Constant::Integer(_))
|
||||
| &Term::Constant(_, Constant::Fixnum(_))
|
||||
| &Term::Constant(_, Constant::Usize(_)) => {
|
||||
&InlinedClauseType::IsInteger(..) => match &terms[0] {
|
||||
&Term::Literal(_, Literal::Integer(_)) | &Term::Literal(_, Literal::Fixnum(_)) => {
|
||||
// | &Term::Literal(_, Literal::Usize(_)) => {
|
||||
code.push(succeed!());
|
||||
}
|
||||
&Term::Var(ref vr, ref name) => {
|
||||
@@ -616,8 +630,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
code.push(fail!());
|
||||
}
|
||||
},
|
||||
&InlinedClauseType::IsVar(..) => match terms[0].as_ref() {
|
||||
&Term::Constant(..) | &Term::Clause(..) | &Term::Cons(..) => {
|
||||
&InlinedClauseType::IsVar(..) => match &terms[0] {
|
||||
&Term::Literal(..)
|
||||
| &Term::Clause(..)
|
||||
| &Term::Cons(..)
|
||||
| &Term::PartialString(..) => {
|
||||
code.push(fail!());
|
||||
}
|
||||
&Term::AnonVar => {
|
||||
@@ -635,7 +652,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
}
|
||||
|
||||
fn call_arith_eval(
|
||||
&self,
|
||||
&mut self,
|
||||
term: &'a Term,
|
||||
target_int: usize,
|
||||
) -> Result<ArithCont, ArithmeticError> {
|
||||
@@ -645,17 +662,17 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
|
||||
fn compile_is_call(
|
||||
&mut self,
|
||||
terms: &'a Vec<Box<Term>>,
|
||||
terms: &'a Vec<Term>,
|
||||
code: &mut Code,
|
||||
term_loc: GenContext,
|
||||
use_default_call_policy: bool,
|
||||
) -> Result<(), CompilationError> {
|
||||
let (mut acode, at) = self.call_arith_eval(terms[1].as_ref(), 1)?;
|
||||
let (mut acode, at) = self.call_arith_eval(&terms[1], 1)?;
|
||||
code.append(&mut acode);
|
||||
|
||||
self.marker.reset_arg(2);
|
||||
|
||||
match terms[0].as_ref() {
|
||||
match &terms[0] {
|
||||
&Term::Var(ref vr, ref name) => {
|
||||
let mut target = vec![];
|
||||
|
||||
@@ -666,31 +683,22 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
code.extend(target.into_iter().map(Line::Query));
|
||||
}
|
||||
}
|
||||
&Term::Constant(_, ref c @ Constant::Integer(_))
|
||||
| &Term::Constant(_, ref c @ Constant::Fixnum(_)) => {
|
||||
code.push(Line::Query(put_constant!(
|
||||
Level::Shallow,
|
||||
c.clone(),
|
||||
temp_v!(1)
|
||||
)));
|
||||
&Term::Literal(_, c @ Literal::Integer(_))
|
||||
| &Term::Literal(_, c @ Literal::Fixnum(_)) => {
|
||||
let v = HeapCellValue::from(c);
|
||||
code.push(Line::Query(put_constant!(Level::Shallow, v, temp_v!(1))));
|
||||
|
||||
self.marker.advance_arg();
|
||||
}
|
||||
&Term::Constant(_, ref c @ Constant::Float(_)) => {
|
||||
code.push(Line::Query(put_constant!(
|
||||
Level::Shallow,
|
||||
c.clone(),
|
||||
temp_v!(1)
|
||||
)));
|
||||
&Term::Literal(_, c @ Literal::Float(_)) => {
|
||||
let v = HeapCellValue::from(c);
|
||||
code.push(Line::Query(put_constant!(Level::Shallow, v, temp_v!(1))));
|
||||
|
||||
self.marker.advance_arg();
|
||||
}
|
||||
&Term::Constant(_, ref c @ Constant::Rational(_)) => {
|
||||
code.push(Line::Query(put_constant!(
|
||||
Level::Shallow,
|
||||
c.clone(),
|
||||
temp_v!(1)
|
||||
)));
|
||||
&Term::Literal(_, c @ Literal::Rational(_)) => {
|
||||
let v = HeapCellValue::from(c);
|
||||
code.push(Line::Query(put_constant!(Level::Shallow, v, temp_v!(1))));
|
||||
|
||||
self.marker.advance_arg();
|
||||
}
|
||||
@@ -700,7 +708,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
}
|
||||
}
|
||||
|
||||
let at = if let &Term::Var(ref vr, ref name) = terms[1].as_ref() {
|
||||
let at = if let &Term::Var(ref vr, ref name) = &terms[1] {
|
||||
ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 2, term_loc, vr, code))
|
||||
} else {
|
||||
at.unwrap_or(interm!(1))
|
||||
@@ -724,7 +732,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
&mut self,
|
||||
code: &mut Code,
|
||||
cell: &'a Cell<VarReg>,
|
||||
var: Rc<Var>,
|
||||
var: Rc<String>,
|
||||
term_loc: GenContext,
|
||||
) {
|
||||
let mut target = Vec::new();
|
||||
@@ -837,9 +845,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile_rule<'b: 'a>(
|
||||
pub(crate) fn compile_rule<'c: 'a>(
|
||||
&mut self,
|
||||
rule: &'b Rule,
|
||||
rule: &'c Rule,
|
||||
) -> Result<Code, CompilationError> {
|
||||
let iter = ChunkedIterator::from_rule(rule);
|
||||
let conjunct_info = self.collect_var_data(iter);
|
||||
@@ -897,10 +905,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
UnsafeVarMarker::from_safe_vars(safe_vars)
|
||||
}
|
||||
|
||||
pub(crate) fn compile_fact<'b: 'a>(&mut self, term: &'b Term) -> Code {
|
||||
pub(crate) fn compile_fact<'c: 'a>(&mut self, term: &'c Term) -> Code {
|
||||
self.update_var_count(post_order_iter(term));
|
||||
|
||||
let mut vs = VariableFixtures::new();
|
||||
|
||||
vs.mark_vars_in_chunk(post_order_iter(term), term.arity(), GenContext::Head);
|
||||
|
||||
vs.populate_restricting_sets();
|
||||
@@ -908,7 +917,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
|
||||
let mut code = Vec::new();
|
||||
|
||||
if let &Term::Clause(_, _, ref args, _) = term {
|
||||
if let &Term::Clause(_, _, ref args) = term {
|
||||
self.marker.reset_at_head(args);
|
||||
|
||||
let iter = FactInstruction::iter(term);
|
||||
@@ -979,7 +988,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
break;
|
||||
}
|
||||
}
|
||||
match **arg {
|
||||
match arg {
|
||||
Term::AnonVar | Term::Var(..) => (),
|
||||
_ => {
|
||||
match optimal_index {
|
||||
@@ -1003,7 +1012,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
for (right_index, clause) in clauses.iter().enumerate() {
|
||||
// Can unwrap safely.
|
||||
if let Some(arg) = clause.args().unwrap().iter().nth(optimal_index) {
|
||||
match **arg {
|
||||
match arg {
|
||||
Term::Var(..) | Term::AnonVar => {
|
||||
if left_index < right_index {
|
||||
subseqs.push((left_index, right_index));
|
||||
@@ -1025,17 +1034,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
subseqs
|
||||
}
|
||||
|
||||
fn compile_pred_subseq<'b: 'a, I: Indexer>(
|
||||
fn compile_pred_subseq<'c: 'a, I: Indexer>(
|
||||
&mut self,
|
||||
clauses: &'b [PredicateClause],
|
||||
clauses: &'c [PredicateClause],
|
||||
optimal_index: usize,
|
||||
) -> Result<Code, CompilationError> {
|
||||
let mut code = VecDeque::new();
|
||||
let mut code_offsets = CodeOffsets::new(
|
||||
self.atom_tbl.clone(),
|
||||
I::new(),
|
||||
optimal_index + 1,
|
||||
);
|
||||
let mut code_offsets = CodeOffsets::new(I::new(), optimal_index + 1);
|
||||
|
||||
let mut skip_stub_try_me_else = false;
|
||||
let jmp_by_locs_len = self.jmp_by_locs.len();
|
||||
@@ -1087,7 +1092,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
|
||||
if let Some(arg) = arg {
|
||||
let index = code.len();
|
||||
code_offsets.index_term(arg, index, &mut clause_index_info);
|
||||
code_offsets.index_term(arg, index, &mut clause_index_info, self.atom_tbl);
|
||||
}
|
||||
|
||||
if !(clauses.len() == 1 && self.settings.is_extensible) {
|
||||
@@ -1122,9 +1127,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
Ok(Vec::from(code))
|
||||
}
|
||||
|
||||
pub(crate) fn compile_predicate<'b: 'a>(
|
||||
pub(crate) fn compile_predicate<'c: 'a>(
|
||||
&mut self,
|
||||
clauses: &'b Vec<PredicateClause>,
|
||||
clauses: &'c Vec<PredicateClause>,
|
||||
) -> Result<Code, CompilationError> {
|
||||
let mut code = Code::new();
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
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::machine::machine_indices::*;
|
||||
use crate::targets::*;
|
||||
use crate::parser::ast::*;
|
||||
use crate::targets::CompilationTarget;
|
||||
|
||||
use crate::temp_v;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::BTreeSet;
|
||||
@@ -15,23 +15,23 @@ use std::rc::Rc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct DebrayAllocator {
|
||||
bindings: IndexMap<Rc<Var>, VarData>,
|
||||
bindings: IndexMap<Rc<String>, VarData>,
|
||||
arg_c: usize,
|
||||
temp_lb: usize,
|
||||
arity: usize, // 0 if not at head.
|
||||
contents: IndexMap<usize, Rc<Var>>,
|
||||
contents: IndexMap<usize, Rc<String>>,
|
||||
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 +44,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 +70,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 +98,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;
|
||||
@@ -149,7 +149,7 @@ impl DebrayAllocator {
|
||||
|
||||
fn alloc_reg_to_var<'a, Target>(
|
||||
&mut self,
|
||||
var: &Var,
|
||||
var: &String,
|
||||
lvl: Level,
|
||||
term_loc: GenContext,
|
||||
target: &mut Vec<Target>,
|
||||
@@ -193,7 +193,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() {
|
||||
@@ -272,7 +272,7 @@ impl<'a> Allocator<'a> for DebrayAllocator {
|
||||
|
||||
fn mark_var<Target>(
|
||||
&mut self,
|
||||
var: Rc<Var>,
|
||||
var: Rc<String>,
|
||||
lvl: Level,
|
||||
cell: &'a Cell<VarReg>,
|
||||
term_loc: GenContext,
|
||||
@@ -302,7 +302,7 @@ impl<'a> Allocator<'a> for DebrayAllocator {
|
||||
|
||||
fn mark_reserved_var<Target>(
|
||||
&mut self,
|
||||
var: Rc<Var>,
|
||||
var: Rc<String>,
|
||||
lvl: Level,
|
||||
cell: &'a Cell<VarReg>,
|
||||
term_loc: GenContext,
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
480
src/forms.rs
480
src/forms.rs
@@ -1,33 +1,38 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::parser::OpDesc;
|
||||
use prolog_parser::{clause_name, is_infix, is_postfix};
|
||||
use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::parser::ast::*;
|
||||
use crate::parser::parser::CompositeOpDesc;
|
||||
use crate::parser::rug::{Integer, Rational};
|
||||
use crate::{is_infix, is_postfix};
|
||||
|
||||
use crate::clause_types::*;
|
||||
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::types::*;
|
||||
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use ordered_float::OrderedFloat;
|
||||
|
||||
use slice_deque::*;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::convert::TryFrom;
|
||||
use std::ops::AddAssign;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub(crate) type PredicateKey = (ClauseName, usize); // name, arity.
|
||||
pub type PredicateKey = (Atom, usize); // name, arity.
|
||||
|
||||
pub(crate) type Predicate = Vec<PredicateClause>;
|
||||
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 +40,7 @@ pub(crate) enum TopLevel {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) enum AppendOrPrepend {
|
||||
pub enum AppendOrPrepend {
|
||||
Append,
|
||||
Prepend,
|
||||
}
|
||||
@@ -51,7 +56,7 @@ impl AppendOrPrepend {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) enum Level {
|
||||
pub enum Level {
|
||||
Deep,
|
||||
Root,
|
||||
Shallow,
|
||||
@@ -67,12 +72,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 +100,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 +128,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 +145,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!(":-")),
|
||||
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 +184,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 +194,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 +209,21 @@ 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),
|
||||
// TODO: add this to `Term` in `crate::parser` like `first_arg`.
|
||||
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 {
|
||||
@@ -228,36 +235,26 @@ impl PredicateClause {
|
||||
}
|
||||
|
||||
#[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 +262,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,
|
||||
}
|
||||
|
||||
impl OpDecl {
|
||||
#[inline]
|
||||
pub(crate) fn new(prec: usize, spec: Specifier, name: ClauseName) -> Self {
|
||||
Self { prec, spec, name }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn remove(&mut self, op_dir: &mut OpDir) {
|
||||
let prec = self.prec;
|
||||
self.prec = 0;
|
||||
|
||||
self.insert_into_op_dir(op_dir);
|
||||
self.prec = prec;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn fixity(&self) -> Fixity {
|
||||
match self.spec {
|
||||
#[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(op_desc: OpDesc, name: Atom) -> Self {
|
||||
Self { op_desc, name }
|
||||
}
|
||||
|
||||
pub(crate) fn insert_into_op_dir(&self, op_dir: &mut OpDir) -> Option<(usize, Specifier)> {
|
||||
let key = (self.name.clone(), self.fixity());
|
||||
#[inline]
|
||||
pub(crate) fn remove(&mut self, op_dir: &mut OpDir) {
|
||||
let prec = self.op_desc.get_prec();
|
||||
self.op_desc.set(0, self.op_desc.get_spec());
|
||||
|
||||
match op_dir.get(&key) {
|
||||
self.insert_into_op_dir(op_dir);
|
||||
self.op_desc.set(prec, self.op_desc.get_spec());
|
||||
}
|
||||
|
||||
pub(crate) fn insert_into_op_dir(&self, op_dir: &mut OpDir) -> Option<OpDesc> {
|
||||
let key = (self.name, fixity(self.op_desc.get_spec() as u32));
|
||||
|
||||
match op_dir.get_mut(&key) {
|
||||
Some(cell) => {
|
||||
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 +334,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 +347,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) => 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: try to rid yourself and the earth of the next two functions.
|
||||
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)
|
||||
) -> Option<OpDesc> {
|
||||
fetch_op_spec_from_existing(name, 1, spec, op_dir)
|
||||
.or_else(|| fetch_op_spec_from_existing(name, 2, 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,36 +400,28 @@ pub(crate) fn fetch_op_spec_from_existing(
|
||||
}
|
||||
}
|
||||
|
||||
spec.or_else(|| fetch_op_spec(name, arity, op_dir))
|
||||
op_desc.or_else(|| fetch_op_spec(name, arity, op_dir))
|
||||
}
|
||||
|
||||
pub(crate) fn fetch_op_spec(
|
||||
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())
|
||||
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())
|
||||
op_dir.get(&(name, Fixity::Post)).and_then(|op_desc| {
|
||||
if op_desc.get_prec() > 0 {
|
||||
Some(*op_desc)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -413,22 +431,22 @@ pub(crate) fn fetch_op_spec(
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type ModuleDir = IndexMap<ClauseName, Module>;
|
||||
pub(crate) type ModuleDir = IndexMap<Atom, Module>;
|
||||
|
||||
#[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,7 +458,10 @@ 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(),
|
||||
@@ -465,61 +486,115 @@ impl Module {
|
||||
}
|
||||
}
|
||||
|
||||
#[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 {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Number::Float(OrderedFloat(0f64))
|
||||
Number::Fixnum(Fixnum::build_with(0))
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Constant> for Number {
|
||||
pub trait ArenaFrom<T> {
|
||||
fn arena_from(value: T, arena: &mut Arena) -> Self;
|
||||
}
|
||||
|
||||
impl ArenaFrom<Integer> for Number {
|
||||
#[inline]
|
||||
fn into(self) -> Constant {
|
||||
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),
|
||||
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 Into<HeapCellValue> for Number {
|
||||
impl ArenaFrom<u64> 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: 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 +603,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,7 +613,7 @@ 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::Rational(ref r) => &**r < &0,
|
||||
@@ -548,36 +623,20 @@ 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::Rational(ref r) => &**r == &0,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn abs(self) -> Self {
|
||||
match self {
|
||||
Number::Fixnum(n) => {
|
||||
if let Some(n) = n.checked_abs() {
|
||||
Number::from(n)
|
||||
} else {
|
||||
Number::from(Integer::from(n).abs())
|
||||
}
|
||||
}
|
||||
Number::Integer(n) => Number::from(Integer::from(n.abs_ref())),
|
||||
Number::Float(f) => Number::Float(OrderedFloat(f.abs())),
|
||||
Number::Rational(r) => Number::from(Rational::from(r.abs_ref())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum OptArgIndexKey {
|
||||
Constant(usize, usize, Constant, Vec<Constant>), // index, IndexingCode location, opt arg, alternatives
|
||||
Literal(usize, usize, Literal, Vec<Literal>), // index, IndexingCode location, opt arg, alternatives
|
||||
List(usize, usize), // index, IndexingCode location
|
||||
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 +648,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 +666,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 +676,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 +690,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 +759,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 +771,7 @@ impl LocalPredicateSkeleton {
|
||||
is_multifile: false,
|
||||
clause_clause_locs: sdeq![],
|
||||
clause_assert_margin: 0,
|
||||
retracted_dynamic_clauses: Some(vec![]),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -730,6 +791,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)]
|
||||
@@ -781,3 +856,12 @@ impl PredicateSkeleton {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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.
|
||||
}
|
||||
|
||||
|
||||
2741
src/heap_iter.rs
2741
src/heap_iter.rs
File diff suppressed because it is too large
Load Diff
1748
src/heap_print.rs
1748
src/heap_print.rs
File diff suppressed because it is too large
Load Diff
308
src/indexing.rs
308
src/indexing.rs
@@ -1,33 +1,20 @@
|
||||
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::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 +22,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 +32,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 +52,20 @@ fn search_skeleton_for_first_key_type(
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(retracted_clauses) = retracted_dynamic_clauses {
|
||||
for clause_index_info in retracted_clauses.iter().rev() {
|
||||
if clause_index_info.opt_arg_index_key.has_key_type(key_type) {
|
||||
return Some(&clause_index_info.opt_arg_index_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
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 +76,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 {
|
||||
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => match v {
|
||||
IndexingCodePtr::External(_) => false,
|
||||
IndexingCodePtr::DynamicExternal(_) => true,
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
_ => unreachable!()
|
||||
_ => unreachable!(),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
Self {
|
||||
skeleton,
|
||||
retracted_dynamic_clauses,
|
||||
indexing_code,
|
||||
offset: 0,
|
||||
append_or_prepend,
|
||||
@@ -105,15 +102,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 +143,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 +177,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 +230,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 +250,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 +280,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 +313,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn index_constant(&mut self, constant: Constant, index: usize) {
|
||||
fn index_constant(&mut self, constant: Literal, index: usize) {
|
||||
loop {
|
||||
let indexing_code_len = self.indexing_code.len();
|
||||
|
||||
@@ -338,10 +344,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 +384,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 +392,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 +441,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 +611,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 +622,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 +664,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 +702,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 +720,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 +741,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 +753,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 +774,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 +810,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 +845,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 +1033,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 +1084,52 @@ fn uncap_choice_seq_with_try(prelude: &mut [IndexedChoiceInstruction]) {
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn constant_key_alternatives(constant: &Constant, atom_tbl: TabledData<Atom>) -> Vec<Constant> {
|
||||
pub(crate) fn constant_key_alternatives(
|
||||
constant: Literal,
|
||||
atom_tbl: &mut AtomTable,
|
||||
// arena: &mut Arena,
|
||||
) -> Vec<Literal> {
|
||||
let mut constants = vec![];
|
||||
|
||||
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));
|
||||
Literal::Atom(ref name) => {
|
||||
if let Some(c) = name.as_char() {
|
||||
constants.push(Literal::Char(c));
|
||||
}
|
||||
}
|
||||
Literal::Char(c) => {
|
||||
let atom = atom_tbl.build_with(&c.to_string());
|
||||
constants.push(Literal::Atom(atom));
|
||||
}
|
||||
/*
|
||||
Literal::Fixnum(ref n) => {
|
||||
constants.push(Literal::Integer(arena_alloc!(n, arena))); //Rc::new(Integer::from(*n))));
|
||||
|
||||
if op.is_some() {
|
||||
constants.push(Constant::Atom(name.clone(), None));
|
||||
}
|
||||
}
|
||||
Constant::Char(c) => {
|
||||
let atom = clause_name!(c.to_string(), atom_tbl);
|
||||
constants.push(Constant::Atom(atom, None));
|
||||
}
|
||||
Constant::Fixnum(ref n) => {
|
||||
constants.push(Constant::Integer(Rc::new(Integer::from(*n))));
|
||||
|
||||
/*
|
||||
if *n >= 0 {
|
||||
if 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 +1138,16 @@ pub(crate) fn constant_key_alternatives(constant: &Constant, atom_tbl: TabledDat
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct StaticCodeIndices {
|
||||
constants: IndexMap<Constant, SliceDeque<IndexedChoiceInstruction>>,
|
||||
constants: IndexMap<Literal, SliceDeque<IndexedChoiceInstruction>>,
|
||||
lists: SliceDeque<IndexedChoiceInstruction>,
|
||||
structures: IndexMap<(ClauseName, usize), SliceDeque<IndexedChoiceInstruction>>,
|
||||
structures: IndexMap<(Atom, usize), SliceDeque<IndexedChoiceInstruction>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct DynamicCodeIndices {
|
||||
constants: IndexMap<Constant, SliceDeque<usize>>,
|
||||
constants: IndexMap<Literal, SliceDeque<usize>>,
|
||||
lists: SliceDeque<usize>,
|
||||
structures: IndexMap<(ClauseName, usize), SliceDeque<usize>>,
|
||||
structures: IndexMap<(Atom, usize), SliceDeque<usize>>,
|
||||
}
|
||||
|
||||
pub(crate) trait Indexer {
|
||||
@@ -1144,9 +1155,9 @@ pub(crate) trait Indexer {
|
||||
|
||||
fn new() -> Self;
|
||||
|
||||
fn constants(&mut self) -> &mut IndexMap<Constant, SliceDeque<Self::ThirdLevelIndex>>;
|
||||
fn constants(&mut self) -> &mut IndexMap<Literal, SliceDeque<Self::ThirdLevelIndex>>;
|
||||
fn lists(&mut self) -> &mut SliceDeque<Self::ThirdLevelIndex>;
|
||||
fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque<Self::ThirdLevelIndex>>;
|
||||
fn structures(&mut self) -> &mut IndexMap<(Atom, usize), SliceDeque<Self::ThirdLevelIndex>>;
|
||||
|
||||
fn compute_index(is_initial_index: bool, index: usize) -> Self::ThirdLevelIndex;
|
||||
|
||||
@@ -1166,10 +1177,7 @@ pub(crate) trait Indexer {
|
||||
prelude: &mut SliceDeque<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;
|
||||
}
|
||||
@@ -1187,7 +1195,7 @@ impl Indexer for StaticCodeIndices {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn constants(&mut self) -> &mut IndexMap<Constant, SliceDeque<IndexedChoiceInstruction>> {
|
||||
fn constants(&mut self) -> &mut IndexMap<Literal, SliceDeque<IndexedChoiceInstruction>> {
|
||||
&mut self.constants
|
||||
}
|
||||
|
||||
@@ -1197,7 +1205,7 @@ impl Indexer for StaticCodeIndices {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque<IndexedChoiceInstruction>> {
|
||||
fn structures(&mut self) -> &mut IndexMap<(Atom, usize), SliceDeque<IndexedChoiceInstruction>> {
|
||||
&mut self.structures
|
||||
}
|
||||
|
||||
@@ -1271,7 +1279,10 @@ impl Indexer for StaticCodeIndices {
|
||||
}
|
||||
|
||||
#[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);
|
||||
@@ -1300,7 +1311,7 @@ impl Indexer for DynamicCodeIndices {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn constants(&mut self) -> &mut IndexMap<Constant, SliceDeque<usize>> {
|
||||
fn constants(&mut self) -> &mut IndexMap<Literal, SliceDeque<usize>> {
|
||||
&mut self.constants
|
||||
}
|
||||
|
||||
@@ -1310,7 +1321,7 @@ impl Indexer for DynamicCodeIndices {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque<usize>> {
|
||||
fn structures(&mut self) -> &mut IndexMap<(Atom, usize), SliceDeque<usize>> {
|
||||
&mut self.structures
|
||||
}
|
||||
|
||||
@@ -1395,19 +1406,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 +1424,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(sdeq![]);
|
||||
|
||||
let is_initial_index = code.is_empty();
|
||||
code.push_back(I::compute_index(is_initial_index, index));
|
||||
|
||||
for constant in &overlapping_constants {
|
||||
let code = self.indices.constants().entry(constant.clone()).or_insert(sdeq![]);
|
||||
let code = self
|
||||
.indices
|
||||
.constants()
|
||||
.entry(*constant)
|
||||
.or_insert(sdeq![]);
|
||||
|
||||
let is_initial_index = code.is_empty();
|
||||
let index = I::compute_index(is_initial_index, index);
|
||||
@@ -1438,8 +1452,9 @@ 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![]);
|
||||
@@ -1456,28 +1471,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);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
@@ -1,46 +1,42 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::clause_name;
|
||||
use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::parser::ast::*;
|
||||
|
||||
use crate::clause_types::*;
|
||||
use crate::forms::*;
|
||||
use crate::indexing::IndexingCodePtr;
|
||||
use crate::types::*;
|
||||
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)]),
|
||||
RegType::Temp(r) => functor!(atom!("x"), [fixnum(r)]),
|
||||
RegType::Perm(r) => functor!(atom!("y"), [fixnum(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")]),
|
||||
Level::Root => functor!(atom!("level"), [atom(atom!("root"))]),
|
||||
Level::Shallow => functor!(atom!("level"), [atom(atom!("shallow"))]),
|
||||
Level::Deep => functor!(atom!("level"), [atom(atom!("deep"))]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ArithmeticTerm {
|
||||
fn into_functor(&self) -> MachineStub {
|
||||
fn into_functor(&self, arena: &mut Arena) -> MachineStub {
|
||||
match self {
|
||||
&ArithmeticTerm::Reg(r) => reg_type_into_functor(r),
|
||||
&ArithmeticTerm::Interm(i) => {
|
||||
functor!("intermediate", [integer(i)])
|
||||
functor!(atom!("intermediate"), [fixnum(i)])
|
||||
}
|
||||
&ArithmeticTerm::Number(ref n) => {
|
||||
vec![n.clone().into()]
|
||||
&ArithmeticTerm::Number(n) => {
|
||||
vec![HeapCellValue::from((n, arena))]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,33 +83,30 @@ impl ChoiceInstruction {
|
||||
match (death, next_or_fail) {
|
||||
(Death::Infinity, NextOrFail::Next(i)) => {
|
||||
functor!(
|
||||
"dynamic_else",
|
||||
[integer(birth), atom("inf"), integer(i)]
|
||||
atom!("dynamic_else"),
|
||||
[fixnum(birth), atom(atom!("inf")), fixnum(i)]
|
||||
)
|
||||
}
|
||||
(Death::Infinity, NextOrFail::Fail(i)) => {
|
||||
let next_functor = functor!("fail", [integer(i)]);
|
||||
let next_functor = functor!(atom!("fail"), [fixnum(i)]);
|
||||
|
||||
functor!(
|
||||
"dynamic_else",
|
||||
[integer(birth), atom("inf"), aux(h, 0)],
|
||||
atom!("dynamic_else"),
|
||||
[fixnum(birth), atom(atom!("inf")), str(h, 0)],
|
||||
[next_functor]
|
||||
)
|
||||
}
|
||||
(Death::Finite(d), NextOrFail::Fail(i)) => {
|
||||
let next_functor = functor!("fail", [integer(i)]);
|
||||
let next_functor = functor!(atom!("fail"), [fixnum(i)]);
|
||||
|
||||
functor!(
|
||||
"dynamic_else",
|
||||
[integer(birth), integer(d), aux(h, 0)],
|
||||
atom!("dynamic_else"),
|
||||
[fixnum(birth), fixnum(d), str(h, 0)],
|
||||
[next_functor]
|
||||
)
|
||||
}
|
||||
(Death::Finite(d), NextOrFail::Next(i)) => {
|
||||
functor!(
|
||||
"dynamic_else",
|
||||
[integer(birth), integer(d), integer(i)]
|
||||
)
|
||||
functor!(atom!("dynamic_else"), [fixnum(birth), fixnum(d), fixnum(i)])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,50 +114,50 @@ impl ChoiceInstruction {
|
||||
match (death, next_or_fail) {
|
||||
(Death::Infinity, NextOrFail::Next(i)) => {
|
||||
functor!(
|
||||
"dynamic_internal_else",
|
||||
[integer(birth), atom("inf"), integer(i)]
|
||||
atom!("dynamic_internal_else"),
|
||||
[fixnum(birth), atom(atom!("inf")), fixnum(i)]
|
||||
)
|
||||
}
|
||||
(Death::Infinity, NextOrFail::Fail(i)) => {
|
||||
let next_functor = functor!("fail", [integer(i)]);
|
||||
let next_functor = functor!(atom!("fail"), [fixnum(i)]);
|
||||
|
||||
functor!(
|
||||
"dynamic_internal_else",
|
||||
[integer(birth), atom("inf"), aux(h, 0)],
|
||||
atom!("dynamic_internal_else"),
|
||||
[fixnum(birth), atom(atom!("inf")), str(h, 0)],
|
||||
[next_functor]
|
||||
)
|
||||
}
|
||||
(Death::Finite(d), NextOrFail::Fail(i)) => {
|
||||
let next_functor = functor!("fail", [integer(i)]);
|
||||
let next_functor = functor!(atom!("fail"), [fixnum(i)]);
|
||||
|
||||
functor!(
|
||||
"dynamic_internal_else",
|
||||
[integer(birth), integer(d), aux(h, 0)],
|
||||
atom!("dynamic_internal_else"),
|
||||
[fixnum(birth), fixnum(d), str(h, 0)],
|
||||
[next_functor]
|
||||
)
|
||||
}
|
||||
(Death::Finite(d), NextOrFail::Next(i)) => {
|
||||
functor!(
|
||||
"dynamic_internal_else",
|
||||
[integer(birth), integer(d), integer(i)]
|
||||
atom!("dynamic_internal_else"),
|
||||
[fixnum(birth), fixnum(d), fixnum(i)]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
&ChoiceInstruction::TryMeElse(offset) => {
|
||||
functor!("try_me_else", [integer(offset)])
|
||||
functor!(atom!("try_me_else"), [fixnum(offset)])
|
||||
}
|
||||
&ChoiceInstruction::RetryMeElse(offset) => {
|
||||
functor!("retry_me_else", [integer(offset)])
|
||||
functor!(atom!("retry_me_else"), [fixnum(offset)])
|
||||
}
|
||||
&ChoiceInstruction::TrustMe(offset) => {
|
||||
functor!("trust_me", [integer(offset)])
|
||||
functor!(atom!("trust_me"), [fixnum(offset)])
|
||||
}
|
||||
&ChoiceInstruction::DefaultRetryMeElse(offset) => {
|
||||
functor!("default_retry_me_else", [integer(offset)])
|
||||
functor!(atom!("default_retry_me_else"), [fixnum(offset)])
|
||||
}
|
||||
&ChoiceInstruction::DefaultTrustMe(offset) => {
|
||||
functor!("default_trust_me", [integer(offset)])
|
||||
functor!(atom!("default_trust_me"), [fixnum(offset)])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -183,18 +176,18 @@ impl CutInstruction {
|
||||
match self {
|
||||
&CutInstruction::Cut(r) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
functor!("cut", [aux(h, 0)], [rt_stub])
|
||||
functor!(atom!("cut"), [str(h, 0)], [rt_stub])
|
||||
}
|
||||
&CutInstruction::GetLevel(r) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
functor!("get_level", [aux(h, 0)], [rt_stub])
|
||||
functor!(atom!("get_level"), [str(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])
|
||||
functor!(atom!("get_level_and_unify"), [str(h, 0)], [rt_stub])
|
||||
}
|
||||
&CutInstruction::NeckCut => {
|
||||
functor!("neck_cut")
|
||||
functor!(atom!("neck_cut"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -219,13 +212,13 @@ impl IndexedChoiceInstruction {
|
||||
pub(crate) fn to_functor(&self) -> MachineStub {
|
||||
match self {
|
||||
&IndexedChoiceInstruction::Try(offset) => {
|
||||
functor!("try", [integer(offset)])
|
||||
functor!(atom!("try"), [fixnum(offset)])
|
||||
}
|
||||
&IndexedChoiceInstruction::Trust(offset) => {
|
||||
functor!("trust", [integer(offset)])
|
||||
functor!(atom!("trust"), [fixnum(offset)])
|
||||
}
|
||||
&IndexedChoiceInstruction::Retry(offset) => {
|
||||
functor!("retry", [integer(offset)])
|
||||
functor!(atom!("retry"), [fixnum(offset)])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -276,9 +269,16 @@ impl Line {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn enqueue_functors(&self, mut h: usize, functors: &mut Vec<MachineStub>) {
|
||||
pub(crate) fn enqueue_functors(
|
||||
&self,
|
||||
mut h: usize,
|
||||
arena: &mut Arena,
|
||||
functors: &mut Vec<MachineStub>,
|
||||
) {
|
||||
match self {
|
||||
&Line::Arithmetic(ref arith_instr) => functors.push(arith_instr.to_functor(h)),
|
||||
&Line::Arithmetic(ref arith_instr) => {
|
||||
functors.push(arith_instr.to_functor(h, arena))
|
||||
}
|
||||
&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)),
|
||||
@@ -300,7 +300,11 @@ impl Line {
|
||||
}
|
||||
IndexingLine::DynamicIndexedChoice(indexed_choice_instrs) => {
|
||||
for indexed_choice_instr in indexed_choice_instrs {
|
||||
let section = functor!("dynamic", [integer(*indexed_choice_instr)]);
|
||||
let section = functor!(
|
||||
atom!("dynamic"),
|
||||
[fixnum(*indexed_choice_instr)]
|
||||
);
|
||||
|
||||
h += section.len();
|
||||
functors.push(section);
|
||||
}
|
||||
@@ -312,7 +316,7 @@ impl Line {
|
||||
functors.push(indexed_choice_instr.to_functor())
|
||||
}
|
||||
&Line::DynamicIndexedChoice(ref indexed_choice_instr) => {
|
||||
functors.push(functor!("dynamic", [integer(*indexed_choice_instr)]));
|
||||
functors.push(functor!(atom!("dynamic"), [fixnum(*indexed_choice_instr)]));
|
||||
}
|
||||
&Line::Query(ref query_instr) => functors.push(query_instr.to_functor(h)),
|
||||
}
|
||||
@@ -336,7 +340,7 @@ pub(crate) fn to_indexing_line(line: &Line) -> Option<&Vec<IndexingLine>> {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum ArithmeticInstruction {
|
||||
pub enum ArithmeticInstruction {
|
||||
Add(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
Sub(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
Mul(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
@@ -380,132 +384,175 @@ pub(crate) enum ArithmeticInstruction {
|
||||
|
||||
fn arith_instr_unary_functor(
|
||||
h: usize,
|
||||
name: &'static str,
|
||||
name: Atom,
|
||||
arena: &mut Arena,
|
||||
at: &ArithmeticTerm,
|
||||
t: usize,
|
||||
) -> MachineStub {
|
||||
let at_stub = at.into_functor();
|
||||
|
||||
functor!(name, [aux(h, 0), integer(t)], [at_stub])
|
||||
let at_stub = at.into_functor(arena);
|
||||
functor!(name, [str(h, 0), fixnum(t)], [at_stub])
|
||||
}
|
||||
|
||||
fn arith_instr_bin_functor(
|
||||
h: usize,
|
||||
name: &'static str,
|
||||
name: Atom,
|
||||
arena: &mut Arena,
|
||||
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();
|
||||
let at_1_stub = at_1.into_functor(arena);
|
||||
let at_2_stub = at_2.into_functor(arena);
|
||||
|
||||
functor!(
|
||||
name,
|
||||
[aux(h, 0), aux(h, 1), integer(t)],
|
||||
[str(h, 0), str(h, 1), fixnum(t)],
|
||||
[at_1_stub, at_2_stub]
|
||||
)
|
||||
}
|
||||
|
||||
impl ArithmeticInstruction {
|
||||
pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
|
||||
pub(crate) fn to_functor(
|
||||
&self,
|
||||
h: usize,
|
||||
arena: &mut Arena,
|
||||
) -> MachineStub {
|
||||
match self {
|
||||
&ArithmeticInstruction::Add(ref at_1, ref at_2, t) => {
|
||||
arith_instr_bin_functor(h, "add", at_1, at_2, t)
|
||||
arith_instr_bin_functor(h, atom!("add"), arena, 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)
|
||||
arith_instr_bin_functor(h, atom!("sub"), arena, 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)
|
||||
arith_instr_bin_functor(h, atom!("mul"), arena, 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)
|
||||
arith_instr_bin_functor(h, atom!("int_pow"), arena, 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)
|
||||
arith_instr_bin_functor(h, atom!("pow"), arena, 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)
|
||||
arith_instr_bin_functor(h, atom!("idiv"), arena, 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)
|
||||
arith_instr_bin_functor(h, atom!("max"), arena, 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)
|
||||
arith_instr_bin_functor(h, atom!("min"), arena, 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)
|
||||
arith_instr_bin_functor(h, atom!("int_floor_div"), arena, 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)
|
||||
arith_instr_bin_functor(h, atom!("rdiv"), arena, 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)
|
||||
arith_instr_bin_functor(h, atom!("div"), arena, 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)
|
||||
arith_instr_bin_functor(h, atom!("shl"), arena, 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)
|
||||
arith_instr_bin_functor(h, atom!("shr"), arena, 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)
|
||||
arith_instr_bin_functor(h, atom!("xor"), arena, 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)
|
||||
arith_instr_bin_functor(h, atom!("and"), arena, 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)
|
||||
arith_instr_bin_functor(h, atom!("or"), arena, 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)
|
||||
arith_instr_bin_functor(h, atom!("mod"), arena, 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)
|
||||
arith_instr_bin_functor(h, atom!("rem"), arena, 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)
|
||||
arith_instr_bin_functor(h, atom!("rem"), arena, 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)
|
||||
arith_instr_bin_functor(h, atom!("gcd"), arena, at_1, at_2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Sign(ref at, t) => {
|
||||
arith_instr_unary_functor(h, atom!("sign"), arena, at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Cos(ref at, t) => {
|
||||
arith_instr_unary_functor(h, atom!("cos"), arena, at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Sin(ref at, t) => {
|
||||
arith_instr_unary_functor(h, atom!("sin"), arena, at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Tan(ref at, t) => {
|
||||
arith_instr_unary_functor(h, atom!("tan"), arena, at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Log(ref at, t) => {
|
||||
arith_instr_unary_functor(h, atom!("log"), arena, at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Exp(ref at, t) => {
|
||||
arith_instr_unary_functor(h, atom!("exp"), arena, at, t)
|
||||
}
|
||||
&ArithmeticInstruction::ACos(ref at, t) => {
|
||||
arith_instr_unary_functor(h, atom!("acos"), arena, at, t)
|
||||
}
|
||||
&ArithmeticInstruction::ASin(ref at, t) => {
|
||||
arith_instr_unary_functor(h, atom!("asin"), arena, at, t)
|
||||
}
|
||||
&ArithmeticInstruction::ATan(ref at, t) => {
|
||||
arith_instr_unary_functor(h, atom!("atan"), arena, at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Sqrt(ref at, t) => {
|
||||
arith_instr_unary_functor(h, atom!("sqrt"), arena, at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Abs(ref at, t) => {
|
||||
arith_instr_unary_functor(h, atom!("abs"), arena, at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Sign(ref at, t) => arith_instr_unary_functor(h, "sign", at, t),
|
||||
&ArithmeticInstruction::Cos(ref at, t) => arith_instr_unary_functor(h, "cos", at, t),
|
||||
&ArithmeticInstruction::Sin(ref at, t) => arith_instr_unary_functor(h, "sin", at, t),
|
||||
&ArithmeticInstruction::Tan(ref at, t) => arith_instr_unary_functor(h, "tan", at, t),
|
||||
&ArithmeticInstruction::Log(ref at, t) => arith_instr_unary_functor(h, "log", at, t),
|
||||
&ArithmeticInstruction::Exp(ref at, t) => arith_instr_unary_functor(h, "exp", at, t),
|
||||
&ArithmeticInstruction::ACos(ref at, t) => arith_instr_unary_functor(h, "acos", at, t),
|
||||
&ArithmeticInstruction::ASin(ref at, t) => arith_instr_unary_functor(h, "asin", at, t),
|
||||
&ArithmeticInstruction::ATan(ref at, t) => arith_instr_unary_functor(h, "atan", at, t),
|
||||
&ArithmeticInstruction::Sqrt(ref at, t) => arith_instr_unary_functor(h, "sqrt", at, t),
|
||||
&ArithmeticInstruction::Abs(ref at, t) => arith_instr_unary_functor(h, "abs", at, t),
|
||||
&ArithmeticInstruction::Float(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "float", at, t)
|
||||
arith_instr_unary_functor(h, atom!("float"), arena, at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Truncate(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "truncate", at, t)
|
||||
arith_instr_unary_functor(h, atom!("truncate"), arena, at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Round(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "round", at, t)
|
||||
arith_instr_unary_functor(h, atom!("round"), arena, at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Ceiling(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "ceiling", at, t)
|
||||
arith_instr_unary_functor(h, atom!("ceiling"), arena, 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)
|
||||
arith_instr_unary_functor(h, atom!("floor"), arena, at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Neg(ref at, t) => arith_instr_unary_functor(
|
||||
h,
|
||||
atom!("-"),
|
||||
arena,
|
||||
at,
|
||||
t,
|
||||
),
|
||||
&ArithmeticInstruction::Plus(ref at, t) => arith_instr_unary_functor(
|
||||
h,
|
||||
atom!("+"),
|
||||
arena,
|
||||
at,
|
||||
t,
|
||||
),
|
||||
&ArithmeticInstruction::BitwiseComplement(ref at, t) => arith_instr_unary_functor(
|
||||
h,
|
||||
atom!("\\"),
|
||||
arena,
|
||||
at,
|
||||
t,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum ControlInstruction {
|
||||
pub enum ControlInstruction {
|
||||
Allocate(usize), // num_frames.
|
||||
// name, arity, perm_vars after threshold, last call, use default call policy.
|
||||
CallClause(ClauseType, usize, usize, bool, bool),
|
||||
@@ -529,25 +576,25 @@ impl ControlInstruction {
|
||||
pub(crate) fn to_functor(&self) -> MachineStub {
|
||||
match self {
|
||||
&ControlInstruction::Allocate(num_frames) => {
|
||||
functor!("allocate", [integer(num_frames)])
|
||||
functor!(atom!("allocate"), [fixnum(num_frames)])
|
||||
}
|
||||
&ControlInstruction::CallClause(ref ct, arity, _, false, _) => {
|
||||
functor!("call", [clause_name(ct.name()), integer(arity)])
|
||||
functor!(atom!("call"), [atom(ct.name()), fixnum(arity)])
|
||||
}
|
||||
&ControlInstruction::CallClause(ref ct, arity, _, true, _) => {
|
||||
functor!("execute", [clause_name(ct.name()), integer(arity)])
|
||||
functor!(atom!("execute"), [atom(ct.name()), fixnum(arity)])
|
||||
}
|
||||
&ControlInstruction::Deallocate => {
|
||||
functor!("deallocate")
|
||||
functor!(atom!("deallocate"))
|
||||
}
|
||||
&ControlInstruction::JmpBy(_, offset, ..) => {
|
||||
functor!("jmp_by", [integer(offset)])
|
||||
functor!(atom!("jmp_by"), [fixnum(offset)])
|
||||
}
|
||||
&ControlInstruction::RevJmpBy(offset) => {
|
||||
functor!("rev_jmp_by", [integer(offset)])
|
||||
functor!(atom!("rev_jmp_by"), [fixnum(offset)])
|
||||
}
|
||||
&ControlInstruction::Proceed => {
|
||||
functor!("proceed")
|
||||
functor!(atom!("proceed"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -564,8 +611,22 @@ pub(crate) enum IndexingInstruction {
|
||||
IndexingCodePtr,
|
||||
IndexingCodePtr,
|
||||
),
|
||||
SwitchOnConstant(IndexMap<Constant, IndexingCodePtr>),
|
||||
SwitchOnStructure(IndexMap<(ClauseName, usize), IndexingCodePtr>),
|
||||
SwitchOnConstant(IndexMap<Literal, IndexingCodePtr>),
|
||||
SwitchOnStructure(IndexMap<(Atom, usize), IndexingCodePtr>),
|
||||
}
|
||||
|
||||
impl IndexingCodePtr {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn to_functor(self) -> MachineStub {
|
||||
match self {
|
||||
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"))]
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexingInstruction {
|
||||
@@ -573,9 +634,9 @@ impl IndexingInstruction {
|
||||
match self {
|
||||
&IndexingInstruction::SwitchOnTerm(arg, vars, constants, lists, structures) => {
|
||||
functor!(
|
||||
"switch_on_term",
|
||||
atom!("switch_on_term"),
|
||||
[
|
||||
integer(arg),
|
||||
fixnum(arg),
|
||||
indexing_code_ptr(h, vars),
|
||||
indexing_code_ptr(h, constants),
|
||||
indexing_code_ptr(h, lists),
|
||||
@@ -591,26 +652,23 @@ impl IndexingInstruction {
|
||||
|
||||
for (c, ptr) in constants.iter() {
|
||||
let key_value_pair = functor!(
|
||||
":",
|
||||
SharedOpDesc::new(600, XFY),
|
||||
[constant(c), indexing_code_ptr(h + 3, *ptr)]
|
||||
atom!(":"),
|
||||
[literal(*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(),
|
||||
)));
|
||||
key_value_list_stub.push(list_loc_as_cell!(h + 1));
|
||||
key_value_list_stub.push(str_loc_as_cell!(h + 3));
|
||||
key_value_list_stub.push(heap_loc_as_cell!(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));
|
||||
key_value_list_stub.push(empty_list_as_cell!());
|
||||
|
||||
functor!(
|
||||
"switch_on_constant",
|
||||
[aux(orig_h, 0)],
|
||||
atom!("switch_on_constant"),
|
||||
[str(orig_h, 0)],
|
||||
[key_value_list_stub]
|
||||
)
|
||||
}
|
||||
@@ -622,33 +680,29 @@ impl IndexingInstruction {
|
||||
|
||||
for ((name, arity), ptr) in structures.iter() {
|
||||
let predicate_indicator_stub = functor!(
|
||||
"/",
|
||||
SharedOpDesc::new(400, YFX),
|
||||
[clause_name(name.clone()), integer(*arity)]
|
||||
atom!("/"),
|
||||
[atom(name), fixnum(*arity)]
|
||||
);
|
||||
|
||||
let key_value_pair = functor!(
|
||||
":",
|
||||
SharedOpDesc::new(600, XFY),
|
||||
[aux(h + 3, 0), indexing_code_ptr(h + 3, *ptr)],
|
||||
atom!(":"),
|
||||
[str(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(),
|
||||
)));
|
||||
key_value_list_stub.push(list_loc_as_cell!(h + 1));
|
||||
key_value_list_stub.push(str_loc_as_cell!(h + 3));
|
||||
key_value_list_stub.push(heap_loc_as_cell!(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));
|
||||
key_value_list_stub.push(empty_list_as_cell!());
|
||||
|
||||
functor!(
|
||||
"switch_on_structure",
|
||||
[aux(orig_h, 0)],
|
||||
atom!("switch_on_structure"),
|
||||
[str(orig_h, 0)],
|
||||
[key_value_list_stub]
|
||||
)
|
||||
}
|
||||
@@ -657,14 +711,14 @@ impl IndexingInstruction {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum FactInstruction {
|
||||
GetConstant(Level, Constant, RegType),
|
||||
pub enum FactInstruction {
|
||||
GetConstant(Level, HeapCellValue, RegType),
|
||||
GetList(Level, RegType),
|
||||
GetPartialString(Level, String, RegType, bool),
|
||||
GetPartialString(Level, Atom, RegType, bool),
|
||||
GetStructure(ClauseType, usize, RegType),
|
||||
GetValue(RegType, usize),
|
||||
GetVariable(RegType, usize),
|
||||
UnifyConstant(Constant),
|
||||
UnifyConstant(HeapCellValue),
|
||||
UnifyLocalValue(RegType),
|
||||
UnifyVariable(RegType),
|
||||
UnifyValue(RegType),
|
||||
@@ -674,13 +728,13 @@ pub(crate) enum FactInstruction {
|
||||
impl FactInstruction {
|
||||
pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
|
||||
match self {
|
||||
&FactInstruction::GetConstant(lvl, ref c, r) => {
|
||||
&FactInstruction::GetConstant(lvl, 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)],
|
||||
atom!("get_constant"),
|
||||
[str(h, 0), cell(c), str(h, 1)],
|
||||
[lvl_stub, rt_stub]
|
||||
)
|
||||
}
|
||||
@@ -688,15 +742,24 @@ impl FactInstruction {
|
||||
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])
|
||||
functor!(
|
||||
atom!("get_list"),
|
||||
[str(h, 0), str(h, 1)],
|
||||
[lvl_stub, rt_stub]
|
||||
)
|
||||
}
|
||||
&FactInstruction::GetPartialString(lvl, ref s, r, has_tail) => {
|
||||
&FactInstruction::GetPartialString(lvl, 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)],
|
||||
atom!("get_partial_string"),
|
||||
[
|
||||
str(h, 0),
|
||||
string(h, s),
|
||||
str(h, 1),
|
||||
boolean(has_tail)
|
||||
],
|
||||
[lvl_stub, rt_stub]
|
||||
)
|
||||
}
|
||||
@@ -704,41 +767,41 @@ impl FactInstruction {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!(
|
||||
"get_structure",
|
||||
[clause_name(ct.name()), integer(arity), aux(h, 0)],
|
||||
atom!("get_structure"),
|
||||
[atom(ct.name()), fixnum(arity), str(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])
|
||||
functor!(atom!("get_value"), [str(h, 0), fixnum(arg)], [rt_stub])
|
||||
}
|
||||
&FactInstruction::GetVariable(r, arg) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!("get_variable", [aux(h, 0), integer(arg)], [rt_stub])
|
||||
functor!(atom!("get_variable"), [str(h, 0), fixnum(arg)], [rt_stub])
|
||||
}
|
||||
&FactInstruction::UnifyConstant(ref c) => {
|
||||
functor!("unify_constant", [constant(h, c)], [])
|
||||
&FactInstruction::UnifyConstant(c) => {
|
||||
functor!(atom!("unify_constant"), [cell(c)])
|
||||
}
|
||||
&FactInstruction::UnifyLocalValue(r) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!("unify_local_value", [aux(h, 0)], [rt_stub])
|
||||
functor!(atom!("unify_local_value"), [str(h, 0)], [rt_stub])
|
||||
}
|
||||
&FactInstruction::UnifyVariable(r) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!("unify_variable", [aux(h, 0)], [rt_stub])
|
||||
functor!(atom!("unify_variable"), [str(h, 0)], [rt_stub])
|
||||
}
|
||||
&FactInstruction::UnifyValue(r) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!("unify_value", [aux(h, 0)], [rt_stub])
|
||||
functor!(atom!("unify_value"), [str(h, 0)], [rt_stub])
|
||||
}
|
||||
&FactInstruction::UnifyVoid(vars) => {
|
||||
functor!("unify_void", [integer(vars)])
|
||||
functor!(atom!("unify_void"), [fixnum(vars)])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -747,14 +810,14 @@ impl FactInstruction {
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum QueryInstruction {
|
||||
GetVariable(RegType, usize),
|
||||
PutConstant(Level, Constant, RegType),
|
||||
PutConstant(Level, HeapCellValue, RegType),
|
||||
PutList(Level, RegType),
|
||||
PutPartialString(Level, String, RegType, bool),
|
||||
PutPartialString(Level, Atom, RegType, bool),
|
||||
PutStructure(ClauseType, usize, RegType),
|
||||
PutUnsafeValue(usize, usize),
|
||||
PutValue(RegType, usize),
|
||||
PutVariable(RegType, usize),
|
||||
SetConstant(Constant),
|
||||
SetConstant(HeapCellValue),
|
||||
SetLocalValue(RegType),
|
||||
SetVariable(RegType),
|
||||
SetValue(RegType),
|
||||
@@ -765,15 +828,15 @@ 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)])
|
||||
functor!(atom!("put_unsafe_value"), [fixnum(norm), fixnum(arg)])
|
||||
}
|
||||
&QueryInstruction::PutConstant(lvl, ref c, r) => {
|
||||
&QueryInstruction::PutConstant(lvl, 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)],
|
||||
atom!("put_constant"),
|
||||
[str(h, 0), cell(c), str(h, 1)],
|
||||
[lvl_stub, rt_stub]
|
||||
)
|
||||
}
|
||||
@@ -781,15 +844,24 @@ impl QueryInstruction {
|
||||
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])
|
||||
functor!(
|
||||
atom!("put_list"),
|
||||
[str(h, 0), str(h, 1)],
|
||||
[lvl_stub, rt_stub]
|
||||
)
|
||||
}
|
||||
&QueryInstruction::PutPartialString(lvl, ref s, r, has_tail) => {
|
||||
&QueryInstruction::PutPartialString(lvl, 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)],
|
||||
atom!("put_partial_string"),
|
||||
[
|
||||
str(h, 0),
|
||||
string(h, s),
|
||||
str(h, 1),
|
||||
boolean(has_tail)
|
||||
],
|
||||
[lvl_stub, rt_stub]
|
||||
)
|
||||
}
|
||||
@@ -797,46 +869,46 @@ impl QueryInstruction {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!(
|
||||
"put_structure",
|
||||
[clause_name(ct.name()), integer(arity), aux(h, 0)],
|
||||
atom!("put_structure"),
|
||||
[atom(ct.name()), fixnum(arity), str(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])
|
||||
functor!(atom!("put_value"), [str(h, 0), fixnum(arg)], [rt_stub])
|
||||
}
|
||||
&QueryInstruction::GetVariable(r, arg) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!("get_variable", [aux(h, 0), integer(arg)], [rt_stub])
|
||||
functor!(atom!("get_variable"), [str(h, 0), fixnum(arg)], [rt_stub])
|
||||
}
|
||||
&QueryInstruction::PutVariable(r, arg) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!("put_variable", [aux(h, 0), integer(arg)], [rt_stub])
|
||||
functor!(atom!("put_variable"), [str(h, 0), fixnum(arg)], [rt_stub])
|
||||
}
|
||||
&QueryInstruction::SetConstant(ref c) => {
|
||||
functor!("set_constant", [constant(h, c)], [])
|
||||
&QueryInstruction::SetConstant(c) => {
|
||||
functor!(atom!("set_constant"), [cell(c)], [])
|
||||
}
|
||||
&QueryInstruction::SetLocalValue(r) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!("set_local_value", [aux(h, 0)], [rt_stub])
|
||||
functor!(atom!("set_local_value"), [str(h, 0)], [rt_stub])
|
||||
}
|
||||
&QueryInstruction::SetVariable(r) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!("set_variable", [aux(h, 0)], [rt_stub])
|
||||
functor!(atom!("set_variable"), [str(h, 0)], [rt_stub])
|
||||
}
|
||||
&QueryInstruction::SetValue(r) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!("set_value", [aux(h, 0)], [rt_stub])
|
||||
functor!(atom!("set_value"), [str(h, 0)], [rt_stub])
|
||||
}
|
||||
&QueryInstruction::SetVoid(vars) => {
|
||||
functor!("set_void", [integer(vars)])
|
||||
functor!(atom!("set_void"), [fixnum(vars)])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
204
src/iterators.rs
204
src/iterators.rs
@@ -1,5 +1,5 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::rc_atom;
|
||||
use crate::atom_table::*;
|
||||
use crate::parser::ast::*;
|
||||
|
||||
use crate::clause_types::*;
|
||||
use crate::forms::*;
|
||||
@@ -16,10 +16,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 +27,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 +38,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(name.clone(), subterms.len(), 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 +78,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 +90,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 {
|
||||
@@ -186,7 +125,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],
|
||||
}
|
||||
@@ -226,9 +165,9 @@ impl<'a> Iterator for QueryIterator<'a> {
|
||||
if child_num == child_terms.len() {
|
||||
match ct {
|
||||
ClauseType::CallN => {
|
||||
self.push_subterm(Level::Shallow, child_terms[0].as_ref())
|
||||
self.push_subterm(Level::Shallow, &child_terms[0]);
|
||||
}
|
||||
ClauseType::Named(..) | ClauseType::Op(..) => {
|
||||
ClauseType::Named(..) => {
|
||||
return match lvl {
|
||||
Level::Root => None,
|
||||
lvl => Some(TermRef::Clause(lvl, cell, ct, child_terms)),
|
||||
@@ -247,33 +186,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));
|
||||
|
||||
if let Some(tail) = tail {
|
||||
self.push_subterm(lvl.child_level(), tail);
|
||||
}
|
||||
} else {
|
||||
self.state_stack
|
||||
.push(TermIterState::FinalCons(lvl, cell, head, tail));
|
||||
self.state_stack.push(TermIterState::FinalCons(lvl, cell, head, tail));
|
||||
|
||||
self.push_subterm(lvl.child_level(), tail);
|
||||
self.push_subterm(lvl.child_level(), head);
|
||||
}
|
||||
TermIterState::InitialPartialString(lvl, cell, string, tail) => {
|
||||
self.state_stack.push(TermIterState::FinalPartialString(lvl, cell, string, tail));
|
||||
|
||||
if let Some(tail) = tail {
|
||||
self.push_subterm(lvl.child_level(), tail);
|
||||
}
|
||||
TermIterState::PartialString(lvl, cell, string, tail) => {
|
||||
}
|
||||
TermIterState::FinalPartialString(lvl, cell, string, tail) => {
|
||||
return Some(TermRef::PartialString(lvl, cell, string, tail));
|
||||
}
|
||||
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 +233,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 +247,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 +303,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);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
TermIterState::InitialPartialString(lvl, cell, string_buf, tail_opt) => {
|
||||
if let Some(tail) = tail_opt {
|
||||
self.push_subterm(Level::Deep, tail);
|
||||
}
|
||||
TermIterState::Constant(lvl, cell, constant) => {
|
||||
return Some(TermRef::Constant(lvl, cell, constant))
|
||||
|
||||
return Some(TermRef::PartialString(lvl, cell, string_buf, tail_opt));
|
||||
}
|
||||
TermIterState::Literal(lvl, cell, constant) => {
|
||||
return Some(TermRef::Literal(lvl, cell, constant))
|
||||
}
|
||||
TermIterState::Var(lvl, cell, var) => {
|
||||
return Some(TermRef::Var(lvl, cell, var));
|
||||
@@ -386,17 +329,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 +350,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 +460,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,7 +490,10 @@ 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)
|
||||
}
|
||||
|
||||
24
src/lib.rs
24
src/lib.rs
@@ -1,25 +1,29 @@
|
||||
#[cfg(feature = "num-rug-adapter")]
|
||||
use num_rug_adapter as rug;
|
||||
#[cfg(feature = "rug")]
|
||||
use rug;
|
||||
#[macro_use]
|
||||
extern crate static_assertions;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
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;
|
||||
mod iterators;
|
||||
pub mod machine;
|
||||
mod raw_block;
|
||||
pub mod read;
|
||||
mod targets;
|
||||
mod write;
|
||||
|
||||
use machine::*;
|
||||
pub mod types;
|
||||
pub mod write;
|
||||
|
||||
@@ -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)
|
||||
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),
|
||||
|
||||
@@ -12,10 +12,22 @@ between(Lower, Upper, X) :-
|
||||
( nonvar(X) ->
|
||||
Lower =< X,
|
||||
X =< Upper
|
||||
; compare(Ord, Lower, Upper),
|
||||
between_(Ord, Lower, Upper, X)
|
||||
; % compare(Ord, Lower, Upper),
|
||||
% between_(Ord, Lower, Upper, X)
|
||||
Lower =< Upper,
|
||||
between_(Lower, Upper, X)
|
||||
).
|
||||
|
||||
between_(Lower, Lower, Lower) :- !.
|
||||
between_(Lower, Upper, Lower1) :-
|
||||
( Lower < Upper,
|
||||
( Lower1 = Lower
|
||||
; Lower0 is Lower + 1,
|
||||
between_(Lower0, Upper, Lower1)
|
||||
)
|
||||
).
|
||||
|
||||
/*
|
||||
between_(<, Lower0, Upper, X) :-
|
||||
( X = Lower0
|
||||
; Lower1 is Lower0 + 1,
|
||||
@@ -23,6 +35,7 @@ between_(<, Lower0, Upper, X) :-
|
||||
between_(Ord, Lower1, Upper, X)
|
||||
).
|
||||
between_(=, Upper, Upper, Upper).
|
||||
*/
|
||||
|
||||
enumerate_nats(I, I).
|
||||
enumerate_nats(I0, N) :-
|
||||
|
||||
@@ -388,9 +388,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)),
|
||||
@@ -679,9 +680,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).
|
||||
|
||||
@@ -1075,17 +1076,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 +1094,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 +1113,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) :-
|
||||
|
||||
@@ -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,6 +22,7 @@
|
||||
instantiation_error/1,
|
||||
type_error/3]).
|
||||
|
||||
:- use_module(library(lists), [maplist/3]).
|
||||
|
||||
:- meta_predicate(call_cleanup(0, 0)).
|
||||
|
||||
@@ -160,8 +161,6 @@ 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
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
:- module(loader, [consult/1,
|
||||
expand_goal/3,
|
||||
expand_term/2,
|
||||
@@ -508,7 +507,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)
|
||||
)
|
||||
)
|
||||
).
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,15 @@
|
||||
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 {
|
||||
@@ -37,7 +39,7 @@ 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();
|
||||
|
||||
@@ -53,28 +55,24 @@ impl MachineState {
|
||||
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,19 +81,26 @@ impl MachineState {
|
||||
self[temp_v!(2)] = value_list_addr;
|
||||
}
|
||||
|
||||
pub(super) fn gather_attr_vars_created_since(&self, b: usize) -> IntoIter<Addr> {
|
||||
pub(super) fn gather_attr_vars_created_since(&mut self, b: usize) -> IntoIter<HeapCellValue> {
|
||||
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,
|
||||
.filter_map(|h| {
|
||||
read_heap_cell!(self.store(self.deref(heap_loc_as_cell!(*h))), //Addr::HeapCell(*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()
|
||||
}
|
||||
|
||||
@@ -109,8 +114,10 @@ impl MachineState {
|
||||
self.stack.index_and_frame_mut(e)[i] = self[RegType::Temp(i)];
|
||||
}
|
||||
|
||||
self.stack.index_and_frame_mut(e)[self.num_of_args + 1] = Addr::CutPoint(self.b0);
|
||||
self.stack.index_and_frame_mut(e)[self.num_of_args + 2] = Addr::Usize(self.num_of_args);
|
||||
self.stack.index_and_frame_mut(e)[self.num_of_args + 1] =
|
||||
fixnum_as_cell!(Fixnum::build_with(self.b0 as i64));
|
||||
self.stack.index_and_frame_mut(e)[self.num_of_args + 2] =
|
||||
fixnum_as_cell!(Fixnum::build_with(self.num_of_args as i64));
|
||||
|
||||
self.verify_attributes();
|
||||
|
||||
@@ -119,33 +126,51 @@ impl MachineState {
|
||||
self.p = CodePtr::Local(LocalCodePtr::DirEntry(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) {
|
||||
while let Some(value) = iter.next() {
|
||||
read_heap_cell!(value,
|
||||
(HeapCellValueTag::AttrVar, h) => {
|
||||
if seen_set.contains(&h) {
|
||||
continue;
|
||||
}
|
||||
|
||||
seen_vars.push(addr);
|
||||
seen_set.insert(*h);
|
||||
seen_vars.push(value);
|
||||
seen_set.insert(h);
|
||||
|
||||
let mut l = h + 1;
|
||||
let mut list_elements = vec![];
|
||||
// let mut list_elements = vec![];
|
||||
// let iter_stack_len = iter.stack_len();
|
||||
|
||||
while let Addr::Lis(elem) = self.store(self.deref(Addr::HeapCell(l))) {
|
||||
list_elements.push(self.heap[elem].as_addr(elem));
|
||||
l = elem + 1;
|
||||
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;
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
for element in list_elements.into_iter().rev() {
|
||||
iter.stack().push(element);
|
||||
// iter.stack_slice_from(iter_stack_len ..).reverse();
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
seen_vars
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::instructions::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct CodeRepo {
|
||||
pub struct CodeRepo {
|
||||
pub(super) code: Code,
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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) {
|
||||
read_heap_cell!(self.target[addr + offset],
|
||||
(HeapCellValueTag::Lis, h) => {
|
||||
if h >= self.old_h {
|
||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(h));
|
||||
*self.value_at_scan() = list_loc_as_cell!(h);
|
||||
self.scan += 1;
|
||||
|
||||
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,208 @@ 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] {
|
||||
fn copy_partial_string(&mut self, scan_tag: HeapCellValueTag, pstr_loc: usize) {
|
||||
read_heap_cell!(self.target[pstr_loc],
|
||||
(HeapCellValueTag::PStrLoc, h) => {
|
||||
if h >= self.old_h {
|
||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(h, n));
|
||||
self.scan += 1;
|
||||
|
||||
return;
|
||||
*self.value_at_scan() = match scan_tag {
|
||||
HeapCellValueTag::PStrLoc => {
|
||||
pstr_loc_as_cell!(h)
|
||||
}
|
||||
}
|
||||
|
||||
let threshold = self.target.threshold();
|
||||
|
||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(threshold, n));
|
||||
|
||||
self.scan += 1;
|
||||
|
||||
let (pstr, has_tail) = match &self.target[addr] {
|
||||
&HeapCellValue::PartialString(ref pstr, has_tail) => {
|
||||
(pstr.clone_from_offset(0), has_tail)
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
tag => {
|
||||
debug_assert!(tag == HeapCellValueTag::PStrOffset);
|
||||
pstr_offset_as_cell!(h)
|
||||
}
|
||||
};
|
||||
|
||||
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));
|
||||
self.scan += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
);
|
||||
|
||||
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));
|
||||
let threshold = self.target.threshold();
|
||||
|
||||
self.trail
|
||||
.push((Ref::HeapCell(h), HeapCellValue::Addr(Addr::HeapCell(h))));
|
||||
*self.value_at_scan() = pstr_loc_as_cell!(threshold);
|
||||
self.scan += 1;
|
||||
|
||||
self.target.push(self.target[pstr_loc]);
|
||||
|
||||
let replacement = pstr_loc_as_cell!(threshold);
|
||||
let trail_item = mem::replace(&mut self.target[pstr_loc], replacement);
|
||||
|
||||
self.trail.push((Ref::heap_cell(pstr_loc), trail_item));
|
||||
self.target.push(self.target[pstr_loc + 1]);
|
||||
}
|
||||
Addr::StackCell(fr, sc) => {
|
||||
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier));
|
||||
self.target.stack().index_and_frame_mut(fr)[sc] = Addr::HeapCell(frontier);
|
||||
|
||||
self.trail.push((
|
||||
Ref::StackCell(fr, sc),
|
||||
HeapCellValue::Addr(Addr::StackCell(fr, sc)),
|
||||
));
|
||||
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::heap_cell(h), heap_loc_as_cell!(h)));
|
||||
}
|
||||
Addr::AttrVar(h) => {
|
||||
(HeapCellValueTag::StackVar, s) => {
|
||||
self.target[frontier] = heap_loc_as_cell!(frontier);
|
||||
self.target.stack()[s] = heap_loc_as_cell!(frontier);
|
||||
|
||||
self.trail.push((Ref::stack_cell(s), stack_loc_as_cell!(s)));
|
||||
}
|
||||
(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)));
|
||||
.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);
|
||||
read_heap_cell!(ra,
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
if h >= self.old_h {
|
||||
*self.value_at_scan() = rd;
|
||||
self.scan += 1;
|
||||
|
||||
return;
|
||||
}
|
||||
_ if addr == rd => {
|
||||
}
|
||||
_ => {}
|
||||
);
|
||||
|
||||
if addr == ra {
|
||||
self.reinstantiate_var(addr, self.scan);
|
||||
self.scan += 1;
|
||||
}
|
||||
_ => {
|
||||
*self.value_at_scan() = HeapCellValue::Addr(rd);
|
||||
}
|
||||
} else {
|
||||
*self.value_at_scan() = ra;
|
||||
// self.copy_compound(rd, ra);
|
||||
}
|
||||
}
|
||||
|
||||
fn copy_structure(&mut self, addr: usize) {
|
||||
match self.target[addr].context_free_clone() {
|
||||
HeapCellValue::NamedStr(arity, name, fixity) => {
|
||||
/*
|
||||
fn copy_compound(&mut self, rd: HeapCellValue, ra: HeapCellValue) {
|
||||
let h = rd.get_value();
|
||||
let trail_item = self.target[h];
|
||||
let threshold = self.target.threshold();
|
||||
|
||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::Str(threshold));
|
||||
self.trail.push((Ref::heap_cell(h), trail_item));
|
||||
self.target[self.scan].set_value(threshold);
|
||||
|
||||
read_heap_cell!(ra,
|
||||
(HeapCellValueTag::Atom, (_name, arity)) => {
|
||||
self.target.push(ra);
|
||||
|
||||
for i in 0..arity {
|
||||
self.target.push(self.target[h + 1 + i]);
|
||||
}
|
||||
|
||||
self.target[h] = str_loc_as_cell!(self.scan + 1);
|
||||
}
|
||||
(HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
|
||||
self.target.push(ra);
|
||||
self.target.push(self.target[h + 1]);
|
||||
|
||||
self.target[h] = pstr_loc_as_cell!(self.scan + 1);
|
||||
}
|
||||
(HeapCellValueTag::CStr, cstr_atom) => {
|
||||
self.target[h] = atom_as_cstr_cell!(cstr_atom);
|
||||
}
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
self.copy_structure(s);
|
||||
return;
|
||||
}
|
||||
_ => {
|
||||
*self.value_at_scan() = rd;
|
||||
self.trail.pop();
|
||||
return;
|
||||
}
|
||||
);
|
||||
|
||||
self.scan += 1;
|
||||
}
|
||||
*/
|
||||
|
||||
fn copy_structure(&mut self, addr: usize) {
|
||||
read_heap_cell!(self.target[addr],
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
let threshold = self.target.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) => {
|
||||
read_heap_cell!(addr,
|
||||
(HeapCellValueTag::Lis, h) => {
|
||||
if h >= self.old_h {
|
||||
self.scan += 1;
|
||||
} else {
|
||||
self.copy_list(h);
|
||||
}
|
||||
}
|
||||
addr @ Addr::AttrVar(_)
|
||||
| addr @ Addr::HeapCell(_)
|
||||
| addr @ Addr::StackCell(..) => {
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var) => {
|
||||
self.copy_var(addr);
|
||||
}
|
||||
Addr::Str(addr) => {
|
||||
self.copy_structure(addr);
|
||||
(HeapCellValueTag::Str, h) => {
|
||||
self.copy_structure(h);
|
||||
}
|
||||
Addr::PStrLocation(addr, n) => {
|
||||
self.copy_partial_string(addr, n);
|
||||
}
|
||||
Addr::Stream(h) => {
|
||||
*self.value_at_scan() = self.target[h].context_free_clone();
|
||||
(HeapCellValueTag::PStrLoc | HeapCellValueTag::PStrOffset, pstr_loc) => {
|
||||
self.copy_partial_string(addr.get_tag(), pstr_loc);
|
||||
}
|
||||
_ => {
|
||||
self.scan += 1;
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
self.scan += 1;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
self.unwind_trail();
|
||||
@@ -286,12 +313,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));
|
||||
}
|
||||
}
|
||||
|
||||
1101
src/machine/gc.rs
Normal file
1101
src/machine/gc.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,140 +1,282 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use prolog_parser::ast::Constant;
|
||||
|
||||
use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::forms::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
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>()
|
||||
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)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn align() -> usize {
|
||||
mem::align_of::<HeapCellValue>()
|
||||
Literal::Rational(bigint_ptr) => {
|
||||
typed_arena_ptr_as_cell!(bigint_ptr)
|
||||
}
|
||||
}
|
||||
|
||||
#[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)) }
|
||||
Literal::Float(f) => HeapCellValue::from(f),
|
||||
Literal::String(s) => {
|
||||
if s == atom!("") {
|
||||
empty_list_as_cell!()
|
||||
} else {
|
||||
None
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: RawBlockTraits> Iterator for HeapIter<'a, T> {
|
||||
type Item = &'a 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 as *const _)) }
|
||||
fn try_from(value: HeapCellValue) -> Result<Literal, ()> {
|
||||
read_heap_cell!(value,
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
if arity == 0 {
|
||||
Ok(Literal::Atom(name))
|
||||
} else {
|
||||
None
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
(HeapCellValueTag::Char, c) => {
|
||||
Ok(Literal::Char(c))
|
||||
}
|
||||
(HeapCellValueTag::Fixnum, n) => {
|
||||
Ok(Literal::Fixnum(n))
|
||||
}
|
||||
(HeapCellValueTag::F64, f) => {
|
||||
Ok(Literal::Float(f))
|
||||
}
|
||||
(HeapCellValueTag::Cons, cons_ptr) => {
|
||||
match_untyped_arena_ptr!(cons_ptr,
|
||||
(ArenaHeaderTag::Integer, n) => {
|
||||
Ok(Literal::Integer(n))
|
||||
}
|
||||
(ArenaHeaderTag::Rational, n) => {
|
||||
Ok(Literal::Rational(n))
|
||||
}
|
||||
_ => {
|
||||
Err(())
|
||||
}
|
||||
)
|
||||
}
|
||||
(HeapCellValueTag::CStr, cstr_atom) => {
|
||||
Ok(Literal::String(cstr_atom))
|
||||
}
|
||||
_ => {
|
||||
Err(())
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// sometimes we need to dereference variables that are found only in
|
||||
// the heap without access to the full WAM (e.g., while detecting
|
||||
// cycles in terms), and which therefore may only point other cells in
|
||||
// the heap (thanks to the design of the WAM).
|
||||
pub fn heap_bound_deref(heap: &[HeapCellValue], mut value: HeapCellValue) -> HeapCellValue {
|
||||
loop {
|
||||
let new_value = read_heap_cell!(value,
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
heap[h]
|
||||
}
|
||||
_ => {
|
||||
value
|
||||
}
|
||||
);
|
||||
|
||||
if new_value != value && new_value.is_var() {
|
||||
value = new_value;
|
||||
continue;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn heap_bound_store(heap: &[HeapCellValue], value: HeapCellValue) -> HeapCellValue {
|
||||
read_heap_cell!(value,
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
heap[h]
|
||||
}
|
||||
_ => {
|
||||
value
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
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 _)) }
|
||||
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 {
|
||||
heap.push(empty_list_as_cell!());
|
||||
pstr_loc_as_cell!(h)
|
||||
}
|
||||
}
|
||||
None => {
|
||||
empty_list_as_cell!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn allocate_pstr(
|
||||
heap: &mut Heap,
|
||||
mut src: &str,
|
||||
atom_tbl: &mut AtomTable,
|
||||
) -> Option<usize> {
|
||||
let orig_h = heap.len();
|
||||
|
||||
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);
|
||||
|
||||
Some(orig_h)
|
||||
};
|
||||
}
|
||||
|
||||
let h = heap.len();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
heap.push(string_as_pstr_cell!(pstr));
|
||||
|
||||
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<LocalCodePtr> {
|
||||
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,
|
||||
}
|
||||
};
|
||||
|
||||
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).map(LocalCodePtr::DirEntry)
|
||||
} else {
|
||||
panic!(
|
||||
"to_local_code_ptr crashed with p.i. {}/{}",
|
||||
name.as_str(),
|
||||
arity,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
impl<T: RawBlockTraits> HeapTemplate<T> {
|
||||
#[inline]
|
||||
pub(crate) fn new() -> Self {
|
||||
@@ -144,67 +286,40 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// TODO: move this to the WAM, then remove the temporary (and by
|
||||
// then, unnecessary and impossible) "arena" argument. OR, remove
|
||||
// this thing totally! if we can. by that I mean, just convert a
|
||||
// little to a HeapCellValue. don't bother writing to the
|
||||
// heap at all. Each of these data is either already inlinable in a
|
||||
// HeapCellValue or a pointer to an GC'ed location in memory.
|
||||
#[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())
|
||||
pub(crate) fn put_literal(&mut self, literal: Literal) -> HeapCellValue {
|
||||
match literal {
|
||||
Literal::Atom(name) => atom_as_cell!(name),
|
||||
Literal::Char(c) => char_as_cell!(c),
|
||||
Literal::EmptyList => empty_list_as_cell!(),
|
||||
Literal::Fixnum(n) => fixnum_as_cell!(n),
|
||||
Literal::Integer(bigint_ptr) => {
|
||||
let h = self.push(typed_arena_ptr_as_cell!(bigint_ptr));
|
||||
self[h]
|
||||
}
|
||||
&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)),
|
||||
Literal::Rational(bigint_ptr) => {
|
||||
let h = self.push(typed_arena_ptr_as_cell!(bigint_ptr));
|
||||
self[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
|
||||
Literal::Float(f) => typed_arena_ptr_as_cell!(f),
|
||||
Literal::String(s) => {
|
||||
if s.as_str().is_empty() {
|
||||
empty_list_as_cell!()
|
||||
} else {
|
||||
self.put_complete_string(&s)
|
||||
}
|
||||
}
|
||||
Constant::Usize(n) => Addr::Usize(n),
|
||||
// TODO: how do we know where the tail is located?? well, there is no tail. separate tag?
|
||||
untyped_arena_ptr_as_cell!(s) // self.put_complete_string(arena, &s)
|
||||
}
|
||||
} // Literal::Usize(n) => Addr::Usize(n),
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
@@ -225,14 +340,14 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
|
||||
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;
|
||||
let new_ptr = self.buf.alloc(mem::size_of::<HeapCellValue>());
|
||||
ptr::write(new_ptr as *mut _, val);
|
||||
}
|
||||
|
||||
h
|
||||
}
|
||||
|
||||
/*
|
||||
#[inline]
|
||||
pub(crate) fn atom_at(&self, h: usize) -> bool {
|
||||
if let HeapCellValue::Atom(..) = &self[h] {
|
||||
@@ -265,76 +380,17 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
|
||||
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;
|
||||
} else {
|
||||
self.push(HeapCellValue::Addr(Addr::HeapCell(h + 1)));
|
||||
return Some(Addr::PStrLocation(orig_h, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#[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 _;
|
||||
let new_ptr = self.buf.top as usize - h * mem::size_of::<HeapCellValue>();
|
||||
self.buf.ptr = new_ptr as *mut _;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn h(&self) -> usize {
|
||||
(self.buf.top as usize - self.buf.base as usize) / mem::size_of::<HeapCellValue>()
|
||||
(self.buf.top as usize - self.buf.ptr as usize) / mem::size_of::<HeapCellValue>()
|
||||
}
|
||||
|
||||
pub(crate) fn append(&mut self, vals: Vec<HeapCellValue>) {
|
||||
@@ -350,84 +406,7 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
for value in values.map(|v| v.into()) {
|
||||
self.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
|
||||
self.push(value);
|
||||
|
||||
h += 2;
|
||||
}
|
||||
|
||||
self.push(HeapCellValue::Addr(Addr::EmptyList));
|
||||
|
||||
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,
|
||||
}
|
||||
};
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
*/
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: get rid of this!!
|
||||
#[inline]
|
||||
pub(crate) fn index_addr<'a>(&'a self, addr: &Addr) -> RefOrOwned<'a, HeapCellValue> {
|
||||
match addr {
|
||||
@@ -437,6 +416,20 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
|
||||
addr => RefOrOwned::Owned(HeapCellValue::Addr(*addr)),
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
impl<T: RawBlockTraits> Index<u64> for HeapTemplate<T> {
|
||||
type Output = HeapCellValue;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, index: u64) -> &Self::Output {
|
||||
unsafe {
|
||||
let ptr =
|
||||
self.buf.top as usize - (index as usize + 1) * mem::size_of::<HeapCellValue>();
|
||||
&*(ptr as *const HeapCellValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RawBlockTraits> Index<usize> for HeapTemplate<T> {
|
||||
@@ -445,7 +438,7 @@ impl<T: RawBlockTraits> Index<usize> for HeapTemplate<T> {
|
||||
#[inline]
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
unsafe {
|
||||
let ptr = self.buf.base as usize + index * mem::size_of::<HeapCellValue>();
|
||||
let ptr = self.buf.top as usize - (index + 1) * mem::size_of::<HeapCellValue>();
|
||||
&*(ptr as *const HeapCellValue)
|
||||
}
|
||||
}
|
||||
@@ -455,8 +448,9 @@ 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>();
|
||||
let ptr = self.buf.top as usize - (index + 1) * 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
@@ -1,53 +1,43 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::clause_name;
|
||||
use crate::parser::ast::*;
|
||||
|
||||
use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::clause_types::*;
|
||||
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_errors::MachineStub;
|
||||
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 indexmap::IndexMap;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::convert::TryFrom;
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt;
|
||||
// use std::mem;
|
||||
use std::net::TcpListener;
|
||||
use std::ops::{Add, AddAssign, Deref, Sub, SubAssign};
|
||||
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,43 +45,95 @@ 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),
|
||||
}
|
||||
// the position-dependent heap template:
|
||||
|
||||
#[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),
|
||||
/*
|
||||
read_heap_cell!(
|
||||
(HeapCellValueTag::AttrVar, n) => {
|
||||
}
|
||||
(HeapCellValueTag::Lis, n) => {
|
||||
}
|
||||
(HeapCellValueTag::Var, n) => {
|
||||
}
|
||||
(HeapCellValueTag::Str, n) => {
|
||||
}
|
||||
(HeapCellValueTag::PStrOffset, n) => {
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
)
|
||||
*/
|
||||
|
||||
impl PartialEq<Ref> for HeapCellValue {
|
||||
fn eq(&self, r: &Ref) -> bool {
|
||||
self.as_var() == Some(*r)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<Ref> for HeapCellValue {
|
||||
fn partial_cmp(&self, r: &Ref) -> Option<Ordering> {
|
||||
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),
|
||||
}
|
||||
}
|
||||
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h1) => {
|
||||
match r.get_tag() {
|
||||
RefTag::StackCell => Some(Ordering::Less),
|
||||
_ => {
|
||||
let h2 = r.get_value() as usize;
|
||||
h1.partial_cmp(&h2)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
/*
|
||||
impl HeapCellValue {
|
||||
#[inline]
|
||||
pub fn as_constant_index(self, machine_st: &MachineState) -> Option<Literal> {
|
||||
read_heap_cell!(self,
|
||||
(HeapCellValueTag::Char, c) => Some(Literal::Char(c)),
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
if arity == 0 {
|
||||
Some(Literal::Atom(name))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
(HeapCellValueTag::Fixnum, n) => {
|
||||
Some(Literal::Fixnum(n))
|
||||
}
|
||||
(HeapCellValueTag::F64, f) => {
|
||||
Some(Literal::Float(f))
|
||||
}
|
||||
(HeapCellValueTag::Cons, ptr) => {
|
||||
match_untyped_arena_ptr!(ptr,
|
||||
(ArenaHeaderTag::Integer, n) => {
|
||||
Some(Literal::Integer(n))
|
||||
}
|
||||
(ArenaHeaderTag::Rational, r) => {
|
||||
Some(Literal::Rational(r))
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
impl Ord for Ref {
|
||||
fn cmp(&self, other: &Ref) -> Ordering {
|
||||
match (self, other) {
|
||||
@@ -114,31 +156,6 @@ impl PartialEq<Ref> for Addr {
|
||||
}
|
||||
}
|
||||
|
||||
// for use crate::in MachineState::bind.
|
||||
impl PartialOrd<Ref> for Addr {
|
||||
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)
|
||||
}
|
||||
}
|
||||
},
|
||||
&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 {
|
||||
@@ -171,57 +188,6 @@ impl Addr {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn order_category(&self, heap: &Heap) -> Option<TermOrderCategory> {
|
||||
match Number::try_from((*self, heap)) {
|
||||
Ok(Number::Integer(_)) | Ok(Number::Fixnum(_)) | Ok(Number::Rational(_)) => {
|
||||
Some(TermOrderCategory::Integer)
|
||||
}
|
||||
Ok(Number::Float(_)) => Some(TermOrderCategory::FloatingPoint),
|
||||
_ => match self {
|
||||
Addr::HeapCell(_) | Addr::AttrVar(_) | Addr::StackCell(..) => {
|
||||
Some(TermOrderCategory::Variable)
|
||||
}
|
||||
Addr::Float(_) => Some(TermOrderCategory::FloatingPoint),
|
||||
&Addr::Con(h) => match &heap[h] {
|
||||
HeapCellValue::Atom(..) => Some(TermOrderCategory::Atom),
|
||||
HeapCellValue::DBRef(_) => None,
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
},
|
||||
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,
|
||||
@@ -230,61 +196,6 @@ impl Addr {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -305,72 +216,9 @@ impl From<Ref> for TrailRef {
|
||||
TrailRef::Ref(r)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum HeapCellValue {
|
||||
Addr(Addr),
|
||||
Atom(ClauseName, Option<SharedOpDesc>),
|
||||
DBRef(DBRef),
|
||||
Integer(Rc<Integer>),
|
||||
LoadStatePayload(Box<LoadStatePayload>),
|
||||
NamedStr(usize, ClauseName, Option<SharedOpDesc>), // arity, name, precedence/Specifier if it has one.
|
||||
Rational(Rc<Rational>),
|
||||
PartialString(PartialString, bool), // the partial string, a bool indicating whether it came from a Constant.
|
||||
Stream(Stream),
|
||||
TcpListener(TcpListener),
|
||||
}
|
||||
|
||||
impl HeapCellValue {
|
||||
#[inline]
|
||||
pub(crate) fn as_addr(&self, focus: usize) -> Addr {
|
||||
match self {
|
||||
HeapCellValue::Addr(ref a) => *a,
|
||||
HeapCellValue::Atom(..)
|
||||
| HeapCellValue::DBRef(..)
|
||||
| HeapCellValue::Integer(..)
|
||||
| HeapCellValue::Rational(..) => Addr::Con(focus),
|
||||
HeapCellValue::LoadStatePayload(_) => Addr::LoadStatePayload(focus),
|
||||
HeapCellValue::NamedStr(_, _, _) => Addr::Str(focus),
|
||||
HeapCellValue::PartialString(..) => Addr::PStrLocation(focus, 0),
|
||||
HeapCellValue::Stream(_) => Addr::Stream(focus),
|
||||
HeapCellValue::TcpListener(_) => Addr::TcpListener(focus),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn context_free_clone(&self) -> HeapCellValue {
|
||||
match self {
|
||||
&HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr),
|
||||
&HeapCellValue::Atom(ref name, ref op) => HeapCellValue::Atom(name.clone(), op.clone()),
|
||||
&HeapCellValue::DBRef(ref db_ref) => HeapCellValue::DBRef(db_ref.clone()),
|
||||
&HeapCellValue::Integer(ref n) => HeapCellValue::Integer(n.clone()),
|
||||
&HeapCellValue::LoadStatePayload(_) => {
|
||||
HeapCellValue::Atom(clause_name!("$live_term_stream"), None)
|
||||
}
|
||||
&HeapCellValue::NamedStr(arity, ref name, ref op) => {
|
||||
HeapCellValue::NamedStr(arity, name.clone(), op.clone())
|
||||
}
|
||||
&HeapCellValue::Rational(ref r) => HeapCellValue::Rational(r.clone()),
|
||||
&HeapCellValue::PartialString(ref pstr, has_tail) => {
|
||||
HeapCellValue::PartialString(pstr.clone(), has_tail)
|
||||
}
|
||||
&HeapCellValue::Stream(ref stream) => HeapCellValue::Stream(stream.clone()),
|
||||
&HeapCellValue::TcpListener(_) => {
|
||||
HeapCellValue::Atom(clause_name!("$tcp_listener"), None)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Addr> for HeapCellValue {
|
||||
#[inline]
|
||||
fn from(value: Addr) -> HeapCellValue {
|
||||
HeapCellValue::Addr(value)
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
#[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
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 +226,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>;
|
||||
@@ -419,7 +267,7 @@ impl Default for CodeIndex {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
|
||||
pub(crate) enum REPLCodePtr {
|
||||
pub enum REPLCodePtr {
|
||||
AddDiscontiguousPredicate,
|
||||
AddDynamicPredicate,
|
||||
AddMultifilePredicate,
|
||||
@@ -456,12 +304,11 @@ pub(crate) enum REPLCodePtr {
|
||||
AddNonCountedBacktracking,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub(crate) enum CodePtr {
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub 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.
|
||||
}
|
||||
@@ -488,7 +335,7 @@ impl CodePtr {
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub(crate) enum LocalCodePtr {
|
||||
pub enum LocalCodePtr {
|
||||
DirEntry(usize), // offset
|
||||
Halt,
|
||||
IndexingBuf(usize, usize, usize), // DirEntry offset, first internal offset, second internal offset
|
||||
@@ -496,7 +343,7 @@ pub(crate) enum LocalCodePtr {
|
||||
}
|
||||
|
||||
impl LocalCodePtr {
|
||||
pub(crate) fn assign_if_local(&mut self, cp: CodePtr) {
|
||||
pub fn assign_if_local(&mut self, cp: CodePtr) {
|
||||
match cp {
|
||||
CodePtr::Local(local) => *self = local,
|
||||
_ => {}
|
||||
@@ -504,7 +351,7 @@ impl LocalCodePtr {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn abs_loc(&self) -> usize {
|
||||
pub fn abs_loc(&self) -> usize {
|
||||
match self {
|
||||
LocalCodePtr::DirEntry(ref p) => *p,
|
||||
LocalCodePtr::IndexingBuf(ref p, ..) => *p,
|
||||
@@ -528,33 +375,21 @@ impl LocalCodePtr {
|
||||
false
|
||||
}
|
||||
|
||||
pub(crate) fn as_functor<T: RawBlockTraits>(&self, heap: &mut HeapTemplate<T>) -> Addr {
|
||||
let addr = Addr::HeapCell(heap.h());
|
||||
|
||||
pub(crate) fn as_functor(&self) -> MachineStub {
|
||||
match self {
|
||||
LocalCodePtr::DirEntry(p) => {
|
||||
heap.append(functor!("dir_entry", [integer(*p)]));
|
||||
functor!(atom!("dir_entry"), [fixnum(*p)])
|
||||
}
|
||||
LocalCodePtr::Halt => {
|
||||
heap.append(functor!("halt"));
|
||||
functor!(atom!("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)]
|
||||
));
|
||||
functor!(
|
||||
atom!("indexed_buf"),
|
||||
[fixnum(*p), fixnum(*o), fixnum(*i)]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
addr
|
||||
}
|
||||
}
|
||||
|
||||
@@ -614,9 +449,8 @@ 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::DirEntry(ref mut i)
|
||||
| &mut LocalCodePtr::IndexingBuf(_, _, ref mut i) => *i += rhs,
|
||||
&mut LocalCodePtr::Halt => unreachable!(),
|
||||
}
|
||||
}
|
||||
@@ -627,11 +461,7 @@ impl Add<usize> for CodePtr {
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
match self {
|
||||
p @ CodePtr::REPL(..) | p @ CodePtr::VerifyAttrInterrupt(_) => {
|
||||
// |
|
||||
// p @ CodePtr::DynamicTransaction(..) => {
|
||||
p
|
||||
}
|
||||
p @ CodePtr::REPL(..) | p @ CodePtr::VerifyAttrInterrupt(_) => p,
|
||||
CodePtr::Local(local) => CodePtr::Local(local + rhs),
|
||||
CodePtr::BuiltInClause(_, local) | CodePtr::CallN(_, local, _) => {
|
||||
CodePtr::Local(local + rhs)
|
||||
@@ -660,12 +490,12 @@ impl SubAssign<usize> for CodePtr {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type HeapVarDict = IndexMap<Rc<Var>, Addr>;
|
||||
pub(crate) type AllocVarDict = IndexMap<Rc<Var>, VarData>;
|
||||
pub(crate) type HeapVarDict = IndexMap<Rc<String>, HeapCellValue>;
|
||||
pub(crate) type AllocVarDict = IndexMap<Rc<String>, VarData>;
|
||||
|
||||
pub(crate) type GlobalVarDir = IndexMap<ClauseName, (Ball, Option<Addr>)>;
|
||||
pub(crate) type GlobalVarDir = IndexMap<Atom, (Ball, Option<HeapCellValue>)>;
|
||||
|
||||
pub(crate) type StreamAliasDir = IndexMap<ClauseName, Stream>;
|
||||
pub(crate) type StreamAliasDir = IndexMap<Atom, Stream>;
|
||||
pub(crate) type StreamDir = BTreeSet<Stream>;
|
||||
|
||||
pub(crate) type MetaPredicateDir = IndexMap<PredicateKey, Vec<MetaSpec>>;
|
||||
@@ -676,7 +506,7 @@ pub(crate) type LocalExtensiblePredicates =
|
||||
IndexMap<(CompilationTarget, PredicateKey), LocalPredicateSkeleton>;
|
||||
|
||||
#[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,22 +518,13 @@ 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 {
|
||||
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) {
|
||||
@@ -712,7 +533,6 @@ impl IndexStore {
|
||||
None
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -737,7 +557,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 +568,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 +584,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 +595,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 +626,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) {
|
||||
if module == atom!("user") {
|
||||
match ClauseType::from(name, arity) {
|
||||
ClauseType::Named(name, arity, _) => self.code_dir.get(&(name, arity)).cloned(),
|
||||
ClauseType::Op(name, spec, ..) => self.code_dir.get(&(name, spec.arity())).cloned(),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
self.modules.get(&module).and_then(|module| {
|
||||
match ClauseType::from(name, arity, op_spec) {
|
||||
self.modules
|
||||
.get(&module)
|
||||
.and_then(|module| match ClauseType::from(name, arity) {
|
||||
ClauseType::Named(name, arity, _) => {
|
||||
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 +665,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,19 +689,19 @@ impl IndexStore {
|
||||
|
||||
#[inline]
|
||||
pub(super) fn new() -> Self {
|
||||
IndexStore::default()
|
||||
index_store!(CodeDir::new(), default_op_dir(), ModuleDir::new())
|
||||
}
|
||||
|
||||
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 = atom!("run_cleaners_with_handling");
|
||||
let r_wo_h = atom!("run_cleaners_without_handling");
|
||||
let iso_ext = atom!("iso_ext");
|
||||
|
||||
let r_w_h = self
|
||||
.get_predicate_code_index(r_w_h, 0, iso_ext.clone(), None)
|
||||
.get_predicate_code_index(r_w_h, 0, iso_ext)
|
||||
.and_then(|item| item.local());
|
||||
let r_wo_h = self
|
||||
.get_predicate_code_index(r_wo_h, 1, iso_ext, None)
|
||||
.get_predicate_code_index(r_wo_h, 1, iso_ext)
|
||||
.and_then(|item| item.local());
|
||||
|
||||
if let Some(r_w_h) = r_w_h {
|
||||
@@ -895,7 +714,7 @@ impl IndexStore {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type CodeDir = BTreeMap<PredicateKey, CodeIndex>;
|
||||
pub(crate) type CodeDir = IndexMap<PredicateKey, CodeIndex>;
|
||||
|
||||
pub(crate) enum RefOrOwned<'a, T: 'a> {
|
||||
Borrowed(&'a T),
|
||||
@@ -918,14 +737,4 @@ impl<'a, T> RefOrOwned<'a, T> {
|
||||
&RefOrOwned::Owned(ref r) => r,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn to_owned(self) -> T
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
match self {
|
||||
RefOrOwned::Borrowed(item) => item.clone(),
|
||||
RefOrOwned::Owned(item) => item,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
766
src/machine/mock_wam.rs
Normal file
766
src/machine/mock_wam.rs
Normal file
@@ -0,0 +1,766 @@
|
||||
pub use crate::arena::*;
|
||||
pub use crate::atom_table::*;
|
||||
use crate::heap_print::*;
|
||||
pub use crate::machine::heap::*;
|
||||
pub use crate::machine::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 test_load_file(&mut self, file: &str) -> Vec<u8> {
|
||||
use std::io::Read;
|
||||
|
||||
let old_output = std::mem::replace(
|
||||
&mut self.user_output,
|
||||
Stream::from_owned_string("".to_owned(), &mut self.machine_st.arena),
|
||||
);
|
||||
|
||||
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);
|
||||
|
||||
let output = self.user_output.bytes().map(|b| b.unwrap()).collect();
|
||||
self.user_output = old_output;
|
||||
output
|
||||
}
|
||||
}
|
||||
|
||||
#[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(heap_loc_as_cell!(0)));
|
||||
}
|
||||
}
|
||||
@@ -1,67 +1,70 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::tabled_rc::*;
|
||||
use prolog_parser::{clause_name, temp_v};
|
||||
pub mod arithmetic_ops;
|
||||
pub mod attributed_variables;
|
||||
pub mod code_repo;
|
||||
pub mod code_walker;
|
||||
#[macro_use]
|
||||
pub mod loader;
|
||||
pub mod compile;
|
||||
pub mod copier;
|
||||
pub mod gc;
|
||||
pub mod heap;
|
||||
pub mod load_state;
|
||||
pub mod machine_errors;
|
||||
pub mod machine_indices;
|
||||
pub mod machine_state;
|
||||
pub mod machine_state_impl;
|
||||
pub mod mock_wam;
|
||||
pub mod partial_string;
|
||||
pub mod preprocessor;
|
||||
pub mod stack;
|
||||
pub mod streams;
|
||||
pub mod system_calls;
|
||||
pub mod term_stream;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use crate::clause_types::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
use crate::machine::loader::*;
|
||||
use crate::machine::term_stream::{LiveTermStream, LoadStatePayload, TermStream};
|
||||
use crate::read::*;
|
||||
|
||||
mod attributed_variables;
|
||||
pub(super) mod code_repo;
|
||||
pub(crate) mod code_walker;
|
||||
#[macro_use]
|
||||
pub(crate) mod loader;
|
||||
mod compile;
|
||||
mod copier;
|
||||
pub(crate) mod heap;
|
||||
mod load_state;
|
||||
pub(crate) mod machine_errors;
|
||||
pub(crate) mod machine_indices;
|
||||
pub(super) mod machine_state;
|
||||
pub(crate) mod partial_string;
|
||||
mod preprocessor;
|
||||
mod raw_block;
|
||||
mod stack;
|
||||
pub(crate) mod streams;
|
||||
mod term_stream;
|
||||
|
||||
#[macro_use]
|
||||
mod arithmetic_ops;
|
||||
#[macro_use]
|
||||
mod machine_state_impl;
|
||||
mod system_calls;
|
||||
|
||||
use crate::machine::code_repo::*;
|
||||
use crate::machine::compile::*;
|
||||
use crate::machine::heap::*;
|
||||
use crate::machine::loader::*;
|
||||
use crate::machine::machine_errors::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::machine::machine_state::*;
|
||||
pub use crate::machine::streams::Stream;
|
||||
use crate::machine::streams::*;
|
||||
use crate::types::*;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
//use std::convert::TryFrom;
|
||||
use prolog_parser::ast::ClauseName;
|
||||
use std::fs::File;
|
||||
use std::mem;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref INTERRUPT: AtomicBool = AtomicBool::new(false);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Machine {
|
||||
pub(super) machine_st: MachineState,
|
||||
pub(super) inner_heap: Heap,
|
||||
pub(super) policies: MachinePolicies,
|
||||
pub(super) indices: IndexStore,
|
||||
pub(super) code_repo: CodeRepo,
|
||||
pub(super) user_input: Stream,
|
||||
pub(super) user_output: Stream,
|
||||
pub(super) user_error: Stream,
|
||||
pub(super) load_contexts: Vec<LoadContext>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct MachinePolicies {
|
||||
call_policy: Box<dyn CallPolicy>,
|
||||
cut_policy: Box<dyn CutPolicy>,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref INTERRUPT: AtomicBool = AtomicBool::new(false);
|
||||
}
|
||||
|
||||
impl MachinePolicies {
|
||||
#[inline]
|
||||
fn new() -> Self {
|
||||
@@ -80,10 +83,10 @@ impl Default for MachinePolicies {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct LoadContext {
|
||||
pub struct LoadContext {
|
||||
pub(super) path: PathBuf,
|
||||
pub(super) stream: Stream,
|
||||
pub(super) module: ClauseName,
|
||||
pub(super) module: Atom,
|
||||
}
|
||||
|
||||
impl LoadContext {
|
||||
@@ -100,32 +103,49 @@ impl LoadContext {
|
||||
LoadContext {
|
||||
path: path_buf,
|
||||
stream,
|
||||
module: clause_name!("user"),
|
||||
module: atom!("user"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Machine {
|
||||
pub(super) machine_st: MachineState,
|
||||
pub(super) policies: MachinePolicies,
|
||||
pub(super) indices: IndexStore,
|
||||
pub(super) code_repo: CodeRepo,
|
||||
pub(super) user_input: Stream,
|
||||
pub(super) user_output: Stream,
|
||||
pub(super) user_error: Stream,
|
||||
pub(super) load_contexts: Vec<LoadContext>,
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn current_dir() -> PathBuf {
|
||||
std::env::current_dir().unwrap_or(PathBuf::from("./"))
|
||||
env::current_dir().unwrap_or(PathBuf::from("./"))
|
||||
}
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/libraries.rs"));
|
||||
|
||||
pub struct MachinePreludeView<'a> {
|
||||
pub indices: &'a mut IndexStore,
|
||||
pub code_repo: &'a mut CodeRepo,
|
||||
pub load_contexts: &'a mut Vec<LoadContext>,
|
||||
}
|
||||
|
||||
impl Machine {
|
||||
fn run_module_predicate(&mut self, module_name: ClauseName, key: PredicateKey) {
|
||||
#[inline]
|
||||
pub fn prelude_view_and_machine_st(&mut self) -> (MachinePreludeView, &mut MachineState) {
|
||||
(
|
||||
MachinePreludeView {
|
||||
indices: &mut self.indices,
|
||||
code_repo: &mut self.code_repo,
|
||||
load_contexts: &mut self.load_contexts,
|
||||
},
|
||||
&mut self.machine_st
|
||||
)
|
||||
}
|
||||
|
||||
pub fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) {
|
||||
let err = self.machine_st.session_error(err);
|
||||
let stub = functor_stub(key.0, key.1);
|
||||
let err = self.machine_st.error_form(err, stub);
|
||||
|
||||
self.machine_st.throw_exception(err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
impl Machine {
|
||||
fn run_module_predicate(&mut self, module_name: Atom, key: PredicateKey) {
|
||||
if let Some(module) = self.indices.modules.get(&module_name) {
|
||||
if let Some(ref code_index) = module.code_dir.get(&key) {
|
||||
let p = code_index.local().unwrap();
|
||||
@@ -140,27 +160,29 @@ impl Machine {
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
pub fn load_file(&mut self, path: String, stream: Stream) {
|
||||
self.machine_st[temp_v!(1)] =
|
||||
Addr::Stream(self.machine_st.heap.push(HeapCellValue::Stream(stream)));
|
||||
pub fn load_file(&mut self, path: &str, stream: Stream) {
|
||||
self.machine_st.registers[1] = stream_as_cell!(stream);
|
||||
self.machine_st.registers[2] = atom_as_cell!(
|
||||
self.machine_st.atom_tbl.build_with(path)
|
||||
);
|
||||
|
||||
self.machine_st[temp_v!(2)] = Addr::Con(self.machine_st.heap.push(HeapCellValue::Atom(
|
||||
clause_name!(path, self.machine_st.atom_tbl),
|
||||
None,
|
||||
)));
|
||||
|
||||
self.run_module_predicate(clause_name!("loader"), (clause_name!("file_load"), 2));
|
||||
self.run_module_predicate(atom!("loader"), (atom!("file_load"), 2));
|
||||
}
|
||||
|
||||
fn load_top_level(&mut self) {
|
||||
let mut path_buf = current_dir();
|
||||
path_buf.push("toplevel.pl");
|
||||
|
||||
let path = path_buf.to_str().unwrap().to_string();
|
||||
path_buf.push("src/toplevel.pl");
|
||||
|
||||
self.load_file(path, Stream::from(include_str!("../toplevel.pl")));
|
||||
let path = path_buf.to_str().unwrap();
|
||||
let toplevel_stream = Stream::from_static_string(
|
||||
include_str!("../toplevel.pl"),
|
||||
&mut self.machine_st.arena,
|
||||
);
|
||||
|
||||
if let Some(toplevel) = self.indices.modules.get(&clause_name!("$toplevel")) {
|
||||
self.load_file(path, toplevel_stream);
|
||||
|
||||
if let Some(toplevel) = self.indices.modules.get(&atom!("$toplevel")) {
|
||||
load_module(
|
||||
&mut self.indices.code_dir,
|
||||
&mut self.indices.op_dir,
|
||||
@@ -178,9 +200,15 @@ impl Machine {
|
||||
path_buf.push("machine/attributed_variables.pl");
|
||||
|
||||
bootstrapping_compile(
|
||||
Stream::from(include_str!("attributed_variables.pl")),
|
||||
Stream::from_static_string(
|
||||
include_str!("attributed_variables.pl"),
|
||||
&mut self.machine_st.arena,
|
||||
),
|
||||
self,
|
||||
ListingSource::from_file_and_path(clause_name!("attributed_variables"), path_buf),
|
||||
ListingSource::from_file_and_path(
|
||||
atom!("attributed_variables"),
|
||||
path_buf,
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -188,44 +216,49 @@ impl Machine {
|
||||
path_buf.push("machine/project_attributes.pl");
|
||||
|
||||
bootstrapping_compile(
|
||||
Stream::from(include_str!("project_attributes.pl")),
|
||||
Stream::from_static_string(
|
||||
include_str!("project_attributes.pl"),
|
||||
&mut self.machine_st.arena,
|
||||
),
|
||||
self,
|
||||
ListingSource::from_file_and_path(clause_name!("project_attributes"), path_buf),
|
||||
ListingSource::from_file_and_path(atom!("project_attributes"), path_buf),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
if let Some(module) = self.indices.modules.get(&clause_name!("$atts")) {
|
||||
if let Some(code_index) = module.code_dir.get(&(clause_name!("driver"), 2)) {
|
||||
if let Some(module) = self.indices.modules.get(&atom!("$atts")) {
|
||||
if let Some(code_index) = module.code_dir.get(&(atom!("driver"), 2)) {
|
||||
self.machine_st.attr_var_init.verify_attrs_loc = code_index.local().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_top_level(&mut self) {
|
||||
use std::env;
|
||||
|
||||
let mut arg_pstrs = vec![];
|
||||
|
||||
for arg in env::args() {
|
||||
arg_pstrs.push(self.machine_st.heap.put_complete_string(&arg));
|
||||
arg_pstrs.push(put_complete_string(
|
||||
&mut self.machine_st.heap,
|
||||
&arg,
|
||||
&mut self.machine_st.atom_tbl,
|
||||
));
|
||||
}
|
||||
|
||||
let list_addr = Addr::HeapCell(self.machine_st.heap.to_list(arg_pstrs.into_iter()));
|
||||
self.machine_st.registers[1] = heap_loc_as_cell!(
|
||||
iter_to_heap_list(&mut self.machine_st.heap, arg_pstrs.into_iter())
|
||||
);
|
||||
|
||||
self.machine_st[temp_v!(1)] = list_addr;
|
||||
|
||||
self.run_module_predicate(clause_name!("$toplevel"), (clause_name!("$repl"), 1));
|
||||
self.run_module_predicate(atom!("$toplevel"), (atom!("$repl"), 1));
|
||||
}
|
||||
|
||||
pub(crate) fn configure_modules(&mut self) {
|
||||
fn update_call_n_indices(loader: &Module, target_code_dir: &mut CodeDir) {
|
||||
for arity in 1..66 {
|
||||
let key = (clause_name!("call"), arity);
|
||||
let key = (atom!("call"), arity);
|
||||
|
||||
match loader.code_dir.get(&key) {
|
||||
Some(src_code_index) => {
|
||||
let target_code_index = target_code_dir
|
||||
.entry(key.clone())
|
||||
.entry(key)
|
||||
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined));
|
||||
|
||||
target_code_index.set(src_code_index.get());
|
||||
@@ -237,15 +270,15 @@ impl Machine {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(loader) = self.indices.modules.swap_remove(&clause_name!("loader")) {
|
||||
if let Some(builtins) = self.indices.modules.get_mut(&clause_name!("builtins")) {
|
||||
if let Some(loader) = self.indices.modules.swap_remove(&atom!("loader")) {
|
||||
if let Some(builtins) = self.indices.modules.get_mut(&atom!("builtins")) {
|
||||
// Import loader's exports into the builtins module so they will be
|
||||
// implicitly included in every further module.
|
||||
load_module(
|
||||
&mut builtins.code_dir,
|
||||
&mut builtins.op_dir,
|
||||
&mut builtins.meta_predicates,
|
||||
&CompilationTarget::Module(clause_name!("builtins")),
|
||||
&CompilationTarget::Module(atom!("builtins")),
|
||||
&loader,
|
||||
);
|
||||
|
||||
@@ -257,7 +290,7 @@ impl Machine {
|
||||
builtins
|
||||
.module_decl
|
||||
.exports
|
||||
.push(ModuleExport::PredicateKey((clause_name!("call"), arity)));
|
||||
.push(ModuleExport::PredicateKey((atom!("call"), arity)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,17 +300,24 @@ impl Machine {
|
||||
|
||||
update_call_n_indices(&loader, &mut self.indices.code_dir);
|
||||
|
||||
self.indices.modules.insert(clause_name!("loader"), loader);
|
||||
self.indices.modules.insert(atom!("loader"), loader);
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(user_input: Stream, user_output: Stream, user_error: Stream) -> Self {
|
||||
pub fn new() -> Self {
|
||||
use ref_thread_local::RefThreadLocal;
|
||||
|
||||
let mut machine_st = MachineState::new();
|
||||
|
||||
let user_input = Stream::stdin(&mut machine_st.arena);
|
||||
let user_output = Stream::stdout(&mut machine_st.arena);
|
||||
let user_error = Stream::stderr(&mut machine_st.arena);
|
||||
|
||||
let mut wam = Machine {
|
||||
machine_st: MachineState::new(),
|
||||
machine_st,
|
||||
inner_heap: Heap::new(),
|
||||
policies: MachinePolicies::new(),
|
||||
indices: IndexStore::new(),
|
||||
code_repo: CodeRepo::new(),
|
||||
@@ -293,23 +333,29 @@ impl Machine {
|
||||
lib_path.push("lib");
|
||||
|
||||
bootstrapping_compile(
|
||||
Stream::from(LIBRARIES.borrow()["ops_and_meta_predicates"]),
|
||||
Stream::from_static_string(
|
||||
LIBRARIES.borrow()["ops_and_meta_predicates"],
|
||||
&mut wam.machine_st.arena,
|
||||
),
|
||||
&mut wam,
|
||||
ListingSource::from_file_and_path(
|
||||
clause_name!("ops_and_meta_predicates.pl"),
|
||||
atom!("ops_and_meta_predicates.pl"),
|
||||
lib_path.clone(),
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
bootstrapping_compile(
|
||||
Stream::from(LIBRARIES.borrow()["builtins"]),
|
||||
Stream::from_static_string(
|
||||
LIBRARIES.borrow()["builtins"],
|
||||
&mut wam.machine_st.arena,
|
||||
),
|
||||
&mut wam,
|
||||
ListingSource::from_file_and_path(clause_name!("builtins.pl"), lib_path.clone()),
|
||||
ListingSource::from_file_and_path(atom!("builtins.pl"), lib_path.clone()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
if let Some(builtins) = wam.indices.modules.get(&clause_name!("builtins")) {
|
||||
if let Some(builtins) = wam.indices.modules.get(&atom!("builtins")) {
|
||||
load_module(
|
||||
&mut wam.indices.code_dir,
|
||||
&mut wam.indices.op_dir,
|
||||
@@ -324,15 +370,15 @@ impl Machine {
|
||||
lib_path.pop(); // remove the "lib" at the end
|
||||
|
||||
bootstrapping_compile(
|
||||
Stream::from(include_str!("../loader.pl")),
|
||||
Stream::from_static_string(include_str!("../loader.pl"), &mut wam.machine_st.arena),
|
||||
&mut wam,
|
||||
ListingSource::from_file_and_path(clause_name!("loader.pl"), lib_path.clone()),
|
||||
ListingSource::from_file_and_path(atom!("loader.pl"), lib_path.clone()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
wam.configure_modules();
|
||||
|
||||
if let Some(loader) = wam.indices.modules.get(&clause_name!("loader")) {
|
||||
if let Some(loader) = wam.indices.modules.get(&atom!("loader")) {
|
||||
load_module(
|
||||
&mut wam.indices.code_dir,
|
||||
&mut wam.indices.op_dir,
|
||||
@@ -352,38 +398,21 @@ impl Machine {
|
||||
}
|
||||
|
||||
pub(crate) fn configure_streams(&mut self) {
|
||||
self.user_input.options_mut().alias = Some(clause_name!("user_input"));
|
||||
self.user_input.options_mut().set_alias_to_atom_opt(Some(atom!("user_input")));
|
||||
|
||||
self.indices
|
||||
.stream_aliases
|
||||
.insert(clause_name!("user_input"), self.user_input.clone());
|
||||
.insert(atom!("user_input"), self.user_input);
|
||||
|
||||
self.indices.streams.insert(self.user_input.clone());
|
||||
self.indices.streams.insert(self.user_input);
|
||||
|
||||
self.user_output.options_mut().alias = Some(clause_name!("user_output"));
|
||||
self.user_output.options_mut().set_alias_to_atom_opt(Some(atom!("user_output")));
|
||||
|
||||
self.indices
|
||||
.stream_aliases
|
||||
.insert(clause_name!("user_output"), self.user_output.clone());
|
||||
.insert(atom!("user_output"), self.user_output);
|
||||
|
||||
self.user_error.options_mut().alias = Some(clause_name!("user_error"));
|
||||
|
||||
self.indices
|
||||
.stream_aliases
|
||||
.insert(clause_name!("user_error"), self.user_error.clone());
|
||||
|
||||
self.indices.streams.insert(self.user_output.clone());
|
||||
}
|
||||
|
||||
fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) {
|
||||
let h = self.machine_st.heap.h();
|
||||
|
||||
let err = MachineError::session_error(h, err);
|
||||
let stub = MachineError::functor_stub(key.0, key.1);
|
||||
let err = self.machine_st.error_form(err, stub);
|
||||
|
||||
self.machine_st.throw_exception(err);
|
||||
return;
|
||||
self.indices.streams.insert(self.user_output);
|
||||
}
|
||||
|
||||
fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) {
|
||||
@@ -604,13 +633,14 @@ impl MachineState {
|
||||
self.b0 = self.stack.index_or_frame(b).prelude.b0;
|
||||
self.p = CodePtr::Local(self.stack.index_or_frame(b).prelude.bp);
|
||||
|
||||
self.pdl.clear();
|
||||
self.fail = false;
|
||||
}
|
||||
|
||||
fn check_machine_index(&mut self, code_repo: &CodeRepo) -> bool {
|
||||
match self.p {
|
||||
CodePtr::Local(LocalCodePtr::DirEntry(p))
|
||||
| CodePtr::Local(LocalCodePtr::IndexingBuf(p, ..))
|
||||
CodePtr::Local(LocalCodePtr::DirEntry(p)) |
|
||||
CodePtr::Local(LocalCodePtr::IndexingBuf(p, ..))
|
||||
if p < code_repo.code.len() => {}
|
||||
CodePtr::Local(LocalCodePtr::Halt) | CodePtr::REPL(..) => {
|
||||
return false;
|
||||
@@ -690,7 +720,9 @@ impl MachineState {
|
||||
self.p = CodePtr::Local(self.attr_var_init.cp);
|
||||
|
||||
let instigating_p = CodePtr::Local(self.attr_var_init.instigating_p);
|
||||
let instigating_instr = code_repo.lookup_instr(false, &instigating_p).unwrap();
|
||||
let instigating_instr = code_repo
|
||||
.lookup_instr(false, &instigating_p)
|
||||
.unwrap();
|
||||
|
||||
if !instigating_instr.as_ref().is_head_instr() {
|
||||
let cp = self.p.local();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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::clause_types::*;
|
||||
use crate::forms::*;
|
||||
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(),
|
||||
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)?;
|
||||
}.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,35 +176,33 @@ 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),
|
||||
}
|
||||
}
|
||||
@@ -224,10 +212,10 @@ fn setup_double_quotes(mut terms: Vec<Box<Term>>) -> Result<DoubleQuotes, Compil
|
||||
let dbl_quotes = *terms.pop().unwrap();
|
||||
|
||||
match terms[0].as_ref() {
|
||||
Term::Constant(_, Constant::Atom(ref name, _))
|
||||
Term::Literal(_, Literal::Atom(ref name, _))
|
||||
if name.as_str() == "double_quotes" => {
|
||||
match dbl_quotes {
|
||||
Term::Constant(_, Constant::Atom(name, _)) => {
|
||||
Term::Literal(_, Literal::Atom(name, _)) => {
|
||||
match name.as_str() {
|
||||
"atom" => Ok(DoubleQuotes::Atom),
|
||||
"chars" => Ok(DoubleQuotes::Chars),
|
||||
@@ -250,34 +238,31 @@ fn setup_double_quotes(mut terms: Vec<Box<Term>>) -> Result<DoubleQuotes, Compil
|
||||
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 +307,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 +346,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 +362,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 +404,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 +417,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 +447,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 +473,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,43 +520,43 @@ 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)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Preprocessor {
|
||||
flags: MachineFlags,
|
||||
queue: VecDeque<VecDeque<Term>>,
|
||||
}
|
||||
|
||||
impl Preprocessor {
|
||||
pub(super) fn new() -> Self {
|
||||
pub(super) fn new(flags: MachineFlags) -> Self {
|
||||
Preprocessor {
|
||||
flags,
|
||||
queue: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_fact(&mut self, term: Term) -> Result<Term, CompilationError> {
|
||||
match term {
|
||||
Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => Ok(term),
|
||||
Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => Ok(term),
|
||||
_ => Err(CompilationError::InadmissibleFact),
|
||||
}
|
||||
}
|
||||
@@ -579,20 +570,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 +597,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 +616,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 +695,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)],
|
||||
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 +798,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 +829,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 +867,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,
|
||||
)?)?;
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use crate::types::*;
|
||||
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::machine::raw_block::*;
|
||||
use crate::raw_block::*;
|
||||
|
||||
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 +17,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();
|
||||
}
|
||||
}
|
||||
@@ -57,7 +48,7 @@ pub(crate) struct AndFramePrelude {
|
||||
pub(crate) univ_prelude: FramePrelude,
|
||||
pub(crate) e: usize,
|
||||
pub(crate) cp: LocalCodePtr,
|
||||
pub(crate) interrupt_cp: LocalCodePtr,
|
||||
pub(crate) interrupt_cp: LocalCodePtr, // TODO: get rid of it!
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -67,22 +58,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 +81,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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -119,18 +132,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 +152,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 +177,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 +218,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 +246,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 +254,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 +262,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 +270,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;
|
||||
|
||||
#[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 _;
|
||||
if base < self.buf.ptr as usize {
|
||||
self.buf.ptr = base as *mut _;
|
||||
}
|
||||
}
|
||||
|
||||
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
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
680
src/macros.rs
680
src/macros.rs
@@ -13,53 +13,421 @@ 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::NullStream
|
||||
| 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,143 +436,126 @@ 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;
|
||||
macro_rules! ar_reg {
|
||||
($r: expr) => {
|
||||
ArithmeticTerm::Reg($r)
|
||||
};
|
||||
}
|
||||
|
||||
$addendum.put_complete_string(&s);
|
||||
macro_rules! unmark_cell_bits {
|
||||
($e:expr) => {{
|
||||
let mut result = $e;
|
||||
|
||||
HeapCellValue::Addr(Addr::PStrLocation(h, 0))
|
||||
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::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(),
|
||||
}
|
||||
&Constant::Usize(u) => {
|
||||
HeapCellValue::Addr(Addr::Usize(u))
|
||||
}
|
||||
&Constant::EmptyList => {
|
||||
HeapCellValue::Addr(Addr::EmptyList)
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! is_atom {
|
||||
@@ -358,22 +709,6 @@ macro_rules! dir_entry {
|
||||
};
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -408,34 +743,6 @@ macro_rules! discard_result {
|
||||
};
|
||||
}
|
||||
*/
|
||||
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! try_or_fail {
|
||||
($s:expr, $e:expr) => {{
|
||||
@@ -448,3 +755,46 @@ macro_rules! try_or_fail {
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! try_or_fail_gen {
|
||||
($s:expr, $e:expr) => {{
|
||||
match $e {
|
||||
Ok(val) => val,
|
||||
Err(msg_fn) => {
|
||||
let e = msg_fn($s);
|
||||
$s.throw_exception(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
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)($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()
|
||||
}};
|
||||
}
|
||||
|
||||
631
src/parser/ast.rs
Normal file
631
src/parser/ast.rs
Normal file
@@ -0,0 +1,631 @@
|
||||
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 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>;
|
||||
|
||||
#[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(
|
||||
(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
747
src/parser/char_reader.rs
Normal 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ερτι μεντιτθμ. Προ φαcερ vολθτπατ
|
||||
σαπιεντεμ ιν. Cθ εροσ περσεqθερισ πρι, εα ποσσιτ cετεροσ δθο. Πρι
|
||||
εα μαλισ μθνερε.
|
||||
|
||||
Qθισ jθστο μαλορθμ cθ qθο. Νεc ατ οδιο σολετ μαιεστατισ, νε
|
||||
φορενσιβθσ σαδιπσcινγ ιθσ, αν qθι ειθσ βρθτε σαπιεντεμ. Cομμθνε
|
||||
περcιπιτθρ ιθσ αδ, μθνερε δολορθμ ιμπεδιτ ηισ νε. Νεc ετιαμ
|
||||
προπριαε vιτθπερατα ιν. Σονετ νεμορε ιθσ cθ, ιν αφφερτ ινερμισ
|
||||
cοτιδιεqθε vισ.
|
||||
|
||||
Ηασ ιδ νονθμυ δοcτθσ cοτιδιεqθε. Σινγθλισ πηιλοσοπηια εξ δθο. Εστ
|
||||
νο ιραcθνδια cονσεqθθντθρ. Τε διcτασ επιcθρει εφφιcιαντθρ δθο, εοσ
|
||||
νε νθλλα νομιναvι. Εθμ cθ ελιτρ λιβεραvισσε, σιτ περσεqθερισ
|
||||
cομπλεcτιτθρ εξ, πονδερθμ σιμιλιqθε ηασ νο.
|
||||
|
||||
Σολθμ ποσσιμ λαβιτθρ εξ ηισ, ει δομινγ εξπετενδισ vελ, διαμ μινιμ
|
||||
σcριπσεριτ ει περ. Αθδιαμ οcθρρερετ προ εξ, δομινγ vολθπταρια ετ
|
||||
qθο. Cονσθλ σανcτθσ αccθμσαν νο ιθσ, αδ εαμ αλβθcιθσ
|
||||
ηονεστατισ. Ετ vιξ φαcιλισ qθαλισqθε ερροριβθσ, ηισ εθ πθρτο
|
||||
ασσεντιορ. Ιθσ βονορθμ ηονεστατισ σcριπσεριτ ατ, ιν ναμ εσσε μοvετ
|
||||
γραεcο. Αθγθε cονσεcτετθερ εστ ατ.
|
||||
|
||||
Αδ ταλε σθασ μθνερε σεδ, vισ φεθγαιτ αντιοπαμ ιδ. Προ εθ ινερμισ
|
||||
σαλθτατθσ, σαεπε qθαεστιο θρβανιτασ cθ περ. Ιν μαλορθμ σαλθτατθσ
|
||||
δετερρθισσετ περ, νε παρτεμ vολθτπατ ινστρθcτιορ vιξ. Νο vισ
|
||||
δεμοcριτθμ εφφιcιαντθρ, επιcθρει αδολεσcενσ εστ cθ, ιδ vιξ
|
||||
λθcιλιθσ αδιπισcινγ. Σεα τε cλιτα ιραcθνδια. Σεα αν σιμθλ
|
||||
εσσεντ. Vοcιβθσ ελειφενδ cονσεqθθντθρ περ αδ, αν ναμ πονδερθμ
|
||||
vολθπταρια.
|
||||
|
||||
Λιβερ ερθδιτι αccθσαμθσ θτ ναμ. Σιτ αντιοπαμ γθβεργρεν νε. Αμετ
|
||||
ανcιλλαε ετ qθι, μεα σολθμ λαθδεμ εα. Εθ μελ παρτεμ οβλιqθε
|
||||
πηαεδρθμ. Εξ μελ jθστο αccομμοδαρε, νε νολθισσε σινγθλισ σενσιβθσ
|
||||
cθμ, vισ εθ τιμεαμ αδιπισcινγ.
|
||||
|
||||
Τε νολθισσε vολθπτατθμ εστ. Ασσθμ νομιναvι πρι νε, ει νοστρθμ
|
||||
επιcθρει μεα. Σεδ 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
@@ -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'
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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
105
src/raw_block.rs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
362
src/read.rs
362
src/read.rs
@@ -1,37 +1,72 @@
|
||||
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 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(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};
|
||||
impl MachineState {
|
||||
pub(crate) fn devour_whitespace(
|
||||
&mut self,
|
||||
mut inner: Stream,
|
||||
) -> Result<bool, ParserError> {
|
||||
let mut parser = Parser::new(inner, self);
|
||||
|
||||
static mut PROMPT: bool = false;
|
||||
parser.devour_whitespace()?;
|
||||
inner.add_lines_read(parser.lines_read());
|
||||
|
||||
const HISTORY_FILE: &'static str = ".scryer_history";
|
||||
parser.eof()
|
||||
}
|
||||
|
||||
pub(crate) fn set_prompt(value: bool) {
|
||||
pub(crate) fn read(
|
||||
&mut self,
|
||||
mut inner: Stream,
|
||||
op_dir: &OpDir,
|
||||
) -> Result<TermWriteResult, ParserError> {
|
||||
let (term, num_lines_read) = {
|
||||
let prior_num_lines_read = inner.lines_read();
|
||||
let mut parser = Parser::new(inner, self);
|
||||
|
||||
parser.add_lines_read(prior_num_lines_read);
|
||||
|
||||
let term = parser.read_term(&CompositeOpDir::new(op_dir, None))?;
|
||||
(term, parser.lines_read() - prior_num_lines_read)
|
||||
};
|
||||
|
||||
inner.add_lines_read(num_lines_read);
|
||||
Ok(write_term_to_heap(&term, &mut self.heap, &mut self.atom_tbl))
|
||||
}
|
||||
}
|
||||
|
||||
static mut PROMPT: bool = false;
|
||||
|
||||
const HISTORY_FILE: &'static str = ".scryer_history";
|
||||
|
||||
pub(crate) fn set_prompt(value: bool) {
|
||||
unsafe {
|
||||
PROMPT = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_prompt() -> &'static str {
|
||||
#[inline]
|
||||
fn get_prompt() -> &'static str {
|
||||
unsafe {
|
||||
if PROMPT {
|
||||
"?- "
|
||||
@@ -39,42 +74,42 @@ pub mod readline {
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ReadlineStream {
|
||||
#[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 {
|
||||
impl ReadlineStream {
|
||||
#[inline]
|
||||
pub(crate) fn new(pending_input: String) -> Self {
|
||||
pub fn new(pending_input: &str) -> Self {
|
||||
let config = Config::builder().check_cursor_position(true).build();
|
||||
let mut rl = Editor::<()>::with_config(config);
|
||||
|
||||
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() {
|
||||
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),
|
||||
pending_input: Cursor::new(pending_input.to_owned()),
|
||||
}
|
||||
}
|
||||
|
||||
#[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> {
|
||||
fn call_readline(&mut self) -> std::io::Result<usize> {
|
||||
match self.rl.readline(get_prompt()) {
|
||||
Ok(text) => {
|
||||
*self.pending_input.get_mut() = text;
|
||||
@@ -92,7 +127,7 @@ pub mod readline {
|
||||
*self.pending_input.get_mut() += "\n";
|
||||
}
|
||||
|
||||
self.pending_input.read(buf)
|
||||
Ok(self.pending_input.get_ref().len())
|
||||
}
|
||||
Err(ReadlineError::Eof) => Ok(0),
|
||||
Err(e) => Err(Error::new(ErrorKind::InvalidInput, e)),
|
||||
@@ -106,149 +141,121 @@ pub mod readline {
|
||||
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() {
|
||||
} 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(0) => {
|
||||
return Ok(0);
|
||||
}
|
||||
Some(b) => {
|
||||
return Ok(b);
|
||||
}
|
||||
None => match self.call_readline(&mut []) {
|
||||
None => match self.call_readline() {
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
Ok(0) => {
|
||||
return Err(Error::new(ErrorKind::UnexpectedEof, "end of file"));
|
||||
self.pending_input.get_mut().push('\u{0}');
|
||||
return Ok(0);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn peek_char(&mut self) -> std::io::Result<char> {
|
||||
_ => {
|
||||
set_prompt(false);
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parser.devour_whitespace()?;
|
||||
impl CharRead for ReadlineStream {
|
||||
fn peek_char(&mut self) -> Option<std::io::Result<char>> {
|
||||
loop {
|
||||
let pos = self.pending_input.position() as usize;
|
||||
|
||||
inner.add_lines_read(parser.num_lines_read());
|
||||
|
||||
let result = parser.eof();
|
||||
let buf = stream.take_buf();
|
||||
|
||||
inner.pause_stream(buf)?;
|
||||
|
||||
result
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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())?;
|
||||
fn consume(&mut self, nread: usize) {
|
||||
let offset = self.pending_input.position() as usize;
|
||||
self.pending_input.set_position((offset + nread) as u64);
|
||||
}
|
||||
|
||||
let (term, num_lines_read) = {
|
||||
let prior_num_lines_read = inner.lines_read();
|
||||
let mut parser = Parser::new(&mut stream, atom_tbl, self.flags);
|
||||
|
||||
parser.add_lines_read(prior_num_lines_read);
|
||||
|
||||
let term = parser.read_term(&CompositeOpDir::new(op_dir, None))?;
|
||||
(term, parser.num_lines_read() - prior_num_lines_read)
|
||||
};
|
||||
|
||||
inner.add_lines_read(num_lines_read);
|
||||
|
||||
// 'pausing' the stream saves the pending top buffer
|
||||
// created by the parsing stream, which was created in this
|
||||
// scope and is about to be destroyed in it.
|
||||
|
||||
let buf = stream.take_buf();
|
||||
inner.pause_stream(buf)?;
|
||||
|
||||
Ok(write_term_to_heap(&term, self))
|
||||
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, machine_st: &mut MachineState) -> TermWriteResult {
|
||||
let term_writer = TermWriter::new(machine_st);
|
||||
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(),
|
||||
}
|
||||
@@ -257,7 +264,7 @@ impl<'a> TermWriter<'a> {
|
||||
#[inline]
|
||||
fn modify_head_of_queue(&mut self, term: &TermRef<'a>, h: usize) {
|
||||
if let Some((arity, site_h)) = self.queue.pop_front() {
|
||||
self.machine_st.heap[site_h] = HeapCellValue::Addr(self.term_as_addr(term, h));
|
||||
self.heap[site_h] = self.term_as_addr(term, h);
|
||||
|
||||
if arity > 1 {
|
||||
self.queue.push_front((arity - 1, site_h + 1));
|
||||
@@ -267,64 +274,82 @@ 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(..) => 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;
|
||||
}
|
||||
}
|
||||
&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(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;
|
||||
}
|
||||
&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 +360,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 {
|
||||
|
||||
@@ -1,37 +1,39 @@
|
||||
use prolog_parser::ast::*;
|
||||
use crate::parser::ast::*;
|
||||
|
||||
use crate::atom_table::*;
|
||||
use crate::clause_types::*;
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
use crate::iterators::*;
|
||||
use crate::types::*;
|
||||
|
||||
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) -> Self;
|
||||
fn to_list(lvl: Level, r: RegType) -> Self;
|
||||
fn to_structure(ct: ClauseType, arity: usize, r: RegType) -> Self;
|
||||
|
||||
fn to_void(_: usize) -> Self;
|
||||
fn to_void(num_subterms: usize) -> Self;
|
||||
fn is_void_instr(&self) -> 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) -> Self;
|
||||
|
||||
fn incr_void_instr(&mut self);
|
||||
|
||||
fn constant_subterm(_: Constant) -> Self;
|
||||
fn constant_subterm(literal: Literal) -> Self;
|
||||
|
||||
fn argument_to_variable(_: RegType, _: usize) -> Self;
|
||||
fn argument_to_value(_: RegType, _: usize) -> Self;
|
||||
fn argument_to_variable(r: RegType, r: usize) -> Self;
|
||||
fn argument_to_value(r: RegType, val: usize) -> Self;
|
||||
|
||||
fn move_to_register(_: RegType, _: usize) -> Self;
|
||||
fn move_to_register(r: RegType, val: usize) -> Self;
|
||||
|
||||
fn subterm_to_variable(_: RegType) -> Self;
|
||||
fn subterm_to_value(_: RegType) -> Self;
|
||||
fn subterm_to_variable(r: RegType) -> Self;
|
||||
fn subterm_to_value(r: RegType) -> Self;
|
||||
|
||||
fn clause_arg_to_instr(_: RegType) -> Self;
|
||||
fn clause_arg_to_instr(r: RegType) -> Self;
|
||||
}
|
||||
|
||||
impl<'a> CompilationTarget<'a> for FactInstruction {
|
||||
@@ -41,8 +43,8 @@ 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) -> Self {
|
||||
FactInstruction::GetConstant(lvl, HeapCellValue::from(constant), reg)
|
||||
}
|
||||
|
||||
fn to_structure(ct: ClauseType, arity: usize, reg: RegType) -> Self {
|
||||
@@ -53,8 +55,8 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
|
||||
FactInstruction::GetList(lvl, reg)
|
||||
}
|
||||
|
||||
fn to_void(subterms: usize) -> Self {
|
||||
FactInstruction::UnifyVoid(subterms)
|
||||
fn to_void(num_subterms: usize) -> Self {
|
||||
FactInstruction::UnifyVoid(num_subterms)
|
||||
}
|
||||
|
||||
fn is_void_instr(&self) -> bool {
|
||||
@@ -64,7 +66,7 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
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) -> Self {
|
||||
FactInstruction::GetPartialString(lvl, string, r, has_tail)
|
||||
}
|
||||
|
||||
@@ -75,8 +77,8 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
fn constant_subterm(constant: Constant) -> Self {
|
||||
FactInstruction::UnifyConstant(constant)
|
||||
fn constant_subterm(constant: Literal) -> Self {
|
||||
FactInstruction::UnifyConstant(HeapCellValue::from(constant))
|
||||
}
|
||||
|
||||
fn argument_to_variable(arg: RegType, val: usize) -> Self {
|
||||
@@ -115,15 +117,15 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
|
||||
QueryInstruction::PutStructure(ct, 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) -> Self {
|
||||
QueryInstruction::PutConstant(lvl, HeapCellValue::from(constant), reg)
|
||||
}
|
||||
|
||||
fn to_list(lvl: Level, reg: RegType) -> Self {
|
||||
QueryInstruction::PutList(lvl, reg)
|
||||
}
|
||||
|
||||
fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self {
|
||||
fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Self {
|
||||
QueryInstruction::PutPartialString(lvl, string, r, has_tail)
|
||||
}
|
||||
|
||||
@@ -145,8 +147,8 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
fn constant_subterm(constant: Constant) -> Self {
|
||||
QueryInstruction::SetConstant(constant)
|
||||
fn constant_subterm(constant: Literal) -> Self {
|
||||
QueryInstruction::SetConstant(HeapCellValue::from(constant))
|
||||
}
|
||||
|
||||
fn argument_to_variable(arg: RegType, val: usize) -> Self {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
:- use_module(library(charsio)).
|
||||
:- use_module(library(files)).
|
||||
:- use_module(library(iso_ext)).
|
||||
:- use_module(library(lambda)).
|
||||
:- use_module(library(lists)).
|
||||
:- use_module(library(si)).
|
||||
|
||||
@@ -17,7 +18,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
|
||||
@@ -272,8 +273,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 +287,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),
|
||||
sort(Vars1, Vars2),
|
||||
charsio:extend_var_list(Vars2, VarList, NewVarList0, fabricated),
|
||||
( bb_get('$first_answer', true) ->
|
||||
write(' '),
|
||||
bb_put('$first_answer', false)
|
||||
|
||||
739
src/types.rs
Normal file
739
src/types.rs
Normal file
@@ -0,0 +1,739 @@
|
||||
use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::forms::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::machine::partial_string::PartialString;
|
||||
use crate::parser::ast::Fixnum;
|
||||
|
||||
use modular_bitfield::prelude::*;
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use std::ops::{Add, Sub, SubAssign};
|
||||
|
||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[bits = 6]
|
||||
pub enum HeapCellValueTag {
|
||||
// non-constants / tags with adjoining forwarding bits.
|
||||
Cons = 0b00,
|
||||
F64 = 0b01,
|
||||
Str = 0b000010,
|
||||
Lis = 0b000011,
|
||||
Var = 0b000110,
|
||||
StackVar = 0b000111,
|
||||
AttrVar = 0b010011,
|
||||
PStrLoc = 0b111111,
|
||||
PStrOffset = 0b001110,
|
||||
// constants.
|
||||
Fixnum = 0b010010,
|
||||
Char = 0b011011,
|
||||
Atom = 0b001010,
|
||||
PStr = 0b001011,
|
||||
CStr = 0b010110, // a complete string.
|
||||
}
|
||||
|
||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[bits = 6]
|
||||
pub enum HeapCellValueView {
|
||||
// non-constants / tags with adjoining forwarding bits.
|
||||
Cons = 0b00,
|
||||
F64 = 0b01,
|
||||
Str = 0b000010,
|
||||
Lis = 0b000011,
|
||||
Var = 0b000110,
|
||||
StackVar = 0b000111,
|
||||
AttrVar = 0b010011,
|
||||
PStrLoc = 0b111111,
|
||||
PStrOffset = 0b001110,
|
||||
// constants.
|
||||
Fixnum = 0b010010,
|
||||
Char = 0b011011,
|
||||
Atom = 0b001010,
|
||||
PStr = 0b001011,
|
||||
CStr = 0b010110,
|
||||
// trail elements.
|
||||
TrailedHeapVar = 0b011110,
|
||||
TrailedStackVar = 0b011111,
|
||||
TrailedAttrVarHeapLink = 0b101110,
|
||||
TrailedAttrVarListLink = 0b100010,
|
||||
TrailedAttachedValue = 0b101010,
|
||||
TrailedBlackboardEntry = 0b100110,
|
||||
TrailedBlackboardOffset = 0b100111,
|
||||
}
|
||||
|
||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[bits = 2]
|
||||
pub enum ConsPtrMaskTag {
|
||||
Cons = 0b00,
|
||||
F64 = 0b01,
|
||||
}
|
||||
|
||||
#[bitfield]
|
||||
#[repr(u64)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ConsPtr {
|
||||
ptr: B61,
|
||||
m: bool,
|
||||
tag: ConsPtrMaskTag,
|
||||
}
|
||||
|
||||
impl ConsPtr {
|
||||
#[inline(always)]
|
||||
pub fn build_with(ptr: *const ArenaHeader, tag: ConsPtrMaskTag) -> Self {
|
||||
ConsPtr::new()
|
||||
.with_ptr(ptr as *const u8 as u64)
|
||||
.with_m(false)
|
||||
.with_tag(tag)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_ptr(self) -> *mut u8 {
|
||||
self.ptr() as *mut _
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug)]
|
||||
#[bits = 6]
|
||||
pub(crate) enum RefTag {
|
||||
HeapCell = 0b0110,
|
||||
StackCell = 0b111,
|
||||
AttrVar = 0b10011,
|
||||
}
|
||||
|
||||
#[bitfield]
|
||||
#[repr(u64)]
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub struct Ref {
|
||||
val: B56,
|
||||
#[allow(unused)] m: bool,
|
||||
#[allow(unused)] f: bool,
|
||||
tag: RefTag,
|
||||
}
|
||||
|
||||
impl Ord for Ref {
|
||||
fn cmp(&self, rhs: &Ref) -> Ordering {
|
||||
match self.get_tag() {
|
||||
RefTag::HeapCell | RefTag::AttrVar => {
|
||||
match rhs.get_tag() {
|
||||
RefTag::StackCell => Ordering::Less,
|
||||
_ => self.get_value().cmp(&rhs.get_value()),
|
||||
}
|
||||
}
|
||||
RefTag::StackCell => {
|
||||
match rhs.get_tag() {
|
||||
RefTag::StackCell =>
|
||||
self.get_value().cmp(&rhs.get_value()),
|
||||
_ =>
|
||||
Ordering::Greater,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Ref {
|
||||
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ref {
|
||||
#[inline(always)]
|
||||
pub(crate) fn build_with(tag: RefTag, value: u64) -> Self {
|
||||
Ref::new().with_tag(tag).with_val(value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn get_tag(self) -> RefTag {
|
||||
self.tag()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn get_value(self) -> u64 {
|
||||
self.val()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn as_heap_cell_value(self) -> HeapCellValue {
|
||||
HeapCellValue::from_bytes(self.into_bytes())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn heap_cell(h: usize) -> Self {
|
||||
Ref::build_with(RefTag::HeapCell, h as u64)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn stack_cell(h: usize) -> Self {
|
||||
Ref::build_with(RefTag::StackCell, h as u64)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn attr_var(h: usize) -> Self {
|
||||
Ref::build_with(RefTag::AttrVar, h as u64)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum TrailRef {
|
||||
Ref(Ref),
|
||||
AttrVarHeapLink(usize),
|
||||
AttrVarListLink(usize, usize),
|
||||
BlackboardEntry(Atom),
|
||||
BlackboardOffset(Atom, HeapCellValue), // key atom, key value
|
||||
}
|
||||
|
||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[bits = 6]
|
||||
pub(crate) enum TrailEntryTag {
|
||||
TrailedHeapVar = 0b011110,
|
||||
TrailedStackVar = 0b011111,
|
||||
TrailedAttrVar = 0b101110,
|
||||
TrailedAttrVarHeapLink = 0b100010,
|
||||
TrailedAttrVarListLink = 0b100011,
|
||||
TrailedAttachedValue = 0b101010,
|
||||
TrailedBlackboardEntry = 0b100110,
|
||||
TrailedBlackboardOffset = 0b100111,
|
||||
}
|
||||
|
||||
#[bitfield]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(u64)]
|
||||
pub(crate) struct TrailEntry {
|
||||
val: B56,
|
||||
#[allow(unused)] f: bool,
|
||||
#[allow(unused)] m: bool,
|
||||
#[allow(unused)] tag: TrailEntryTag,
|
||||
}
|
||||
|
||||
impl TrailEntry {
|
||||
#[inline(always)]
|
||||
pub(crate) fn build_with(tag: TrailEntryTag, value: u64) -> Self {
|
||||
TrailEntry::new()
|
||||
.with_tag(tag)
|
||||
.with_m(false)
|
||||
.with_f(false)
|
||||
.with_val(value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn get_tag(self) -> TrailEntryTag {
|
||||
match self.tag_or_err() {
|
||||
Ok(tag) => tag,
|
||||
Err(_) => TrailEntryTag::TrailedAttachedValue,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn get_value(self) -> u64 {
|
||||
self.val()
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u64)]
|
||||
#[bitfield]
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct HeapCellValue {
|
||||
val: B56,
|
||||
f: bool,
|
||||
m: bool,
|
||||
tag: HeapCellValueTag,
|
||||
}
|
||||
|
||||
impl fmt::Debug for HeapCellValue {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
|
||||
match self.get_tag() {
|
||||
tag @ (HeapCellValueTag::Cons | HeapCellValueTag::F64) => {
|
||||
let cons_ptr = ConsPtr::from_bytes(self.into_bytes());
|
||||
|
||||
f.debug_struct("HeapCellValue")
|
||||
.field("tag", &tag)
|
||||
.field("ptr", &cons_ptr.ptr())
|
||||
.field("m", &cons_ptr.m())
|
||||
.finish()
|
||||
}
|
||||
HeapCellValueTag::Atom => {
|
||||
let (name, arity) = cell_as_atom_cell!(self)
|
||||
.get_name_and_arity();
|
||||
|
||||
f.debug_struct("HeapCellValue")
|
||||
.field("tag", &HeapCellValueTag::Atom)
|
||||
.field("name", &name.as_str())
|
||||
.field("arity", &arity)
|
||||
.field("m", &self.m())
|
||||
.field("f", &self.f())
|
||||
.finish()
|
||||
}
|
||||
HeapCellValueTag::PStr => {
|
||||
let (name, _) = cell_as_atom_cell!(self)
|
||||
.get_name_and_arity();
|
||||
|
||||
f.debug_struct("HeapCellValue")
|
||||
.field("tag", &HeapCellValueTag::PStr)
|
||||
.field("contents", &name.as_str())
|
||||
.field("m", &self.m())
|
||||
.field("f", &self.f())
|
||||
.finish()
|
||||
}
|
||||
tag => {
|
||||
f.debug_struct("HeapCellValue")
|
||||
.field("tag", &tag)
|
||||
.field("value", &self.get_value())
|
||||
.field("m", &self.get_mark_bit())
|
||||
.field("f", &self.get_forwarding_bit())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<TypedArenaPtr<T>> for HeapCellValue {
|
||||
#[inline]
|
||||
fn from(arena_ptr: TypedArenaPtr<T>) -> HeapCellValue {
|
||||
HeapCellValue::from(arena_ptr.header_ptr() as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<F64Ptr> for HeapCellValue {
|
||||
#[inline]
|
||||
fn from(f64_ptr: F64Ptr) -> HeapCellValue {
|
||||
HeapCellValue::from_bytes(
|
||||
ConsPtr::from(f64_ptr.as_ptr() as u64)
|
||||
.with_tag(ConsPtrMaskTag::F64)
|
||||
.with_m(false)
|
||||
.into_bytes(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConsPtr> for HeapCellValue {
|
||||
#[inline(always)]
|
||||
fn from(cons_ptr: ConsPtr) -> HeapCellValue {
|
||||
HeapCellValue::from_bytes(
|
||||
ConsPtr::from(cons_ptr.as_ptr() as u64)
|
||||
.with_tag(ConsPtrMaskTag::Cons)
|
||||
.with_m(false)
|
||||
.into_bytes(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<(Number, &mut Arena)> for HeapCellValue {
|
||||
#[inline(always)]
|
||||
fn from((n, arena): (Number, &mut Arena)) -> HeapCellValue {
|
||||
match n {
|
||||
Number::Float(n) => HeapCellValue::from(arena_alloc!(n, arena)),
|
||||
Number::Integer(n) => HeapCellValue::from(n),
|
||||
Number::Rational(n) => HeapCellValue::from(n),
|
||||
Number::Fixnum(n) => fixnum_as_cell!(n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HeapCellValue {
|
||||
#[inline(always)]
|
||||
pub fn build_with(tag: HeapCellValueTag, value: u64) -> Self {
|
||||
HeapCellValue::new()
|
||||
.with_tag(tag)
|
||||
.with_val(value)
|
||||
.with_m(false)
|
||||
.with_f(false)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_string_terminator(self, heap: &[HeapCellValue]) -> bool {
|
||||
read_heap_cell!(self,
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
name == atom!("[]") && arity == 0
|
||||
}
|
||||
(HeapCellValueTag::CStr) => {
|
||||
true
|
||||
}
|
||||
(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::Var |
|
||||
tag @ HeapCellValueTag::AttrVar => {
|
||||
HeapCellValue::build_with(tag, (self.get_value() + rhs.abs() as usize) as u64)
|
||||
}
|
||||
_ => {
|
||||
self
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.sub(rhs as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
304
src/write.rs
304
src/write.rs
@@ -1,10 +1,17 @@
|
||||
use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::clause_types::*;
|
||||
use crate::forms::*;
|
||||
use crate::indexing::IndexingCodePtr;
|
||||
use crate::instructions::*;
|
||||
use crate::machine::loader::CompilationTarget;
|
||||
use crate::machine::machine_errors::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::machine::partial_string::*;
|
||||
use crate::machine::streams::*;
|
||||
use crate::parser::rug::{Integer, Rational};
|
||||
use crate::types::*;
|
||||
|
||||
use ordered_float::OrderedFloat;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
@@ -13,7 +20,9 @@ impl fmt::Display for LocalCodePtr {
|
||||
match self {
|
||||
LocalCodePtr::DirEntry(p) => write!(f, "LocalCodePtr::DirEntry({})", p),
|
||||
LocalCodePtr::Halt => write!(f, "LocalCodePtr::Halt"),
|
||||
LocalCodePtr::IndexingBuf(p, o, i) => write!(f, "LocalCodePtr::IndexingBuf({}, {}, {})", p, o, i),
|
||||
LocalCodePtr::IndexingBuf(p, o, i) => {
|
||||
write!(f, "LocalCodePtr::IndexingBuf({}, {}, {})", p, o, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,74 +30,50 @@ impl fmt::Display for LocalCodePtr {
|
||||
impl fmt::Display for REPLCodePtr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
REPLCodePtr::AddDiscontiguousPredicate =>
|
||||
write!(f, "REPLCodePtr::AddDiscontiguousPredicate"),
|
||||
REPLCodePtr::AddDynamicPredicate =>
|
||||
write!(f, "REPLCodePtr::AddDynamicPredicate"),
|
||||
REPLCodePtr::AddMultifilePredicate =>
|
||||
write!(f, "REPLCodePtr::AddMultifilePredicate"),
|
||||
REPLCodePtr::AddGoalExpansionClause =>
|
||||
write!(f, "REPLCodePtr::AddGoalExpansionClause"),
|
||||
REPLCodePtr::AddTermExpansionClause =>
|
||||
write!(f, "REPLCodePtr::AddTermExpansionClause"),
|
||||
REPLCodePtr::AddInSituFilenameModule =>
|
||||
write!(f, "REPLCodePtr::AddInSituFilenameModule"),
|
||||
REPLCodePtr::AbolishClause =>
|
||||
write!(f, "REPLCodePtr::AbolishClause"),
|
||||
REPLCodePtr::Assertz =>
|
||||
write!(f, "REPLCodePtr::Assertz"),
|
||||
REPLCodePtr::Asserta =>
|
||||
write!(f, "REPLCodePtr::Asserta"),
|
||||
REPLCodePtr::Retract =>
|
||||
write!(f, "REPLCodePtr::Retract"),
|
||||
REPLCodePtr::ClauseToEvacuable =>
|
||||
write!(f, "REPLCodePtr::ClauseToEvacuable"),
|
||||
REPLCodePtr::ScopedClauseToEvacuable =>
|
||||
write!(f, "REPLCodePtr::ScopedClauseToEvacuable"),
|
||||
REPLCodePtr::ConcludeLoad =>
|
||||
write!(f, "REPLCodePtr::ConcludeLoad"),
|
||||
REPLCodePtr::DeclareModule =>
|
||||
write!(f, "REPLCodePtr::DeclareModule"),
|
||||
REPLCodePtr::LoadCompiledLibrary =>
|
||||
write!(f, "REPLCodePtr::LoadCompiledLibrary"),
|
||||
REPLCodePtr::LoadContextSource =>
|
||||
write!(f, "REPLCodePtr::LoadContextSource"),
|
||||
REPLCodePtr::LoadContextFile =>
|
||||
write!(f, "REPLCodePtr::LoadContextFile"),
|
||||
REPLCodePtr::LoadContextDirectory =>
|
||||
write!(f, "REPLCodePtr::LoadContextDirectory"),
|
||||
REPLCodePtr::LoadContextModule =>
|
||||
write!(f, "REPLCodePtr::LoadContextModule"),
|
||||
REPLCodePtr::LoadContextStream =>
|
||||
write!(f, "REPLCodePtr::LoadContextStream"),
|
||||
REPLCodePtr::PopLoadContext =>
|
||||
write!(f, "REPLCodePtr::PopLoadContext"),
|
||||
REPLCodePtr::PopLoadStatePayload =>
|
||||
write!(f, "REPLCodePtr::PopLoadStatePayload"),
|
||||
REPLCodePtr::PushLoadContext =>
|
||||
write!(f, "REPLCodePtr::PushLoadContext"),
|
||||
REPLCodePtr::PushLoadStatePayload =>
|
||||
write!(f, "REPLCodePtr::PushLoadStatePayload"),
|
||||
REPLCodePtr::UseModule =>
|
||||
write!(f, "REPLCodePtr::UseModule"),
|
||||
REPLCodePtr::MetaPredicateProperty =>
|
||||
write!(f, "REPLCodePtr::MetaPredicateProperty"),
|
||||
REPLCodePtr::BuiltInProperty =>
|
||||
write!(f, "REPLCodePtr::BuiltInProperty"),
|
||||
REPLCodePtr::DynamicProperty =>
|
||||
write!(f, "REPLCodePtr::DynamicProperty"),
|
||||
REPLCodePtr::MultifileProperty =>
|
||||
write!(f, "REPLCodePtr::MultifileProperty"),
|
||||
REPLCodePtr::DiscontiguousProperty =>
|
||||
write!(f, "REPLCodePtr::DiscontiguousProperty"),
|
||||
REPLCodePtr::IsConsistentWithTermQueue =>
|
||||
write!(f, "REPLCodePtr::IsConsistentWithTermQueue"),
|
||||
REPLCodePtr::FlushTermQueue =>
|
||||
write!(f, "REPLCodePtr::FlushTermQueue"),
|
||||
REPLCodePtr::RemoveModuleExports =>
|
||||
write!(f, "REPLCodePtr::RemoveModuleExports"),
|
||||
REPLCodePtr::AddNonCountedBacktracking =>
|
||||
write!(f, "REPLCodePtr::AddNonCountedBacktracking"),
|
||||
REPLCodePtr::AddDiscontiguousPredicate => {
|
||||
write!(f, "REPLCodePtr::AddDiscontiguousPredicate")
|
||||
}
|
||||
REPLCodePtr::AddDynamicPredicate => write!(f, "REPLCodePtr::AddDynamicPredicate"),
|
||||
REPLCodePtr::AddMultifilePredicate => write!(f, "REPLCodePtr::AddMultifilePredicate"),
|
||||
REPLCodePtr::AddGoalExpansionClause => write!(f, "REPLCodePtr::AddGoalExpansionClause"),
|
||||
REPLCodePtr::AddTermExpansionClause => write!(f, "REPLCodePtr::AddTermExpansionClause"),
|
||||
REPLCodePtr::AddInSituFilenameModule => {
|
||||
write!(f, "REPLCodePtr::AddInSituFilenameModule")
|
||||
}
|
||||
REPLCodePtr::AbolishClause => write!(f, "REPLCodePtr::AbolishClause"),
|
||||
REPLCodePtr::Assertz => write!(f, "REPLCodePtr::Assertz"),
|
||||
REPLCodePtr::Asserta => write!(f, "REPLCodePtr::Asserta"),
|
||||
REPLCodePtr::Retract => write!(f, "REPLCodePtr::Retract"),
|
||||
REPLCodePtr::ClauseToEvacuable => write!(f, "REPLCodePtr::ClauseToEvacuable"),
|
||||
REPLCodePtr::ScopedClauseToEvacuable => {
|
||||
write!(f, "REPLCodePtr::ScopedClauseToEvacuable")
|
||||
}
|
||||
REPLCodePtr::ConcludeLoad => write!(f, "REPLCodePtr::ConcludeLoad"),
|
||||
REPLCodePtr::DeclareModule => write!(f, "REPLCodePtr::DeclareModule"),
|
||||
REPLCodePtr::LoadCompiledLibrary => write!(f, "REPLCodePtr::LoadCompiledLibrary"),
|
||||
REPLCodePtr::LoadContextSource => write!(f, "REPLCodePtr::LoadContextSource"),
|
||||
REPLCodePtr::LoadContextFile => write!(f, "REPLCodePtr::LoadContextFile"),
|
||||
REPLCodePtr::LoadContextDirectory => write!(f, "REPLCodePtr::LoadContextDirectory"),
|
||||
REPLCodePtr::LoadContextModule => write!(f, "REPLCodePtr::LoadContextModule"),
|
||||
REPLCodePtr::LoadContextStream => write!(f, "REPLCodePtr::LoadContextStream"),
|
||||
REPLCodePtr::PopLoadContext => write!(f, "REPLCodePtr::PopLoadContext"),
|
||||
REPLCodePtr::PopLoadStatePayload => write!(f, "REPLCodePtr::PopLoadStatePayload"),
|
||||
REPLCodePtr::PushLoadContext => write!(f, "REPLCodePtr::PushLoadContext"),
|
||||
REPLCodePtr::PushLoadStatePayload => write!(f, "REPLCodePtr::PushLoadStatePayload"),
|
||||
REPLCodePtr::UseModule => write!(f, "REPLCodePtr::UseModule"),
|
||||
REPLCodePtr::MetaPredicateProperty => write!(f, "REPLCodePtr::MetaPredicateProperty"),
|
||||
REPLCodePtr::BuiltInProperty => write!(f, "REPLCodePtr::BuiltInProperty"),
|
||||
REPLCodePtr::DynamicProperty => write!(f, "REPLCodePtr::DynamicProperty"),
|
||||
REPLCodePtr::MultifileProperty => write!(f, "REPLCodePtr::MultifileProperty"),
|
||||
REPLCodePtr::DiscontiguousProperty => write!(f, "REPLCodePtr::DiscontiguousProperty"),
|
||||
REPLCodePtr::IsConsistentWithTermQueue => {
|
||||
write!(f, "REPLCodePtr::IsConsistentWithTermQueue")
|
||||
}
|
||||
REPLCodePtr::FlushTermQueue => write!(f, "REPLCodePtr::FlushTermQueue"),
|
||||
REPLCodePtr::RemoveModuleExports => write!(f, "REPLCodePtr::RemoveModuleExports"),
|
||||
REPLCodePtr::AddNonCountedBacktracking => {
|
||||
write!(f, "REPLCodePtr::AddNonCountedBacktracking")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,7 +92,7 @@ impl fmt::Display for CompilationTarget {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
CompilationTarget::User => write!(f, "user"),
|
||||
CompilationTarget::Module(ref module_name) => write!(f, "{}", module_name),
|
||||
CompilationTarget::Module(ref module_name) => write!(f, "{}", module_name.as_str()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -122,11 +107,17 @@ impl fmt::Display for FactInstruction {
|
||||
write!(f, "get_list {}{}", lvl, r.reg_num())
|
||||
}
|
||||
&FactInstruction::GetPartialString(lvl, ref s, r, has_tail) => {
|
||||
write!(f, "get_partial_string({}, {}, {}, {})",
|
||||
lvl, s, r, has_tail)
|
||||
write!(
|
||||
f,
|
||||
"get_partial_string({}, {}, {}, {})",
|
||||
lvl,
|
||||
s.as_str(),
|
||||
r,
|
||||
has_tail
|
||||
)
|
||||
}
|
||||
&FactInstruction::GetStructure(ref ct, ref arity, ref r) => {
|
||||
write!(f, "get_structure {}/{}, {}", ct.name(), arity, r)
|
||||
write!(f, "get_structure {}/{}, {}", ct.name().as_str(), arity, r)
|
||||
}
|
||||
&FactInstruction::GetValue(ref x, ref a) => {
|
||||
write!(f, "get_value {}, A{}", x, a)
|
||||
@@ -166,11 +157,17 @@ impl fmt::Display for QueryInstruction {
|
||||
write!(f, "put_list {}{}", lvl, r.reg_num())
|
||||
}
|
||||
&QueryInstruction::PutPartialString(lvl, ref s, r, has_tail) => {
|
||||
write!(f, "put_partial_string({}, {}, {}, {})",
|
||||
lvl, s, r, has_tail)
|
||||
write!(
|
||||
f,
|
||||
"put_partial_string({}, {}, {}, {})",
|
||||
lvl,
|
||||
s.as_str(),
|
||||
r,
|
||||
has_tail
|
||||
)
|
||||
}
|
||||
&QueryInstruction::PutStructure(ref ct, ref arity, ref r) => {
|
||||
write!(f, "put_structure {}/{}, {}", ct.name(), arity, r)
|
||||
write!(f, "put_structure {}/{}, {}", ct.name().as_str(), arity, r)
|
||||
}
|
||||
&QueryInstruction::PutUnsafeValue(y, a) => write!(f, "put_unsafe_value Y{}, A{}", y, a),
|
||||
&QueryInstruction::PutValue(ref x, ref a) => write!(f, "put_value {}, A{}", x, a),
|
||||
@@ -214,12 +211,12 @@ impl fmt::Display for ClauseType {
|
||||
&ClauseType::System(SystemClauseType::SetCutPoint(r)) => {
|
||||
write!(f, "$set_cp({})", r)
|
||||
}
|
||||
&ClauseType::Named(ref name, _, ref idx) | &ClauseType::Op(ref name, _, ref idx) => {
|
||||
&ClauseType::Named(ref name, _, ref idx) => {
|
||||
let idx = idx.0.get();
|
||||
write!(f, "{}/{}", name, idx)
|
||||
write!(f, "{}/{}", name.as_str(), idx)
|
||||
}
|
||||
ref ct => {
|
||||
write!(f, "{}", ct.name())
|
||||
write!(f, "{}", ct.name().as_str())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -227,6 +224,52 @@ impl fmt::Display for ClauseType {
|
||||
|
||||
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!()
|
||||
}
|
||||
)
|
||||
/*
|
||||
match self {
|
||||
&HeapCellValue::Addr(ref addr) => write!(f, "{}", addr),
|
||||
&HeapCellValue::Atom(ref atom, _) => write!(f, "{}", atom.as_str()),
|
||||
@@ -260,9 +303,11 @@ impl fmt::Display for HeapCellValue {
|
||||
write!(f, "$tcp_listener({})", tcp_listener.local_addr().unwrap())
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl fmt::Display for DBRef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
@@ -273,7 +318,9 @@ impl fmt::Display for DBRef {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
impl fmt::Display for Addr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
@@ -296,6 +343,7 @@ impl fmt::Display for Addr {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl fmt::Display for ControlInstruction {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
@@ -353,29 +401,45 @@ impl fmt::Display for ChoiceInstruction {
|
||||
&ChoiceInstruction::DynamicElse(offset, Death::Finite(d), NextOrFail::Fail(i)) => {
|
||||
write!(f, "dynamic_else {}, {}, fail({})", offset, d, i)
|
||||
}
|
||||
&ChoiceInstruction::DynamicInternalElse(offset, Death::Infinity, NextOrFail::Next(i)) => {
|
||||
&ChoiceInstruction::DynamicInternalElse(
|
||||
offset,
|
||||
Death::Infinity,
|
||||
NextOrFail::Next(i),
|
||||
) => {
|
||||
write!(f, "dynamic_internal_else {}, {}, {}", offset, "inf", i)
|
||||
}
|
||||
&ChoiceInstruction::DynamicInternalElse(offset, Death::Infinity, NextOrFail::Fail(i)) => {
|
||||
write!(f, "dynamic_internal_else {}, {}, fail({})", offset, "inf", i)
|
||||
&ChoiceInstruction::DynamicInternalElse(
|
||||
offset,
|
||||
Death::Infinity,
|
||||
NextOrFail::Fail(i),
|
||||
) => {
|
||||
write!(
|
||||
f,
|
||||
"dynamic_internal_else {}, {}, fail({})",
|
||||
offset, "inf", i
|
||||
)
|
||||
}
|
||||
&ChoiceInstruction::DynamicInternalElse(offset, Death::Finite(d), NextOrFail::Next(i)) => {
|
||||
&ChoiceInstruction::DynamicInternalElse(
|
||||
offset,
|
||||
Death::Finite(d),
|
||||
NextOrFail::Next(i),
|
||||
) => {
|
||||
write!(f, "dynamic_internal_else {}, {}, {}", offset, d, i)
|
||||
}
|
||||
&ChoiceInstruction::DynamicInternalElse(offset, Death::Finite(d), NextOrFail::Fail(i)) => {
|
||||
&ChoiceInstruction::DynamicInternalElse(
|
||||
offset,
|
||||
Death::Finite(d),
|
||||
NextOrFail::Fail(i),
|
||||
) => {
|
||||
write!(f, "dynamic_internal_else {}, {}, fail({})", offset, d, i)
|
||||
}
|
||||
&ChoiceInstruction::TryMeElse(offset) =>
|
||||
write!(f, "try_me_else {}", offset),
|
||||
&ChoiceInstruction::TryMeElse(offset) => write!(f, "try_me_else {}", offset),
|
||||
&ChoiceInstruction::DefaultRetryMeElse(offset) => {
|
||||
write!(f, "retry_me_else_by_default {}", offset)
|
||||
}
|
||||
&ChoiceInstruction::RetryMeElse(offset) =>
|
||||
write!(f, "retry_me_else {}", offset),
|
||||
&ChoiceInstruction::DefaultTrustMe(_) =>
|
||||
write!(f, "trust_me_by_default"),
|
||||
&ChoiceInstruction::TrustMe(_) =>
|
||||
write!(f, "trust_me"),
|
||||
&ChoiceInstruction::RetryMeElse(offset) => write!(f, "retry_me_else {}", offset),
|
||||
&ChoiceInstruction::DefaultTrustMe(_) => write!(f, "trust_me_by_default"),
|
||||
&ChoiceInstruction::TrustMe(_) => write!(f, "trust_me"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -434,8 +498,8 @@ impl fmt::Display for SessionError {
|
||||
write!(
|
||||
f,
|
||||
"module {} does not contain claimed export {}/{}",
|
||||
module,
|
||||
key.0,
|
||||
module.as_str(),
|
||||
key.0.as_str(),
|
||||
key.1,
|
||||
)
|
||||
}
|
||||
@@ -452,12 +516,23 @@ impl fmt::Display for SessionError {
|
||||
write!(f, "queries cannot be defined as facts.")
|
||||
}
|
||||
&SessionError::ModuleCannotImportSelf(ref module_name) => {
|
||||
write!(f, "modules ({}, in this case) cannot import themselves.",
|
||||
module_name)
|
||||
write!(
|
||||
f,
|
||||
"modules ({}, in this case) cannot import themselves.",
|
||||
module_name.as_str()
|
||||
)
|
||||
}
|
||||
&SessionError::PredicateNotMultifileOrDiscontiguous(ref compilation_target, ref key) => {
|
||||
write!(f, "module {} does not define {}/{} as multifile or discontiguous.",
|
||||
compilation_target.module_name(), key.0, key.1)
|
||||
&SessionError::PredicateNotMultifileOrDiscontiguous(
|
||||
ref compilation_target,
|
||||
ref key,
|
||||
) => {
|
||||
write!(
|
||||
f,
|
||||
"module {} does not define {}/{} as multifile or discontiguous.",
|
||||
compilation_target.module_name().as_str(),
|
||||
key.0.as_str(),
|
||||
key.1
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -466,14 +541,19 @@ impl fmt::Display for SessionError {
|
||||
impl fmt::Display for ExistenceError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&ExistenceError::Module(ref module_name) => {
|
||||
write!(f, "the module {} does not exist", module_name)
|
||||
&ExistenceError::Module(module_name) => {
|
||||
write!(f, "the module {} does not exist", module_name.as_str())
|
||||
}
|
||||
&ExistenceError::ModuleSource(ref module_source) => {
|
||||
write!(f, "the source/sink {} does not exist", module_source)
|
||||
}
|
||||
&ExistenceError::Procedure(ref name, arity) => {
|
||||
write!(f, "the procedure {}/{} does not exist", name, arity)
|
||||
&ExistenceError::Procedure(name, arity) => {
|
||||
write!(
|
||||
f,
|
||||
"the procedure {}/{} does not exist",
|
||||
name.as_str(),
|
||||
arity
|
||||
)
|
||||
}
|
||||
&ExistenceError::SourceSink(ref addr) => {
|
||||
write!(f, "the source/sink {} does not exist", addr)
|
||||
@@ -489,10 +569,10 @@ impl fmt::Display for ModuleSource {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&ModuleSource::File(ref file) => {
|
||||
write!(f, "at the file {}", file)
|
||||
write!(f, "at the file {}", file.as_str())
|
||||
}
|
||||
&ModuleSource::Library(ref library) => {
|
||||
write!(f, "at library({})", library)
|
||||
write!(f, "at library({})", library.as_str())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -538,7 +618,9 @@ impl fmt::Display for Line {
|
||||
Ok(())
|
||||
}
|
||||
&Line::IndexedChoice(ref indexed_choice_instr) => write!(f, "{}", indexed_choice_instr),
|
||||
&Line::DynamicIndexedChoice(ref indexed_choice_instr) => write!(f, "{}", indexed_choice_instr),
|
||||
&Line::DynamicIndexedChoice(ref indexed_choice_instr) => {
|
||||
write!(f, "{}", indexed_choice_instr)
|
||||
}
|
||||
&Line::Query(ref query_instr) => write!(f, "{}", query_instr),
|
||||
}
|
||||
}
|
||||
@@ -547,10 +629,10 @@ impl fmt::Display for Line {
|
||||
impl fmt::Display for Number {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&Number::Fixnum(n) => write!(f, "{}", n),
|
||||
&Number::Float(fl) => write!(f, "{}", fl),
|
||||
&Number::Integer(ref bi) => write!(f, "{}", bi),
|
||||
&Number::Rational(ref r) => write!(f, "{}", r),
|
||||
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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,21 +31,23 @@ impl Expectable for &[u8] {
|
||||
pub(crate) fn load_module_test<T: Expectable>(file: &str, expected: T) {
|
||||
use scryer_prolog::*;
|
||||
|
||||
let input = machine::Stream::from("");
|
||||
let output = machine::Stream::from(String::new());
|
||||
let error = machine::Stream::from(String::new());
|
||||
// let input = machine::Stream::from("");
|
||||
// let output = machine::Stream::from(String::new());
|
||||
// let error = machine::Stream::from(String::new());
|
||||
|
||||
let mut wam = machine::Machine::new(input, output.clone(), error);
|
||||
let mut wam = machine::Machine::new(); // input, output.clone(), error);
|
||||
expected.assert_eq(wam.test_load_file(file).as_slice());
|
||||
|
||||
wam.load_file(
|
||||
file.into(),
|
||||
machine::Stream::from(
|
||||
std::fs::read_to_string(AsRef::<std::path::Path>::as_ref(file)).unwrap(),
|
||||
),
|
||||
);
|
||||
|
||||
let output = output.bytes().unwrap();
|
||||
expected.assert_eq(output.as_slice());
|
||||
// wam.load_file(
|
||||
// file.into(),
|
||||
// machine::Stream::from_owned_string(
|
||||
// std::fs::read_to_string(AsRef::<std::path::Path>::as_ref(file)).unwrap(),
|
||||
// &mut wam.machine_st.arena,
|
||||
// ),
|
||||
// );
|
||||
//
|
||||
// let output = output.bytes().unwrap();
|
||||
// expected.assert_eq(output.as_slice());
|
||||
}
|
||||
|
||||
pub const SCRYER_PROLOG: &str = "scryer-prolog";
|
||||
|
||||
Reference in New Issue
Block a user