use new heap term representation

This commit is contained in:
Mark Thom
2021-11-14 13:39:56 -07:00
parent d0b74a95f4
commit 0404c3bd94
72 changed files with 26285 additions and 17019 deletions

2
.gitignore vendored
View File

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

565
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package]
name = "scryer-prolog"
version = "0.8.128"
version = "0.9.0"
authors = ["Mark Thom <markjordanthom@gmail.com>"]
edition = "2021"
description = "A modern Prolog implementation written mostly in Rust."
@@ -12,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]

View File

@@ -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();
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -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),
}
}

View File

@@ -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(())
}

View 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 = "*"

View File

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

View File

@@ -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
View 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!() }
);
}
}

View File

@@ -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
View File

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

View File

@@ -1,16 +1,12 @@
fn main() {
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();
}

File diff suppressed because it is too large Load Diff

View File

@@ -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();

View File

@@ -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 {

View File

@@ -1,4 +1,4 @@
use prolog_parser::ast::*;
use crate::parser::ast::*;
use crate::forms::*;
use crate::instructions::*;
@@ -84,8 +84,8 @@ type VariableFixture<'a> = (VarStatus, Vec<&'a Cell<VarReg>>);
#[derive(Debug)]
pub(crate) struct VariableFixtures<'a> {
perm_vars: IndexMap<Rc<Var>, VariableFixture<'a>>,
last_chunk_temp_vars: IndexSet<Rc<Var>>,
perm_vars: IndexMap<Rc<String>, VariableFixture<'a>>,
last_chunk_temp_vars: IndexSet<Rc<String>>,
}
impl<'a> VariableFixtures<'a> {
@@ -96,11 +96,11 @@ impl<'a> VariableFixtures<'a> {
}
}
pub(crate) fn insert(&mut self, var: Rc<Var>, vs: VariableFixture<'a>) {
pub(crate) fn insert(&mut self, var: Rc<String>, vs: VariableFixture<'a>) {
self.perm_vars.insert(var, vs);
}
pub(crate) fn insert_last_chunk_temp_var(&mut self, var: Rc<Var>) {
pub(crate) fn insert_last_chunk_temp_var(&mut self, var: Rc<String>) {
self.last_chunk_temp_vars.insert(var);
}
@@ -115,7 +115,7 @@ impl<'a> VariableFixtures<'a> {
// Compute the conflict set of u.
// 1.
let mut use_sets: IndexMap<Rc<Var>, OccurrenceSet> = IndexMap::new();
let mut use_sets: IndexMap<Rc<String>, OccurrenceSet> = IndexMap::new();
for (var, &mut (ref mut var_status, _)) in self.iter_mut() {
if let &mut VarStatus::Temp(_, ref mut var_data) = var_status {
@@ -153,11 +153,11 @@ impl<'a> VariableFixtures<'a> {
}
}
fn get_mut(&mut self, u: Rc<Var>) -> Option<&mut VariableFixture<'a>> {
fn get_mut(&mut self, u: Rc<String>) -> Option<&mut VariableFixture<'a>> {
self.perm_vars.get_mut(&u)
}
fn iter_mut(&mut self) -> indexmap::map::IterMut<Rc<Var>, VariableFixture<'a>> {
fn iter_mut(&mut self) -> indexmap::map::IterMut<Rc<String>, VariableFixture<'a>> {
self.perm_vars.iter_mut()
}
@@ -218,11 +218,11 @@ impl<'a> VariableFixtures<'a> {
}
}
pub(crate) fn into_iter(self) -> indexmap::map::IntoIter<Rc<Var>, VariableFixture<'a>> {
pub(crate) fn into_iter(self) -> indexmap::map::IntoIter<Rc<String>, VariableFixture<'a>> {
self.perm_vars.into_iter()
}
fn values(&self) -> indexmap::map::Values<Rc<Var>, VariableFixture<'a>> {
fn values(&self) -> indexmap::map::Values<Rc<String>, VariableFixture<'a>> {
self.perm_vars.values()
}

View File

@@ -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,41 +262,25 @@ 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,
@@ -307,29 +288,45 @@ impl OpDecl {
}
}
pub(crate) fn insert_into_op_dir(&self, op_dir: &mut OpDir) -> Option<(usize, Specifier)> {
let key = (self.name.clone(), self.fixity());
match op_dir.get(&key) {
impl OpDecl {
#[inline]
pub(crate) fn new(op_desc: OpDesc, name: Atom) -> Self {
Self { op_desc, name }
}
#[inline]
pub(crate) fn remove(&mut self, op_dir: &mut OpDir) {
let prec = self.op_desc.get_prec();
self.op_desc.set(0, self.op_desc.get_spec());
self.insert_into_op_dir(op_dir);
self.op_desc.set(prec, self.op_desc.get_spec());
}
pub(crate) fn insert_into_op_dir(&self, op_dir: &mut OpDir) -> Option<OpDesc> {
let key = (self.name, fixity(self.op_desc.get_spec() as u32));
match op_dir.get_mut(&key) {
Some(cell) => {
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.
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,33 +1,20 @@
use prolog_parser::ast::*;
use 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);
}
_ => {}
}

View File

@@ -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)])
}
}
}

View File

@@ -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)
}

View File

@@ -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;

View File

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

View File

@@ -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) :-

View File

@@ -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) :-

View File

@@ -14,7 +14,7 @@
partial_string_tail/2,
setup_call_cleanup/3,
call_nth/2,
variant/2,
% variant/2,
copy_term_nat/2]).
:- use_module(library(error), [can_be/2,
@@ -22,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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -1,5 +1,6 @@
use crate::machine::machine_indices::*;
use crate::atom_table::*;
use crate::machine::stack::*;
use crate::types::*;
use std::mem;
use std::ops::IndexMut;
@@ -7,20 +8,24 @@ use std::ops::IndexMut;
type Trail = Vec<(Ref, HeapCellValue)>;
#[derive(Debug, Clone, Copy)]
pub(crate) enum AttrVarPolicy {
pub enum AttrVarPolicy {
DeepCopy,
StripAttributes,
}
pub(crate) trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
fn deref(&self, val: Addr) -> Addr;
fn push(&mut self, val: HeapCellValue);
pub trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
fn store(&self, value: HeapCellValue) -> HeapCellValue;
fn deref(&self, value: HeapCellValue) -> HeapCellValue;
fn push(&mut self, value: HeapCellValue);
fn stack(&mut self) -> &mut Stack;
fn store(&self, val: Addr) -> Addr;
fn threshold(&self) -> usize;
}
pub(crate) fn copy_term<T: CopierTarget>(target: T, addr: Addr, attr_var_policy: AttrVarPolicy) {
pub(crate) fn copy_term<T: CopierTarget>(
target: T,
addr: HeapCellValue,
attr_var_policy: AttrVarPolicy,
) {
let mut copy_term_state = CopyTermState::new(target, attr_var_policy);
copy_term_state.copy_term_impl(addr);
}
@@ -47,50 +52,51 @@ impl<T: CopierTarget> CopyTermState<T> {
#[inline]
fn value_at_scan(&mut self) -> &mut HeapCellValue {
let scan = self.scan;
&mut self.target[scan]
&mut self.target[self.scan]
}
fn trail_list_cell(&mut self, addr: usize, threshold: usize) {
let trail_item = mem::replace(
&mut self.target[addr],
HeapCellValue::Addr(Addr::Lis(threshold)),
);
self.trail.push((Ref::HeapCell(addr), trail_item));
let trail_item = mem::replace(&mut self.target[addr], list_loc_as_cell!(threshold));
self.trail.push((Ref::heap_cell(addr), trail_item));
}
fn copy_list(&mut self, addr: usize) {
for offset in 0..2 {
if let Addr::Lis(h) = self.target[addr + offset].as_addr(addr + offset) {
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

File diff suppressed because it is too large Load Diff

View File

@@ -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<'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;
impl TryFrom<HeapCellValue> for Literal {
type Error = ();
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

View File

@@ -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),
/*
read_heap_cell!(
(HeapCellValueTag::AttrVar, n) => {
}
(HeapCellValueTag::Lis, n) => {
}
(HeapCellValueTag::Var, n) => {
}
(HeapCellValueTag::Str, n) => {
}
(HeapCellValueTag::PStrOffset, n) => {
}
_ => {
}
)
*/
impl Ref {
pub(crate) fn as_addr(self) -> Addr {
match self {
Ref::AttrVar(h) => Addr::AttrVar(h),
Ref::HeapCell(h) => Addr::HeapCell(h),
Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc),
}
impl 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
View 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)));
}
}

View File

@@ -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

View File

@@ -1,12 +1,10 @@
use prolog_parser::ast::*;
use prolog_parser::tabled_rc::*;
use prolog_parser::{atom, clause_name, rc_atom};
use crate::atom_table::*;
use crate::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,
)?)?;

View File

@@ -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;
if base < self.buf.ptr as usize {
self.buf.ptr = base as *mut _;
}
}
}
#[inline]
fn inner_truncate(&mut self, b: usize) {
let base = b + self.buf.base as usize;
#[cfg(test)]
mod tests {
use super::*;
if base < self.buf.top as usize {
self.buf.top = base as *const _;
}
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));
}
pub(crate) fn drop_in_place(&mut self) {
self.truncate(mem::align_of::<Addr>());
and_frame[5] = empty_list_as_cell!();
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>()
});
assert_eq!(and_frame[5], empty_list_as_cell!());
let b = wam.machine_st.stack.allocate_or_frame(5);
let or_frame = wam.machine_st.stack.index_or_frame_mut(b);
for idx in 0..5 {
assert_eq!(or_frame[idx], stack_loc_as_cell!(OrFrame, b, idx));
}
let next_e = wam.machine_st.stack.allocate_and_frame(9); // create an AND frame!
let and_frame = wam.machine_st.stack.index_and_frame_mut(next_e);
for idx in 0..9 {
assert_eq!(and_frame[idx + 1], stack_loc_as_cell!(AndFrame, next_e, idx + 1));
}
let and_frame = wam.machine_st.stack.index_and_frame(e);
assert_eq!(and_frame[5], empty_list_as_cell!());
assert_eq!(
wam.machine_st.stack[stack_loc!(AndFrame, e, 5)],
empty_list_as_cell!()
);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -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())
macro_rules! ar_reg {
($r: expr) => {
ArithmeticTerm::Reg($r)
};
}
&Constant::Char(c) => {
HeapCellValue::Addr(Addr::Char(c))
}
&Constant::Fixnum(n) => {
HeapCellValue::Addr(Addr::Fixnum(n))
}
&Constant::Integer(ref n) => {
HeapCellValue::Integer(n.clone())
}
&Constant::Rational(ref r) => {
HeapCellValue::Rational(r.clone())
}
&Constant::Float(f) => {
HeapCellValue::Addr(Addr::Float(f))
}
&Constant::String(ref s) => {
let len: usize = $aux_lens.iter().sum();
let h = len + $arity + 1 + $addendum.h() + $over_h;
$addendum.put_complete_string(&s);
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
}};
}
&Constant::Usize(u) => {
HeapCellValue::Addr(Addr::Usize(u))
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::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
View 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
View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

105
src/raw_block.rs Normal file
View File

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

View File

@@ -1,24 +1,59 @@
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);
parser.devour_whitespace()?;
inner.add_lines_read(parser.lines_read());
parser.eof()
}
pub(crate) fn read(
&mut self,
mut inner: Stream,
op_dir: &OpDir,
) -> Result<TermWriteResult, ParserError> {
let (term, num_lines_read) = {
let prior_num_lines_read = inner.lines_read();
let mut parser = Parser::new(inner, self);
parser.add_lines_read(prior_num_lines_read);
let term = parser.read_term(&CompositeOpDir::new(op_dir, None))?;
(term, parser.lines_read() - prior_num_lines_read)
};
inner.add_lines_read(num_lines_read);
Ok(write_term_to_heap(&term, &mut self.heap, &mut self.atom_tbl))
}
}
static mut PROMPT: bool = false;
@@ -41,6 +76,12 @@ pub mod readline {
}
}
#[inline]
pub fn input_stream(arena: &mut Arena) -> Stream {
let input_stream = ReadlineStream::new("");
Stream::from_readline_stream(input_stream, arena)
}
#[derive(Debug)]
pub struct ReadlineStream {
rl: Editor<()>,
@@ -49,32 +90,26 @@ pub mod readline {
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,51 +141,32 @@ 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"));
}
_ => {}
},
}
}
@@ -160,95 +176,86 @@ pub mod readline {
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,
Ok(0) => {
self.call_readline()?;
self.pending_input.read(buf)
}
result => result
}
}
}
#[inline]
pub fn input_stream() -> Stream {
let input_stream = ReadlineStream::input_stream(String::from(""));
Stream::from(input_stream)
impl CharRead for ReadlineStream {
fn peek_char(&mut self) -> Option<std::io::Result<char>> {
loop {
let pos = self.pending_input.position() as usize;
match self.pending_input.get_ref()[pos ..].chars().next() {
Some('\u{0}') => {
return Some(Ok('\u{0}'));
}
Some(c) => {
return Some(Ok(c));
}
None => {
match self.call_readline() {
Err(e) => {
return Some(Err(e));
}
Ok(0) => {
self.pending_input.get_mut().push('\u{0}');
return Some(Ok('\u{0}'));
}
_ => {
set_prompt(false);
}
}
}
}
}
}
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);
parser.devour_whitespace()?;
inner.add_lines_read(parser.num_lines_read());
let result = parser.eof();
let buf = stream.take_buf();
inner.pause_stream(buf)?;
result
fn consume(&mut self, nread: usize) {
let offset = self.pending_input.position() as usize;
self.pending_input.set_position((offset + nread) as u64);
}
pub(crate) fn read(
&mut self,
mut inner: Stream,
atom_tbl: TabledData<Atom>,
op_dir: &OpDir,
) -> Result<TermWriteResult, ParserError> {
let mut stream = parsing_stream(inner.clone())?;
let (term, num_lines_read) = {
let prior_num_lines_read = inner.lines_read();
let mut parser = Parser::new(&mut stream, atom_tbl, self.flags);
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 {

View File

@@ -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 {

View File

@@ -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
View 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)
}
}
}

View File

@@ -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()),
}
}
}

View File

@@ -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";